[转]Programmatically Register Assemblies in C#.

时间:2021-10-05 08:40:29

标签:

1. Introduction.

1.1 After publishing Programmatically Register COM Dlls in C# back in 2011, I received a number of requests for advise on how to register managed assemblies as COM servers.

1.2 In this blog, I will present the reader with a sample C# program that will perform such registration.

1.3 The sample assembly COM-registration source codes can be used to target 32-bit and 64-bit assemblies.

1.4 I will also provide 2 sets of programs (one 32-bit and the other 64-bit) for testing.

2. The Assembly Registration Program.

2.1 The full source codes for this article can be found here in CodePlex.

2.1 Shown below is a partial listing of the source codes for the program :

// Program.cs // Main control source codes. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Collections; using System.Collections.Specialized; using System.Reflection; using System.IO; namespace RegisterAssembly {     // The managed definition of the ICreateTypeLib interface.     [ComImport()]     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]     [Guid("00020406-0000-0000-C000-000000000046")]     public interface ICreateTypeLib     {         IntPtr CreateTypeInfo(string szName, System.Runtime.InteropServices.ComTypes.TYPEKIND tkind);         void SetName(string szName);         void SetVersion(short wMajorVerNum, short wMinorVerNum);         void SetGuid(ref Guid guid);         void SetDocString(string szDoc);         void SetHelpFileName(string szHelpFileName);         void SetHelpContext(int dwHelpContext);         void SetLcid(int lcid);         void SetLibFlags(uint uLibFlags);         void SaveAllChanges();     }     partial class Program     {         // Command line options.         const string TYPELIB = "TYPELIB";         const string CODE_BASE = "CODE_BASE";         const string VERBOSE = "VERBOSE";         const string UNREGISTER = "UNREGISTER";         // Windows API to register a COM type library.         [DllImport("Oleaut32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]         public extern static UInt32 RegisterTypeLib(ITypeLib tlib, string szFullPath, string szHelpDir);         [DllImport("Oleaut32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]         public extern static UInt32 UnRegisterTypeLib(ref Guid libID, UInt16 wVerMajor, UInt16 wVerMinor, int lcid, System.Runtime.InteropServices.ComTypes.SYSKIND syskind);         public static bool Is32Bits()         {             if (IntPtr.Size == 4)             {                 // 32-bit                 return true;             }             return false;         }         public static bool Is64Bits()         {             if (IntPtr.Size == 8)             {                 // 64-bit                 return true;             }             return false;         }         static void DisplayUsage()         {             Console.WriteLine("Usage :");             Console.WriteLine("RegisterAssembly [CODE_BASE] [CREATE_TYPELIB] [VERBOSE] [UNREGISTER] <path to managed assembly file>");             Console.WriteLine("where CODE_BASE, CREATE_TYPELIB, VERBOSE, UNREGISTER are optional parameters");             Console.WriteLine("Note that the UNREGISTER parameter cannot be used with the CODE_BASE or the CREATE_TYPELIB parameters.");             Console.WriteLine();         }         static bool ProcessArguments(string[] args)         {             const int iCountMinimumParametersRequired = 1;             if (args == null)             {                 Console.WriteLine(string.Format("Invalid number of parameters."));                 return false;             }             if (args.Length < iCountMinimumParametersRequired)             {                 Console.WriteLine(string.Format("Invalid number of parameters (minimum parameters : [{0:D}]).",                     iCountMinimumParametersRequired));                 return false;             }             for (int i = 0; i < args.Length; i++)             {                 switch (args[i].Trim())                 {                     case TYPELIB:                         {                             m_bTypeLib = true;                             break;                         }                     case CODE_BASE:                         {                             m_bCodeBase = true;                             break;                         }                     case VERBOSE:                         {                             m_bVerbose = true;                             break;                         }                     case UNREGISTER:                         {                             m_bUnregister = true;                             break;                         }                     default:                         {                             if (string.IsNullOrEmpty(m_strTargetAssemblyFilePath))                             {                                 m_strTargetAssemblyFilePath = args[i].Trim();                                 break;                             }                             else                             {                                 Console.WriteLine(string.Format("Invalid parameter : [{0:S}].", args[i]));                                 return false;                             }                         }                 }             }             if (m_bUnregister)             {                 if (m_bCodeBase)                 {                     Console.WriteLine(string.Format("UNEGISTER flag cannot be used with the CODE_BASE flag."));                     return false;                 }             }             return true;         }                 static bool DoWork()         {             try             {                 if (m_bVerbose)                 {                     Console.WriteLine(string.Format("Target Assembly File : [{0:S}].", m_strTargetAssemblyFilePath));                 }                 if (m_bUnregister)                 {                     if (PerformAssemblyUnregistration(m_strTargetAssemblyFilePath) == false)                     {                         return false;                     }                                          if (m_bTypeLib == true)                     {                         return PerformTypeLibUnRegistration(m_strTargetAssemblyFilePath);                     }                     else                     {                         return true;                     }                 }                 else                 {                     if (PerformAssemblyRegistration(m_strTargetAssemblyFilePath, m_bCodeBase) == false)                     {                         return false;                     }                     if (m_bTypeLib == true)                     {                         return PerformTypeLibCreationAndRegistration(m_strTargetAssemblyFilePath);                     }                     else                     {                         return true;                     }                 }             }             catch (Exception ex)             {                 Console.WriteLine(string.Format("An exception occurred. Exception description : [{0:S}].", ex.Message));                 return false;             }         }         static void Main(string[] args)         {             if (ProcessArguments(args) == false)             {                 DisplayUsage();                 return;             }             if (ReadConfigSettings() == false)             {                 return;             }             DoWork();         }         public static bool m_bVerbose = false;         private static bool m_bTypeLib = false;         private static bool m_bCodeBase = false;         private static bool m_bUnregister = false;         private static string m_strTargetAssemblyFilePath = null;         private static ITypeLibExporterNotifySink m_pITypeLibExporterNotifySink = null;     } }

The program begins by inspecting its arguments (in ProcessArguments()).

Member variables are set according to the arguments.

If there is any error discovered inside ProcessArguments(), the program will display instructions on the program arguments and then the program will stop.

Next, via ReadConfigSettings(), the configuration file of the program is examined to check for the type to be created for the ITypeLibExporterNotifySink object (more on this later).

If ReadConfigSettings() encounters an error, a false will be returned and the program will end.

Otherwise,the DoWork() method will be called to perform the registration task.

The sections that follow will provide more details on the running process of the program.

2. The Arguments to the Program.

2.1 The program takes at minimum one parameter (i.e. the path to the assembly to be registered).

2.2 VERBOSE , UNREGISTER, CODE_BASE and TYPELIB are optional parameters which can be used in combination.

2.3 The VERBOSE option indicates to the program to display additional useful information at runtime.

2.4 Unless the UNREGISTER parameter is used, it is assumed that the program is to perform assembly un-registration.

2.3 The CODE_BASE parameter indicates that the assembly registration includes the assembly’s full path in the registry.

Note that this option cannot be used together with the UNREGISTER argument.

2.4 The presence of the TYPELIB argument indicates the following :

For assembly registration, an associated type library will be created and registered.

For assembly un-registration, the type library associated with the assembly will be un-registered.

3. PerformAssemblyRegistration().