本地C++和C#互操作

6
我正在设计一个应用程序,其中必须使用C++工作,但MFC/ATL太混乱了,所以我有一个很好的想法,即将所有“思考”代码放在本机C++中,将所有漂亮的UI代码放在C#中。然而,问题在于两者之间的互操作性。在我沉迷于此之前,我想知道这是否是一个已经解决的问题,并且是否有一种非常好的方法来实现它。请注意,我不想在同一模块中混合逻辑和显示,因为它会导致耦合度极高。
这是我目前的进展:
告诉我,它能做得更好吗?

1
因为已经有一个暴露了C++ API的现有代码库,而且这是我的共同语言。如果没有指针,我会迷失方向。 - Clark Gaebel
2个回答

11

处理这个问题最简单的方法是使用C++/CLI,将您的逻辑公开为.NET类型。

ref class包装本地C++类非常容易,可以直接从C#用户界面使用。

话虽如此,这正是我在当前项目中的计划。 我的想法是,我需要本地代码来处理我们通常要做的一些重型数学工作。 但是,我发现直接将大部分逻辑移植到C#中(与UI代码分离,但仍在一个C#程序集中)比尝试在C++中实现更容易、更快、更好。

我的经验是速度不是问题-当调优时,不安全的C#代码几乎总能达到与等效的C++相同甚至更快的速度,并且更容易分析和调整C#代码。


那么我放在Proxy.dll中的包装器代码基本上是相同的策略吗?我可以把它看作是“看起来不错”吗? - Clark Gaebel
就您图表中的.NET/C++接口部分而言,看起来不错。我曾经在现有的C++代码库中做过类似的事情,我想用C#来做GUI界面。 - AaronLS
我也曾将C代码重写为C#,并对所见到的性能非常满意。只有在处理器密集型应用程序中才会注意到它。 - Jeffrey Cameron
即使是非常耗费处理器资源的C++,在C#中也可以更快,令人惊讶... @wowus:是的。您可以将本机API(proxy.dll?)包装在一个或多个ref类实例中,并直接从C#中访问它们。 它非常好用。 - Reed Copsey
我只是使用Proxy.dll作为所有包装代码的容器,这样两个模块都不必知道对方的存在。 - Clark Gaebel

1

你可能有让你的核心成为DLL的充分理由,但这并非必要。我曾经成功地使用了一个C++应用程序,它创建了一个应用程序域并将一个程序集加载到其中,然后在应用程序域中实例化一个对象并调用它,将一个接口传递给应用程序。这基本上就是当你制作一个非托管应用程序时C运行时所做的事情。

C++代码向C#代码公开的接口是在C#中定义的。我认为这比在纯COM中定义接口更容易。C#互操作性比C++更具有控制权。

  • 创建一个名为app_interface.cs的文件来定义接口
  • 将app_interface.cs编译成dll,我们不关心dll,我们需要类型库。
  • 在C++代码中,使用#import <app_interface.tlb> raw_interfaces_only将类型库转换为带有接口定义的C++ .h文件:app_interface.tlh
  • 实现接口

您可以在app_interface.cs中添加控制封送的属性,例如:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("ffffffff-ffff-ffff-ffff-ffffffffffff")] // guid changed from what I really use 
public interface IMyHostApplication
{
   ...

   void   AddErrorDetails (
      [MarshalAs(UnmanagedType.Error)] uint hr, 
      [MarshalAs(UnmanagedType.LPWStr)] string  szErrDetails);

   ...
}

我想尽可能地将C++代码与C#代码分开,保持最小的表面积。此外,在进行本机操作时,我不想考虑托管代码。 - Clark Gaebel
重点是,从零开始时,最好从一开始就在C#中定义两个部分之间的接口。 #import保证了C++和C#看到的接口定义都来自单个文件。 - John Knoeller
不管你怎么做,都应该尽量减少C++和C#之间的接口表面积。 - John Knoeller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接