1

I'm writing a proxy library (called Library A) that is just an interface to another DLL (called Library B) that may be present or not on the system. The idea is that a program would link to this library A instead of the original library B ; and Library A would handle the errors if Library B wasn't installed on the system.

So a typical proxy function would look like this:

int function(int arg1, int arg2)
{
    HINSTANCE hinstLib;
    UINT errormode = SetErrorMode(SEM_FAILCRITICALERRORS);
    SetErrorMode(errormode | SEM_FAILCRITICALERRORS);
    hinstLib = LoadLibrary(TEXT(ORIGINAL_DLL));
    SetErrorMode (errormode);
    if (hinstLib != NULL)
    {
        ProcAdd = (void *) GetProcAddress(hinstLib, TEXT("function"));
        if (NULL != ProcAdd)
        {
            return (ProcAdd) (arg1, arg2);
        }
        FreeLibrary(hinstLib);
    }
    return ERROR;
}

Now, I would do this for all original entries in Library B. There could be a lot of calls to it. So loading / unloading the DLL so frequently is certainly going to have an impact speed-wise.

I was wondering if it would be acceptable to use a global variable hinstLib ; something like

HINSTANCE hinstLib = LoadLibrary(TEXT(ORIGINAL_DLL));

int function(int arg1, int arg2)
{
    if (hinstLib != NULL)
    {
        ProcAdd = (void *) GetProcAddress(hinstLib, TEXT("function"));
        if (NULL != ProcAdd)
        {
            return (ProcAdd) (arg1, arg2);
        }
    }
    return ERROR;
}

And let Windows automatically unload the DLL when the program exits (assuming it does unload it).

Thanks in advance for your wise remarks...

Jean-Yves

jyavenard
  • 2,142
  • 1
  • 26
  • 35

1 Answers1

2

Unless the unloading is particular use case, then this is fine. However I would implement some thread safety to ensure that there are no race conditions through this code using a Critical Section.

This is simillar example to the one from the wikipedia article

    /* Sample C/C++, Windows, link to kernel32.dll */
    #include <windows.h>

    static CRITICAL_SECTION cs;

    static HINSTANCE hinstLib = LoadLibrary(TEXT(ORIGINAL_DLL));

    /* Initialize the critical section before entering multi-threaded context. */
    InitializeCriticalSection(&cs);

    void f() {
        /* Enter the critical section -- other threads are locked out */
        __try {
           EnterCriticalSection(&cs);

           if (hinstLib != NULL)     {
           ProcAdd = (void *) GetProcAddress(hinstLib, TEXT("function"));
         } __finally { 
            LeaveCriticalSection(&cs);
         }
         if (NULL != ProcAdd) {
               return (ProcAdd) (arg1, arg2);
         }
    }

.
.
.

    /* Release system object when all finished -- usually at the end of the cleanup code */
    DeleteCriticalSection(&cs);
Preet Sangha
  • 64,563
  • 18
  • 145
  • 216
  • That was fast.. I can not easily add a cleanup code however ; because I do not want to modify in any ways the original code that was calling Library B (and will now call Library A). If I could, I would have done the FreeLibrary there.. – jyavenard Oct 02 '10 at 09:43
  • Using pthreads.h and lock would be trivial to prevent racing conditions. Need to find out if similar APIs exist under Windows. I'm no Windows expert. – jyavenard Oct 02 '10 at 09:52
  • see here http://stackoverflow.com/questions/2150938/can-i-get-cs-pthread-h-to-compile-in-windows – Preet Sangha Oct 02 '10 at 09:57
  • Regarding critical sections. What happens if DeleteCriticalSection isn't called once the program terminates? Is its call compulsory? – jyavenard Oct 02 '10 at 10:33