将 char* C 函数编组到 C#
Marshalling char* C function to C#
我试图了解如何通过在托管和非托管代码之间来回传递和修改字符串来编组 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
谢谢!
您可以将导入函数的 return 类型声明为 string
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static string CharTest(string ptchar, string ptuchar);
但是由于您实际上是 return 参数之一,您将不得不依赖编组器在复制 return 缓冲区之前不释放参数缓冲区。
您还有两个选择:
- 自己编组。确保将其放在
try/finally
中以防出现异常
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest(IntPtr ptchar, string ptuchar);
static void Main()
{
string ptchar = "ptchar";
string ptuchar = "ptuchar";
IntPtr ptcharPtr = IntPtr.Zero;
try
{
ptcharPtr = Marshal.StringToHGlobalAnsi(ptchar);
Console.WriteLine(Marshal.PtrToStringAnsi(CharTest(ptcharPtr, ptuchar)));
}
finally
{
Marshal.FreeHGlobal(ptcharPtr);
}
}
- 将参数声明为
StringBuilder
,这意味着它将被双向复制。在这种情况下,您不需要查看 return 值,因为它将与参数相同。
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest([In, Out] StringBuilder ptchar, string ptuchar);
static void Main()
{
StringBuilder ptchar = new StringBuilder("ptchar");
string ptuchar = "ptuchar";
CharTest(ptchar, ptuchar);
Console.WriteLine(ptchar);
}
我试图了解如何通过在托管和非托管代码之间来回传递和修改字符串来编组 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
谢谢!
您可以将导入函数的 return 类型声明为 string
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static string CharTest(string ptchar, string ptuchar);
但是由于您实际上是 return 参数之一,您将不得不依赖编组器在复制 return 缓冲区之前不释放参数缓冲区。
您还有两个选择:
- 自己编组。确保将其放在
try/finally
中以防出现异常
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest(IntPtr ptchar, string ptuchar);
static void Main()
{
string ptchar = "ptchar";
string ptuchar = "ptuchar";
IntPtr ptcharPtr = IntPtr.Zero;
try
{
ptcharPtr = Marshal.StringToHGlobalAnsi(ptchar);
Console.WriteLine(Marshal.PtrToStringAnsi(CharTest(ptcharPtr, ptuchar)));
}
finally
{
Marshal.FreeHGlobal(ptcharPtr);
}
}
- 将参数声明为
StringBuilder
,这意味着它将被双向复制。在这种情况下,您不需要查看 return 值,因为它将与参数相同。
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr CharTest([In, Out] StringBuilder ptchar, string ptuchar);
static void Main()
{
StringBuilder ptchar = new StringBuilder("ptchar");
string ptuchar = "ptuchar";
CharTest(ptchar, ptuchar);
Console.WriteLine(ptchar);
}