PInvoke,来回数据传输

发布于 2024-12-11 07:48:21 字数 694 浏览 0 评论 0原文

我正在尝试使用 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* 数组 值,而是 C++ P/Invoke 之前的原始值! 我怎样才能转移计算值?

问候,斯特凡

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

绿萝 2024-12-18 07:48:21

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

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?

書生途 2024-12-18 07:48:21

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

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 ));
}
红颜悴 2024-12-18 07:48:21

据我所知,存在几个问题。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文