【发布时间】:2021-08-20 10:29:53
【问题描述】:
我试图了解如何通过在托管和非托管代码之间来回传递和修改字符串来编组 char* 类型。托管到非托管代码似乎可以正常工作,但反之则不行。 IntPtr 适合这种情况吗?
C
EXPORT char* CharTest(char* ptchar, unsigned char* ptuchar)
{
ptchar[0] = 'x';
ptchar[1] = 'y';
printf("%s %s\n", ptchar, ptuchar);
return(ptchar);
}
C#
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest(string ptchar, string ptuchar);
static void Main()
{
string ptchar = "ptchar";
string ptuchar = "ptuchar";
Console.WriteLine(Marshal.PtrToStringAnsi(CharTest(ptchar, ptuchar)));
}
输出
xychar ptuchar
x?J
谢谢!
【问题讨论】:
-
这里发生了一大堆关于谁拥有哪块内存的问题。编组器正在为
ptchar和ptuchar分配新的char*缓冲区,并将您的字符串复制到其中。它在本机调用返回后立即释放这些缓冲区。但是,您随后会从您的函数中返回其中一个缓冲区——但它刚刚被释放! -
我的第一反应是将 C# 中的方法声明为
extern static string CharTest(...);并让互操作层处理所有转换。你试过了吗? -
这并不能解决问题,因为你搞砸了谁拥有什么。如果你没有遵循 marshaller 默认为你提供的所有权语义,你真的需要回退到传递
IntPtr并自己进行内存管理 -
先生们您好,谢谢您的回答,@Heinzi 声明为字符串而不是 IntPtr 似乎已经解决了这个问题,我对 char* 和 unsigned char* “转换”感到有点不安作为一个字符串。我不应该在函数声明中添加额外的编组信息,例如 In Out 或 MarshalAs 吗?
-
@canton7 可能是错误的,但如果 C 的返回类型是
string,编组器不会在对参数缓冲区执行任何free之前复制字符串吗?
标签: c# c marshalling unmanaged managed