1

我有一个非托管 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 (...) 块,但它没有捕获错误。

如果我gcnew Managed();用它替换这条线MessageBox::Show("Alive!");就可以了。所以我的猜测是我的 c# 项目设置有问题。

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

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

更新:

在评论和回答中提出建议后,我附上了调试器。现在我看到有人System.IO.FileNotFoundException说找不到托管 DLL(或其依赖项之一)。

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

更新:

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

4

1 回答 1

1
  extern "C" __declspec(dllexport) 

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

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

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

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

于 2012-11-16T17:43:56.023 回答