C# 访问库函数时char**的封送处理问题
我正在将一个用C++/VisualStudio编写的现有库/DLL移植到codeblocks/GCC。Windows中的DLL已经在C、C、C++、Python、Delphi、java、VB.NET、LabVIEW等测试,工作稳定、稳定。 然而,当将它移植到Linux时,我在从Mono/C#测试它时遇到了问题,而在FreePascal和Python中它工作正常 问题的根源是一个函数,该函数检测某些设备,并通过参数返回一个整数,其中包含检测到的设备数量,以及设备所在的路径列表(ASCII字符字符串数组):C# 访问库函数时char**的封送处理问题,c#,linux,gcc,mono,C#,Linux,Gcc,Mono,我正在将一个用C++/VisualStudio编写的现有库/DLL移植到codeblocks/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#中保留了一些内存空间:
string[] DevicePaths = new string[50];
for (int i=0; i<DevicePaths.Length; i++)
DevicePaths[i] = new string('\0', 255);
string[]设备路径=新字符串[50];
对于(int i=0;i尝试使用LPTStr
,它将字符串转换为平台的默认字符串编码。对于Mono,这是UTF-8
UnmanagedType.LPStr
=>ansi
UnmanagedType.LPWStr
=>unicode
UnmanagedType.LPTStr
=>平台默认值
还有其他UnmanagedType
也可以帮助…BStr
也许
如果这没有帮助,那么考虑使用自定义封送处理或手动封送处理。< /P>
这个问题非常好。我终于找到了封送问题的解决方案
在Windows(.NET framework)和Visual Studio中,允许通过以下方式返回字符串的C数组(字符数组的数组)参数:
[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();
}
}
然后,在代码中,使用以下方法检索每个字符串:
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();
}
}
const int VCOUNT=50;
常量int MAXSTRINGSIZE=255;
字符串[]MyValues=新字符串[VCOUNT];
IntPtr[]ptr=新的IntPtr[VCOUNT];
对于(int i=0;i0){
对于(int i=0;i
这是一种更为C/C++的风格,它增加了复杂性,但也有意义。
所以我认为要么Mono没有完全实现,要么某处有一个bug
如果有人有更好的解决方案,我会非常感激。编译时使用的字符集是什么(unicode还是多字节)?strcpy(DevicePaths[I++],(*it).c_str())
如果你没有超过数组,你在哪里检查呢?@LeonardoSeccia真诚地说,我没有在codeblocks/GCC中设置这个,所以我认为它被视为ASCII@Selvin因为我是测试这个的人,我可以确认内存不是问题。我不认为这是相关的。还要考虑到我已经简化了这个问题在这里,删除所有不相关的代码。可能是GCC上的字符编码问题?我应该如何正确设置字符编码?我已经测试了上面的所有选项,但没有成功。LPWStr返回正确的字符计数,但所有字符值都是63。BStr创建了一个异常。我也检查了此文档,但没有找到任何异常这对我的特殊问题很有用。@Carles-关于LPTStr
?你得到了什么?什么都没有,都设置为初始值:0。唯一给我带来问题的是LPWStr,它的结果是我期望的字符数,但它们都设置为63(我认为是多字节或unicode字符的较高部分)。