c++dlldllexportloadlibrarygetprocaddress

GetProcAddress for importing a decorated C++ function into C++


In Visual C++ 2013, I'm trying to export a function from a 'plugin' project:

void registerFactories(FactoryRegister<BaseShape> & factoryRegister);

Which is compliled into a dynamic dll which will be linked at runtime by an 'application' project. First I define the function pointer type:

    typedef void (*RegisterFactoriesType)(FactoryRegister<BaseShape> &);

Which is used as:

        auto registerFactories = (RegisterFactoriesType)GetProcAddress(dll, "registerFactories");
        if (!registerFactories) {
            if (verbose) {
                ofLogWarning("ofxPlugin") << "No factories for FactoryRegister<" << typeid(ModuleBaseType).name() << "> found in DLL " << path;
            }
            FreeLibrary(dll);
            return false;
        }

However, the GetProcAddress returns NULL.

I can confirm that I can export C functions (using extern "C") and import them from the same DLL using GetProcAddress, but I importing the C++ function fails. e.g. this works:

extern "C" {
    OFXPLUGIN_EXPORT void testFunction(int shout);
}

then

auto testFunction = (TestFunction)GetProcAddress(dll, "testFunction");
if (testFunction) {
    testFunction(5);
}

So my presumption is that I need to somehow consider the mangled name which is exported for registerFactories. Since it needs to deal with C++ types, ideally I want to do this without export "C".

Here's what dumpbin.exe sees:

Dump of file examplePlugin.dll

File Type: DLL

Section contains the following exports for examplePlugin.dll

  00000000 characteristics
  558A441E time date stamp Wed Jun 24 14:46:06 2015
      0.00 version
         1 ordinal base
         2 number of functions
         2 number of names

  ordinal hint RVA      name

        1    0 001B54E0 ?registerFactories@@YAXAEAV?$FactoryRegister@VBaseShape@@@ofxPlugin@@@Z = ?registerFactories@@YAXAEAV?$FactoryRegister@VBaseShape@@@ofxPlugin@@@Z (void __cdecl registerFactories(class ofxPlugin::FactoryRegister<class BaseShape> &))
        2    1 001B5520 testFunction = testFunction

Summary

     86000 .data
     8E000 .pdata
    220000 .rdata
      E000 .reloc
      1000 .rsrc
    65D000 .text

EDIT :

registerFactories is not the name to give to GetProcAddress. By manually copying the mangled name from bindump e.g.:

        auto registerFactories = (RegisterFactoriesType)GetProcAddress(dll, "?registerFactories@@YAXPEAV?$FactoryRegister@VBaseShape@@@ofxPlugin@@@Z");

It works! Therefore many of the answers below are related to discovering this mangled name at runtime.


Solution

  • I would not start a hunt for the mangled name. It's compiler dependent (which means also version dependent) and even if it works it would be a fragile solution.

    I would suggest to get the address of your RegisterFactoriesType in antother way.

    Assuming you have, in your plugin, a C-Style init function (whose address is available via GetProcAddress) I would do this:

    struct init_data_t
    {
       RegisterFactoriesType  factory ;
       ... other members
    } ;
    

    then inside init (so inside the DLL)

    void init(init_data_t *data)
    {
        init_data->factory = &dll_factory ;
    }
    

    Basically you ask the DLL to give you the address of the factory function. The dll code does not need GetProcAddr, it can use address of (&)