P/Invoke不安全代码会产生哪些异常?

6
在我的解决方案中,我已经写下了以下内容:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern unsafe bool CopyFileEx(string lpExistingFileName,  
 string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData,  
 Boolean* pbCancel,    CopyFileFlags dwCopyFlags);

...

bool result;

unsafe{
  result = CopyFileEx(sourceFile, targetFile, null, IntPtr.Zero,  
                      null /* pointer */, 0);
}

if(!result)
    Win32Exception exc = new Win32Exception(Marshal.GetLastWin32Error()); 
// parameter could be omitted according to Win32Exception constructor 
// implementation

在假设CopyFileEx被导出时使用了带有SetLastError = true参数的DllImport属性的情况下,我有机会在这里获得任何未停止的异常吗?
我特别关注包含在RuntimeWrappedException实例中的非CLR异常。在C++中,“throw 1”是一个有效的结构。那么我应该从这样的P/Invoke调用中期望哪些异常,我在哪里可以获取有关异常的信息(MSDN没有提到CopyFileEx的异常)?

可能是重复的问题:.NET PInvoke 异常处理 - Sam Harwell
实际上,我在那里没有找到一个不可辩驳的答案。 - xenn_33
1个回答

9
如果一个动态链接库(DLL)使用Win32结构化异常处理系统,那么由该DLL引发的任何异常都会被转换为OutOfMemoryException、AccessViolationException、NullReferenceException(很少出现)或SEHException。
RuntimeWrappedException仅在托管C++抛出非Exception派生对象时使用。它不用于非托管DLL。如果你有一个托管C++ DLL执行了throw 1,则可以捕获RuntimeWrappedException。
SEHException充当非托管DLL中无法映射的SEH异常的万能异常处理程序。这将包括任何C++类或throw 1示例。据我所知,没有办法从SEHException中提取特定于C++的异常信息,但如果你努力尝试,肯定是可行的。
请注意,有一些DLL不使用Win32结构化异常处理系统,最著名的是Cygwin DLL。在这种情况下,任何C++异常都可能导致进程崩溃或至少导致线程崩溃。当然,所有Windows DLL(包括定义CopyFileEx的DLL)都使用Win32结构化异常处理,Microsoft的C++编译器创建的任何非托管DLL也是如此。
还要注意,Win32 API(包括CopyFileEx)通常不使用Win32结构化异常报告错误;它们通过GetLastError报告错误。使大多数Win32函数抛出Win32结构化异常的唯一方法是传递非常无效的参数(例如要求它写入到ntdll.dll的中间)。

1
这是关于此主题最全面的解释之一,特别是关于 RuntimeWrappedException 只能包装托管 C++ 异常。MSDN 对此并不清楚。 - Weipeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接