Search code examples
c++cloadlibrarydlopen

dlopen/LoadLibrary on same application


I need to call an exported symbol from my own application - therefore I need to know if it's safe to call dlopen / LoadLibrary on "yourself".

An example would be:

LoadLibrary("test.exe");

inside a program called test.exe.

I tested it and it seems to work, but I'm not quite sure if it is actually supported behavior.


Solution

  • From the MSDN documentation here...

    The system maintains a per-process reference count on all loaded modules. Calling LoadLibrary increments the reference count. Calling the FreeLibrary or FreeLibraryAndExitThread function decrements the reference count. The system unloads a module when its reference count reaches zero or when the process terminates (regardless of the reference count).

    It will work, just remember to clean-up after yourself by calling FreeLibrary, as stated above.

    What you may have really wanted instead is GetModuleHandle.

    Retrieves a module handle for the specified module. The module must have been loaded by the calling process.

    In fact, what you're trying to do is even a special case.

    lpModuleName [in, optional]

    ...

    If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).

    So, trying this...

    #include <stdio.h>
    #include <windows.h>
    
    __declspec(dllexport) void print(void) {
      puts("OK");
    }
    
    main() {
      HMODULE mod = GetModuleHandle(0);
      FARPROC proc = GetProcAddress(mod, "print");
      proc();
      return 0;
    }
    

    ... appears to work:

    C:\dev\scrap>gcc -oprint print.c
    
    C:\dev\scrap>print
    OK
    

    For dlopen, it appears very similar.

    If filename is a NULL pointer, then the returned handle is for the main program. When given to dlsym(), this handle causes a search for a symbol in the main program, followed by all shared libraries loaded at program startup, and then all shared libraries loaded by dlopen() with the flag RTLD_GLOBAL.