Как использовать объединение свойств C ++ в C # через оболочку Visual Studio COM (или каким-либо другим способом)

Я пытаюсь поговорить с устройством, используя предоставленные производителем com / dll (написанные на c ++), однако я сталкиваюсь с проблемой, когда я не могу установить значение поля в структуре.

В C ++ эта структура реализована следующим образом в соответствии с предоставленным документом:

typedef struct tagFCITEST
{
FCITESTTYPE TestType;
[switch_type( FCITESTTYPE ), switch_is( TestType )]
union
{
[case(FCI_TYPE_PROPORTIONAL)] FCI_TEST_PROPORTIONAL Test;
[case(FCI_TYPE_SWITCH)] FCI_TEST_SWITCH SwitchTest;
[default];
};
} FCITEST;

однако, когда я «Перейти к определению» в Visual Studio, я нахожу следующее:

public struct tagFCITEST
{
public __MIDL___MIDL_itf_mftFCINTF_0209_0005 __MIDL_0022;
public tagFCITESTTTYPE TestType;
}

а также

public struct __MIDL___MIDL_itf_mftFCINTF_0209_0005
{
}

по-видимому, C # не поддерживает такого рода союзы, и похоже, что Visual Studio не работает при создании оболочки, поэтому я попытался сделать следующее:

    public struct tagFCITEST
{
public MFTFCINTFLib.tagFCITESTTTYPE TestType;
public __MIDL___MIDL_itf_mftFCINTF_0209_0005 __MIDL_0022;
}

[StructLayout(LayoutKind.Explicit)]
public struct __MIDL___MIDL_itf_mftFCINTF_0209_0005
{
[FieldOffset(0)]
public MFTFCINTFLib.tagFCI_TEST_PROPORTIONAL Test;
[FieldOffset(0)]
public MFTFCINTFLib.tagFCI_TEST_SWITCH SwitchTest;
}

если я использую свою пользовательскую структуру в вызовах методов, компилятор недоволен и говорит мне, что есть неверный аргумент. И даже если бы я создал собственную подпись метода:

    [DllImport("mftFCINTF.dll")]
public static extern void DownloadTag(int ISessionID,
string szwDeviceTag,
string szwDeviceSeriaINum,
ref MFTFCINTFLib.tagFCICOMMDEF pCommDef,
ref MFTFCINTFLib.tagFCIDEVIN pInputDef,
ref MFTFCINTFLib.tagFCIDEVOUT pOutputDef,
ref MFTFCINTFLib.tagFCIDEVRELATION pRelationDef,
ref tagFCITEST pTestDef,        // This is the changed line
string szwSetupInstructions,
string szwCleanupInstructions,
out string pszwLocationInCalibrator,
out MFTFCINTFLib.tagFCISTATUS pStatus);

подпись не используется. Есть ли способ изменить реализацию оболочки в Visual Studio? Или, может быть, есть лучший способ решить эту проблему?

Спасибо!

Редактировать:

Вот сгенерированный файл .IDL

// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: mftFCINTF.dll

