如何将C#字符串[]转换为System.IntPtr

本文关键字:转换 System IntPtr 字符串 | 更新日期: 2023-09-27 18:20:04

我需要在应用程序中使用本机dll结构。dll.h文件中的结构体da_i2k_input_file_info为

struct DA_I2K_EXPORT_API da_i2k_input_file_info {
  const WDCHAR *  image_path;
  const WDCHAR ** image_files;
  int             num_images;
};

这就是如果用C++编写的用户代码的样子

in_file_info.num_images = 3;
in_file_info.image_files = new const WDCHAR*[in_file_info.num_images];
in_file_info.image_files[0] = WSTR("IMG_8670.JPG");
in_file_info.image_files[1] = WSTR("IMG_8671.JPG");
in_file_info.image_files[2] = WSTR("IMG_8672.JPG");

但是这个C#代码

[StructLayout(LayoutKind.Sequential)]
public struct da_i2k_input_file_info
{
    [MarshalAs(UnmanagedType.LPTStr)]
    public string image_path;
    public IntPtr image_files;
    public int num_images;
}
var openFileDialog = new OpenFileDialog{Multiselect = true};
da_i2k_input_file_info in_file_info;
in_file_info.image_path = null; // use full path in .image_files
in_file_info.num_images = openFileDialog.FileNames.Length;
in_file_info.image_files = openFileDialog.FileNames;

导致此错误

无法将类型"string[]"隐式转换为"System.IntPtr"

将openFileDialog.FileNames强制转换为IntPtr没有帮助。如何从openFileDialog.FileNames加载in_file_info.image_files?

编辑:OP在此交叉发布

如何将C#字符串[]转换为System.IntPtr

我认为您需要将结构更改为如下所示:

[StructLayout(LayoutKind.Sequential)]
public struct da_i2k_input_file_info
{
    [MarshalAs(UnmanagedType.LPTStr)]
    public string image_path;
    [MarshalAs(UnmanagedType.LPArray)]
    public string[] image_files;
    public int num_images;
}

这里发布了一个有效的答案。

代码如下
(包括tomfanning)

    private static void DoTest()
    {
        var openFileDialog = new OpenFileDialog { Multiselect = true };
        da_i2k_input_file_info in_file_info;
        openFileDialog.ShowDialog();
        in_file_info.image_path = null; // use full path in .image_files
        in_file_info.num_images = openFileDialog.FileNames.Length;
        // Create an array of IntPtrs.
        IntPtr[] image_files_array = new IntPtr[in_file_info.num_images];
        // Each IntPtr array element will point to a copy of a
        // string element in the openFileDialog.FileNames array.
        for (int i = 0; i < openFileDialog.FileNames.Length; i++)
        {
            image_files_array[i] = Marshal.StringToCoTaskMemUni(openFileDialog.FileNames[i]);
        }
        // In order to obtain the address of the IntPtr array, 
        // we must fix it in memory. We do this using GCHandle.
        GCHandle gch = GCHandle.Alloc(image_files_array, GCHandleType.Pinned);
        // pimage_files will point to the head of the IntPtr array.
        IntPtr pimage_files = gch.AddrOfPinnedObject();
        // Set pimage_files as the value of the "image_files" field/
        in_file_info.image_files = pimage_files;
        // Call a Test API.
        TestStructure(in_file_info);
        // After the API is called, free the GCHandle.
        gch.Free();
        // Free each string contained in the IntPtr array.
        for (int i = 0; i < openFileDialog.FileNames.Length; i++)
        {
            Marshal.FreeCoTaskMem(image_files_array[i]);
        }
    }