从托管c ++中调用c#代码崩溃

时间:2012-11-16 15:06:27

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

我有一个非托管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 ++实际上是一个lib,所以代码也可以正常工作。但是当托管c ++尝试加载c#DLL时,它会在错误的目录中查找它。

更新

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

1 个答案:

答案 0 :(得分:1)

  extern "C" __declspec(dllexport) 

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

您可以使用本机代码执行的最佳操作是使用__try/__except关键字来捕获托管异常。异常代码为0xe0434f4d。但是,这仍然无法让您访问所需的信息,异常消息和神圣堆栈跟踪。

你可以调试它。 Project + Properties,Debugging,将Debugger Type更改为“Mixed”。然后选择Debug + Exceptions,勾选CLR Exceptions的Thrown复选框。抛出异常时调试器会停止,这样你就可以看到错误了。

在发送代码后获得合适的诊断需要更好的互操作机制。就像使用COM互操作或自己托管CLR一样。