c# - 访问库函数时 char** 的编码问题

标签 c# linux gcc mono

我正在将用 C++/VisualStudio 编写的现有库/DLL 移植到代码块/GCC。 Windows 中的 DLL 已经在 C#、C、C++、Python、Delphi、Java、VB.NET、LabVIEW 等环境中进行了测试,运行良好且稳定。 但是,将它移植到 Linux 时,我在从 Mono/C# 测试它时遇到了问题,而它在 FreePascal 和 Python 上运行良好。

问题的根源是一个函数,它检测一些设备并返回一个整数,其中检测到的设备数量,以及设备所在路径的列表(字符的 ASCII 字符串数组),通过参数:

int DetectDevices(char ** DevicePaths);

我在库中复制结果的方式是:

i=0;
for (vector<string>::iterator it=lstDetected.begin(); it!=lstDetected.end(); ++it)
    strcpy(DevicePaths[i++], (*it).c_str());

在 C# 中,我使用以下代码声明外部函数:

[DllImport(LIBRARY_PATH)]
public static extern int DetectDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] DevicePaths);

我想指出,在调用函数并获取返回值之前,我实际上在 C# 中保留了一些内存空间:

string[] DevicePaths = new string[50];
for (int i=0; i<DevicePaths.Length; i++)
    DevicePaths[i] = new string('\0', 255);

这在 Windows/VisualStudio 中工作正常,但在 Linux/Mono 中却不行。

用 LPWStr 替换 LPStr 并执行调试,显示字符应该到达,但接收到的等效 ASCII 代码对于 LPStr 中的所有字符为 0,在 LPWStr 中为 63。

我认为这可能与字符编码相关的问题有关,但我可能错了。

有没有人知道这里可能出了什么问题? 非常感谢您的帮助!

最佳答案

我终于设法找到了编码问题的解决方案。

在Windows(.NET framework)和Visual Studio中,允许通过以下方式返回一个C字符串数组(array of char array)参数:

[DllImport(LIBRARY_PATH)]
public static extern int DetectDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] DevicePaths);

出于某种原因,这在 Linux/Mono 中不起作用,我不得不使用以下方法:

public static extern int DetectDevices(IntPtr[] pDevicePaths);

然后,在代码中使用以下方法检索每个字符串:

const int VCOUNT = 50;
const int MAXSTRINGSIZE = 255;
string[] MyValues = new string[VCOUNT];

IntPtr[] ptr = new IntPtr[VCOUNT];
for (int i = 0; i < ptr.Length; i++) ptr[i] = Marshal.AllocCoTaskMem(MAXSTRINGSIZE);

int n = DetectDevices(ptr);
if (n > 0) {
    for (int i = 0; i < n; i++) {
        StringBuilder sb = new StringBuilder(Marshal.PtrToStringAnsi(ptr[i]));
        MyValues[i] = sb.ToString();
    }
}

这是一种更像 C/C++ 的风格,虽然增加了复杂性,但也很有意义。 所以我认为要么 Mono 没有完全实现,要么某处存在错误。

如果有人有更好的解决方案,我将不胜感激。

关于c# - 访问库函数时 char** 的编码问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56525096/

相关文章:

c# - 如何将表达式 Func<T,int> 转换为 Func<T,object>

对 SignalR 集线器方法的 Javascript 调用不返回值

linux - 在一行代码中使用 basename 替换扩展名

c# - 私有(private)服务器/客户端的自签名证书安全

c# - LINQ 查询的位置

linux - 简短的唯一 ID

linux - 如何在 tcl/tk 中开发对话仪表,通过移动它来获取循环值并更新刻度小部件

c++ - 如何在 Powershell 中运行 C++ 程序,就像 CMD 一样?

c++ - 没有第二个操作数的三元运算符

c - '…' 标记之前是否需要声明说明符或 '<'?