我正在尝试使用来自C#的非托管API,并将头撞墙。 (关于PInvoke,我是个初学者。)

头文件的相关部分如下所示:

#define CTAPICALL       __stdcall
#ifdef __cplusplus
    extern "C" {
#endif

extern  BOOL    CTAPICALL   ctTagReadEx(HANDLE,LPCSTR,LPSTR,DWORD,CT_TAGVALUE_ITEMS*);      /* read extended data from tag          */

#ifdef __cplusplus
}
#endif


CT_TAGVALUE_ITEMS看起来像这样:

typedef struct
{
    DWORD                   dwLength;                           /* size, in bytes, of this structure    */
    unsigned __int64        nTimestamp;                         /*  timestamp                           */
    unsigned __int64        nValueTimestamp;                    /*  value timestamp                     */
    unsigned __int64        nQualityTimestamp;                  /*  quality timestamp                   */
    BYTE                    bQualityGeneral;                    /*  quality general                     */
    BYTE                    bQualitySubstatus;                  /*  quality substatus                   */
    BYTE                    bQualityLimit;                      /*  quality limit                       */
    BYTE                    bQualityExtendedSubstatus;          /*  quality extended substatus          */
    UINT                    nQualityDatasourceErrorCode;        /*  quality datasource error            */
    BOOLEAN                 bOverride;                          /*  quality override flag               */
    BOOLEAN                 bControlMode;                       /*  quality control mode flag           */
}   CT_TAGVALUE_ITEMS;


我的C#方法声明:

    [DllImport("ctapi.dll", SetLastError = true)]
    public static extern bool ctTagReadEx(
        IntPtr hCTAPI,
        [MarshalAs(UnmanagedType.LPStr)] string tag,
        [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder value,
        int length,
        CtTagValueItems tagValueItems);


C#结构:

[StructLayout(LayoutKind.Sequential)]
public struct CtTagValueItems
{
    public int dwLength;
    public ulong nTimestamp;
    public ulong nValueTimestamp;
    public ulong nQualityTimestamp;
    public byte bQualityGeneral
    public byte bQualitySubstatus;
    public byte bQualityLimit;
    public byte bQualityExtendedSubstatus;
    public uint nQualityDatasourceErrorCode;
    public uint bOverride;
    public uint bControlMode;
}


当我这样称呼它时(从以x86构建的测试程序集中),我得到一个System.AccessViolationException : Attempted to read or write protected memory

StringBuilder valueBuilder = new StringBuilder(300);
CtTagValueItems tagValueItems = new CtTagValueItems {dwLength = Marshal.SizeOf(typeof (CtTagValueItems))};
bool ok = CTAPI.ctTagReadEx(new IntPtr(handle), "TIC_Hold_PV", valueBuilder, valueBuilder.Capacity, tagValueItems);


我一直在尝试各种方法,例如使用LayoutKind.Explicit和/或CallingConvention = CallingConvention.Cdecl,但无济于事。

有人可以帮忙吗?

最佳答案

为什么将UINT映射为ushort。它没有4个字节吗?
本机BOOLEAN类型映射为4个字节,即AFAIK。
您需要通过ref传递CtTagValueItems(作为类或ref)。
检查调用约定。
检查注释中写了些什么。

关于c# - 将结构传递给非托管代码时发生System.AccessViolationException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14505104/

10-11 03:31