2013-12-16 35 views
5

我正在使用非托管dll与抛出std::exception的函数。在.NET中捕获非托管dll异常

我正在使用.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 

回答

2

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

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

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

如果你想要一个标准的机制返回比错误代码更多的信息,你需要看看COM,它有IErrorInfo

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

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

更新

如所建议的通过IInspectable,另一个选择是创建一个混合模式组件。

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

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

+0

的确如此,着名的'E msc'异常。我会删除我的评论以换取积分。您仍然可以添加关于编写C++/CLI包装器的说明,将C++异常转换为.NET异常,这似乎是最干净的解决方案。混合模式程序集甚至可以被本机代码和托管代码使用。 – IInspectable

+0

干杯。一个C++/CLI包装器发生在我身上,但我不知道本机异常如何与C++/CLR交互。 [这篇文章](http://msdn.microsoft.com/en-us/library/df24ysb6.aspx)几乎意味着它可以工作,所以我给它一个去,它确实。我已经更新了我的答案。 – arx

相关问题