向C#公开C++ API

Siy*_*ion 7 c# c++ clr interop marshalling

所以我所拥有的是*.dll中包含的C++ API,我想使用C#应用程序来调用API中的方法.

到目前为止,我已经创建了一个包含本机C++ API的C++/CLR项目,并设法创建一个类似于以下内容的"桥"类:

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

.

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

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

int Bridge::bridge_test2(api_struct* temp)
{
    return test2(temp);
}
Run Code Online (Sandbox Code Playgroud)

我还有一个C#应用程序,它引用了C++/CLR"Bridge.dll",然后使用其中包含的方法.我有很多问题:

  1. 我无法弄清楚如何在C#程序中调用bridge_test2,因为它不知道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;
Run Code Online (Sandbox Code Playgroud)

我想我已经想出如何让enum工作; 我已经在托管代码中重新声明它并执行"native_enum test = static_cast(eEnumExample)"将托管版本切换为本机版本.

然而,工会让我难倒,我不确定如何攻击它..想法有人吗?

Han*_*ant 3

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

您可以通过声明结构的托管版本来解决它:

public value struct managed_api_struct {
  // Members...
};
Run Code Online (Sandbox Code Playgroud)

现在您可以将该方法声明为

int bridge_test2(managed_api_struct temp);   // pass by value
Run Code Online (Sandbox Code Playgroud)

或者

int bridge_test2(managed_api_struct% temp);  // pass by reference
Run Code Online (Sandbox Code Playgroud)

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

这一切都非常机械,您可能会从 SWIG获得帮助。我自己没有使用过它,不确定它是否足够智能来处理传递的结构。

一种完全不同的方法是通过为包装类提供一个构造函数和/或属性来让您构建 api_struct 的内容,从而使包装类更清晰。或者您可以为该结构声明一个包装器引用类,就像在托管代码中一样。