protected string GetTypeLibrary() { string typeLibKey = string.Format(CultureInfo.InvariantCulture, @"TYPELIB\{0}\{1}\{2}\win32", TypeLibGuid, TypeLibVersion, TypeLibLocale); using (RegistryKey registryKey = Registry.ClassesRoot.OpenSubKey(typeLibKey)) { // TODO: if there's no direct match, then use a type library // with the same major version, and the highest minor version // TODO: check if the library identifier matches the one of the // reference if (registryKey == null) { throw CreateTypeLibraryNotRegisteredException(); } string typeLibValue = (string)registryKey.GetValue(null); if (StringUtils.IsNullOrEmpty(typeLibValue)) { throw CreateInvalidTypeLibraryRegistrationException(); } // extract path to type library from reg value string typeLibPath = TlbImpTask.ExtractTypeLibPath(typeLibValue); // check if the typelib actually exists if (!File.Exists(typeLibPath)) { throw CreateTypeLibraryPathDoesNotExistException(typeLibPath); } return(typeLibValue); } }
protected override void ImportTypeLibrary() { TlbImpTask tlbImp = new TlbImpTask(); // parent is solution task tlbImp.Parent = SolutionTask; // inherit project from solution task tlbImp.Project = SolutionTask.Project; // inherit namespace manager from solution task tlbImp.NamespaceManager = SolutionTask.NamespaceManager; // inherit verbose setting from solution task tlbImp.Verbose = SolutionTask.Verbose; // make sure framework specific information is set tlbImp.InitializeTaskConfiguration(); tlbImp.TypeLib = new FileInfo(GetTypeLibrary()); tlbImp.OutputFile = new FileInfo(WrapperAssembly); // use other imported type libraries to resolve references // // there's one serious limitation in the current implementation: // // if type library A references type library B, then we should // first import type library B and use a reference to that // imported type library when we import type library A. // // however, we have no way to find out in which order the type // libraries should be imported. So only if type library B is // first listed in the project file, it will work fine. // // we should find a way to analyse a type library to determine // dependencies on other type libraries // // according to JR ([email protected]) a possible // solution could be to "use TypeLibConverter.ConvertTypeLibToAssembly. // This has a callback of type ITypeLibImporterNotifySink, which I // speculate allows one to recognize when one type library // depends on another. I believe what you have to do is start // with an arbitrary type library, and if that type library calls // back on the ResolveRef() method, and if that type library is // one you were planning to add later, you compile it // immediately and pass the assembly back out of ResolveRef. I // haven't tested this yet, but it's my best understanding of // how it all works. foreach (ReferenceBase reference in Parent.References) { // we're only interested in imported type libraries WrapperReferenceBase wrapper = reference as WrapperReferenceBase; // avoid stack overflow causes by mutual dependencies if (wrapper == null || !wrapper.IsCreated || wrapper.WrapperTool != "tlbimp") { continue; } tlbImp.References.Includes.Add(wrapper.WrapperAssembly); } // increment indentation level tlbImp.Project.Indent(); try { // execute task tlbImp.Execute(); } finally { // restore indentation level tlbImp.Project.Unindent(); } }
protected override void ImportTypeLibrary() { TlbImpTask tlbImp = new TlbImpTask(); // parent is solution task tlbImp.Parent = SolutionTask; // inherit project from solution task tlbImp.Project = SolutionTask.Project; // inherit namespace manager from solution task tlbImp.NamespaceManager = SolutionTask.NamespaceManager; // inherit verbose setting from solution task tlbImp.Verbose = SolutionTask.Verbose; // make sure framework specific information is set tlbImp.InitializeTaskConfiguration(); tlbImp.TypeLib = new FileInfo(GetTypeLibrary()); tlbImp.OutputFile = new FileInfo(WrapperAssembly); tlbImp.Namespace = TypeLibraryName; // according to "COM Programming with Microsoft .NET" (page 59) // the /sysarray option should always be set in order to // generate wrappers that match those generated by VS.NET tlbImp.SysArray = true; // transform [out, retval] parameters of methods on dispatch-only // interfaces (dispinterfaces) into return values. // // this only affects .NET 1.1 or higher, as tlbimp does not expose // this on .NET 1.0. tlbImp.Transform = "dispret"; // use other imported type libraries to resolve references // // there's one serious limitation in the current implementation: // // if type library A references type library B, then we should // first import type library B and use a reference to that // imported type library when we import type library A. // // however, we have no way to find out in which order the type // libraries should be imported. So only if type library B is // first listed in the project file, it will work fine. // // we should find a way to analyse a type library to determine // dependencies on other type libraries // // according to JR ([email protected]) a possible // solution could be to "use TypeLibConverter.ConvertTypeLibToAssembly. // This has a callback of type ITypeLibImporterNotifySink, which I // speculate allows one to recognize when one type library // depends on another. I believe what you have to do is start // with an arbitrary type library, and if that type library calls // back on the ResolveRef() method, and if that type library is // one you were planning to add later, you compile it // immediately and pass the assembly back out of ResolveRef. I // haven't tested this yet, but it's my best understanding of // how it all works. foreach (ReferenceBase reference in Parent.References) { // we're only interested in imported type libraries WrapperReferenceBase wrapper = reference as WrapperReferenceBase; // avoid stack overflow causes by mutual dependencies if (wrapper == null || !wrapper.IsCreated || wrapper.WrapperTool != "tlbimp") { continue; } tlbImp.References.Includes.Add(wrapper.WrapperAssembly); } if (ProjectSettings.AssemblyOriginatorKeyFile != null) { tlbImp.KeyFile = new FileInfo(FileUtils.CombinePaths(Parent.ProjectDirectory.FullName, ProjectSettings.AssemblyOriginatorKeyFile)); } if (ProjectSettings.AssemblyKeyContainerName != null) { tlbImp.KeyContainer = ProjectSettings.AssemblyKeyContainerName; } // increment indentation level tlbImp.Project.Indent(); try { // execute task tlbImp.Execute(); } finally { // restore indentation level tlbImp.Project.Unindent(); } }