我必须在运行时动态地将模块加载为 dll,因为它们事先并不知道,只是它们符合类接口。我注意到的是,在我捕获 dll 抛出的异常(在主线程的主程序中)后,会调用正确的析构函数,并销毁模块并卸载 dll,但随后作为 catch 块末尾的 }当 Visual Studio C++ 调试器逐行单步执行时,我收到另一个异常,该异常导致程序崩溃
xxxxx.exe 中 0x68ad2377 (msvcr90d.dll) 处的首次机会异常:0xC0000005:读取位置 0x02958f14 时出现访问冲突。
如果我启用异常中断,则第二个异常中断将显示位置为
msvcr90d.dll!__DestructExceptionObject(EHExceptionRecord * pExcept=0x0017ee4c, unsigned char fThrowNotAllowed=0) 第 1803 行 + 0xf 字节
但看起来帧堆栈可能已损坏。我不明白为什么会抛出这个异常。
我的代码结构的简化版本如下:
程序的非常简化的结构:
//shared header:
class Module
{
public:
virtual void Foo(void) = 0;
};
//dll:
class SomeSpecificModule : public Module
{
public:
virtual void Foo(void);
};
void SomeSpecificModule::Foo(void)
{
throw 1;
}
extern "C" __declspec(dllexport) Module* GetModule()
{
return new SomeSpecificModule;
}
//program:
typedef ptrGetModule* (*GetModule)();
int main(void)
{
HANDLE hMod = LoadLibrary("SomeSpecificModule.dll");
ptrGetModule GetModule = (ptrGetModule)GetProcAddress(hMod, "GetModule");
try
{
Module *d = GetModule();
d->Foo();
}
catch (...)
{
cout << '!' << endl;
}
return 0;
}
需要记住的是,C 运行时库的每个副本都有自己的状态。如果 SomeSpecificModule.dll 静态链接到 C 运行时库,则可能会发生此类问题。如果是这种情况,请尝试链接 C 运行时库的 DLL 版本。您还必须确保 SomeSpecificModule.dll 的编译和链接方式与主模块完全相同。
您提到 DLL 被卸载并调用了正确的析构函数,听起来您的真实程序比您发布的示例有更多的内容。如果您在 try 块中卸载了 SomeSpecificModule.dll,那么您就已经卸载了 SomeSpecificModule::Foo() 的异常记录,我猜这就是您在 m 处崩溃的原因svcr90d.dll!__DestructExceptionObject(EHExceptionRecord * ...
然而,一般来说,跨 DLL 边界抛出异常是自找麻烦。如果您抛出非 POD 对象,则可能会遇到不同堆中不同 C 运行时库分配的内存问题、不同编译器设置、STL 版本...您明白了。
更改代码,这样就不会跨越 DLL 边界。有一天,您团队中的某人更改了编译器设置或更改了第三方标头#define,并且您的程序开始崩溃,您将很难追踪根本原因。
无论如何,在没有看到真正的代码的情况下,我只是想猜测可能会出现什么问题。希望能帮助到你。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)