GetProcAddress для импорта украшенной функции C++ в C++

В Visual C++ 2013 я пытаюсь экспортировать функцию из проекта плагина:

void registerFactories(FactoryRegister<BaseShape> & factoryRegister);

Которая компилируется в динамическую dll, которая будет связана во время выполнения с помощью проекта приложения. Сначала я определяю тип указателя на функцию:

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

Который используется как:

        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;
        }

Тем не менее GetProcAddress возвращает NULL.

Я могу подтвердить, что я могу экспортировать функции C (используя extern "C") и импортировать их из одной и той же DLL, используя GetProcAddress, но я не могу импортировать функцию C++. например, это работает:

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

затем

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

Поэтому я предполагаю, что мне нужно как-то рассмотреть искаженное имя, которое экспортируется для registerFactories, Поскольку он должен иметь дело с типами C++, в идеале я хочу сделать это без export "C",

Вот что dumpbin.exe видит:

Дамп файла examplePlugin.dll

Тип файла: 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

РЕДАКТИРОВАТЬ:

registerFactories это не имя, чтобы дать GetProcAddress, Путем ручного копирования искаженного имени из bindump, например:

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

Оно работает! Поэтому многие из ответов ниже связаны с обнаружением этого искаженного имени во время выполнения.

2 ответа

Решение

Я бы не стал охотиться за искалеченным именем. Это зависит от компилятора (что означает, также зависит от версии), и даже если он работает, это будет хрупкое решение.

Я бы предложил получить адрес вашего RegisterFactoriesType другим способом.

Предполагая, что в вашем плагине есть функция инициализации C-Style (адрес которой доступен через GetProcAddress), я бы сделал это:

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

затем внутри init (так внутри DLL)

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

По сути, вы просите DLL дать вам адрес заводской функции. Код dll не нуждается в GetProcAddr, он может использовать адрес (&)

Я создал библиотеку специально для этой цели некоторое время назад. Здесь есть пример использования, который, я надеюсь, поможет.

Другие вопросы по тегам