5

从外部 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
}

但这对我没有帮助。

提前致谢!

4

2 回答 2

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.

于 2012-09-04T15:50:09.823 回答
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);
  }
于 2012-09-04T14:34:30.800 回答