向DLL传递对象指针:Editor.exe与game.dll交互问题咨询
问题分析与解决方案
这种跨模块传递类指针的问题我碰到过好多次,核心原因基本都是模块间的类布局或ABI不兼容,咱们一步步拆解问题和解决办法:
最可能的问题根源
- Core类内存布局不一致:Editor.exe和game.dll是独立编译的,如果两边使用的
core.h有差异(比如类成员顺序/数量不同、条件编译导致的结构变化),或者编译选项(比如内存对齐、Debug/Release模式、C++标准)不一致,DLL里对Core对象的内存访问就会直接出错。 - ABI兼容性冲突:不同编译器版本、不同CRT(C运行时库)链接方式,或者函数调用约定不匹配,都会导致函数调用时的参数传递、栈处理出错。
- 虚函数表不匹配:如果Core包含虚函数,两边编译生成的虚表顺序不一致,DLL调用虚函数时就会跳转到错误的地址。
针对性解决办法
1. 强制Core类定义与编译选项完全统一
- 确保Editor和game.dll使用完全相同的
core.h头文件,头文件里不能有任何会改变类结构的条件编译(比如#ifdef _DEBUG添加额外成员)。 - 统一所有编译选项:
- 内存对齐选项(比如VS的
/Zp参数)必须一致; - 统一使用Debug或Release模式,混合模式大概率出问题;
- 统一C标准版本(比如都是C17);
- 统一CRT链接方式:如果Core里用到了STL容器(比如
std::string),必须都用动态链接CRT(/MD或/MDd),避免跨模块内存分配/释放崩溃。
- 内存对齐选项(比如VS的
2. 改用接口隔离(推荐方案)
直接传递具体类指针很容易踩ABI的坑,最好用纯虚基类作为接口,让Core继承这个接口,DLL只依赖接口定义:
// core.h - 两边共用的接口定义 class ICore { public: virtual void requiredMethod() = 0; virtual int getValue() const = 0; virtual ~ICore() = default; // 必须声明虚析构,避免内存泄漏 }; // Editor.exe中的Core实现 class Core : public ICore { private: int internalValue; public: void requiredMethod() override { /* 具体实现 */ } int getValue() const override { return internalValue; } }; // game.dll中的gameInit声明与实现 extern "C" __declspec(dllexport) void gameInit(ICore* core) { // 只通过ICore接口调用方法,不直接访问Core的私有成员 core->requiredMethod(); } // Editor.exe中调用代码调整为 gameInitFuncPtr init = (gameInitFuncPtr)GetProcAddress(LoadLibraryA("game.dll"), "gameInit"); init(static_cast<ICore*>(&core));
这种方式只要接口不变,Core的内部实现怎么改都不会影响DLL,从根源避免了布局不兼容的问题。
3. 确保函数调用约定匹配
GetProcAddress获取的函数默认是C调用约定(__cdecl),一定要保证gameInit的声明在两边完全一致:
// core.h中明确声明调用约定 extern "C" __declspec(dllexport) void __cdecl gameInit(Core* core);
如果用了__stdcall,类型转换时也要对应上,否则会导致栈损坏。
内容的提问来源于stack exchange,提问作者marciovmf
相关产品推荐
相关产品推荐

