C# WPF 将 UTF16 字符串传递给接受 char * 的函数

C# WPF passing UTF16 string to a function that accepts char *

我创建了一个 wpf 项目,它有一个 helper static class,其中包含我所有的 C++ 后端代码。一个这样的函数被定义为:

public static unsafe class Backend {

    [DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public extern static void write(void* ptr, char* path);
}
public partial class MainWindow : Window
    {
        public MainWindow()
        {
            string path = "mypath";
            InitializeComponent();
            unsafe
            {
                char *p; //convert
                void* myObj = Backend.init_obj(1920, 1080);
                Backend.gen(myObj);
                Backend.write(myObj, p);
            }
        }
    }

void* ptr 实际上是我的对象,为了将其编组到 C# 端而被强制转换。我面临的问题是,每当我尝试在 wpf 中使用字符串文字调用它时,我发现 Visual C# 无法转换它,因为字符串文字是用 UTF16 编码的。自然地,除了手动将相关字节复制到 char 数组之外,我尝试了很多其他方法。有什么建议吗?

CLR 可以很好地与 C/C++ 代码进行互操作的其中一件事是在托管代码和非托管代码之间编组数据结构。由于字符串非常重要,因此为使字符串编组尽可能好做了大量工作。

附带说明一下,您正在使用 void* 作为由 init 创建并传递给 write 的上下文对象。由于您只是将其交还,因此可以将其替换为 IntPtr 并完全避免 unsafe 块。 IntPtr 始终是当前体系结构中指针的大小。

首先,让我们更改导入函数的声明。 CharSet.Ansi 告诉它将字符串编组为 ANSI。 ptr 参数变为 IntPtr

[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static IntPtr init(int width, int height);

[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void gen(IntPtr ptr);

[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(IntPtr ptr, string path);

从那里,您可以弄清楚如何修改函数以解除分配 ptr 以及您必须调用的任何其他函数。

使用这些功能变得更加容易和简洁。您不需要 unsafe 块,您可以将 path 直接传递给 write.

public MainWindow()
{
    string path = "mypath";
    InitializeComponent();

    IntPtr myObj = Backend.init_obj(1920, 1080);
    Backend.gen(myObj);
    Backend.write(myObj, path);
}

使它起作用的原始评论:

Instead of trying to create the char* parameter yourself, change the declaration so the second parameter is string and let the Runtime marshal it for you. Because it's an ANSI string, you're never going to get full unicode fidelity but that's a problem created by the C++ code.