Reputation: 97
I 'm trying to use P/Invoke to call a C++ function from C#.
[DllImport(PATH)]
public static extern int PQunescapeByteaWrapper(
ref byte[] src,
ref byte[] dst);
The matching C++ function looks like the following:
extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst)
{
size_t dst_len;
dst = PQunescapeBytea(src, &dst_len);
return ((int)dst_len);
}
And the call of the C#:
PQfun.PQunescapeByteaWrapper(ref EscapedMessage, ref UnescapedMessage);
Debugging into the C++ I can see that "src" is transferred correctly and also "dst" is computed, but when I jump back to C# the "dst" byte[] array does not hold the "dst" unsigned char* array value but the original one before the C++ P/Invoke!! How can I manage to transfer the computed value?
Regards, Stefan
Upvotes: 0
Views: 814
Reputation: 9060
There are several problems as much as i can see.
1) C# uses __stdcall to call C functions. So you must add attribute [DllImport(PATH, CallingConvention=CallingConvention.Cdecl)] or specify the __stdcall attribute to your C function.
2) If you need to pass an array, you don't need the "ref" keyword.
[DllImport(PATH)]
public static extern int MyFunction(byte[] src);
extern DECLSPEC int __stdcall MyFunction(unsigned char* src);
3) You cannot use in C# an array allocated from C++. You need to copy it in managed memory (a C# array). To do that you can do two functions for example. One that counts how much characters you need for your new array. Another one that performs the conversion in the destination array.
So you can do something like this:
public static byte[] MyConvert(byte[] myArray)
{
// Function defined in your C/C++ dll that compute how much space you need.
int count = CountRequiredChars(myArray);
byte[] myNewArray = new byte[count];
// Function defined in your C/C++ dll that writes into myNewArray the output.
PerformMyConversion(myArray, myNewArray);
return myNewArray;
}
PerformMyConversion must not return a new array, it must copies the content of the conversion into the output parameter.
Upvotes: 0
Reputation: 36092
I think you should write it like this instead and allocate the dst
buffer outside in your C# code.
int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst, size_t maxlen)
{
size_t dst_len = 0;
unsgigned char* tmp = PQunescapeBytea( src, &dst_len );
memcpy( dst, tmp, min( maxlen, dst_len ));
}
Upvotes: 1
Reputation: 15130
You're C++ method signature and implementation is wrong. You are assigning a new address to the parameter. You should use a pointer to a pointer e.g.
extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char** dst)
{
size_t dst_len;
*dst = PQunescapeBytea(src, &dst_len);
return ((int)dst_len);
}
BTW, dont you have a memory leak here? did you intent to overwrite the values within the existing array referred to by dst or did you intent to create a new array and assign that to dst?
Upvotes: 1