我正在将用 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/