使用 SWIG 和 C# 时将 char* 缓冲区转换为字节数组

5
我维护一个C ++ SDK,现在需要将其转换为其他语言(特别是C#和Java)。 我使用SWIG生成包装器代码,并已成功完成Java工作。 现在我需要让C#正常工作。
我有一个C ++函数(忽略函数签名中的Header对象 - 我已经解决了)
int send(Header header, char *payload);

此外,我在C++中有一个名为director的类,其代码如下:

class Callbacks {
public:
    virtual ~Callbacks() { }
    virtual void receive(Header header, char *payload) { }
};

这使我能够在我的Java和C#代码中创建回调函数。

对于sendreceive,我需要在C#中获得以下函数签名:

int send(Header header, byte[] payload);

并且

void receive(Header header, byte[] payload);

在SWIG中,类型映射似乎是可行的方法,因此这是我尝试为C#实现类型映射的方式:

%module(directors="1") example

%{
#include "example.h"
%}

%feature("director") Callbacks;

%include "arrays_csharp.i"
CSHARP_ARRAYS(char, byte)
%typemap(imtype, inattributes="[In, MarshalAs(UnmanagedType.LPArray, SizeConst=2048, ArraySubType=UnmanagedType.U1)]") char INPUT[] "byte[]"

%apply char INPUT[] {char *payload}

%include "example/include/example.h"

接口文件的结果已经得到我所需的函数签名,但是我的字节数组只有大小为1,并且我只得到了原始char缓冲区中的第一个项目。似乎SWIG将char*解释为char指针,因此将char*缓冲区的第一个元素放入了byte数组中,并认为这样就行了。但是我想创建一个大小为2048的byte数组(没有有效载荷的大小会大于2048),并将该byte数组从char*缓冲区中填充。如果有任何区别的话,我的Header类对象具有char*缓冲区的大小,但我现在真正关心的是一个总体大小为2048个字节。
欢迎提出意见或帮助! @Flexo,我在StackOverflow上看到了你的其他SWIG帖子,你似乎是可以帮我解决问题的人。希望你能看到这条消息!
1个回答

4

我曾经遇到过同样的问题,现在已经解决了。

C++ 代码如下

// Access.h

class Access
{
    void foo(unsigned char *inputBytes, int nbytes);
};

Swig的.i文件如下。重要的是%apply出现在包装代码的%include之前,如果在之后就不会有任何变化。

%include "arrays_csharp.i"
%apply unsigned char INPUT[]  {unsigned char *inputBytes}  
%include "Access.h"

C#的语法就像这样

byte[] data = ...
var access = new Access();
access.foo(fileBytes, fileBytes.Length);

使用swig 3.0.2时,我完全无法使其正常工作。但使用swig 3.0.12后,我成功了。

至今我还没有需要输出数组的情况,但该方法至少可以在C#中使用预分配的缓冲区。


这在我的 SWIG 4.1.0(当前主版本)中有效。请注意,unsigned char INPUT[] 的拼写很重要!将其更改为 unsigned char DATA[] 不起作用 - emmenlau
实际上,您提出的解决方案和其他选项在SWIG C#文档中得到了很好的解释,网址为https://www.swig.org/Doc4.0/CSharp.html#CSharp_arrays。 - emmenlau

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