PInvoke,来回传输数据

PInvoke, data transfer forth and back

本文关键字:传输 数据 PInvoke      更新时间:2023-10-16

我正在尝试使用p/Invoke从c#调用c++函数。

[DllImport(PATH)]
public static extern int PQunescapeByteaWrapper(
    ref byte[] src,
    ref byte[] dst);

匹配的c++函数如下:

extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst)
{
size_t dst_len;
dst = PQunescapeBytea(src, &dst_len);
return ((int)dst_len);
}

和c#的调用:

PQfun.PQunescapeByteaWrapper(ref EscapedMessage, ref UnescapedMessage);

调试到c++中,我可以看到"src"被正确传输,也"dst"被计算,但是当我跳回c#时,"dst"字节[]数组不保存"dst" unsigned char*数组值,而是c++ p/Invoke之前的原始值!!我怎样才能转移计算值?

问候,Stefan

你的c++方法签名和实现是错误的。您正在为参数分配一个新地址。应该使用指向指针的指针,例如

extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char** dst)
{
    size_t dst_len;
    *dst = PQunescapeBytea(src, &dst_len);
    return ((int)dst_len);
}

顺便说一句,你这里没有内存泄漏吗?您是打算覆盖由DST引用的现有数组中的值,还是打算创建一个新数组并将其分配给DST ?

我认为你应该这样写,而不是在你的c#代码中分配dst缓冲区。

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 ));
}

据我所知有几个问题。

1) c#使用__stdcall来调用C函数。所以你必须添加属性[DllImport(PATH, CallingConvention=CallingConvention. cdecl)]或指定__stdcall属性到你的C函数。

2)如果你需要传递一个数组,你不需要ref关键字。

[DllImport(PATH)]
public static extern int MyFunction(byte[] src);
extern DECLSPEC int __stdcall MyFunction(unsigned char* src);

3)在c#中不能使用从c++中分配的数组。你需要将它复制到托管内存中(c#数组)。要做到这一点,你可以做两个函数。一个计算新数组需要多少字符的函数。在目标数组中执行转换的另一个。

你可以这样做:

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不能返回一个新的数组,它必须将转换的内容复制到输出参数中