【问题标题】:Calling c# code from managed c++ crashes从托管 c++ 崩溃中调用 c# 代码
【发布时间】:2012-11-16 15:06:26
【问题描述】:

我有一个非托管 c++ DLL,它通过托管 c++ 包装器调用 c# 代码。非托管 c++ DLL 是某些应用程序的插件(不在我的控制范围内)。当此应用程序调用非托管 c++ DLL 时,一切正常,直到托管 c++ 代码尝试使用 c# 代码。然后它崩溃了。

我编写了一个测试应用程序,它与应用程序执行相同的操作,即调用非托管 c++ DLL。 这很好用。

代码尽可能简单:

非托管 c++:

extern "C" __declspec(dllexport) void UnmanagedMethodCalledUponByApplication()
{
    new Bridge();
}

托管 c++:

Bridge::Brigde()
{
    gcnew Managed(); // This line crashes
}

c#:

public class Managed
{
}

我尝试在有问题的行周围添加一个 try-catch (...) 块,但它没有捕捉到错误。

如果我用MessageBox::Show("Alive!"); 替换gcnew Managed(); 行,它可以正常工作。所以我的猜测是我的 c# 项目设置有问题。

我尝试用不同的平台(任何 CPU 和 x86)编译它。我试图改变目标框架。我试图在Managed 中调用静态方法,而不是使用gcnew。仍然崩溃。

任何想法可能是什么问题?

更新:

在 cmets 提出建议并回答后,我附加了调试器。现在我看到我收到了一个System.IO.FileNotFoundException,说找不到托管 DLL(或其依赖项之一)。

这里有一个猜测:这些 DLL 放在一起,但它们不在当前目录中。非托管 c++ DLL 正确加载,因为主应用程序指定了它的路径。托管 c++ 实际上是一个库,因此代码也可以正常工作。但是当托管 c++ 尝试加载 c# DLL 时,它会在错误的目录中查找它。

更新:

解决此问题的方法是使用反射动态加载 c# DLL。

【问题讨论】:

  • @pivotnig 是的,Bridge 不受管理。
  • 可能宿主应用程序之前加载了不同版本的 .NET 运行时 (CLR),从而阻止您的代码加载它需要的代码。出于这个原因,不鼓励在插件中使用托管代码,尽管 .NET 4 在同一进程中并行加载多个版本方面取得了一些进展。
  • 另外,在调试器中捕获异常。
  • 当你调试应用程序并打开异常时——你得到的异常是什么。

标签: dll c++-cli managed managed-c++


【解决方案1】:
  extern "C" __declspec(dllexport) 

是的,这是一种让编译器生成加载和初始化 CLR 以执行托管代码所需的存根的廉价且简单的方法。问题是,它没有做任何合理的事情来处理托管代码抛出的异常。并且托管代码喜欢抛出异常,它们是一个了不起的故障排除工具。当您无法检索异常信息时,这将不再是了不起的。

您可以从本机代码中做的最好的事情是使用 __try/__except 关键字来捕获托管异常。异常代码为 0xe0434f4d。但这仍然无法让您访问所需的信息、异常消息和神圣的堆栈跟踪。

你可以调试它。项目+属性,调试,将调试器类型更改为“混合”。然后 Debug + Exceptions,勾选 CLR Exceptions 的 Throw 复选框。抛出异常时调试器停止,以便您查看问题所在。

在交付代码后获得体面的诊断需要更好的互操作机制。就像使用 COM 互操作或自己托管 CLR。​​

【讨论】:

  • 我忘了提到我已经尝试过调试(你描述的方式),但它不会在断点处停止,即使在非托管 c++ 中也是如此。但是,自从我收到此错误以来,我没有尝试附加调试器。现在我收到System.IO.FileNotFoundException,说找不到托管 DLL(或依赖项)。
猜你喜欢
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多