System.AccessViolation将结构传递给非托管代码时的异常
本文关键字:非托管代码 异常 AccessViolation 结构 System | 更新日期: 2023-09-27 17:56:05
我正在尝试使用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
)。 - 检查调用约定。
- 检查评论中写的内容。
问题可能对齐。 尝试像
StructLayout(LayoutKind.Sequential, Pack = 1)
C# 调用中的 handle
变量从何而来?
我更喜欢在DllImport
方法定义中使用IntPtr
。以这种方式管理和编组似乎更容易。
我已经更改了相当多的struct
定义,因为我的定义与您不同。我的ctTagReadEx
函数中也没有太多的主体(我将尝试充实它以确保传入的参数与收到的参数匹配)。但这对我有用。
更新:看起来所有参数和结构值都已正确传递。
C
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;
}
C#
[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);
}