2010-04-09 127 views
7

因此,我所拥有的是包含在* .dll中的C++ API,并且我想使用C#应用程序来调用API中的方法。将C++ API暴露给C#

到目前为止,我已经创建了一个C++/CLR项目,包括本地C++ API和管理,以创建一个“桥”类,它看起来有点像下面这样:

// ManagedBridge.h 
#include <CoreAPI.h> 
using namespace __CORE_API; 

namespace ManagedAPIWrapper 
{ 
    public ref class Bridge 
    { 
     public: 
      int    bridge_test(void); 
      int    bridge_test2(api_struct* temp); 
    } 
} 

// ManagedBridge.cpp 
#include <ManagedBridge.h> 

int Bridge::bridge_test(void) 
{ 
    return test(); 
} 

int Bridge::bridge_test2(api_struct* temp) 
{ 
    return test2(temp); 
} 

我也有具有到C++/CLR“Bridge.dll”的引用,然后使用包含内的方法C#应用程序。我有许多问题与此:

  1. 我无法弄清楚如何调用bridge_test2的C#程序中,因为它没有一个什么样的api_struct实际上就是知识。我知道我需要在某个地方编组对象,但是我在C#程序还是C++/CLR桥中执行?
  2. 这看起来像一个暴露API中所有方法的啰嗦方式,有没有更容易的方式,我错过了? (不使用的P/Invoke!)

编辑:好了,我已经得到了现在的工作得益于以下反应的基础知识,但我的结构(称之为“api_struct2”在这个例子中)在C++的本机代码既有本地枚举和工会,如下所示:

typedef struct 
{ 
    enum_type1 eEnumExample; 
    union 
    { 
      long  lData; 
      int  iData; 
      unsigned char ucArray[128]; 
      char  *cString; 
      void  *pvoid; 
    } uData; 
} api_struct2; 

我想我已经找到了如何让枚举工作;我已经在托管代码中重新声明了它,并且正在执行“native_enum test = static_cast(eEnumExample)”以将托管版本切换为本机。

然而,工会让我难住,我不太确定如何攻击它..想法任何人?

回答

3

是的,你通过引用传递一个非托管结构。这对于C#程序来说是个问题,指针与垃圾回收非常不兼容。不包括它可能没有结构声明的事实。

可以通过声明结构的托管版本解决这个问题:

public value struct managed_api_struct { 
    // Members... 
}; 

现在你可以声明方法

int bridge_test2(managed_api_struct temp); // pass by value 

int bridge_test2(managed_api_struct% temp); // pass by reference 

选择后者,如果该结构具有超过4个字段(~16字节)。该方法需要将结构成员一个接一个地复制到非托管的api_struct中,并调用非托管的类方法。这是不幸的,因为托管结构的内存布局是不可预测的。

这是非常机械的,你可能会得到帮助from SWIG。我自己并没有使用它,不确定它是否足够聪明来处理通过的结构。

一个完全不同的方法是通过给它一个构造函数和/或属性让包装类更清洁,让它可以构建api_struct的内容。或者你可以为结构声明一个wrapper ref类,就像在托管代码中一样。

+0

那么这是否意味着我在C++/CLI * .dll或C#代码本身中创建了managed_api_struct?另外,我认为只要您使用StructLayout属性,就可以将托管结构传递给本机代码? – Siyfion 2010-04-12 07:43:28

+0

这并不重要,但C++/CLI可以避免循环依赖。是的,[StructLayout]可以工作,但是你必须使用Marshal :: StructureToPtr()调用。托管结构的布局不可预测。 – 2010-04-12 10:26:18

+0

好的,谢谢,我现在就去看看,看看我在哪里。 – Siyfion 2010-04-12 13:10:11

2

,因为它没有一个什么样的api_struct实际上是

您需要在.NET程序集定义一个托管版本的知识,使用属性(如StructLayoutAttribute),以确保其正确编组。

这似乎是一个很啰嗦[...]

另一种方法是建立在你的API COM包装(例如使用ATL)。这可能会更加努力,但至少可以避免P/Invoke所需的结构和函数定义的双重编码。

修正:您已经创建了一个C++/CLI项目:所以只需要添加正确的“的#pragma”来告诉编译器,这是.NET代码,然后将输出的是C#项目可以直接引用的组件。

+0

什么将添加#pragma帮助我?是否有任何方法可以将所有编组放在C++/CLI项目中,以便引用它的每个项目都不必重新声明相应的.NET结构/类? – Siyfion 2010-04-09 10:10:57

+0

@Siyfion:'#pragma managed'允许切入和切出托管代码。请参阅http://msdn.microsoft.com/en-us/library/0adb9zxe(VS.100).aspx – Richard 2010-04-09 10:37:11

+0

我明白,但它目前工作,所以我不明白什么添加,将使我能做! ? – Siyfion 2010-04-09 10:38:15

2

尤奥正试图做到这一点更复杂,它确实是。你想要的是两个不同的结构。一个管理和一个非托管。您从外部公开受管版本(到您的C#应用​​程序)。这将是所有“.Net-ish”,没有任何工会的概念。

在您的网桥中,您会收到管理版本的结构,手动创建非托管结构并编写代码以将数据逐字段移至非托管结构。然后调用您的非托管代码,最后将数据移回托管结构。

有关C++/CLI的美妙之处在于托管代码还可以处理非托管代码和数据(并包含非托管的.h文件)。