Вызов функций, возвращающих указатель на структуру, из нативной dll - C#
Формулировка задачи:
Тут на форуме уже не раз задавали вопросы, как вызвать функцию из нативной dll. И в случае, если функция возвращает "нормальный" тип, у меня с этим вопросов нет: DllImport и всё такое. Но вот если функция возвращает указатель на интерфейс, вот тут у меня возникли проблемы.
Имеется dll-ка (написана, кажется, на CBuilder), экспортирующая всего 2 функции. Так же имеются примеры работы с этой dll-кой в Delphi и в С++.
На Delphi это выглядит так:
Rtusbapi.pas
Вызываются эти функции так:
unit Rtusbapi; interface uses windows; type pSHORT = ^SHORT; pBYTE = ^BYTE; type // структура, задающая режимы ввода данных для модуля USB-3000 INPUT_PARS_USB3000 = packed record // (size=438) size : WORD; InputEnabled : BOOL; // флажок разрешение/запрещение ввода данных (только при чтении) CorrectionEnabled : BOOL; // управление корректировкой входных данных (с АЦП) InputClockSource : WORD; // источник тактовых импульсов для ввода данных InputType : WORD; // тип вводимых с модуля даных (АЦП или ТТЛ) SynchroType : WORD; // тип синхронизации вводимых с модуля даных SynchroAdType : WORD; // тип аналоговой синхронизации SynchroAdMode : WORD; // режим аналоговой сихронизации SynchroAdChannel : WORD; // канал АЦП при аналоговой синхронизации SynchroAdPorog : SHORT; // порог срабатывания АЦП при аналоговой синхронизации ChannelsQuantity : WORD; // число активных логических каналов ControlTable : array [0..127] of WORD; // управляющая таблица с активными логическими каналами InputFifoBaseAddress : WORD; // базовый адрес FIFO буфера ввода InputFifoLength : WORD; // длина FIFO буфера ввода InputRate : double; // тактовая частота ввода данных в кГц InterKadrDelay : double; // межкадровая задержка в мс ChannelRate : double; // частота ввода фиксированного логического канала AdcOffsetCoef : array [0..7] of double; // корректировочные коэф. смещение нуля для АЦП AdcScaleCoef : array [0..7] of double; // корректировочные коэф. масштаба для АЦП end; pINPUT_PARS_USB3000 = ^INPUT_PARS_USB3000; // структура, задающая режимы вывода данных для модуля USB-3000 OUTPUT_PARS_USB3000 = packed record // (size = 18) size : WORD; OutputEnabled : BOOL; // разрешение/запрещение вывода данных OutputRate : double; // частота вывода данных в кГц OutputFifoBaseAddress : WORD; // базовый адрес FIFO буфера вывода OutputFifoLength : WORD; // длина FIFO буфера вывода end; pOUTPUT_PARS_USB3000 = ^OUTPUT_PARS_USB3000; // структура пользовательского ППЗУ FLASH_USB3000 = packed record // (size = 256) CRC16 : WORD; // контрольная сумма size : WORD; // размер структуры SerialNumber : array [0..8] of BYTE; // серийный номер модуля Name : array [0..10] of BYTE; // название модуля Revision : CHAR; // ревизия модуля DspType : array [0..16] of BYTE; // тип установленного DSP IsDacPresented : BYTE; // флажок наличия ЦАП DspClockout : DWORD; // тактовая частота DSP в Гц AdcOffsetCoef : array [0..7] of single; // корректировочные коэф. смещения нуля для АЦП AdcScaleCoef : array [0..7] of single; // корректировочные коэф. масштаба для АЦП DacOffsetCoef : array [0..1] of single; // корректировочные коэф. смещения нуля для ЦАП DacScaleCoef : array [0..1] of single; // корректировочные коэф. масштаба для ЦАП ReservedByte : array [0..128] of BYTE; // зарезервировано end; pFLASH_USB3000 = ^FLASH_USB3000; // структура, содержащая информацию о версии драйвера DSP DSP_INFO_USB3000 = packed record // (size = 18) Target : array [0..9] of BYTE; // модуль, для которого предназначен данный драйвер DSP DrvLabel : array [0..5] of BYTE; // метка разработчика драйвера DSP DspMajor : BYTE; // старшие число версии драйвера DSP DspMinor : BYTE; // младшее число версии драйвера DSP end; pDSP_INFO_USB3000 = ^DSP_INFO_USB3000; // интерфейс модуля USB3000 ` IRTUSB3000 = class public // USB интерфейс модуля Function OpenDevice(VirtualSlot : WORD) : boolean; virtual; stdcall; abstract; Function CloseDevice : boolean; virtual; stdcall; abstract; Function GetModuleHandle : THandle; virtual; stdcall; abstract; Function GetUsbSpeed(UsbSpeed : pByte) : boolean; virtual; stdcall; abstract; Function GetModuleName(ModuleName : pCHAR) : boolean; virtual; stdcall; abstract; Function GetModuleSerialNumber(SerialNumber : pCHAR) : boolean; virtual; stdcall; abstract; Function GetAvrVersion(AvrVersion : pCHAR) : boolean; virtual; stdcall; abstract; Function ReleaseInstance : boolean; virtual; stdcall; abstract; // функции для работы с DSP модуля Function RESET_DSP : boolean; virtual; stdcall; abstract; Function LOAD_DSP(FileName : pCHAR = nil) : boolean; virtual; stdcall; abstract; Function MODULE_TEST : boolean; virtual; stdcall; abstract; Function GET_DSP_INFO(DspInfo : pDSP_INFO_USB3000): boolean; virtual; stdcall; abstract; Function SEND_COMMAND(Command : WORD) : boolean; virtual; stdcall; abstract; // функции для работы с памятью DSP модуля Function PUT_VAR_WORD(Address : WORD; Data : SHORT) : boolean; virtual; stdcall; abstract; Function GET_VAR_WORD(Address : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract; Function PUT_DM_WORD(Address : WORD; Data : SHORT) : boolean; virtual; stdcall; abstract; Function GET_DM_WORD(Address : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract; Function PUT_PM_WORD(Address : WORD; Data : DWORD) : boolean; virtual; stdcall; abstract; Function GET_PM_WORD(Address : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract; Function PUT_DM_ARRAY(BaseAddress, NPoints : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract; Function GET_DM_ARRAY(BaseAddress, NPoints : WORD; Data : pSHORT) : boolean; virtual; stdcall; abstract; Function PUT_PM_ARRAY(BaseAddress, NPoints : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract; Function GET_PM_ARRAY(BaseAddress, NPoints : WORD; Data : pDWORD) : boolean; virtual; stdcall; abstract; // функции для работы в режиме ввода данных Function GET_INPUT_PARS(ap : pINPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract; Function SET_INPUT_PARS(ap : pINPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract; Function START_READ : boolean; virtual; stdcall; abstract; Function STOP_READ : boolean; virtual; stdcall; abstract; Function READ_KADR(Data : pSHORT) : boolean; virtual; stdcall; abstract; Function READ_SAMPLE(Channel : WORD; Sample : pSHORT) : boolean; virtual; stdcall; abstract; Function ReadData(lpBuffer : pSHORT; nNumberOfWordsToRead, lpNumberOfBytesRead : pDWORD; lpOverlapped : POverlapped) : boolean; virtual; stdcall; abstract; // функции для работы в режиме вывода данных Function GET_OUTPUT_PARS(dp : pOUTPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract; Function SET_OUTPUT_PARS(dp : pOUTPUT_PARS_USB3000) : boolean; virtual; stdcall; abstract; Function START_WRITE : boolean; virtual; stdcall; abstract; Function STOP_WRITE : boolean; virtual; stdcall; abstract; Function WRITE_SAMPLE(Channel : WORD; Sample : pSHORT) : boolean; virtual; stdcall; abstract; Function WriteData(lpBuffer : pSHORT; nNumberOfWordsToWrite, lpNumberOfBytesWritten : pDWORD; lpOverlapped : POverlapped) : boolean; virtual; stdcall; abstract; // функции для работы с ТТЛ линиями Function ENABLE_TTL_OUT(EnabledTtlOut : boolean) : boolean; virtual; stdcall; abstract; Function TTL_OUT(TtlOut : WORD) : boolean; virtual; stdcall; abstract; Function TTL_IN(TtlIn : pWORD) : boolean; virtual; stdcall; abstract; // функции для работы ППЗУ Function ENABLE_FLASH_WRITE(EnableFlashWrite : boolean) : boolean; virtual; stdcall; abstract; Function PUT_FLASH(fi : pFLASH_USB3000) : boolean; virtual; stdcall; abstract; Function GET_FLASH(fi : pFLASH_USB3000) : boolean; virtual; stdcall; abstract; // функция выдачи строки с последней ошибкой Function GetLastErrorString(lpBuffer : pCHAR; nSize : DWORD) : Integer; virtual; stdcall; abstract; end; PIRTUSB3000 = ^IRTUSB3000; const // текущая версия библиотеки Rtusbapi.dll VERMAJOR_RTUSBAPI = $0001; VERMINOR_RTUSBAPI = $0005; CURRENT_VERSION_RTUSBAPI = ((VERMAJOR_RTUSBAPI shl 16) or VERMINOR_RTUSBAPI); // объявление экспортируемых из Rtusbapi.dll функций Function RtGetDllVersion : DWORD; stdcall; Function RtCreateInstance(DeviceName : PChar) : Pointer; stdcall; implementation Function RtGetDllVersion : DWORD; External 'Rtusbapi.dll' Function RtCreateInstance(DeviceName : PChar) : Pointer; External 'Rtusbapi.dll' end.
var // версия библиотеки Rtusbapi.dll DllVersion : DWORD; // интерфейс модуля USB3000 pModule : IRTUSB3000; begin // проверим версию используемой DLL библиотеки DllVersion := RtGetDllVersion; // <-- тут всё понятно if DllVersion <> CURRENT_VERSION_RTUSBAPI then begin ErrorString := 'Неверная версия DLL библиотеки Rtusbapi.dll! ' + #10#13 + ' Текущая: ' + IntToStr(DllVersion shr 16) + '.' + IntToStr(DllVersion and $FFFF) + '.' + ' Требуется: ' + IntToStr(CURRENT_VERSION_RTUSBAPI shr 16) + '.' + IntToStr(CURRENT_VERSION_RTUSBAPI and $FFFF) + '.'; TerminateApplication(ErrorString); end else WriteLn(' DLL Version --> OK'); // попробуем получить указатель на интерфейс для модуля USB3000 pModule := RtCreateInstance(pCHAR('usb3000')); // <-- а тут на Delphi тоже всё выглядит просто if pModule = nil then TerminateApplication('Не могу найти интерфейс модуля USB3000!') else WriteLn(' Module Interface --> OK'); // попробуем обнаружить модуль USB3000 в первых 127 виртуальных слотах for i := 0 to 126 do if pModule.OpenDevice(i) then break; // и т.д.
Решение задачи: «Вызов функций, возвращающих указатель на структуру, из нативной dll»
textual
Листинг программы
struct IRTUSB3000Test { public IntPtr vtable; // поля... } struct IRTUSB3000TestVTable { [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate bool Method1Delegate(IntPtr self, ushort VirtualSlot); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate bool Method2Delegate(IntPtr self); public Method1Delegate OpenDevice; public Method2Delegate CloseDevice; // ... } IntPtr structPtr = Rtusbapi.RtCreateInstance("usb3000"); IRTUSB3000Test pModule = (IRTUSB3000Test)Marshal.PtrToStructure(structPtr, typeof(IRTUSB3000Test)); IRTUSB3000TestVTable vt = (IRTUSB3000TestVTable)Marshal.PtrToStructure(pModule.vtable, typeof(IRTUSB3000TestVTable)); bool result = vt.OpenDevice(structPtr, 0); vt.CloseDevice(structPtr);
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д