Вызов функций, возвращающих указатель на структуру, из нативной 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);
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д