【问题标题】:Catch unmanaged dll exception in .NET在 .NET 中捕获非托管 dll 异常
【发布时间】:2013-12-16 12:02:12
【问题描述】:

我正在使用一个非托管 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

【问题讨论】:

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


    【解决方案1】:

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

    原生 C++ 异常不利于互操作性。

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

    如果您希望标准机制返回比错误代码更多的信息,您需要查看 COM,它有 IErrorInfo

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

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

    更新

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

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

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

    【讨论】:

    • 没错,著名的E msc 例外。我将删除我的 cmets 以换取支持。您仍然可以添加有关编写 C++/CLI 包装器以将 C++ 异常转换为 .NET 异常的注释,这似乎是最干净的解决方案。混合模式程序集甚至可以被本机代码和托管代码使用。
    • 干杯。我想到了一个 C++/CLI 包装器,但我不知道本机异常如何与 C++/CLR 交互。 This article 几乎暗示它会起作用,所以我试了一下,它确实起作用了。我已经更新了我的答案。
    猜你喜欢
    • 2011-10-14
    • 1970-01-01
    • 2011-05-12
    • 2021-03-28
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    相关资源
    最近更新 更多