将 char* C 函数编组到 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

谢谢!

解决方法

您可以将导入函数的返回类型声明为 string

[DllImport("Sandbox.dll",CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Ansi)]
extern static string CharTest(string ptchar,string ptuchar);

但由于您实际上是在返回参数之一,因此您将不得不依赖编组器在复制返回缓冲区之前不释放参数缓冲区。

您还有两个选择:

  • 自行编组。确保将其放在 try/finally 中以防万一
[DllImport("Sandbox.dll",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,这意味着它将被双向复制。在这种情况下,您无需查看返回值,因为它与参数相同。
[DllImport("Sandbox.dll",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);
}