2017-04-27 67 views
1

基本上我需要从Visual C++代码调用C#代码。 在阅读了很多关于可能方式的文章后,我决定使用C++/CLI机制。从Visual C++调用C#代码

最初我决定在C++本地代码(dll库项目)中使用一些函数,它们会从CLR项目中调用一些函数,它会从C#项目中调用一些函数。

之后,我想也许我可以摆脱桥梁项目(CLR项目),因为它只是过渡到托管世界。我认为我可以创建我的本地项目,并且可以向其中添加一个C++源文件,并且可以为该文件启用CLR支持,而不是整个项目。 所以这意味着我的本地项目将只包含一个可以使用C++/CLI语法的文件并且代表桥接。所有其他文件都只是本机C++源文件。 从设计的角度来看,这是正确的吗?!

为了达到上述目的,我想我必须将托管的C#dll文件添加到C++本机dll文件的Additional #using Directories属性中。 问题是我不知道如何设置基于当前配置的C#dll调试或发布版本的路径。

另外我知道我不能将本机C++ DLL添加到C#项目引用。 但它看起来像我可以在本机C++项目中添加一个C#dll作为参考。怎么来的 ?!这甚至工作?! 如果我可以将C#dll添加到本机C++项目引用,是否需要设置这些#using目录?!

回答

5

我可以只启用该文件CLR的支持,而不是整个项目

有这样做的,通过选择CLR项目模板入门之间没有有效的区别。无论哪种方式,结果都是混合模式.NET程序集,包含MSIL和本机代码。在项目级别执行此操作只会为项目中的.cpp文件设置/ clr的默认值。您也可以通过覆盖单个.cpp文件(现在禁用/ clr)的设置来使用CLR项目模板来执行此操作。最终结果都是一样的。

我想我必须在托管的C#dll文件添加到其他使用#using目录

是的,这是做这件事。同样可以解决您的查询,您可以在路径名中使用$(Configuration)宏。在编译时解析为“调试”或“释放”,具体取决于您构建的配置。我应该强调这实际上并非必要。编译器仅使用C#程序集中的元数据。只是声明。 .h文件的确切等价物,请注意您很少根据配置使#include变得不同。唯一的情况是,当您在C#源代码中使用#if DEBUG来包含/排除代码时,这种情况并不常见。

但它看起来像我可以添加一个C#DLL作为本地C++项目

这已经在每个VS版本中修修补补用,不是100%肯定,你在做什么内部参考。实际上,添加引用时很少发生,它只是让编译器驱动程序添加/FU compile option。如果.cpp文件没有用/ clr编译,那么它什么也不做,编译器完全忽略它。当您在源代码中使用#using并且没有使用/ clr时,它会大声抱怨。否则两者之间没有真正的区别,只是更容易用/ FU来控制文件的路径。

,因为它不仅使过渡到管理世界

一个忠告是适当的在这里,有很多事情。你在这里做的是称为“反向调整”,本地代码调用托管代码。 C++/CLI主要是为了完全相反。涉及更多的是,需要发生的不平凡的事情是CLR需要在第一次调用时加载和初始化。这完全是automagic,由使用__declspec(dllexport)时自动生成的存根提供。与Robert Giesecke的“Unmanaged Exports”实用程序所依赖的魔术一样,您应该看看另一个选项。

但它是有限的。你不能公开一个对象模型,只是简单的函数。函数调用会增加额外的开销,尽管它非常适中。而这个大问题,你不能轻易诊断错误。 CLR和大多数C#代码都希望调用者知道如何处理异常。问题是你不能从本机C++代码。你有一些在使用__try/__except的余地,但你不能得到有关例外的任何细节。这会将非常简单的问题(如FileNotFoundException)变成完全不可知的崩溃。您可以通过将调试器类型设置为“混合”来进行调试,但在发货后您无法做任何有用的工作。非常难看的支持电话。

在没有这些问题的情况下完成相同操作的其他方法是在C#库中使用[ComVisible(true)],允许在本机C++代码中使用#import。并通过其托管接口自定义托管CLR,这种方法使用的是支持用托管代码编写的插件的程序。像AutoCAD这样的CAD程序就是很好的例子。和Visual Studio。

0

尝试ILASM 2.0https://msdn.microsoft.com/tr-tr/library/496e4ekx(v=vs.110).aspx

基本上,工作是一样的C++/CLI的出口。

// unmexports.il 
// Compile with : ilasm unmexports.il /dll 
.assembly extern mscorlib { auto } 
.assembly UnmExports {} 
.module UnmExports.dll 
.method public static void Bar() 
{ 
    .export [1] as bar 
    ldstr "Hello from managed function" 
    call void [mscorlib]System.Console::WriteLine(string) 
    ret 
} 

注意:您可以使用ILDASM反编译C#和C++/CLI以了解如何导出它。 (如例子中)