[
uuid(C81FC550-84AC-437B-AD0E-DA283ACE4687),
version(1.0),
helpstring("mftFCINTF 1.0 Type Library"),
custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 83951780),
custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1058814716)

]
library MFTFCINTFLib
{
// TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");

// Forward declare all types defined in this typelib
interface ICalibratorInfo;
interface ICalibratorDownload;
interface ICalibratorUpload;
interface IConfigurator;

[
uuid(34E98744-678E-4D9A-B57F-6A96521BB609),
helpstring("MFT 1.0 by Meriam Process Technologies")
]
coclass mftFCI {
[restricted] interface ICalibratorInfo;
[restricted] interface ICalibratorDownload;
[restricted] interface ICalibratorUpload;
[restricted] interface IConfigurator;
};

[
odl,
uuid(FF5EFD41-7B15-11D1-B326-00001CBE02AA),
version(1.0),
helpstring("ICalibratorInfo Interface")
]
interface ICalibratorInfo : IUnknown {
HRESULT _stdcall DriverProperties([out] tagFCISTATUS* pStatus);
HRESULT _stdcall Open(
[in] int nPortNumber,
[out] long* plSessionId,
[out] long* plCapabilities,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall Close(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall Properties(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall GetId(
[in] long lSessionId,
[out] LPWSTR* pszwCalManufacturer,
[out] LPWSTR* pszwCalModel,
[out] LPWSTR* pszwCalSerialNum,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall GetCalDates(
[in] long lSessionId,
[out] _SYSTEMTIME* pLastCalDate,
[out] _SYSTEMTIME* pNextCalDueDate,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall SetDateAndTime(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall SetTempStandard(
[in] long lSessionId,
[in] int nTemperatureStd,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall GetTestResultsCount(
[in] long lSessionId,
[out] int* pnCount,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall ClearMemory(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall ValidateTag(
[in] tagFCICOMMDEF* pCommDef,
[in] tagFCIDEVIN* pInputDef,
[in] tagFCIDEVOUT* pOutputDef,
[in] tagFCIDEVRELATION* pRelationDef,
[in] tagFCITEST* pTestDef,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall GetSensorModuleId(
[in] long lSessionId,
long nSensorIndex,
[out] LPWSTR* pszwCalManufacturer,
[out] LPWSTR* pszwCalModel,
[out] LPWSTR* pszwCalSerialNum,
[out] LPWSTR* pszwCalDate,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall ClearCalFatEntry(
[in] long nIndex,
[out, retval] VARIANT_BOOL* pResult);
HRESULT _stdcall SetAppDriverMode([in] long nMode);
};

typedef enum {
FCI_OK = 0,
FCI_FAILED = 1,
FCI_COMM_ERROR = 2,
FCI_REVISION_ERROR = 3,
FCI_CANCELED = 4,
FCI_NOT_SUPPORTED = 5,
FCI_ALREADY_OPEN = 6,
FCI_WRONG_SESSION = 7,
FCI_WRONG_CALIBRATOR = 8,
FCI_ERR_IN_RANGE = 9,
FCI_ERR_IN_UNITS = 10,
FCI_ERR_IN_TYPE = 11,
FCI_ERR_IN_MANUAL = 12,
FCI_ERR_OUT_RANGE = 13,
FCI_ERR_OUT_UNITS = 14,
FCI_ERR_OUT_TYPE = 15,
FCI_ERR_OUT_MANUAL = 16,
FCI_ERR_INOUT = 17,
FCI_ERR_RELATION = 18,
FCI_ERR_PROBE = 19,
FCI_ERR_CJC = 20,
FCI_ERR_ENUM = 21,
FCI_ERR_RESOURCE = 22,
FCI_ERR_TESTPOINT = 23,
FCI_ERR_TESTTYPE = 24,
FCI_ERR_POWER = 25,
FCI_ERR_TAG = 26,
FCI_MEM_FULL = 27,
FCI_MEM_EMPTY = 28,
FCI_MEM_HAS_DATA = 29,
FCI_END_OF_UPLOAD = 30,
FCI_ERR_DOWNLOAD = 31,
FCI_ERR_TAGLENGTH = 32,
FCI_ERR_SNLENGTH = 33,
FCI_ERR_MAXPOINTS = 34,
FCI_END = 35
} tagFCISTATUS;

typedef struct tag_SYSTEMTIME {

unsigned short wYear;

unsigned short wMonth;

unsigned short wDayOfWeek;

unsigned short wDay;

unsigned short wHour;

unsigned short wMinute;

unsigned short wSecond;

unsigned short wMilliseconds;
} _SYSTEMTIME;

typedef struct tagtagFCICOMMDEF {

tagFCICOMMTYPE CommType;

__MIDL___MIDL_itf_mftFCINTF_0209_0001 __MIDL_0016;
} tagFCICOMMDEF;

typedef enum {
FCI_COMMTYPE_NONE = 1,
FCI_COMMTYPE_HART = 2
} tagFCICOMMTYPE;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0001 {

tagFCI_COMMDEF_HART HartData;
} __MIDL___MIDL_itf_mftFCINTF_0209_0001;

typedef struct tagtagFCI_COMMDEF_HART {

unsigned char cBlockId;

unsigned char cURev;

unsigned char cPollAddr;

unsigned char acUid[5];

unsigned char acTag[6];

unsigned char acDescriptor[12];

unsigned char acDate[3];

unsigned char acMessage[24];
} tagFCI_COMMDEF_HART;

typedef struct tagtagFCIDEVIN {

tagFCIBLOCKTYPE DevType;

__MIDL___MIDL_itf_mftFCINTF_0209_0002 __MIDL_0017;
} tagFCIDEVIN;

typedef enum {
FCI_BLKTYPE_GENERIC = 1,
FCI_BLKTYPE_TEMP_RTD = 2,
FCI_BLKTYPE_TEMP_TC = 3,
FCI_BLKTYPE_FREQUENCY = 4,
FCI_BLKTYPE_PRESSURE = 5,
FCI_BLKTYPE_TEMP_MEASRTD = 6,
FCI_BLKTYPE_TEMP_MEASTC = 7,
FCI_BLKTYPE_HART = 8,
FCI_BLKTYPE_SWITCH = 9,
FCI_BLKTYPE_DIFFTEMP = 10
} tagFCIBLOCKTYPE;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0002 {

tagFCI_BLKDEF_PRESSURE PressureData;

tagFCI_BLKDEF_RTD TempRtdData;

tagFCI_BLKDEF_TC TempTcData;

tagFCI_BLKDEF_RTD TempMeasRtdData;

tagFCI_BLKDEF_TC TempMeasTcData;

tagFCI_BLKDEF_FREQUENCY FrequencyData;

tagFCI_BLKDEF_HART HartData;

tagFCI_BLKDEF_DIFFTEMP DiffTempData;

tagFCI_BLKDEF_GENERIC GenericData;
} __MIDL___MIDL_itf_mftFCINTF_0209_0002;

typedef struct tagtagFCI_BLKDEF_PRESSURE {

single rURV;

single rLRV;

single rSettling;

unsigned short wUnits;

unsigned short wPressureType;
} tagFCI_BLKDEF_PRESSURE;

typedef struct tagtagFCI_BLKDEF_RTD {

single rURV;

single rLRV;

single rSettling;

unsigned short wUnits;

unsigned short wProbeType;

unsigned short wNumWires;

unsigned short wRESERVED;
} tagFCI_BLKDEF_RTD;

typedef struct tagtagFCI_BLKDEF_TC {

single rURV;

single rLRV;

single rSettling;

single rManualCJC;

unsigned short wUnits;

unsigned short wProbeType;

unsigned short wCJC;

unsigned short wProbeConnect;
} tagFCI_BLKDEF_TC;

typedef struct tagtagFCI_BLKDEF_FREQUENCY {

single rURV;

single rLRV;

single rSettling;

single rAmplitude;

unsigned short wUnits;

unsigned short wWaveForm;
} tagFCI_BLKDEF_FREQUENCY;

typedef struct tagtagFCI_BLKDEF_HART {

single rUSL;

single rLSL;

single rSettling;

unsigned short wUnits;
} tagFCI_BLKDEF_HART;

typedef struct tagtagFCI_BLKDEF_DIFFTEMP {

single rURV;

single rLRV;

single rSettling;

unsigned short wUnits;

unsigned short wDeviceVariable1;

unsigned short wDeviceVariable2;
} tagFCI_BLKDEF_DIFFTEMP;

typedef struct tagtagFCI_BLKDEF_GENERIC {

single rURV;

single rLRV;

single rSettling;

unsigned short wUnits;
} tagFCI_BLKDEF_GENERIC;

typedef struct tagtagFCIDEVOUT {

tagFCIBLOCKTYPE DevType;

__MIDL___MIDL_itf_mftFCINTF_0209_0003 __MIDL_0018;
} tagFCIDEVOUT;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0003 {

tagFCI_BLKDEF_PRESSURE PressureData;

tagFCI_BLKDEF_RTD TempMeasRtdData;

tagFCI_BLKDEF_TC TempMeasTcData;

tagFCI_BLKDEF_FREQUENCY FrequencyData;

tagFCI_BLKDEF_HART HartData;

tagFCI_BLKDEF_SWITCH Switch;

tagFCI_BLKDEF_GENERIC GenericData;
} __MIDL___MIDL_itf_mftFCINTF_0209_0003;

typedef struct tagtagFCI_BLKDEF_SWITCH {

unsigned short wContactType;

unsigned short wForm;

unsigned short wTripDirection;

single rWetContactVoltage;
} tagFCI_BLKDEF_SWITCH;

typedef struct tagtagFCIDEVRELATION {

tagFCIRELATIONTYPE RelType;

__MIDL___MIDL_itf_mftFCINTF_0209_0004 __MIDL_0020;
} tagFCIDEVRELATION;

typedef enum {
FCI_RELTYPE_LINEAR = 0,
FCI_RELTYPE_SQRT = 1,
FCI_SQRT_3RD_PWR = 2,
FCI_SQRT_5TH_PWR = 3,
FCI_RELTYPE_TABLE = 4,
FCI_RELTYPE_SWITCH = 230
} tagFCIRELATIONTYPE;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0004 {

tagFCI_RELDEF_SQRT SqrtData;

tagFCI_RELDEF_TABLE TableData;
} __MIDL___MIDL_itf_mftFCINTF_0209_0004;

typedef struct tagtagFCI_RELDEF_SQRT {

single rBreakPoint;
} tagFCI_RELDEF_SQRT;

typedef struct tagtagFCI_RELDEF_TABLE {

unsigned short wNumPoints;

unsigned short wInterpolate;

single rInput[30];

single rOutput[30];
} tagFCI_RELDEF_TABLE;

typedef struct tagtagFCITEST {

tagFCITESTTTYPE TestType;

__MIDL___MIDL_itf_mftFCINTF_0209_0005 __MIDL_0022;
} tagFCITEST;

typedef enum {
FCI_TYPE_PROPORTIONAL = 1,
FCI_TYPE_SWITCH = 2
} tagFCITESTTTYPE;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0005 {

tagFCI_TEST_PROPORTIONAL Test;

tagFCI_TEST_SWITCH SwitchTest;
} __MIDL___MIDL_itf_mftFCINTF_0209_0005;

typedef struct tagtagFCI_TEST_PROPORTIONAL {

unsigned short wRESERVED;

unsigned short wPowerSource;

unsigned short wCalSourceInput;

unsigned short wCalReadInput;

unsigned short wCalMeasureOutput;

unsigned short wNumTestPoints;

single arTestPoint[21];

single rTestPointTolerance;

single rAdjustmentLimit;

single rMaxErrorLimit;
} tagFCI_TEST_PROPORTIONAL;

typedef struct tagtagFCI_TEST_SWITCH {

single rTripSetPoint;

single rTripTolerance;

single rResetDeadband;

single rDeadbandTolerance;

single rRampTime;

long bTestReset;
} tagFCI_TEST_SWITCH;

[
odl,
uuid(FF5EFD42-7B15-11D1-B326-00001CBE02AA),
version(1.0),
helpstring("ICalibratorDownload Interface")
]
interface ICalibratorDownload : IUnknown {
HRESULT _stdcall StartDownloading(
[in] long lSessionId,
[in] LPWSTR szSessionName,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall DownloadTag(
[in] long lSessionId,
[in] LPWSTR szwDeviceTag,
[in] LPWSTR szwDeviceSerialNum,
[in] tagFCICOMMDEF* pCommDef,
[in] tagFCIDEVIN* pInputDef,
[in] tagFCIDEVOUT* pOutputDef,
[in] tagFCIDEVRELATION* pRelationDef,
[in] tagFCITEST* pTestDef,
[in] LPWSTR szwSetupInstructions,
[in] LPWSTR szwCleanupInstructions,
[out] LPWSTR* pszwLocationInCalibrator,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall FinishDownloading(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall AbortDownload(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
};

[
odl,
uuid(FF5EFD43-7B15-11D1-B326-00001CBE02AA),
version(1.0),
helpstring("ICalibratorUpload Interface")
]
interface ICalibratorUpload : IUnknown {
HRESULT _stdcall StartUploading(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall UploadNextTag(
[in] long lSessionId,
[out] LPWSTR* pszwLocationInCalibrator,
[out] LPWSTR* pszwDeviceTag,
[out] LPWSTR* pszwDeviceSerialNum,
[out] LPWSTR* pszwTechnician,
[out] LPWSTR* pszwServiceNote,
[out] int* pnTemperatureStd,
[out] tagFCICOMMDEF* pCommDef,
[out] tagFCIRESULT* pAsFound,
[out] tagFCIRESULT* pAsLeft,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall FinishUploading(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall AbortUpload(
[in] long lSessionId,
[out] tagFCISTATUS* pStatus);
HRESULT _stdcall PreviewNextTag(
[in] long lSessionId,
[out] LPWSTR* pszwLocationInCalibrator,
[out] LPWSTR* pszwDeviceTag,
[out] LPWSTR* pszwDeviceSerialNum,
[out] long* plRecordType,
[out] _SYSTEMTIME* pDate,
[out] tagFCISTATUS* pStatus);
};

typedef struct tagtagFCIRESULT {

tagFCITESTTTYPE ResultType;

__MIDL___MIDL_itf_mftFCINTF_0209_0006 __MIDL_0024;
} tagFCIRESULT;

typedef union tag__MIDL___MIDL_itf_mftFCINTF_0209_0006 {

tagFCI_RESULT_PROPORTIONAL Results;

tagFCI_RESULT_SWITCH SwitchResults;
} __MIDL___MIDL_itf_mftFCINTF_0209_0006;

typedef struct tagtagFCI_RESULT_PROPORTIONAL {

double dInputLowerRangeValue;

double dInputUpperRangeValue;

int nInputRangeUnits;

double dOutputLowerRangeValue;

double dOutputUpperRangeValue;

int nOutputRangeUnits;

int nRelationship;

int nNumberOfTestPoints;

double adInput[21];

double adOutput[21];

LPWSTR szwAuxEquipManufacturer;

LPWSTR szwAuxEquipModel;

LPWSTR szwAuxEquipSerialNum;

double dAmbientTemperature;

int nAmbientTemperatureUnits;

_SYSTEMTIME TestDate;
} tagFCI_RESULT_PROPORTIONAL;

typedef struct tagtagFCI_RESULT_SWITCH {

unsigned short wUnits;

single rTripPoint;

single rResetPoint;

unsigned short bResetTested;

_SYSTEMTIME TestDate;

LPWSTR szwAuxEquipManufacturer;

LPWSTR szwAuxEquipModel;

LPWSTR szwAuxEquipSerialNum;
} tagFCI_RESULT_SWITCH;

[
odl,
uuid(084ABD42-30CE-49AD-B1FA-9C869AAD2A27),
version(1.0),
helpstring("IConfigurator Interface")
]
interface IConfigurator : IUnknown {
[helpstring("method UploadConfiguration")]
HRESULT _stdcall UploadConfiguration(
long* pDataAvailabe,
BSTR bstrFilePath,
[in, out] BSTR* pbstrTag,
[in, out] long* plDof,
[in, out] long* plAsFoundAsLeft,
[in, out] long* pnLocation,
[in, out] long* pnMultivar,
[in, out] BSTR* pbstrDeviceSerialNum,
[out, retval] VARIANT_BOOL* pResult);
[helpstring("method DownloadConfiguration")]
HRESULT _stdcall DownloadConfiguration(
[in] BSTR bstrFilePath,
[in, out] long* pnLocation,
[out, retval] VARIANT_BOOL* pResult);
[helpstring("method ClearConfiguratorMemory")]
HRESULT _stdcall ClearConfiguratorMemory();
[helpstring("method GetConfigCount")]
HRESULT _stdcall GetConfigCount([out, retval] long* lCount);
[helpstring("method PreviewConfiguration")]
HRESULT _stdcall PreviewConfiguration(
long* pDataAvailabe,
[in, out] BSTR* pbstrTag,
[in, out] long* plDof,
[in, out] long* plAsFoundAsLeft,
[in, out] long* plOrigin,
[in, out] long* pnLocation,
[in, out] BSTR* pbstrDeviceSerialNum,
[out] _SYSTEMTIME* pDate,
[out, retval] VARIANT_BOOL* pResult);
[helpstring("method SetPortNumber")]
HRESULT _stdcall SetPortNumber(long nPort);
[helpstring("method ClearConfigFatEntry")]
HRESULT _stdcall ClearConfigFatEntry(
long nIndex,
[out, retval] VARIANT_BOOL* pResult);
};
};

2

Решение

Вы, несомненно, получили эти объявления от импорта библиотеки типов COM-сервера. Либо добавив ссылку на dll COM, либо запустив Tlbimp.exe вручную.

Да, это проблема, библиотеки типов поддерживают только часть из того, что может быть выражено в IDL. И эти дискриминационные союзы, конечно, не являются его частью. Они важны только для правильного построения структуры через границу квартиры, только DLL прокси / заглушки должны видеть их правильно, и это автоматически сгенерированный код.

Два основных способа решения проблемы, ни один из них не особенно приятен:

  • Вы можете отредактировать библиотеку взаимодействия, которая была сгенерирована из библиотеки типов, и исправить объявление структуры. Это начинается с декомпиляции DLL с помощью ildasm.exe, редактирования IL и повторного объединения его с ilasm.exe. Вы можете использовать пример программы C #, которую вы декомпилируете, чтобы увидеть, как должен выглядеть IL. Это работает, но важно, чтобы компонент COM был стабильным, чтобы вам не приходилось делать это снова и снова. Там есть How-To статья в MSDN, который описывает процедуру.

  • Напишите оболочку для компонента на языке C ++ / CLI. Вы можете #include .h файл, который был создан midl.exe из IDL. Понятно, что это будет работать, только если у вас есть доступ к IDL или есть файл .h, вам нужно будет связаться с продавцом или автором, если у вас его нет. Одно из преимуществ такого подхода состоит в том, что вы также обойдете проблемы других типов. Недостатком является то, что вам нужно знать основы языка и программирования COM-клиента на C ++.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]