我完成了我的小应用程序,我正在努力确保没有内存泄漏和没有错误。在查看我的输出之后,我注意到我的一个函数是抛出First-Chance异常,但该函数运行良好且不会崩溃。
该函数调用CLR C ++ DLL中的另一个函数。我删除了DLL函数中的几乎所有代码只是为了测试而且仍然抛出异常所以我知道这是我的EXE函数就是问题。
这是调用DLL函数的EXE函数的代码。
LPCTSTR CHAXC0RDlg::Encrypt(LPCTSTR strValue)
{
const char* Return;
HINSTANCE hDLL = LoadLibrary(L"Library.dll");
if(hDLL)
{
FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");
if(hMethod)
{
typedef const char* (*FunctionSig)(LPCTSTR);
FunctionSig MethodCall = FunctionSig(hMethod);
Return = MethodCall(strValue);
FreeLibrary(hDLL);
}
}
return _tcsdup(CString(Return));
}
这是DLL函数(你可以看到我删除了除了生成返回值的代码之外的所有代码,只是作为测试):
const char* Encrypt(LPCTSTR strPValue)
{
String^ strValue = gcnew String(strPValue);
string strReturn = (const char*)(Marshal::StringToHGlobalAnsi(strValue)).ToPointer();
char* csValue = new char[strReturn.size()];
strcpy(csValue, strReturn.c_str());
return const_cast<const char*> (csValue);
}
EXE函数抛出“const char* Return = MethodCall(strValue);
”上的异常(我启用了对此异常的破解,这是我所知道的。)
为什么这个函数确实抛出了这个异常?
谢谢!
修改
更新:我的字符集是UNICODE。
更新#2:从我在建议和答案中读到的内容,您假设此代码不起作用,但确实如此。我启用了第一次机会异常中断(是的,我确实知道第一次机会异常是什么),因为我希望这个程序质量好,所有错误都消失了。代码运行正常,我只是想弄清楚为什么抛出第一次机会异常,因为我喜欢成为一个更好的程序员。所以我想解决这个问题。
更新#3:我现在让我的代码检查hDLL和hMethod的值,并且在运行此函数时两者都不为null。问题似乎在于它自己调用DLL。我假设函数签名是100%正确的,这个代码确实有效,它只是抛出了第一次机会异常。
更新#4:我在上面的函数中添加了新的更改,并添加了DLL函数代码。 DLL函数是CLR C ++ DLL。我已经删除了DLL函数中的所有代码,以确保它不是我的DLL。
答案 0 :(得分:4)
从代码片段中不清楚,但看起来您在使用C ++ / CLI编写的托管函数上使用了__declspec(dllexport)。 String ^和Marshal类使这一点毫不含糊。
在一个完全原生的应用程序中运行托管代码是可能的,但它需要加载和初始化CLR。有几种方法可以做到这一点,我猜你找到了最简单的方法。在托管函数上使用__declspec(dllexport)会强制编译器发出一个存根,该存根负责确保CLR已初始化并使本机到托管代码转换。
所以是的,第一次时间你调用这个导出的函数,在你的背后执行一个完整的代码。这是存根需要加载和初始化CLR并加载包含托管代码的程序集的时间。看到这个抛出和处理异常的代码一般都不用担心。无论如何,你无能为力,你没有这个的源代码。您可以通过自己托管CLR来减少意外事件。这需要一大堆COM代码,不太确定它是否值得花费。
根据您提供的明确证据,这实际上不会导致问题,这是功能,而不是错误。请注意,您可以使用此类代码触发真实的,未处理的异常。如果托管代码抛出托管异常,它在托管代码中很常见,那么您将受到Windows SEH异常的攻击,异常代码为0xe0434f4d。这总是很糟糕,您可以使用__try和__catch关键字来捕获它,但是您无法获得适当的诊断,因为在堆栈展开回代码时,有关托管异常的所有信息都是奇闻趣事。
答案 1 :(得分:1)
您会看到类似“C ++异常”或“访问冲突”的内容,以及其他诊断信息(如果您很幸运)。
这个第一次机会异常有可能是“正常” - 即它总是发生在有效输入上。这很少见,因为正常的执行路径不应该抛出异常。
返回值
如果返回的值位于DLL内部的静态/内部缓冲区中(不需要释放),则在卸载DLL时它将变为无效。
如果返回值由DLL动态分配(例如DLL执行new []或malloc或_tcsdup),则DLL也必须释放该字符串,否则该字符串将泄漏。 不释放调用者中的字符串,因为DLL和调用者可能使用或不使用不同的堆。
检查DLL的文档,它应该说明谁需要释放返回的指针,以及返回指针的有效性和/或时长。
答案 2 :(得分:1)
只有在第一次从DLL调用导出的函数时才会抛出异常。它与第一次加载/初始化CLR有关,与代码无关(在代码有机会执行之前发生)。对Encrypt的后续调用不会生成此异常。似乎可以安全地忽略它。
答案 3 :(得分:0)
目前尚不清楚项目中使用了哪个“字符集”(请参阅配置属性/常规)。您在'LoadLibary'中使用L宏而不在'GetProcAddress'中使用它。
HINSTANCE hDLL = LoadLibrary(L"Library.dll");
FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");
尝试使用_T宏代替:
HINSTANCE hDLL = LoadLibrary(_T("Library.dll"));
FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");
由于您的项目设置,它会为您设置'L'。
修改强>
试
_declspec( dllexport ) const char* Encrypt(LPCTSTR strPValue)
{
...
}
并确保您的模块定义文件包含
LIBRARY "Library"
EXPORTS
Encrypt @1
SECTIONS
.data READ WRITE
也不是为什么不使用
const char* Encrypt(char* strPValue)
答案 4 :(得分:0)
我把你的代码放在VS2010上,调用者(EXE)是C ++ Console app。并且C ++ / CLI DLL是使用V90工具集构建的,但我没有看到任何第一次机会异常被抛出。
我很确定你的头文件中有_declspec(dllexport),但我不确定你是如何定义它的。我就是这样。
extern "C"
{
__declspec(dllexport) const char* Encrypt(LPCTSTR strPValue);
}
没有模块定义文件(.def)。 你能告诉我输出窗口显示的内容吗?