在.NET中捕获非托管DLL异常

时间:2013-12-16 12:02:12

标签: c++ .net vb.net winapi dll

我正在使用一个非托管DLL,其函数抛出std::exception

我正在使用.NET DLL包装器,因此可以将其分发以用于.NET程序。

我希望能够从本机异常中捕获消息,但我得到的只是System.Runtime.InteropServices.SEHException("External component has thrown an exception.")

有没有办法传播异常细节?也许我应该从本机DLL导出自定义异常?我该怎么做?

由于

原生DLL:

__declspec(dllexport) void __stdcall W32DLLFunc(int param) {
  if (param < 0) {
    throw new exception("Error: param must be > 0");
  }
  ...
}

.net DLL:

[DllImport("nw32.dll", CharSet = CharSet::Auto)]
static void W32DLLFunc(int param);

vb.net程序:

Try
  W32DLLFunc(-1)
Catch ex As Exception
  MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

1 个答案:

答案 0 :(得分:2)

本机C ++异常是本机C ++异常。它们不适用于非C ++的东西。它们甚至不能在不同版本的C ++之间工作。

本机C ++异常不利于互操作性。

从DLL返回错误信息的标准机制是返回一个值来指示成功或失败,并在函数失败时使用SetLastErrorGetLastError来传达错误代码。

如果您希望标准机制返回的信息多于错误代码,则需要查看具有IErrorInfo的COM。

但是定义一些错误代码会更简单。

如果可能的话,我会更改原始DLL,以便它根本不泄漏异常。如果这是不可能的,因为现有的C ++客户端依赖于当前的设计,那么我将添加一个并行API:每个导出函数的新版本调用原始函数,捕获异常并返回错误代码。这是可以隐藏在宏中的所有样板。如果您无法触摸DLL,我会添加一个本机包装器来转换异常。

<强>更新

正如IInspectable所建议的,另一种选择是创建混合模式程序集。

将.Net类添加到现有的C ++库中。这应该为每个调用原始API的API函数提供一个包装器,捕获任何异常,将详细信息复制到.Net异常中并抛出.Net异常。

通过在DLL中保留所有本机异常处理,可以避免跨越DLL边界的C ++异常的问题。包装的异常可以在任何.Net语言中使用,而无需为导出的函数创建声明。唯一的缺点是您需要一个额外的API来与其他本机代码进行互操作。