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?
source to share
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);
}
source to share