/// <summary> /// For a given type, analyze all the functions implemented by it. That means all the argument and return types. /// </summary> private void ScanDefinedFunctions(ITypeInfo typeInfo, TYPEATTR typeAttributes) { for (int definedFuncIndex = 0; definedFuncIndex < typeAttributes.cFuncs; definedFuncIndex++) { IntPtr funcDescHandleToRelease = IntPtr.Zero; try { ComReference.GetFuncDescForDescIndex(typeInfo, definedFuncIndex, out FUNCDESC funcDesc, out funcDescHandleToRelease); int offset = 0; // Analyze the argument types for (int paramIndex = 0; paramIndex < funcDesc.cParams; paramIndex++) { var elemDesc = (ELEMDESC)Marshal.PtrToStructure( new IntPtr(funcDesc.lprgelemdescParam.ToInt64() + offset), typeof(ELEMDESC)); AnalyzeElement(typeInfo, elemDesc); offset += Marshal.SizeOf <ELEMDESC>(); } // Analyze the return value type AnalyzeElement(typeInfo, funcDesc.elemdescFunc); } finally { if (funcDescHandleToRelease != IntPtr.Zero) { typeInfo.ReleaseFuncDesc(funcDescHandleToRelease); } } } }
/// <summary> /// Initialize the object with type library attributes /// </summary> internal bool InitializeWithTypeLibAttrs(TaskLoggingHelper log, bool silent, TYPELIBATTR tlbAttr, ITaskItem originalTaskItem, string targetProcessorArchitecture) { TYPELIBATTR remappableTlbAttr = tlbAttr; ComReference.RemapAdoTypeLib(log, silent, ref remappableTlbAttr); // for attribute references, the path is not specified, so we need to get it from the registry if (!ComReference.GetPathOfTypeLib(log, silent, ref remappableTlbAttr, out this.fullTypeLibPath)) { return(false); } // Now that we have the path, we can call InitializeWithPath to get the correct TYPELIBATTR set up // and the correct ITypeLib pointer. return(InitializeWithPath(log, silent, this.fullTypeLibPath, originalTaskItem, targetProcessorArchitecture)); }
/// <summary> /// Analyze the given type looking for dependencies on other type libraries /// </summary> /// <param name="typeInfo"></param> private void AnalyzeTypeInfo(ITypeInfo typeInfo) { ITypeLib containingTypeLib = null; try { typeInfo.GetContainingTypeLib(out containingTypeLib, out int indexInContainingTypeLib); ComReference.GetTypeLibAttrForTypeLib(ref containingTypeLib, out TYPELIBATTR containingTypeLibAttributes); // Have we analyzed this type info already? If so skip it. var typeInfoId = new AnalyzedTypesInfoKey( containingTypeLibAttributes.guid, containingTypeLibAttributes.wMajorVerNum, containingTypeLibAttributes.wMinorVerNum, containingTypeLibAttributes.lcid, indexInContainingTypeLib); // Get enough information about the type to figure out if we want to register it as a dependency ComReference.GetTypeAttrForTypeInfo(typeInfo, out TYPEATTR typeAttributes); // Is it one of the types we don't care about? if (!CanSkipType(typeInfo, containingTypeLib, typeAttributes, containingTypeLibAttributes)) { _dependencies.Add(containingTypeLibAttributes); if (_analyzedTypes.Add(typeInfoId)) { // We haven't already analyzed this type, so rescan ScanImplementedTypes(typeInfo, typeAttributes); ScanDefinedVariables(typeInfo, typeAttributes); ScanDefinedFunctions(typeInfo, typeAttributes); } } // Make sure if we encounter this type again, we won't rescan it, since we already know we can skip it else { _analyzedTypes.Add(typeInfoId); } } finally { if (containingTypeLib != null) { _marshalReleaseComObject(containingTypeLib); } } }
/// <summary> /// For a given type, analyze all the variables defined by it /// </summary> private void ScanDefinedVariables(ITypeInfo typeInfo, TYPEATTR typeAttributes) { for (int definedVarIndex = 0; definedVarIndex < typeAttributes.cVars; definedVarIndex++) { IntPtr varDescHandleToRelease = IntPtr.Zero; try { ComReference.GetVarDescForVarIndex(typeInfo, definedVarIndex, out VARDESC varDesc, out varDescHandleToRelease); AnalyzeElement(typeInfo, varDesc.elemdescVar); } finally { if (varDescHandleToRelease != IntPtr.Zero) { typeInfo.ReleaseVarDesc(varDescHandleToRelease); } } } }
/// <summary> /// Initialize the object with a type library path /// </summary> internal bool InitializeWithPath(TaskLoggingHelper log, bool silent, string path, ITaskItem originalTaskItem, string targetProcessorArchitecture) { ErrorUtilities.VerifyThrowArgumentNull(path, "path"); this.taskItem = originalTaskItem; // Note that currently we DO NOT remap file ADO references. This is because when pointing to a file on disk, // it seems unnatural to remap it to something else - a file reference means "use THIS component". // This is still under debate though, and may be revised later. // save both the stripped and full path in our object -- for the most part we just need the stripped path, but if // we're using tlbimp.exe, we need to pass the full path w/ type lib number to it, or it won't generate the interop // assembly correctly. this.fullTypeLibPath = path; this.strippedTypeLibPath = ComReference.StripTypeLibNumberFromPath(path, File.Exists); // use the unstripped path to actually load the library switch (targetProcessorArchitecture) { case ProcessorArchitecture.AMD64: case ProcessorArchitecture.IA64: this.typeLibPointer = (ITypeLib)NativeMethods.LoadTypeLibEx(path, (int)NativeMethods.REGKIND.REGKIND_LOAD_TLB_AS_64BIT); break; case ProcessorArchitecture.X86: this.typeLibPointer = (ITypeLib)NativeMethods.LoadTypeLibEx(path, (int)NativeMethods.REGKIND.REGKIND_LOAD_TLB_AS_32BIT); break; case ProcessorArchitecture.ARM: case ProcessorArchitecture.MSIL: default: // Transmit the flag directly from the .targets files and rely on tlbimp.exe to produce a good error message. this.typeLibPointer = (ITypeLib)NativeMethods.LoadTypeLibEx(path, (int)NativeMethods.REGKIND.REGKIND_NONE); break; } try { // get the type lib attributes from the retrieved interface pointer. // do NOT remap file ADO references, since we'd end up with a totally different reference than specified. ComReference.GetTypeLibAttrForTypeLib(ref this.typeLibPointer, out this.attr); // get the type lib name from the retrieved interface pointer if (!ComReference.GetTypeLibNameForITypeLib( log, silent, this.typeLibPointer, GetTypeLibId(log), out this.typeLibName)) { ReleaseTypeLibPtr(); return(false); } } catch (COMException) { ReleaseTypeLibPtr(); throw; } return(true); }