在C#代码中,您可以捕获某个非托管库中从深处抛出的本机异常吗?如果是这样,您需要采取其他措施来捕获它还是使用标准try ... catch来获取它?
Answers:
您可以使用Win32Exception并使用其NativeErrorCode属性适当地处理它。
// http://support.microsoft.com/kb/186550
const int ERROR_FILE_NOT_FOUND = 2;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_NO_APP_ASSOCIATED = 1155;
void OpenFile(string filePath)
{
Process process = new Process();
try
{
// Calls native application registered for the file type
// This may throw native exception
process.StartInfo.FileName = filePath;
process.StartInfo.Verb = "Open";
process.StartInfo.CreateNoWindow = true;
process.Start();
}
catch (Win32Exception e)
{
if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND ||
e.NativeErrorCode == ERROR_ACCESS_DENIED ||
e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED)
{
MessageBox.Show(this, e.Message, "Error",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
}
}
不带()的捕获将捕获不符合CLS要求的异常,包括本机异常。
try
{
}
catch
{
}
有关更多信息,请参见以下FxCop规则: http://msdn.microsoft.com/zh-cn/bb264489.aspx
C#和本机代码之间的互操作层会将异常转换为托管形式,从而使其可以被您的C#代码捕获。从.NET 2.0开始,catch (Exception)
应该捕获除不可恢复的错误以外的任何内容。
使用.NET Reflector的某个地方,我看过以下代码:
try {
...
} catch(Exception e) {
...
} catch {
...
}
嗯,C#不允许抛出不是从System.Exception类派生的异常。据我所知,interop编组器的任何异常处理都是由继承System.Exception的异常类包装的。
所以我的问题是是否有可能捕获不是System.Exception的异常。
这取决于您正在谈论的本机异常类型。如果您指的是SEH异常,则CLR将执行以下两项操作之一。
这两个都将通过一个简单的“ catch(Exception)”块来捕获。
可以跨越本机/托管边界的另一种本机异常是C ++异常。我不确定它们是如何映射/处理的。我的猜测是,由于Windows在SEH之上实现C ++异常,因此它们以相同的方式映射。
Windows implements C++ exceptions on top of SEH
-这似乎仅对VC是正确的吗?
差不多,但是不完全是。您将通过捕获异常
try
{
...
}
catch (Exception e)
{
...
}
但是您仍然会遇到潜在的问题。根据MSDN的说明,为了确保调用异常析构函数,您必须像这样捕获:
try
{
...
}
catch
{
...
}
这是确保调用异常析构函数的唯一方法(尽管我不确定为什么)。但是,这需要您在蛮力与可能的内存泄漏之间进行权衡。
顺便说一句,如果使用(Exception e)方法,您应该知道可能遇到的不同类型的异常。RuntimeWrappedException是任何托管的非异常类型都将映射到的类型(对于可以抛出字符串的语言),其他类型将被映射,例如OutOfMemoryException和AccessViolationException。COM Interop HRESULTS或E___FAIL以外的异常将映射到COMException,最后在最后,您具有E_FAIL的SEHException或任何其他未映射的异常。
那你该怎么办?最好的选择是不要在非托管代码中抛出异常!哈哈 确实,尽管您可以选择,但会设置障碍并失败,这会使得选择更加糟糕,在异常处理过程中可能会发生内存泄漏,或者不知道您的异常类型。
如果您使用
try
{
}
catch(Exception ex)
{
}
它会捕获所有异常,具体取决于您调用外部库的方式,您可能会获得与com相关的异常,该异常封装了错误,但可以捕获该错误。