Взаимодействие, работающее в .Net Core, не работает в Framework - PullRequest
0 голосов
/ 16 октября 2019

У меня есть обертка для 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?

1 Ответ

0 голосов
/ 16 октября 2019

См. Выше, отредактируйте ответ. Просто продолжал отключаться - работает в обоих сейчас. Я полагаю, что .Net Core кроссплатформенный, имеет больше / лучше эвристики вокруг PInvoke и Interop? Есть ли какая-то причина, по которой это не используется в .NEt Framework? Есть ли документация о том, как / почему .Net Core делает это по-другому?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...