用于将修饰的C++函数导入C++的GetProcAddress

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

本文关键字:C++ 导入 GetProcAddress 函数 用于      更新时间:2023-10-16

在Visual C++2013中,我正试图从"插件"项目导出一个函数:

void registerFactories(FactoryRegister<BaseShape> & factoryRegister);

它被编译成一个动态dll,该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"),并使用GetProcAddress从同一DLL导入它们,但我导入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");

它有效!因此,下面的许多答案都与在运行时发现这个损坏的名称有关。

我不会开始寻找损坏的名称。它依赖于编译器(也意味着依赖于版本),即使它有效,它也是一个脆弱的解决方案。

我建议以其他方式获取您的RegisterFactoriesType的地址。

假设你的插件中有一个C风格的init函数(其地址可通过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,它可以使用(&)的地址

我不久前专门为此创建了一个库。这里有一个用法示例,我希望它能有所帮助。