从外部C DLL调用以下内容时,我一直收到AccessViolationException:
short get_device_list(char ***device_list, int *number_of_devices);
我设置了一个DLLImport声明:
[DLLImport("mydll.dll")]
static public extern short get_device_list([MarshalAs(UnmanagedType.LPArray)] ref string[] devices, ref int number_of_devices);
我的C#应用程序代码:
{
string[] devices = new string[20];
int i = 0;
short ret = 0;
ret = get_device_list(ref devices, ref i); // I receive the AccessViolation Exception here
// devices[0] = "2255f796e958f7f31a7d2e6b833d2d426c634621" which is correct.
}
虽然我收到异常,但设备阵列正确填充了连接设备的2个UUID(并且还调整为size = 2; i也是2;)。
有什么问题?
PS:经过长时间的研究,我也尝试过:[DLLImport("mydll.dll")]
static public extern short get_device_list(ref IntPtr devices, ref int number_of_devices);
和
{
IntPtr devices = new IntPtr();
int i = 0;
short ret = 0;
ret = get_device_list(ref devices, ref i); // No AccessViolation Exception here
string b = Marshal.PtrToStringAuto(devices); // b = "歀ׄ", which is incorrect
}
但这对我没有帮助。
提前致谢!
答案 0 :(得分:3)
[DLLImport("mydll.dll")]
static public extern short get_device_list(out IntPtr devices,
out int number_of_devices);
是解决这个问题的最佳方法。内存在接口的本机端分配和拥有。诀窍是如何实现它。这样的事情应该有效。
static public string[] getDevices()
{
IntPtr devices;
int deviceCount;
short ret = get_device_list(out devices, out deviceCount);
//need to test ret in case of error
string[] result = new string[deviceCount];
for (int i=0; i<deviceCount; i++)
{
IntPtr ptr = (IntPtr)Marshal.PtrToStructure(devices, typeof(IntPtr));
result[i] = Marshal.PtrToStringAnsi(ptr);
devices += IntPtr.Size;//move to next element of array
}
return result;
}
您的代码正在使用PtrToStringAuto
,但这会将数据解释为UTF-16
编码。但是您的C ++代码使用的是char*
,它是8位ANSI。所以你需要PtrToStringAnsi
。好的,这里假设编码不是UTF-8,但这是我无法提供的细节。这很容易适应UTF-8。
您还应该仔细检查本机代码是否使用stdcall
调用约定并且未使用cdecl
。
答案 1 :(得分:2)
编辑:
好的,我想我第二次尝试就知道了这个问题。
{
IntPtr devices = new IntPtr();
int i = 0;
short ret = 0;
ret = get_device_list(ref devices, ref i); // No AccessViolation Exception here
string b = Marshal.PtrToStringAuto(devices); // b = "歀ׄ", which is incorrect
}
您尝试将指向字符串数组的指针转换为字符串。你必须先尊重它。请检查这是否适合您:
IntPtr devices = new IntPtr();
int numDevices = 0;
short ret = get_device_list(ref devices, ref numDevices); // No AccessViolation Exception here
for (int i=0; i<numDevices; i++)
{
IntPtr ptrToString = Marshal.ReadIntPtr(devices);
string deviceString = Marshal.PtrToStringAnsi(ptrToString);
devices += IntPtr.size;
Console.WriteLine(deviceString);
}