【问题标题】:C# not catching unhandled exceptions from unmanaged C++ dllC# 没有从非托管 C++ dll 中捕获未处理的异常
【发布时间】:2011-05-12 12:41:45
【问题描述】:

我有一个从 C# 应用程序调用的非托管 C++ dll,我正在尝试让 C# 应用程序捕获所有异常,以便在 dll 由于非托管异常而失败时用户将收到一条不太像样的错误消息(C# 应用程序是一个实现其自己的 http 处理程序的 Web 服务)。

我遇到的问题是并非所有类型都被捕获。因此,如果我创建以下内容并执行 C# 应用程序,则 dll 会引发错误并且整个应用程序终止。有什么想法吗?

这是在 VS2005 中创建并使用 .Net framework v2

C++ - 测试.h

#ifndef INC_TEST_H
#define INC_TEST_H

extern "C" __declspec(dllexport) void ProcessBadCall();

#endif

C++ - 测试.cpp

#include <iostream>
#include <vector>

using namespace std;

void ProcessBadCall()
{
  vector<int> myValues;
  int a = myValues[1];
  cout << a << endl;
}

C# - Program.cs

class Program
{
  [DllImport("Test.dll", EntryPoint="ProcessBadCall")]
  static extern void ProcessBadCall();

  static void Main(string[] args)
  {
    try
    {
      ProcessBadCall();
    }
    catch (SEHException ex)
    {
      Console.WriteLine("SEH Exception: {0}", ex.Message);
    }
    catch (Exception ex)
    {
      Console.WriteLine("Exception: {0}", ex.Message);
    }
  }
}

正在使用以下编译器标志在发布配置下编译 dll。

/O2 /GL /D "WIN32" /D "NDEBUG" /D "_CRT_SECURE_NO_WARNINGS" /D "_UNICODE" /D "UNICODE" /D "_WINDLL" /FD /EHa /MD /Fo“释放” /Fd"Release\vc80.pdb" /W4 /WX /nologo /c /Wp64 /Zi /TP /errorReport:prompt

【问题讨论】:

  • 在调试模式下编译dll时,不会引发SEH Exception,但会导致断言失败。
  • 对不起,漏掉了,dll是在release模式下编译的
  • 你试过"catch { Console.WriteLine("blah"); }"吗?
  • 刚试过,还是不行。似乎正在发生的事情是 DLL 引发了一个未处理的异常,该异常立即终止了自身和 c# 应用程序
  • 您应该在抛出异常的同一运行时捕获异常。否则堆栈展开和析构函数调用可能无法按预期工作。而且您通常无法从访问冲突中恢复,因此您应该在显示错误后终止应用程序。

标签: c# c++ dll exception-handling pinvoke


【解决方案1】:

尝试使用ExternalException 类进行捕获:

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.externalexception%28v=VS.100%29.aspx

然后,尝试使用异步异常处理 (/EHa) 编译非托管 C++ DLL。 看起来您在 DLL 中遇到了读取访问冲突,这是一种异步异常。

AFAIK,只有 .NET v4 及更高版本默认禁用异步异常的传递。即使这样,您也可以将 legacyCorruptedStateExceptionsPolicy=true 添加到 app.config 以启用它。在此之前,它会自动启用(检查您是否已在 app.config 中将其设置为 false)。

请注意,我个人认为,非托管 DLL 中的 AV 本质上是不好的(而且很危险),对于 .NET 来说,简单地终止应用程序可能是正确的行为。尝试抛出 std::exception 。如果您坚持要捕获异步异常,最好的方法是拥有一个 thunking DLL,它将 try-catch-all 包装在对潜在错误函数调用的调用中。同样,强烈/不/推荐(尽管我可以看到它在调试行为不端的 DLL 时会有多大用处)。

【讨论】:

  • 更新了关于使用 /EHa 编译器选项重新编译 DLL 的评论。请再试一次。
  • 同样,我已将编译器标志添加到原始问题中。干杯
  • 你能先尝试在你的非托管 DLL 中抛出 std::exception 吗?我想知道.NET 是否甚至从非托管代码重新打包异步异常。
  • 如果没有,您可以引入一个非托管 DLL,该 DLL 插入导出 ProcessBadCall() 的 DLL。然后,thunking DLL 会将调用包装在 try { } catch (...) { return errorCode; }。这样,只需要使用 /EHa 编译 thunking DLL。
  • @Baldrick 阅读 this article,有一个 [HandleProcessCorruptedStateExceptions] 属性允许您仅在某些方法中捕获这些异常,而在其他任何地方保留默认的 .NET 4 行为。
猜你喜欢
  • 2011-02-20
  • 2011-10-14
  • 1970-01-01
  • 2020-05-08
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多