//
you're reading...
Programming Issues/Tips

Programmatically Register COM Dlls in C#

1. Introduction.

1.1 Recently, someone from the MSDN forum asked for advise on how to programmatically register a COM DLL using managed code.

1.2 The answer is simple indeed : a COM DLL must export 2 APIs : DllRegisterServer() and DllUnregisterServer().

1.3 To register the DLL, the DLL is loaded (by the registration program, e.g. regsvr32.exe) and its DllRegisterServer() API is called.

1.4 To unregister the DLL, DllUnregisterServer() is called.

1.5 Using the above simple principle, any program (be it managed or unmanaged) can be written to perform registration/unregistration of a COM DLL.

1.6 I have written a small sample program below for the reader to study and try out.

2. Sample Code in C#.

2.1 The full program source code is listed below :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace COMRegistration
{
    class Program
    {
        // All COM DLLs must export the DllRegisterServer()
        // and the DllUnregisterServer() APIs for self-registration/unregistration.
        // They both have the same signature and so only one
        // delegate is required.
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate UInt32 DllRegUnRegAPI();

        [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string strLibraryName);

        [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        static extern Int32 FreeLibrary(IntPtr hModule);

        [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

        static void DisplayUsage()
        {
            Console.WriteLine("Usage : COMRegistration [/r or /u] [Path to DLL].");
        }

        static bool CheckArguments(string[] args, out bool bRegistration)
        {
            // Ensure that there are at least 2 arguments.
            if (args.Length < 2)
            {
                DisplayUsage();
                bRegistration = false;
                return false;
            }

            // We take the first argument as the path to the COM DLL to register/unregister.
            if (args[0] == "/r")
            {
                bRegistration = true;
                return true;
            }
            else if (args[0] == "/u")
            {
                bRegistration = false;
                return true;
            }
            else
            {
                Console.WriteLine("Invalid flag : {0:S}.", args[0]);
                DisplayUsage();
                bRegistration = false;
                return false;
            }
        }

        static void Main(string[] args)
        {
            // Boolean to determine if registration or unregistration
            // is required.
            bool bRegistration;

            // Check the arguments for correctness.
            // Note that if the path to the DLL contains spaces,
            // the path must be enclosed in quotations, e.g. :
            // "c:\my path\my dll.dll"
            if (CheckArguments(args, out bRegistration) == false)
            {
                return;
            }

            // Load the DLL.
            IntPtr hModuleDLL = LoadLibrary(args[1]); ;

            if (hModuleDLL == IntPtr.Zero)
            {
                Console.WriteLine("Unable to load DLL : {0:S}.", args[1]);
                DisplayUsage();
                return;
            }

            // Obtain the required exported API.
            IntPtr pExportedFunction = IntPtr.Zero;

            if (bRegistration)
            {
                pExportedFunction = GetProcAddress(hModuleDLL, "DllRegisterServer");
            }
            else
            {
                pExportedFunction = GetProcAddress(hModuleDLL, "DllUnregisterServer");
            }

            if (pExportedFunction == IntPtr.Zero)
            {
                Console.WriteLine("Unable to get required API from DLL.");
                return;
            }

            // Obtain the delegate from the exported function, whether it be
            // DllRegisterServer() or DllUnregisterServer().
            DllRegUnRegAPI pDelegateRegUnReg =
              (DllRegUnRegAPI)(Marshal.GetDelegateForFunctionPointer(pExportedFunction, typeof(DllRegUnRegAPI)))
              as DllRegUnRegAPI;

            // Invoke the delegate.
            UInt32 hResult = pDelegateRegUnReg();

            if (hResult == 0)
            {
                if (bRegistration)
                {
                    Console.WriteLine("Registration Successful.");
                }
                else
                {
                    Console.WriteLine("Unregistration Successful.");
                }
            }
            else
            {
                Console.WriteLine("Error occurred : {0:X}.", hResult);
            }

            FreeLibrary(hModuleDLL);
            hModuleDLL = IntPtr.Zero;
        }
    }
}

The above program can be compiled into a console application. The following are some pertinent points about the code above :

  • The DllRegisterServer() and the DllUnregisterServer() APIs have the same signature and so only one delegate (DllRegUnRegAPI()) is required.
  • It is possible that LoadLibrary() may fail on a DLL. This is if the DLL has dependencies (e.g. other DLLs) and these could not be loaded.
  • Note one important point on using the above program : if the path to the DLL contains spaces, the path must be enclosed in quotations, e.g. : “c:\my path\my dll.dll”.

 

About these ads

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.

Discussion

3 thoughts on “Programmatically Register COM Dlls in C#

  1. brilliant many thanks, much better way of doing this over the obvious answer of making a call to regsvr32 from within the code using the Process class.

    Posted by steve | May 6, 2012, 7:04 am
  2. good day! is the code applicable to custom made dll?

    Posted by RRM | September 12, 2013, 8:43 am

Trackbacks/Pingbacks

  1. Pingback: How To Fix Dllunregisterserver Clr Error Errors - Windows Vista, Windows 7 & 8 - November 17, 2014

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: