Вызов функций, возвращающих указатель на структуру, из нативной dll - C#

Узнай цену своей работы

Формулировка задачи:

Тут на форуме уже не раз задавали вопросы, как вызвать функцию из нативной dll. И в случае, если функция возвращает "нормальный" тип, у меня с этим вопросов нет: DllImport и всё такое. Но вот если функция возвращает указатель на интерфейс, вот тут у меня возникли проблемы. Имеется dll-ка (написана, кажется, на CBuilder), экспортирующая всего 2 функции. Так же имеются примеры работы с этой dll-кой в Delphi и в С++. На Delphi это выглядит так: Rtusbapi.pas
Листинг программы
  1. unit Rtusbapi;
  2. interface
  3. uses
  4. windows;
  5. type
  6. pSHORT = ^SHORT;
  7. pBYTE = ^BYTE;
  8. type
  9. // структура, задающая режимы ввода данных для модуля USB-3000
  10. INPUT_PARS_USB3000 = packed record // (size=438)
  11. size : WORD;
  12. InputEnabled : BOOL; // флажок разрешение/запрещение ввода данных (только при чтении)
  13. CorrectionEnabled : BOOL; // управление корректировкой входных данных (с АЦП)
  14. InputClockSource : WORD; // источник тактовых импульсов для ввода данных
  15. InputType : WORD; // тип вводимых с модуля даных (АЦП или ТТЛ)
  16. SynchroType : WORD; // тип синхронизации вводимых с модуля даных
  17. SynchroAdType : WORD; // тип аналоговой синхронизации
  18. SynchroAdMode : WORD; // режим аналоговой сихронизации
  19. SynchroAdChannel : WORD; // канал АЦП при аналоговой синхронизации
  20. SynchroAdPorog : SHORT; // порог срабатывания АЦП при аналоговой синхронизации
  21. ChannelsQuantity : WORD; // число активных логических каналов
  22. ControlTable : array [0..127] of WORD; // управляющая таблица с активными логическими каналами
  23. InputFifoBaseAddress : WORD; // базовый адрес FIFO буфера ввода
  24. InputFifoLength : WORD; // длина FIFO буфера ввода
  25. InputRate : double; // тактовая частота ввода данных в кГц
  26. InterKadrDelay : double; // межкадровая задержка в мс
  27. ChannelRate : double; // частота ввода фиксированного логического канала
  28. AdcOffsetCoef : array [0..7] of double; // корректировочные коэф. смещение нуля для АЦП
  29. AdcScaleCoef : array [0..7] of double; // корректировочные коэф. масштаба для АЦП
  30. end;
  31. pINPUT_PARS_USB3000 = ^INPUT_PARS_USB3000;
  32. // структура, задающая режимы вывода данных для модуля USB-3000
  33. OUTPUT_PARS_USB3000 = packed record // (size = 18)
  34. size : WORD;
  35. OutputEnabled : BOOL; // разрешение/запрещение вывода данных
  36. OutputRate : double; // частота вывода данных в кГц
  37. OutputFifoBaseAddress : WORD; // базовый адрес FIFO буфера вывода
  38. OutputFifoLength : WORD; // длина FIFO буфера вывода
  39. end;
  40. pOUTPUT_PARS_USB3000 = ^OUTPUT_PARS_USB3000;
  41. // структура пользовательского ППЗУ
  42. FLASH_USB3000 = packed record // (size = 256)
  43. CRC16 : WORD; // контрольная сумма
  44. size : WORD; // размер структуры
  45. SerialNumber : array [0..8] of BYTE; // серийный номер модуля
  46. Name : array [0..10] of BYTE; // название модуля
  47. Revision : CHAR; // ревизия модуля
  48. DspType : array [0..16] of BYTE; // тип установленного DSP
  49. IsDacPresented : BYTE; // флажок наличия ЦАП
  50. DspClockout : DWORD; // тактовая частота DSP в Гц
  51. AdcOffsetCoef : array [0..7] of single; // корректировочные коэф. смещения нуля для АЦП
  52. AdcScaleCoef : array [0..7] of single; // корректировочные коэф. масштаба для АЦП
  53. DacOffsetCoef : array [0..1] of single; // корректировочные коэф. смещения нуля для ЦАП
  54. DacScaleCoef : array [0..1] of single; // корректировочные коэф. масштаба для ЦАП
  55. ReservedByte : array [0..128] of BYTE; // зарезервировано
  56. end;
  57. pFLASH_USB3000 = ^FLASH_USB3000;
  58. // структура, содержащая информацию о версии драйвера DSP
  59. DSP_INFO_USB3000 = packed record // (size = 18)
  60. Target : array [0..9] of BYTE; // модуль, для которого предназначен данный драйвер DSP
  61. DrvLabel : array [0..5] of BYTE; // метка разработчика драйвера DSP
  62. DspMajor : BYTE; // старшие число версии драйвера DSP
  63. DspMinor : BYTE; // младшее число версии драйвера DSP
  64. end;
  65. pDSP_INFO_USB3000 = ^DSP_INFO_USB3000;
  66. // интерфейс модуля USB3000 `
  67. IRTUSB3000 = class
  68. public
  69. // USB интерфейс модуля
  70. Function OpenDevice(VirtualSlot : WORD) : boolean; virtual; stdcall; abstract;
  71. Function CloseDevice : boolean; virtual; stdcall; abstract;
  72. Function GetModuleHandle : THandle; virtual; stdcall; abstract;
  73. Function GetUsbSpeed(UsbSpeed : pByte) : boolean; virtual; stdcall; abstract;
  74. Function GetModuleName(ModuleName : pCHAR) : boolean; virtual; stdcall; abstract;
  75. Function GetModuleSerialNumber(SerialNumber : pCHAR) : boolean; virtual; stdcall; abstract;
  76. Function GetAvrVersion(AvrVersion : pCHAR) : boolean; virtual; stdcall; abstract;
  77. Function ReleaseInstance : boolean; virtual; stdcall; abstract;
  78. // функции для работы с DSP модуля
  79. Function RESET_DSP : boolean; virtual; stdcall; abstract;
  80. Function LOAD_DSP(FileName : pCHAR = nil) : boolean; virtual; stdcall; abstract;
  81. Function MODULE_TEST : boolean; virtual; stdcall; abstract;
  82. Function GET_DSP_INFO(DspInfo : pDSP_INFO_USB3000): boolean; virtual; stdcall; abstract;
  83. Function SEND_COMMAND(Command : WORD) : boolean; virtual; stdcall; abstract;
  84. // функции для работы с памятью DSP модуля
  85. Function PUT_VAR_WORD(Address : WORD; Data : SHORT) : boolean; virtual; stdcall; abstract;
  86. Function GET_VAR_WORD(Address : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract;
  87. Function PUT_DM_WORD(Address : WORD; Data : SHORT) : boolean; virtual; stdcall; abstract;
  88. Function GET_DM_WORD(Address : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract;
  89. Function PUT_PM_WORD(Address : WORD; Data : DWORD) : boolean; virtual; stdcall; abstract;
  90. Function GET_PM_WORD(Address : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract;
  91. Function PUT_DM_ARRAY(BaseAddress, NPoints : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract;
  92. Function GET_DM_ARRAY(BaseAddress, NPoints : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract;
  93. Function PUT_PM_ARRAY(BaseAddress, NPoints : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract;
  94. Function GET_PM_ARRAY(BaseAddress, NPoints : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract;
  95. // функции для работы в режиме ввода данных
  96. Function GET_INPUT_PARS(ap : pINPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract;
  97. Function SET_INPUT_PARS(ap : pINPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract;
  98. Function START_READ : boolean; virtual; stdcall; abstract;
  99. Function STOP_READ : boolean; virtual; stdcall; abstract;
  100. Function READ_KADR(Data : pSHORT) : boolean; virtual; stdcall; abstract;
  101. Function READ_SAMPLE(Channel : WORD; Sample : pSHORT) : boolean; virtual; stdcall; abstract;
  102. Function ReadData(lpBuffer : pSHORT; nNumberOfWordsToRead, lpNumberOfBytesRead : pDWORD; lpOverlapped : POverlapped) : boolean; virtual; stdcall; abstract;
  103. // функции для работы в режиме вывода данных
  104. Function GET_OUTPUT_PARS(dp : pOUTPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract;
  105. Function SET_OUTPUT_PARS(dp : pOUTPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract;
  106. Function START_WRITE : boolean; virtual; stdcall; abstract;
  107. Function STOP_WRITE : boolean; virtual; stdcall; abstract;
  108. Function WRITE_SAMPLE(Channel : WORD; Sample : pSHORT) : boolean; virtual; stdcall; abstract;
  109. Function WriteData(lpBuffer : pSHORT; nNumberOfWordsToWrite, lpNumberOfBytesWritten : pDWORD; lpOverlapped : POverlapped) : boolean; virtual; stdcall; abstract;
  110. // функции для работы с ТТЛ линиями
  111. Function ENABLE_TTL_OUT(EnabledTtlOut : boolean) : boolean; virtual; stdcall; abstract;
  112. Function TTL_OUT(TtlOut : WORD) : boolean; virtual; stdcall; abstract;
  113. Function TTL_IN(TtlIn : pWORD) : boolean; virtual; stdcall; abstract;
  114. // функции для работы ППЗУ
  115. Function ENABLE_FLASH_WRITE(EnableFlashWrite : boolean) : boolean; virtual; stdcall; abstract;
  116. Function PUT_FLASH(fi : pFLASH_USB3000) : boolean; virtual; stdcall; abstract;
  117. Function GET_FLASH(fi : pFLASH_USB3000) : boolean; virtual; stdcall; abstract;
  118. // функция выдачи строки с последней ошибкой
  119. Function GetLastErrorString(lpBuffer : pCHAR; nSize : DWORD) : Integer; virtual; stdcall; abstract;
  120. end;
  121. PIRTUSB3000 = ^IRTUSB3000;
  122. const
  123. // текущая версия библиотеки Rtusbapi.dll
  124. VERMAJOR_RTUSBAPI = $0001;
  125. VERMINOR_RTUSBAPI = $0005;
  126. CURRENT_VERSION_RTUSBAPI = ((VERMAJOR_RTUSBAPI shl 16) or VERMINOR_RTUSBAPI);
  127. // объявление экспортируемых из Rtusbapi.dll функций
  128. Function RtGetDllVersion : DWORD; stdcall;
  129. Function RtCreateInstance(DeviceName : PChar) : Pointer; stdcall;
  130. implementation
  131. Function RtGetDllVersion : DWORD; External 'Rtusbapi.dll'
  132. Function RtCreateInstance(DeviceName : PChar) : Pointer; External 'Rtusbapi.dll'
  133. end.
Вызываются эти функции так:
Листинг программы
  1. var
  2. // версия библиотеки Rtusbapi.dll
  3. DllVersion : DWORD;
  4. // интерфейс модуля USB3000
  5. pModule : IRTUSB3000;
  6. begin
  7. // проверим версию используемой DLL библиотеки
  8. DllVersion := RtGetDllVersion; // <-- тут всё понятно
  9. if DllVersion <> CURRENT_VERSION_RTUSBAPI then
  10. begin
  11. ErrorString := 'Неверная версия DLL библиотеки Rtusbapi.dll! ' + #10#13 +
  12. ' Текущая: ' + IntToStr(DllVersion shr 16) + '.' + IntToStr(DllVersion and $FFFF) + '.' +
  13. ' Требуется: ' + IntToStr(CURRENT_VERSION_RTUSBAPI shr 16) + '.' + IntToStr(CURRENT_VERSION_RTUSBAPI and $FFFF) + '.';
  14. TerminateApplication(ErrorString);
  15. end
  16. else WriteLn(' DLL Version --> OK');
  17. // попробуем получить указатель на интерфейс для модуля USB3000
  18. pModule := RtCreateInstance(pCHAR('usb3000')); // <-- а тут на Delphi тоже всё выглядит просто
  19. if pModule = nil then TerminateApplication('Не могу найти интерфейс модуля USB3000!')
  20. else WriteLn(' Module Interface --> OK');
  21. // попробуем обнаружить модуль USB3000 в первых 127 виртуальных слотах
  22. for i := 0 to 126 do
  23. if pModule.OpenDevice(i) then break;
  24. // и т.д.

Решение задачи: «Вызов функций, возвращающих указатель на структуру, из нативной dll»

textual
Листинг программы
  1.     struct IRTUSB3000Test
  2.     {
  3.         public IntPtr vtable;
  4.         // поля...
  5.     }
  6.  
  7.     struct IRTUSB3000TestVTable
  8.     {
  9.         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  10.         public delegate bool Method1Delegate(IntPtr self, ushort VirtualSlot);
  11.         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  12.         public delegate bool Method2Delegate(IntPtr self);
  13.  
  14.         public Method1Delegate OpenDevice;
  15.         public Method2Delegate CloseDevice;
  16.         // ...
  17.     }
  18.  
  19.     IntPtr structPtr = Rtusbapi.RtCreateInstance("usb3000");
  20.  
  21.     IRTUSB3000Test pModule = (IRTUSB3000Test)Marshal.PtrToStructure(structPtr, typeof(IRTUSB3000Test));
  22.  
  23.     IRTUSB3000TestVTable vt = (IRTUSB3000TestVTable)Marshal.PtrToStructure(pModule.vtable, typeof(IRTUSB3000TestVTable));
  24.  
  25.     bool result = vt.OpenDevice(structPtr, 0);
  26.  
  27.     vt.CloseDevice(structPtr);

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

9   голосов , оценка 4.111 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут