【问题标题】:P/Inoke catching native exceptionP/Inoke 捕获本机异常
【发布时间】:2012-07-13 17:15:40
【问题描述】:

我正在测试一个 C# .NET 4.0 应用程序,该应用程序通过 PInvoke 与 C++ 非托管 DLL 交互,我想捕获 dll 引发的任何异常。 我在 try/catch 子句中包装了 dll 函数来处理本机异常,但是当它被触发时,它被忽略了。试过了:

try { } catch {}
try {} catch (Exception)
try {} catch (SEHException)
try {} catch (Win32Exception)

无济于事

唯一可行的方法是将 DllImport SetLastError 属性设置为 true 并且 调用函数检查后:

if (Marshal.GetLastWin32Error() !=0) 

这是一个令人满意的解决方案,但我只是想知道为什么其他选项没有任何效果,以及想知道本机异常是由非托管 dll 还是由 Windows API 本身触发的,因为例如异常是:

System.ComponentModel.Win32Exception (0x80004005): There is not enough space on the disk

这是来自 Windows API 本身的通知吗?

【问题讨论】:

  • 什么样的DLL会抛出异常?这是非常不寻常的。你确定 DLL 真的会抛出吗?
  • 你是对的。我所做的是if (Marshal.GetLastWin32Error() !=0) throw new Win32Exception(); 所以我实际上自己抛出了异常
  • 您正在抛出错误,并且您也在询问我们错误的含义。你扔了。你应该知道。我们怎么知道?
  • 我没有问错误是什么,但是我如何才能在不必驻留在if (Marshal.GetLastWin32Error() !=0)的情况下捕获它。
  • 这个问题的答案可以在@Hans 的回答的第一句话中找到。你无法抓住一开始就没有扔过的东西!

标签: pinvoke


【解决方案1】:

简单的解释是本机代码不会抛出异常。是的,使用 GetLastWin32Error() 是任何 Windows api 函数的样板。其他代码也可能使用它,虽然它不是很常见,但任何人都可以调用 SetLastError() 来设置线程的错误代码。否则 C 代码永远不会故意抛出异常,该语言不支持它。

0x80004005 错误代码是 COM 错误代码,E_FAIL。您不使用 pinvoke 调用 COM 函数,CLR 对 COM 互操作的支持通过导入库来处理它。您确实获得了 COM 错误的异常,CLR 在看到 COM 方法返回失败代码时会抛出它们。它还使用 IErrorInfo 来获得错误代码的更好描述,在 Exception.Message 属性中返回。

【讨论】:

  • 非常感谢简洁的回答,再一次。您能告诉我 Win32Exception 和 SEHException 之间的区别是什么吗?
  • Win32Exception 是一个特定的异常,仅由托管代码引发,用于表示 winapi 调用失败。与 COM 调用失败时引发的异常的想法相同,错误代码转换为异常。当本机代码抛出非托管异常时,会引发 SEHException。由编组器捕获并转换为托管异常。永远不要捕获 SEHException,它总是坏消息。捕获 Win32Exception 很好。
  • Win32Exception 是一个特定的异常,仅由托管代码引发这很清楚
  • 0x80004005 错误代码是 COM 错误代码,E_FAIL。 我在执行if (Marshal.GetLastWin32Error() !=0) throw new Win32Exception(); 时收到此错误,更具体地说 磁盘空间不足 对应于系统错误 112 (0x70)。这是 Win32 还是 COM 错误?或者可能是 Win32 错误被翻译成 COM 异常?
猜你喜欢
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 2014-02-20
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多