基本上我需要从Visual C ++代码中调用C#代码。 在阅读了很多关于可能方法的文章后,我决定使用C ++ / CLI机制。
最初我决定在C ++本机代码(dll库项目)中有一些函数,它们将调用CLR项目中的一些函数,这些函数将调用C#项目中的一些函数。
之后我认为也许我可以摆脱桥梁项目(CLR项目),因为它只能转变为托管世界。我认为我可以创建我的原生项目,我可以添加一个c ++源文件,我可以只为该文件而不是整个项目启用CLR支持。 所以这意味着我的本机项目将只包含一个可以使用C ++ / CLI语法并代表桥接的文件。所有其他文件只是本机C ++源文件。 从设计角度看这是对的吗?!
为了做到这一点,我想我必须将托管的C#dll文件添加到C ++本机dll文件的其他#using Directories属性中。 问题是我不知道如何根据当前配置设置C#dll调试或发布版本的路径。
另外我知道我无法将本机C ++ DLL添加到C#项目引用中。 但看起来我可以在本机C ++项目中添加一个C#dll作为引用。怎么会 ?!这甚至有用吗? 如果我可以将C#dll添加到本机C ++项目引用中,是否需要设置那些#using目录?!
答案 0 :(得分:6)
我只能为该文件而不是整个项目启用CLR支持
通过选择CLR项目模板,在执行此操作和开始之间没有有效的区别。无论哪种方式,结果都是混合模式.NET程序集,包含MSIL和本机代码。在项目级别执行此操作仅为项目中的.cpp文件设置/ clr的默认值。您也可以通过覆盖单个.cpp文件的设置来使用CLR项目模板执行此操作,现在禁用/ clr。最终结果都是一样的。
我认为我必须将托管的C#dll文件添加到其他#using目录
是的,这是一种方法。也解决了您的查询,您可以在路径名中使用$(Configuration)宏。根据您构建的配置,在编译时解析为“Debug”或“Release”。我应该强调,这实际上并不是必要的。编译器仅使用C#程序集中的元数据。只是声明。完全相当于.h文件,请注意您很少根据配置使#include不同。唯一的一个例子就是当您在C#源代码中使用#if DEBUG
来包含/排除代码时,这种情况并不常见。
但看起来我可以在本机C ++项目中添加C#dll作为引用
这在每个VS版本中都被修改过,而不是100%确定你在做什么。在添加引用时,实际上很少发生,它只是让编译器驱动程序添加/FU compile option。如果.cpp文件没有使用/ clr编译,那么它什么都不做,编译器就完全忽略了它。当您在源代码中使用#using
并且未使用/ clr时,它会大声抱怨。两者之间没有真正的区别,否则,用/ FU更容易控制文件的路径。
因为它只会转换为托管世界
这里需要谨慎,还有很多事情要做。你在这里做的是“反向pinvoke”,本机代码调用托管代码。 C ++ / CLI主要是为了完全相反而设计的。它涉及更多,需要发生的非平凡事情是需要在第一次调用时加载和初始化CLR。这都是自动的,由使用__declspec(dllexport)
时自动生成的存根提供。罗伯特·吉塞克(Robert Giesecke)的“非管理出口”(Unmanaged Exports)实用程序所依赖的魔法,你应该看到的另一种选择。
但它有限。您不能公开对象模型,只需简单的函数。函数调用中增加了开销,尽管它非常适中。而大的,大的问题,你不能轻易诊断错误。 CLR和大多数C#代码都希望调用者知道如何处理异常。问题是你不是从本机C ++代码。您在使用__try/__except
时有一些余地,但您无法获得有关该例外的任何详细信息。这将非常简单的问题(如FileNotFoundException)转变为完全不可诊断的崩溃。您可以通过将调试器类型设置为“混合”来调试它,但在发货后您无法执行任何有用的操作。非常难看的支持电话。
在没有这些问题的情况下实现相同的其他方法是在C#库中使用[ComVisible(true)],允许在本机C ++代码中使用#import。并通过其托管接口自定义托管CLR,这种方法支持使用托管代码编写的插件。像AutoCAD这样的CAD程序就是很好的例子。和Visual Studio。
答案 1 :(得分:1)
我怀疑你可以让整个项目非CLI,并且只在CLI中使用一个文件。总的来说,这种方法相当棘手。
我建议您考虑使用DllExportAttribute
导出C#函数:https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports
答案 2 :(得分:0)
尝试ILASM 2.0
https://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以查看如何导出它。 (如示例中所示)