Я пытаюсь поговорить с устройством, используя предоставленные производителем 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);
};
};
Вы, несомненно, получили эти объявления от импорта библиотеки типов 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 ++.
Других решений пока нет …