C# Source Code: Registering COM components using reflection (C# equivalent of Regsvr32.exe)
[
Home
|
Contents
|
Search
|
Reply
| Previous | Next ]
C# Source Code
Registering COM components using reflection (C# equivalent of Regsvr32.exe)
By:
Andrew Baker
Email (spam proof):
Email the originator of this post
Date:
Wednesday, August 17, 2005
Hits:
4383
Category:
Attributes/Reflection/Debugging
Article:
Below is a useful utility class for registering and unregistering COM components. This uses reflection to perform the same functionality as the Regsvr32.exe command line tool. using System; using System.Collections.Specialized; using System.IO; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; namespace VBusers.Utils.COM { ///
/// Thread safe class to register COM components. ///
///
/// // Create new ComRegister object /// ComRegister reg = new ComRegister( @"C:\MyDll.dll" ); /// // Register the dll /// reg.Register(); /// // Unregister the dll /// reg.Unregister(); ///
public class ComRegister { #region Win32 Api Calls ///
/// Loads and registers a type library. ///
[ DllImport("oleaut32.dll", EntryPoint = "LoadTypeLib", CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true) ] private static extern int LoadTypeLib ( string filename, [MarshalAs(UnmanagedType.IUnknown)]ref object pTypeLib ); ///
/// Adds information about a type library to the system registry. ///
[ DllImport("oleaut32.dll", EntryPoint = "RegisterTypeLib", CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true) ] private static extern int RegisterTypeLib ( [MarshalAs(UnmanagedType.IUnknown)] object pTypeLib, string fullpath, string helpdir ); ///
/// The LoadLibrary function maps the specified executable module into the address space of the calling process. ///
[ DllImport("Kernel32.dll", EntryPoint = "LoadLibrary", CharSet=System.Runtime.InteropServices.CharSet.Unicode, SetLastError=true) ] private static extern IntPtr LoadLibrary ( string fullpath ); ///
/// The FreeLibrary function decrements the reference count of the loaded dynamic-link library (DLL). When the reference count reaches zero, the module is unmapped from the address space of the calling process and the handle is no longer valid. ///
[ DllImport("Kernel32.dll", SetLastError=true) ] private static extern int FreeLibrary ( IntPtr hModule ); ///
/// The GetProcAddress function retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). ///
[ DllImport("Kernel32.dll", SetLastError=true) ] private static extern IntPtr GetProcAddress ( IntPtr handle, string lpprocname ); private const int WIN32ERROR_ProcNotFound = 127; private const int WIN32ERROR_FileNotFound = 2; #endregion Win32 Api Calls #region Private Variables private string _fileName = null; #endregion Private Variables #region Constructors ///
/// Default constructor. ///
public ComRegister() { } ///
/// Constructor that takes the filename of the component to register/unregister. ///
///
The file name of the component to register or unregister. public ComRegister( string filename ) { _fileName = filename; } #endregion Constructors #region Public Properties ///
///The name of the file to register/unregister. ///
public string FileName { get { return _fileName; } set { _fileName = value; } } #endregion Public Properties #region Public Methods ///
/// Registers the COM component. ///
public void Register() { switch(Path.GetExtension(_fileName).ToLower()) { case ".tlb": RegisterTypelib(_fileName, false); break; case ".exe": RegisterExeServer(_fileName, false); break; case ".dll":case ".ocx": RegisterDllServer(_fileName, false); break; default: RegisterDllServer(_fileName, false); break; } } ///
/// Unregisters the COM component. ///
public void Unregister() { Unregister(true); } ///
/// Unregisters the COM component. ///
///
Whether to throw an error if unregistration fails for .dll or .ocx. public void Unregister(bool raiseErrorOnFailure) { switch(Path.GetExtension(_fileName).ToLower()) { case ".tlb": RegisterTypelib(_fileName, true); break; case ".exe": RegisterExeServer(_fileName, true); break; case ".dll": case ".ocx": RegisterDllServer(_fileName, true, raiseErrorOnFailure); break; default: RegisterDllServer(_fileName, true, raiseErrorOnFailure); break; } } ///
/// Register an inproc COM server, usually a .dll or .ocx ///
///
The path to the component to register. ///
If true unregisters the component, else registers the component. public void RegisterDllServer(string path, bool unregister) { RegisterDllServer(path, unregister, true); } ///
/// Register an inproc COM server, usually a .dll or .ocx ///
///
The path to the component to register. ///
If true unregisters the component, else registers the component. ///
Whether to throw an error if unregistration fails. public void RegisterDllServer(string path, bool unregister, bool raiseErrorOnFailure) { IntPtr handle = new IntPtr(); handle = LoadLibrary( path ); int error = Marshal.GetLastWin32Error(); if ( handle.ToInt32() == 0 && error != 0 ) { throw new InvalidOperationException("Error loading dll : " + path); } string entryPoint = "DllRegisterServer"; string action = "register"; if ( unregister ) { entryPoint = "DllUnregisterServer"; action = "unregister"; } IntPtr address = GetProcAddress( handle, entryPoint ); error = Marshal.GetLastWin32Error(); if ( address.ToInt32() == 0 && error != 0 ) { FreeLibrary(handle); if (raiseErrorOnFailure) { string message = string.Format("Error {0}ing dll. {1} has no {2} function.", action, path, entryPoint ); throw new InvalidOperationException( message); } else { // Exit since we do not want to throw errors return; } } // Unload the library FreeLibrary(handle); error = Marshal.GetLastWin32Error(); try { // Do the actual registration here DynamicPInvoke.DynamicDllFuncInvoke(path, entryPoint ); } catch(Exception e) { string message = "Error during registration " + e.Message; throw new InvalidOperationException(message); } finally { if( handle.ToInt32() != 0) { // Need to call FreeLibrary a second time as the DynPInvoke added an extra ref FreeLibrary(handle); } } } ///
/// Register a COM type library ///
///
The path to the component to register. ///
If true unregisters the component, else registers the component. public void RegisterTypelib(string path, bool unregister) { object Typelib = new object(); int error = 0; // Load typelib LoadTypeLib(path, ref Typelib ); error = Marshal.GetLastWin32Error(); if (error != 0 || (Typelib == null) ) { throw new InvalidOperationException("Error loading typelib " + path); } if (unregister) { // TODO: need to get access to ITypeLib interface from c# } else { // Perform registration RegisterTypeLib( Typelib, path, null); error = Marshal.GetLastWin32Error(); if (error != 0) { throw new InvalidOperationException("Error registering typelib " + path); } } } ///
/// Register exe servers. ///
///
The path to the component to register. ///
If true unregisters the component, else registers the component. public void RegisterExeServer(string path, bool unregister) { // Create process with the /regserver flag Process process = new Process(); process.StartInfo.FileName = path; if ( unregister ) { process.StartInfo.Arguments = path + " /unregserver"; } else { process.StartInfo.Arguments = path + " /regserver"; } process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.UseShellExecute = false; process.StartInfo.WorkingDirectory = Path.GetDirectoryName(path); try { process.Start(); } catch (Exception e) { throw new InvalidOperationException(" Error Registering " + path + e.Message); } bool exited = process.WaitForExit(5000); // kill if it doesn't terminate after 5s if (!exited || ! process.HasExited) { process.Kill(); throw new InvalidOperationException(" Error " + path + " is not a COM server"); } // check for error output. COM exe servers should not ouput to stdio on register. StreamReader stdErr = process.StandardError; string errors = stdErr.ReadToEnd(); if (errors.Length > 0) { throw new InvalidOperationException(" Error " + path + " doesn't support the /regserver option" + Environment.NewLine + "Error: " + errors); } StreamReader stdOut = process.StandardOutput; string output = stdOut.ReadToEnd(); if (output.Length > 0) { throw new InvalidOperationException(" Error " + path + " doesn't support the /regserver option" + Environment.NewLine + "Error: " + output); } } #endregion Public Methods #region Private DynamicPInvoke Class ///
/// Helper class to synamically build an assembly with the correct P Invoke signature ///
private class DynamicPInvoke { ///
/// Dynamically calls a function in a dll ///
///
The filename containing the function to invoke. ///
The name of the method to call. ///
The result of the function call.
public static object DynamicDllFuncInvoke( string fileName, string methodName ) { Type returnType = typeof(int); Type [] parameterTypes = null; object[] parameterValues = null; // Create a dynamic assembly and a dynamic module AssemblyName asmName = new AssemblyName(); asmName.Name = "dllRegAssembly"; AssemblyBuilder dynamicAsm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); ModuleBuilder dynamicMod = dynamicAsm.DefineDynamicModule("tempModule"); // Dynamically construct a global PInvoke signature // using the input information MethodBuilder dynamicMethod = dynamicMod.DefinePInvokeMethod( methodName, fileName, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.PinvokeImpl, CallingConventions.Standard, returnType, parameterTypes, CallingConvention.Winapi, CharSet.Ansi); // This global method is now complete dynamicMod.CreateGlobalFunctions(); // Get a MethodInfo for the PInvoke method MethodInfo mi = dynamicMod.GetMethod(methodName); // Invoke the static method and return whatever it returns return mi.Invoke(null, parameterValues); } } #endregion Private DynamicPInvoke Class } }
Terms and Conditions
Support this site
Download a trial version of the best FTP application on the internet