Как использовать структуры c++ из dll-ки в с#

275
19 марта 2019, 04:20

Есть dll написаная на с++. Необходмо испльзовать ее в с#. heder c++

    //---------------------------------------------------------------------------
#ifndef CRZUSBH
#define CRZUSBH
//---------------------------------------------------------------------------
#ifdef CRZUSB_EXPORTS
#define CRZUSB_API extern "C" __declspec(dllexport)
#else
#define CRZUSB_API extern "C" __declspec(dllimport)
#endif
//---------------------------------------------------------------------------
#define SIZE_MATR_ADDR_RECV         512
#define MAX_COUNT_RZ_DATA               128
#define MAX_COUNT_CHANNELS          16
#define FREQ_RZ_GET_DEVICE          0x00
#define FREQ_RZ_12and5kHz               0x01
#define FREQ_RZ_50kHZ                       0x02
#define FREQ_RZ_100kHZ                  0x03
#define FREQ_RZ_UNKNOWN                 0xFF
#define FORMAT_RZ_DOP                       0x00
#define FORMAT_RZ_OSN                       0x01
#define CTRL_PARR_PARITY                0x00
#define CTRL_PARR_ODDNESS               0x01
#define IDDEV_2RZTOUSB                  0x01
#define ENABLE_ADDR_REC                 0x01
#define DISABLE_ADDR_REC                0x00
//---------------------------------------------------------------------------
//#pragma pack(show)
#pragma pack(push,1)
//#pragma pack(show)
struct sInitDevice
{
    unsigned char ucFreqRZ;
    unsigned char ucFormatRZ;
    unsigned char ucCtrlParr;
    unsigned char ucAddrRecv;
    unsigned char pucMatrAddrRecv[SIZE_MATR_ADDR_RECV];
};
struct sInitDeviceEx
{
    struct sInitChannel
    {
        BYTE FreqRZ;
        BYTE FormatRZ;
        BYTE CtrlParr;
    } ParamChannel[MAX_COUNT_CHANNELS];
    BYTE AddrRecv;
    BYTE MatrAddrRecv[SIZE_MATR_ADDR_RECV];
};
struct sInfoDevice
{
    bool bCorrectInfo;      
    unsigned char   ucCodeErrorDevice;
    unsigned char   ucIDDevice;
    unsigned char   ucFreqRZ;
    unsigned char  ucCountChannels;
    unsigned short  usDensityRZ;
    unsigned short usPlantNum;
    unsigned short usNumPO;
    unsigned short usVersionPO;
};
struct sInfoDeviceEx
{
    bool bCorrectInfo;
    BYTE CodeErrorDevice;
    BYTE IDDevice;
    WORD NumPO;
    WORD VersionPO;
    WORD PlantNum;
    BYTE CountChannels;
    struct sInfoChannel
    {
        BYTE FreqRZ;
        WORD DensityRZ;
    } InfoChannel[MAX_COUNT_CHANNELS];
};
struct sRZStream
{
    unsigned char  CountRZMessage;
    unsigned short CountTrashRZMessage;
    unsigned short CountMissingRZMessage;
    bool IsMissingRZMessage;
    struct
    {
        unsigned char Address;
        unsigned char Low;
        unsigned char High;
        unsigned char Additional;
        unsigned char Channel;
    } RZ_DATA[MAX_COUNT_RZ_DATA];
    //Index RZ_DATA: [0 ... (CountRZMessage - 1)]
};
struct sRZStreamEx
{
    struct
    {
        union
        {
            struct
            {
                BYTE Low;
                BYTE High;
                BYTE Additional;    
                BYTE Address;                       
            };
            DWORD RzMessage;
        };
    } RZ_DATA[MAX_COUNT_RZ_DATA];
    struct 
    {
        BYTE Channel_0 : 4;
        BYTE Channel_1 : 4;
    } CHANNELS[MAX_COUNT_RZ_DATA / 2];
    BYTE System00;
    BYTE CountRZMessage;
    union
    {
        struct
        {   
            BYTE CountTrashRZMessageL;
            BYTE CountTrashRZMessageH;
        };
        WORD CountTrashRZMessage;
    };
    BYTE IsMissingRZMessage;
    union
    {
        struct
        {   
            BYTE CountMissingRZMessageL;
            BYTE CountMissingRZMessageH;
        };
        WORD CountMissingRZMessage;
    };
    BYTE System07;
    BYTE System08;
    BYTE System09;
    BYTE System10;
    BYTE System11;
    BYTE System12;
    BYTE System13;
    BYTE System14;
    BYTE System15;
    inline BYTE GetChannelRZMessage (int IndexRZMessage)
    {
        return (IndexRZMessage & 0x01) ? CHANNELS[IndexRZMessage >> 1].Channel_1 : CHANNELS[IndexRZMessage >> 1].Channel_0;
    }
};
struct sRZTimingData
{
    BYTE Data[MAX_COUNT_RZ_DATA];
};
#pragma pack(pop)
//#pragma pack(show)
//---------------------------------------------------------------------------
CRZUSB_API bool RzUsb_ConnectDevice (void);
CRZUSB_API bool RzUsb_IsConnectToDevice (void);
CRZUSB_API bool RzUsb_DisconnectDevice (void);
CRZUSB_API bool RzUsb_InitDevice (sInitDevice*, sInfoDevice*);
CRZUSB_API bool RzUsb_InitDeviceEx (sInitDeviceEx*, sInfoDeviceEx*);
CRZUSB_API void RzUsb_SetReadTimeout (unsigned long);
CRZUSB_API void RzUsb_SetWriteTimeout (unsigned long);
CRZUSB_API bool RzUsb_RunReceiveRZ (void);
CRZUSB_API bool RzUsb_StopReceiveRZ (void);
CRZUSB_API bool RzUsb_ReceiveRZStream (sRZStream*);
CRZUSB_API bool RzUsb_ReceiveRZStreamEx (sRZStreamEx*);
CRZUSB_API bool RzUsb_IsReceiveRZStream (void);
//--------------------SUPPORT TIMING DATA------------------------------------
CRZUSB_API bool RzUsb_IsSupportTimingData (void);
CRZUSB_API bool RzUsb_GetTimingData (sRZTimingData*);
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

