5

外部CDLLから以下を呼び出すと、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で正しく満たされます(また、サイズ= 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です。OK、ここではエンコーディングがUTF-8ではないという仮定がありますが、それは私が提供できない詳細です。これをUTF-8に適応させるのは簡単です。

stdcallまた、ネイティブコードが呼び出し規約を使用しており、を使用していないことを再確認する必要がありますcdecl

于 2012-09-04T15:50:09.823 に答える
2

編集:

わかりました、私はあなたの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 に答える