У меня есть обертка для SPI-устройства National Instruments - она отлично работает в .Net Core. Я хочу обернуть пользовательский интерфейс, так что перенес ту же оболочку в .Net Framework. Там большинство вызовов работают, но один не получается .... Я пробовал разные входящие подписи без удачи, и, честно говоря, я удивился, почему он работает в .Net Core 3.0, но не в Framework 4.7.2.
Я также сделал стандартный пакет-оболочку .Net, на который ссылаются в обоих приложениях. Эта же DLL-оболочка работает в проекте ядра .Net, но не в Framework! Что здесь происходит? Похоже, что .Net Core имеет некоторыедополнительная эвристика о том, как обрабатывать Interop. Вопрос в том, как и почему? Альфа-плагин .Net Core Winforms просто не стабилен или недостаточно полнофункциональн, чтобы я мог его использовать, и мне действительно нужно работать в стандартном проекте .Net Framework.
Он работает для настройки, настройки DIO и т. Д. Но он терпит крах, когда мы пытаемся сделать
NI845x.ni845xSpiWriteRead(handle, SPIHandle, (uint)B.Length, B, ref ReadSize, ref ReadMsg);
У кого-нибудь есть какие-нибудь хорошие идеи о том, как заставить это работать или какдля устранения проблемы? Спасибо!
Подписи ниже:
public class NI845x
{
public const byte kNi845x33Volts = 33; // 3.3V
public const byte kNi845x25Volts = 25; // 2.5V
public const byte kNi845x18Volts = 18; // 1.8V
public const byte kNi845x15Volts = 15; // 1.5V
public const byte kNi845x12Volts = 12; // 1.2V
public const byte kNi845xSpiClockPolarityIdleLow = 0;// Idle Low
public const byte kNi845xSpiClockPolarityIdleHigh = 1; // Idle High
public const byte kNi845xSpiClockPhaseFirstEdge = 0; // First Edge
public const byte kNi845xSpiClockPhaseSecondEdge = 1; // Second Edge
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xFindDevice(StringBuilder FirstDevice, ref ulong FindDeviceHandle, ref UInt32 NumberFound);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiWriteRead(ulong DeviceHandle, ulong ConfigurationHandle, UInt32 WriteSize, byte[] WriteData, ref UInt32 ReadSize, ref byte[] ReadData);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xOpen(StringBuilder ResourceName, ref ulong DeviceHandle);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSetIoVoltageLevel(ulong DeviceHandle, byte VoltageLevel);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationOpen(ref ulong SPIHandle);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationSetChipSelect(ulong SPIHandle, UInt32 ChipSelect);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationSetClockRate(ulong SPIHandle, UInt16 ClockRate);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationSetClockPolarity(ulong SPIHandle, Int32 ClockPolarity);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationSetClockPhase(ulong SPIHandle, Int32 ClockPhase);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiConfigurationClose(ulong DeviceHandle);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xClose(ulong DeviceHandle);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xDioWriteLine(ulong DeviceHandle, byte PortNumber, byte LineNumber, Int32 WriteData);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xDioSetPortLineDirectionMap(ulong DeviceHandle, byte PortNumber, byte Map);
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSetTimeout(ulong DeviceHandle, UInt32 Timeout);
Вот файл .h из NI:
#ifndef __Ni845x_HEADER__
#define __Ni845x_HEADER__
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32)
#define NI845X_FUNC __stdcall
#elif defined(WIN64)
#define NI845X_FUNC __fastcall
#elif defined(macosxU)
#define NI845X_FUNC
#endif
#if (defined(WIN32) || defined(WIN64))
#if defined(kExportSymbols)
#define kNI845XExport
#else
#define kNI845XExport
#endif
#elif defined (macosxU)
#if defined(kExportSymbols)
#if ( __GNUC__ >= 4 )
#define kNI845XExport __attribute__((visibility("default")))
#else
#define kNI845XExport __attribute__ ((section ("__TEXT,__export")))
#endif
#else
#define kNI845XExport
#endif
#endif
#ifdef _CVI_
#pragma EnableLibraryRuntimeChecking
#endif
#ifndef _NI_int8_DEFINED_
#define _NI_int8_DEFINED_
typedef char int8;
#endif
#ifndef _NI_uInt8_DEFINED_
#define _NI_uInt8_DEFINED_
typedef unsigned char uInt8;
#endif
#ifndef _NI_int16_DEFINED_
#define _NI_int16_DEFINED_
typedef short int16;
#endif
#ifndef _NI_uInt16_DEFINED_
#define _NI_uInt16_DEFINED_
typedef unsigned short uInt16;
#endif
#ifndef _NI_int32_DEFINED_
#define _NI_int32_DEFINED_
typedef long int32;
#endif
#ifndef _NI_uInt32_DEFINED_
#define _NI_uInt32_DEFINED_
typedef unsigned long uInt32;
#endif
#if defined(WIN64)
typedef unsigned long long NiHandle;
#elif defined(WIN32)
typedef unsigned long NiHandle;
#endif
typedef struct {
uInt32 dimSize;
uInt8 elt[1];
} Array1DU8_t;
typedef Array1DU8_t **Array1DU8Handle_t;
#define kNi845xWarningClockRateCoerced 301700
#define kNi845xWarningSpiSampleDataIgnored 301701
#define kNi845xWarningUnknown 301719
#define kNi845xErrorNoError 0
#define kNi845xErrorInsufficientMemory -301700
#define kNi845xErrorInvalidResourceName -301701
#define kNi845xErrorInvalidClockRate -301702
#define kNi845xErrorTooManyScriptReads -301703
#define kNi845xErrorInvalidScriptReadIndex -301704
#define kNi845xErrorInvalidScriptReference -301705
#define kNi845xErrorInvalidDeviceId -301706
#define kNi845xErrorConnectionLost -301707
#define kNi845xErrorTimeout -301708
#define kNi845xErrorInternal -301709
#define kNi845xErrorInvalidConfigurationReference -301710
#define kNi845xErrorTooManyConfigurations -301711
#define kNi845xErrorInvalidActiveProperty -301712
#define kNi845xErrorInvalidParameter -301713
#define kNi845xErrorResourceBusy -301714
#define kNi845xErrorInvalidMasterCode -301715
#define kNi845xErrorMasterCodeAck -301716
#define kNi845xErrorOverCurrentError -301718
#define kNi845xErrorSpiStreamingModeNotSupported -301780
#define kNi845xErrorI2cSlaveModeNotSupported -301781
#define kNi845xErrorInvalidI2cSlaveEventResponse -301782
#define kNi845xErrorI2cSlaveEventPending -301783
#define kNi845xErrorUnknown -301719
//=====================================
//
// General Errors from the device
//
//=====================================
#define kNi845xErrorBadOpcode -301720
#define kNi845xErrorUnknownStatus -301721
#define kNi845xErrorProtocolViolation -301722
#define kNi845xErrorInvalidScript -301723
#define kNi845xErrorInvalidFirmware -301724
#define kNi845xErrorIncompatibleFirmware -301725
//=====================================
//
// SPI Errors from the device
//
//=====================================
#define kNi845xErrorMasterWriteCollision -301730
#define kNi845xErrorInvalidSpiPortNumber -301732
#define kNi845xErrorInvalidCsPortNumber -301733
#define kNi845xErrorInvalidChipSelect -301734
#define kNi845xErrorInvalidBitsPerSample -301735
//=====================================
//
// I2C Errors from the device
//
//=====================================
#define kNi845xErrorMasterBusFreeTimeout -301740
#define kNi845xErrorMasterCodeArbLost -301741
#define kNi845xErrorMasterAddressNotAcknowledged -301742
#define kNi845xErrorMasterDataNotAcknowledged -301743
#define kNi845xErrorMasterAddressArbitrationLost -301744
#define kNi845xErrorMasterDataArbitrationLost -301745
#define kNi845xErrorInvalidI2CPortNumber -301746
//=====================================
//
// DIO Errors from the device
//
//=====================================
#define kNi845xErrorInvalidDioPortNumber -301750
#define kNi845xErrorInvalidDioLineNumber -301751
//=====================================
//
// SPI Streaming Errors from the device
//
//=====================================
#define kNi845xErrorInStreamingMode -301717
#define kNi845xErrorNotInStreamingMode -301760
//=====================================
//
// SPI Function Arguments
//
//=====================================
#define kNi845xSpiClockPolarityIdleLow 0 // Idle Low
#define kNi845xSpiClockPolarityIdleHigh 1 // Idle High
#define kNi845xSpiClockPhaseFirstEdge 0 // First Edge
#define kNi845xSpiClockPhaseSecondEdge 1 // Second Edge
//=====================================
//
// DIO Function Arguments
//
//=====================================
#define kNi845xDioInput 0 // DIO Direction Input
#define kNi845xDioOutput 1 // DIO Direction Output
#define kNi845xDioLogicLow 0 // DIO Level Low
#define kNi845xDioLogicHigh 1 // DIO Level High
//=====================================
//
// Generic Function Arguments
//
//=====================================
#define kNi845xOpenDrain 0 // Open Drain
#define kNi845xPushPull 1 // Push Pull
#define kNi845x33Volts 33 // 3.3V
#define kNi845x25Volts 25 // 2.5V
#define kNi845x18Volts 18 // 1.8V
#define kNi845x15Volts 15 // 1.5V
#define kNi845x12Volts 12 // 1.2V
//These defines are deprecated and the 845x Driver Type and IO Voltage Level
//should be used instead
#define kNi845xOpenDrain 0 // Open-Drain
#define kNi845xPushPull33Volts 1 // 3.3V Push-Pull
kNI845XExport int32 NI845X_FUNC ni845xFindDevice (
char * FirstDevice,
NiHandle * FindDeviceHandle,
uInt32 * NumberFound
);
kNI845XExport int32 NI845X_FUNC ni845xFindDeviceNext (
NiHandle FindDeviceHandle,
char * NextDevice
);
kNI845XExport int32 NI845X_FUNC ni845xCloseFindDeviceHandle(
NiHandle FindDeviceHandle
);
kNI845XExport int32 NI845X_FUNC ni845xOpen(
char * ResourceName,
NiHandle * DeviceHandle
);
kNI845XExport int32 NI845X_FUNC ni845xClose (
NiHandle DeviceHandle
);
kNI845XExport int32 NI845X_FUNC ni845xDeviceLock (
NiHandle DeviceHandle
);
kNI845XExport int32 NI845X_FUNC ni845xDeviceUnlock (
NiHandle DeviceHandle
);
kNI845XExport void NI845X_FUNC ni845xStatusToString(
int32 StatusCode,
uInt32 MaxSize,
int8 * StatusString
);
kNI845XExport int32 NI845X_FUNC ni845xSetIoVoltageLevel(
NiHandle DeviceHandle,
uInt8 VoltageLevel
);
kNI845XExport int32 NI845X_FUNC ni845xSetTimeout(
NiHandle DeviceHandle,
uInt32 Timeout
);
//==============================================================================
//
// SPI BASIC API FUNCTION PROTOTYPES
//
//==============================================================================
kNI845XExport int32 NI845X_FUNC ni845xSpiWriteRead(
NiHandle DeviceHandle,
NiHandle ConfigurationHandle,
uInt32 WriteSize,
uInt8 * WriteData,
uInt32 * ReadSize,
uInt8 * ReadData
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationOpen (
NiHandle * ConfigurationHandle
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationClose (
NiHandle ConfigurationHandle
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetChipSelect (
NiHandle ConfigurationHandle,
uInt32 ChipSelect
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetClockRate (
NiHandle ConfigurationHandle,
uInt16 ClockRate
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetClockPolarity (
NiHandle ConfigurationHandle,
int32 ClockPolarity
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetClockPhase (
NiHandle ConfigurationHandle,
int32 ClockPhase
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetNumBitsPerSample (
NiHandle ConfigurationHandle,
uInt16 NumBitsPerSample
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationSetPort (
NiHandle ConfigurationHandle,
uInt8 PortNumber
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationGetChipSelect (
NiHandle ConfigurationHandle,
uInt32 * ChipSelect
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationGetClockRate (
NiHandle ConfigurationHandle,
uInt16 * ClockRate
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationGetClockPolarity (
NiHandle ConfigurationHandle,
int32 * ClockPolarity
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationGetClockPhase (
NiHandle ConfigurationHandle,
int32 * ClockPhase
);
int32 NI845X_FUNC ni845xSpiConfigurationGetNumBitsPerSample (
NiHandle ConfigurationHandle,
uInt16 * NumBitsPerSample
);
kNI845XExport int32 NI845X_FUNC ni845xSpiConfigurationGetPort (
NiHandle ConfigurationHandle,
uInt8 * PortNumber
);
kNI845XExport int32 NI845X_FUNC ni845xDioWritePort (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 WriteData
);
kNI845XExport int32 NI845X_FUNC ni845xDioReadPort (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 * ReadData
);
kNI845XExport int32 NI845X_FUNC ni845xDioWriteLine (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 LineNumber,
int32 WriteData
);
kNI845XExport int32 NI845X_FUNC ni845xDioReadLine (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 LineNumber,
int32 * ReadData
);
//This function has been deprecated and ni845xDioSetDriverType and
//ni845xSetIoVoltageLevel should be used instead.
kNI845XExport int32 NI845X_FUNC ni845xDioSetPortVoltageType (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 Type
);
kNI845XExport int32 NI845X_FUNC ni845xDioSetDriverType(
NiHandle DeviceHandle,
uInt8 DioPort,
uInt8 Type
);
kNI845XExport int32 NI845X_FUNC ni845xDioSetPortLineDirectionMap (
NiHandle DeviceHandle,
uInt8 PortNumber,
uInt8 Map
);
#ifdef __cplusplus
}
#endif
#endif // __Ni845x_HEADER__
Эта подпись, кажется, работает в. чистый птamework:
[DllImport("Ni845x.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern Int32 ni845xSpiWriteRead(ulong DeviceHandle, ulong ConfigurationHandle, UInt32 WriteSize, [In] byte[] WriteData, out UInt32 ReadSize, [Out] byte[] ReadData);
Итак, есть ли документация о том, как / почему .Net Core правильно обрабатывает объявление out?