【发布时间】:2019-10-08 08:49:32
【问题描述】:
我在尝试从加载的 DLL 调用方法时遇到了奇怪的问题。
让我们从简单的 Log 类开始,方法 Write 采用 const char* 参数。
class ENGINE_API Log
{
private:
const char* Category;
public:
Log(const char* Category);
void Write(const char* format, ...);
};
该类由__declspec(使用ENGINE_API宏)标记为dllexport,同时在“所有者”DLL中构建它并标记为dllimport,同时在构建另一个时仅使用标题动态链接库。
第一个“所有者”DLL 还导出了名为 CreateLogInstance 的外部 C 函数,它只是创建 Log 类的实例并返回它。
PUBLIC_FUNCTION Log* CreateLogInstance(const char* name)
{
return new Log(name);
}
在第二个 DLL 中,我调用 LoadLibrary 和 GetProcAddress 并正确转换为函数指针。比我简单地调用带有一些文本的Write 方法。
typedef Log*(*CreateLogInstanceFunction)(const char*);
HINSTANCE moduleHandle = LoadLibrary("Engine.dll");
CreateLogInstanceFunction createLogInstanceFunction = (CreateLogInstanceFunction)GetProcAddress(moduleHandle, "CreateLogInstanceWithName");
// omitting the null checks etc
Output = createLogInstanceFunction("Game");
Output->Write("Hello Game");
一切正常,只有一个要求 - Write 方法必须标记为 virtual,如果不是编译,它自身在 LNK2019 未解决的外部符号错误上失败,其中 @ 987654336@方法被调用。
在我的情况下(对于某些多态性)我不需要它是 virtual,我的问题是 - 为什么需要 virtual 说明符才能完成这项工作?
当我选择使用 Load-Time Dynamic Linking 并在构建期间针对 .lib 文件进行链接时,这也有效(没有 virtual 说明符),但我喜欢坚持使用 Run-时间动态链接。
谢谢。
使用带有最新 Windows SDK 的 Windows 10 (1809) 和 Visual Studio 2019。
【问题讨论】:
-
您是否将 lib 文件包含在 exe 构建中?认为没有。以及通过动态链接导入某些函数和通过
GetProcAddress导入另一个函数有什么意义?包含 lib 文件而不使用 GetProcAddress。 GetProcAddress 用于每个导出的函数 -
你的windows版本,你的vs版本,你用的是vs——这里绝对不相关
-
当你使用 virtual 时(比如
Write是 virtual 方法) -Output->Write通过对象上的 vtable 调用。当你不使用 virtual - 你从哪里得到Write地址? (现在它不存在于 vtable 中)。或通过GetProcAddress或通过导入表。你什么都不做 -
RbMm 是对的。函数的地址在编译时确定,但
Log::Write的代码实际上并未在第二个 DLL 中编译。你不应该导出 C++ 的东西(比如 Log 类)。相反,CreateLogInstance应该返回void*,而一些新函数Log_Write应该采用两个参数,void*和const char*。 -
@Dialectus:导出 C++ 的东西非常好。不应该做的是导出 c++ STL-stuff(编译器和版本依赖)!
标签: c++ winapi visual-c++