Как преобразовать структуры для с#?

Answer 1

Это как бы смешивание управляемого и нативного кода. В данном случае в C# хорошо интегрируются COM объекты. Поэтому одним из способов интеграции является создание обвязки в виде COM объекта. В этом случае данные dll можно преобразовать в данные, понятные в управляемом коде.

Еще одним способом (мне нравится больше) является использование C++ CLR. Для этого создается проект типа Class Library и в нем CLR класс который будет управлять нативным dll. Здесь тоже придется данные преобразовывать, но это можно сделать в виде тех же CLR объектов.

Ниже я написал небольшой код для примера. Я в нем загружаю библиотеку работы с сокетом.

#pragma once
#include "windows.h"
#include <atlstr.h>
using namespace System;
namespace NativeClasses {
public ref class AddrIn
{
public:
    int  Port;
    String^ sAddr;
};
public ref class NativeSocket 
{
u_short (*htons)(u_short);
unsigned long (*inet_addr)(const char*);
public:
    NativeSocket(void)
    {
        HMODULE hm = LoadLibrary (L"ws2_32.dll");
        if ( hm )
        {
            SOCKET (*socket)(int,int,int) = (SOCKET (*)(int,int,int)) GetProcAddress(hm, "socket"); 
            int (*closesocket)(SOCKET) = (int (*)(SOCKET)) GetProcAddress(hm, "socket"); 
            htons = (u_short (*)(u_short)) GetProcAddress(hm, "htons"); 
            inet_addr = (unsigned long (*)(const char*)) GetProcAddress(hm, "inet_addr"); 
            SOCKET s = (*socket) (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if (s)
                (*closesocket) (s);
            FreeLibrary(hm);
        }
    }
    void SetAddr( AddrIn^ Addr )
     {
         sockaddr_in addr = {0};
         addr.sin_family = AF_INET;
         addr.sin_port = (*htons)(Addr->Port);
         CString sAddr(Addr->sAddr); 
         CW2A asAddr(sAddr);
         addr.sin_addr.S_un.S_addr = (*inet_addr)(asAddr);
     }    
};
}

Сборку с классами затем включается в ссылки проекта на C# и может использоваться обычным вызовом:

NativeClasses.NativeSocket s = new NativeClasses.NativeSocket();
NativeClasses.AddrIn addr = new NativeClasses.AddrIn() ;
addr.Port = 1000;
addr.sAddr = "10.1.0.100";
s.SetAddr(addr);

Для преобразования строк на мой взгляд удобнее всего использовать ATL. Остальное на усмотрение.

READ ALSO
Не запускается служба на сервера

Не запускается служба на сервера

Конфиг: Windows Server 2016, x64, 1Гб ОЗУ Создал службу по мануалу Размещение ASPNET Core в службе Windows установил на дом

121
Переписать кусок кода на другой язык

Переписать кусок кода на другой язык

Есть кусок кода,написанный в python, с помощью api йобита выводит цену по определенной паре

110
Реализация ToDo Списка на php

Реализация ToDo Списка на php

В личном кабинете пользователь может создать список своих делРеализация может показаться вам глупой, но мне интересно ваше мнение по поводу...

112
Разделить количество блоков на два

Разделить количество блоков на два

УвЗнатоки помогите с решением данной задачи

144