Вызов функций, возвращающих указатель на структуру, из нативной 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);

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


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

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

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