Распространенные проблемы

2

У меня есть С++ DLL, которая взаимодействует с устройством чтения карт. Для этого требуется указатель на структуру данных, что не является проблемой. Однако при попытке взаимодействия с DLL на С# у меня возникают всевозможные проблемы. Ошибки записи в защищенную память, приложение просто закрывается после выполнения команды getData и т.д. Вот что мы имеем.

С++ Метод из заголовка

void readCard(cardData* dataBuffer);

Код С#

Wrapper.cs
public struct cardData{
   Byte[] data01;
   Byte[] data02;
}

[dllImport("card.dll")]
public static extern void readCard(ref cardData data);

Form1.cs

Wrapper.cardData tmpData = new wrapper.cardData();
tmpData.data01 = new Byte[];
tmpData.data02 = new Byte[];
readCard(ref tmpData);

Я также пробовал передавать cardData как IntPtr, используя Marshal.StructureToPtr, который не возвращал никаких данных, когда возвращался, пытался прочитать ptr в структуру Marshal.PtrToStructure...

Я пытался работать с файлами справки и другими сообщениями, потому что кажется, что многие люди не могут работать с C/С++ DLL. Я даже попытался написать все это на С++ и вернуть ему строку с данными, проанализированными в С++ DLL, но которая бросает чтение/запись на защищенную память

  • 0
    Можете ли вы показать определение структуры C ++? Я думаю, что в вашем отображении что-то не так ...
Теги:
interop
pinvoke
marshalling

7 ответов

1

Самая большая проблема, которую я вижу с вашим кодом, заключается в том, что вы не указали своим байтам [] члены явного размера. Без этого оператора размера маршаллер будет рассматривать их точно так же, как простой ссылочный тип. Полученная структура будет иметь размер 8 байтов на 32-битной платформе и почти наверняка приведет к написанию защищенной памяти.

Предполагая, что байтовые массивы имеют фиксированный размер в коде C, вы должны использовать атрибут MarshalAs, чтобы дать байт-массивам одну и ту же семантику в управляемом коде. Это влечет за собой предоставление фиксированного размера.

[StructLayout(LayoutKind.Sequential)]
public struct cardData{
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
   Byte[] data01;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
   Byte[] data02;
}

Измените 300 на любой размер, указанный в собственном коде для массива.

Также вы должны добавить атрибут StructLayout.

0

Ok. Таким образом, структура была задана в соответствии со структурой структуры.

Wrapper.cs

[StructLayout(LayoutKind.Sequential)]
public struct cardData{
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=99)]
   Byte[] data01;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=101)]
   Byte[] data02;
}

[DllImport("card.Dll")]
public static extern void readCard(ref cardData data);

И теперь он просто закрывается... Нет ошибок, никаких изменений в данных, приложение просто отключается.

0

Инструмент подписи PInvoke помог мне в прошлом.

Например, следующий C/С++:

struct cardData{
 byte[] data01;
 byte[] data02;
}

void readCard(cardData* dataBuffer);

Он имеет:

 System.Runtime.InteropServices.StructLayoutAttribute(  System.Runtime.InteropServices.LayoutKind.Sequential)]
 public struct cardData {

  /// byte[]
  public byte[] data01;

  /// byte[]
  public byte[] data02;
}

/// Return Type: cardData
///dataBuffer: cardData*
public delegate cardData readCard(ref cardData dataBuffer);
0

Вот фрагмент C-DLL-оболочки в С#, который я сделал.

Как упоминал Юрий, вам не хватает атрибута StructLayout, и вы, вероятно, должны использовать собственные типы в своей структуре и объявлении своей функции. Вероятно, вам понадобится использовать ключевое слово unsafe в нескольких местах, что может быть или не быть приемлемым для вас, но это было хорошо для меня.

[StructLayout(LayoutKind.Sequential)]
 public unsafe struct X_Message
 {
      public byte id;
      public byte* data;
      public DWORD data_length;
 }

 // ...

 [DllImport("x-driver.dll")]
 protected unsafe static extern int X_ReadMessage(void* h, X_Message* message);
0

Я заметил, что ваш байт [] не имеет никакого размера, связанного с ними. Знаете ли вы, какого размера должны быть массивы? IIRC, пространство для массивов должно выделяться при инициализации.

Если я ухожу из базы, дайте мне знать, и я удалю этот пост.

0

Возможно, вашей карточке необходимо использовать StructLayoutAttribute. Также вы можете использовать Dependency Walker для поиска местоположения в файле card.dll для этого метода и добавить его как именованный параметр.

-1

Используйте IntPtr вместо байта []. Ваша DLL не может обрабатывать управляемые данные.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню