PInvoke,数据传输前后

时间:2011-10-21 10:13:40

标签: c# c++ pinvoke bytearray dllimport

我正在尝试使用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”byte []数组不能保持“dst”unsigned char * array 值,但是在C ++ P / Invoke之前的原始值! 如何设置传输计算值?

此致,Stefan

3 个答案:

答案 0 :(得分:1)

你是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?

答案 1 :(得分:1)

我认为你应该这样写,并在你的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 ));
}

答案 2 :(得分:0)

我可以看到几个问题。

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

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