mray190
mray190

Reputation: 506

Convert char* buffers to byte arrays when using SWIG and C#

I maintain a C++ SDK that now needs to be converted to other languages (specifically C# and Java). I am using SWIG to generate my wrapper code and successfully have completed the Java work. I now need to get C# working.

I have a C++ function (ignore the Header object in the function signature - I have that worked out already)

int send(Header header, char *payload);

Furthermore, I have a director class in C++ that is as follows:

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

Which allows me to create callbacks in my Java and C# code.

I need the following function signatures for send and receive in C#:

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

and

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

Typemaps in SWIG seem to be the way to go so here was my attempt at typemapping for 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"

The results of that interface file gets my desired function signatures but my byte arrays are only size 1 and I only get the first item in my original char buffers. It seems as if SWIG interpreted the char* as a pointer to a char and therefore stuck the first element in my char* buffer into a byte array and called it good. But I would like to create a byte array of size 2048 (no payload will have a size greater than that) and fill that byte array from the char* buffer. If it makes any difference, my Header class object has the size of the char* buffer but I really could care less about that right now and stick with an overall size of 2048 bytes.

Thoughts or help would be appreciated!

@Flexo I have seen your other SWIG posts on StackOverflow and you seem to by my guy for helping me out. Fingers crossed you see this!

Upvotes: 5

Views: 2156

Answers (1)

Matt T
Matt T

Reputation: 617

I have had the same problem, and have just got it to work.

C++ as follows

// Access.h

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

Swig .i file is then as follows. It appears to be important that the %apply appears before the %include of the code to be wrapped. If it is after then nothing changes.

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

C# is then like this

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

With swig 3.0.2 I could not get this to work at all. With swig 3.0.12 I was successful.

I have not yet needed an output array, but this method would at least work with a pre-allocated buffer in C#.

Upvotes: 4

Related Questions