Friday, July 31, 2009

DllRegisterServer w/o regsvr32

I have a need to register some COM DLLs from a C# program. Every example I found on the web used regsvr32 to perform the registration. This didn't make much sense to me as all regsvr32 does is call DllRegisterServer() exported in the DLL. So I worked out how to do the same from C# using P/Inovke and System.Runtime.InteropServices.

And here it is for you to use. This is a small sample but it compiles and registers the DLLs that are listed on the command line. Be sure to compile with the /unsafe switch. Also, I have more error checking and reporting in my application which I removed from this sample. Enjoy!

   1:  using System;
   2:  using System.Runtime.InteropServices;
   3:   
   4:  public class RegisterDll
   5:  {
   6:      unsafe internal delegate UInt32 DllRegisterServer();
   7:      
   8:      public static void Main(string[] args)
   9:      {
  10:          foreach (string file in args)
  11:          {
  12:              Console.WriteLine("Registering {0}", file);
  13:              RegisterCOMDll(file);
  14:          }
  15:   
  16:          Console.WriteLine("Done!");
  17:      }
  18:   
  19:      private static void RegisterCOMDll(string file)
  20:      {
  21:          IntPtr library = LoadLibraryEx(file, IntPtr.Zero, 0);
  22:          if (library == IntPtr.Zero)
  23:          {
  24:              string msg = "Unable to load '" + file + "' error is " + Marshal.GetLastWin32Error().ToString();
  25:              throw new ApplicationException(msg);
  26:          }
  27:   
  28:          IntPtr proc = GetProcAddress(library, "DllRegisterServer");
  29:          if (proc == IntPtr.Zero)
  30:          {
  31:              int err = Marshal.GetLastWin32Error();
  32:              string msg = "Unable to load 'DllRegisterServer' from '" + file + "' error is " + err.ToString();
  33:              throw new ApplicationException(msg);
  34:          }
  35:   
  36:          DllRegisterServer drs = (DllRegisterServer)Marshal.GetDelegateForFunctionPointer(proc, typeof(DllRegisterServer));
  37:          UInt32 result = drs();
  38:          if (result != 0)
  39:          {
  40:              string msg = "Error " + result.ToString() + " returned from DllRegisterServer in " + file;
  41:              throw new ApplicationException(msg);
  42:          }
  43:   
  44:          FreeLibrary(library);
  45:      }
  46:   
  47:      [Flags]
  48:      public enum LoadLibraryFlags : uint
  49:      {
  50:          DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
  51:          LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
  52:          LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
  53:          LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008,
  54:      }
  55:   
  56:      [DllImport("kernel32.dll", EntryPoint = "FreeLibrary", SetLastError = true)]
  57:      public static extern bool FreeLibrary(IntPtr hModule);
  58:   
  59:      [DllImport("kernel32.dll", EntryPoint = "LoadLibraryExW", CharSet = CharSet.Unicode, SetLastError = true)]
  60:      public static extern IntPtr LoadLibraryEx(
  61:          [MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
  62:          IntPtr hFile,
  63:          [MarshalAs(UnmanagedType.U4)] LoadLibraryFlags dwFlags);
  64:   
  65:      [DllImport("kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "GetProcAddress", ExactSpelling = true, SetLastError = true)]
  66:      public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
  67:  }