How-To: Dynamically Invoke C++ DLL Function in C#?

March 1st, 2010 One Commented

I decided to share this topic when I came across the need to register a ActiveX COM DLL in C#. Of course, we can use the readily available program, RegSvr32.exe. Initially, I used that too.

RegSvr32.exe < MyCom.dll > /s

The parameter “/s” restricts any display of message boxes from the application. It’s true that we don’t want our program to pop-up a message stating

DllRegsiterServer in < MyCom.dll > succeeded.

and wait for the user to click the OK button. Legally, it’s fine but unacceptable in the eyes of the UI designers, furthermore, we may want to hide the fact that we are calling RegSvr32 from our users.

Unfortunately, the “/s” parameter also poses a problem, especially when errors occurred. The error is hidden from us and there is no way for us to be aware of that. This could lead to some problems which I experienced.

Therefore, I was motivated to write a piece of small code to dynamically invoke C++ function in C#. The example code below shows how to register an ActiveX COM DLL. I added some checking too, of course, to prevent crashes.

using System;
using System.Runtime.InteropServices;

class Program
{
    // Static invocations.
    [DllImport("kernel32.dll")]
    extern static int LoadLibrary(String strLib);

    [DllImport("kernel32.dll")]
    extern static int FreeLibrary(int iModule);

    [DllImport("kernel32.dll")]
    extern static IntPtr GetProcAddress(int iModule, String strProcName);

    // Delegate method.
    delegate int MyFunc();

    static void Main(string[] args)
    {
        String strDLL = "MyCOM.dll";
        // Load the DLL library.
        int iModule = LoadLibrary(strDLL);
        if (iModule == 0)
        {
            // Handle the error here.
            Console.WriteLine("Failed to load [" + strDLL + "].");
            return;
        }

        // Retrieve the function pointer.
        IntPtr pProc = GetProcAddress(iModule, "DllRegisterServer");
        if ((int)pProc == 0)
        {
            // Handle the error here.
            Console.WriteLine("Failed to retrieve function [DllRegisterServer]");
        }
        else
        {
            // Convert the function pointer to delegate method.
            MyFunc pFunc = (MyFunc)Marshal.GetDelegateForFunctionPointer(pProc, typeof(MyFunc));

            // Execute the function.
            int iRes = pFunc();
            if (iRes != 0)
            {
                // Handle the error here.
                Console.WriteLine("Fail to execute function DllRegisterServer.");
            }
            else
            {
                // Handle the success here.
                Console.WriteLine("DLL [" + strDLL + "] registered successfully.");
            }
        }

        // Unload the DLL library.
        FreeLibrary(iModule);
    }
}

I included some DllImport attributes for callling the unmanaged WIN32 API functions, LoadLibrary(), FreeLibrary() and GetProcAddress(). Also, we need to add a delegate method. A delegate is a type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. As DllRegisterServer funtion declaration is as the following,

HRESULT __stdcall DllRegisterServer(void);

we declare our delegate similar to it.

delegate int MyFunc();

The code is very simple. In this case, I called the LoadLibrary() and GetProcAdress() to get the function pointer. If you are familiar with WIN32 programming, you’ll know them. Next, I did a conversion of the unmanaged function pointer to a delegate to be called by C# using the Marshal.GetDelegateForFunctionPointer(). After the conversion, we can just execute it. Lastly, remember to call FreeLibrary() to ensure the memory is released. As you can see, the delegate method returns a value which I can use for checking. Thus, my problem is solved.

Also, by doing some code massaging, you can also use it to load other functions of unmanaged WIN32 DLL dynamically. It depends how you code it.

Of course, one may argue that this can be done with static invocation. Yes, if the DLL location is fixed. What if its location is determined by the user during runtime? This is when the dynamic invocation is preferred.

I also include a code-snippet of the C++ version for those who are interested to know.

HINSTANCE hInstLib = LoadLibrary(TEXT("MyCom.dll"));
if(hInstLib == NULL)
{
    // Handle error.
}
else
{
    typedef HRESULT (STDAPICALLTYPE * MyFunc)(void);
    MyFunc fn = (MyFunc)GetProcAddress(hInstLib, "DllRegisterServer");
    if(fn != NULL)
    {
        // Handle error here.
    }
    else
    {
        HRESULT hr = fn();
        if(SUCCEEDED(hr))
        {
            // Handle success here.
        }
        else
        {
            // Handle error here.
        }
    }
	
    FreeLibrary(hInstLib);
}

I hope you’ll find this helpful. :)

Tags:
, , , , ,

One response to “How-To: Dynamically Invoke C++ DLL Function in C#?”

  1. divinelight says:

    I used this method about half year ago, when I need to use COM for my .net application. Google is your best friend ^^

    Hope your tutorial posted on google too, it’s great for people who searched for this.

Leave a Reply


9 − five =