System.AccessViolationException while passing struct to unmanaged code

I am trying to use an unmanaged API from C # and banging my head against a wall. (I'm more of a start when it comes to PInvoke.)

The relevant parts of the header file are as follows:

#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

as follows:

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;

      

My C # method declaration:

    [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 # structure:

[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;
}

      

When I call this (from a test build built as x86) I get 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);

      

I've tried all sorts of things like using LayoutKind.Explicit

and / or CallingConvention = CallingConvention.Cdecl

to no avail.

Does anyone help?

+3


source to share


3 answers


  • Why did you display UINT

    as ushort

    . Doesn't it have 4 bytes?
  • The native type BOOLEAN

    displays 4 bytes, AFAIK.
  • You need to pass CtTagValueItems

    by ref (as a class or ref

    ).
  • Check the calling agreement.
  • Check what is written in the comments.


+2


source


The problem can be reconciled. try something like



StructLayout(LayoutKind.Sequential, Pack = 1)

      

+1


source


Where handle

does the variable in the C # call come from ?

I prefer to use IntPtr

in my method definitions DllImport

. Seems to be easier to manage and marshal this way.

I changed the definition a bit struct

because I don't have the same definitions as you. I also don't have a lot of body in my function ctTagReadEx

(I will try to execute it to make sure the parameters are passed in according to the received parameters). But it works for me.

Update: It looks like all structure parameters and values ​​were passed correctly.

FROM

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


CTAPICALL int ctTagReadEx(void *, const char *, char *, int, CT_TAGVALUE_ITEMS *);

int ctTagReadEx(void * hCTAPI, const char * tag, char * value, int length, CT_TAGVALUE_ITEMS *tagValueItems) {
    return 15;
}

      

FROM#

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

[DllImport("ctapi.dll")]
static extern int ctTagReadEx(IntPtr hCTAPI, IntPtr tag, IntPtr value, int length, IntPtr tagValueItems);

public void TestMe() {

    var tagValueItems = new CtTagValueItems();
    var tagValueItemsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CtTagValueItems)));
    Marshal.StructureToPtr(tagValueItems, tagValueItemsPtr, true);

    var tag = "tag";
    var tagPtr = Marshal.StringToHGlobalAnsi(tag);

    var value = "value";
    var valuePtr = Marshal.StringToHGlobalAnsi(value);

    int length = value.Length;

    var result = ctTagReadEx(IntPtr.Zero, tagPtr, valuePtr, length, tagValueItemsPtr);
    if (result != 15) throw new Exception();

    Marshal.FreeHGlobal(tagValueItemsPtr);
    Marshal.FreeHGlobal(tagPtr);
    Marshal.FreeHGlobal(valuePtr);
}

      

+1


source







All Articles