当对c到c使用P/Invoke并将c结构混搭到c时,会产生AccessViolationException,原因可能是什
本文关键字:AccessViolationException 使用 Invoke 并将 结构 当对 | 更新日期: 2023-09-27 18:23:40
我必须在我的p/Invoke项目中使用一个c++dll,我正在调用一个函数,该函数也涉及一个结构,即生成AccessViolationException。
具体如下:下面是c++函数。
Int BII_Read_Transaction_Log_Ex(int iOption, int iUpdateFlag, int *iMaxEntries, BII_Transaction_Log_Ex *log)
这是我的方法声明。
[DllImport(@"C:'Program Files (x86)'Bioscrypt'SecureSDK'DLL'BII_V1100.dll", EntryPoint = "BII_Read_Transaction_Log_Ex")]
public unsafe static extern int GetTransactionLogs(int option, int updateFlag, ref int maxEnteries, ref BII_Transaction_Log_Ex[] transactionLogs);
它涉及以下结构。
typedef struct
{
unsigned int id; // ID of the template whose action was recorded
unsigned char reserved_1;
unsigned char index; // Index of the template whose action was recorded
unsigned short year; // Years since 2002 action was recorded
unsigned char month; // Months since January action was recorded (0-11) unsigned char
unsigned char day; // Day of month action was recorded (1-31)
unsigned char hour; // Hour (0-23), Minute and Second (0-59) – Time of action
unsigned char min;
unsigned char sec;
unsigned char trans_code; // Trans_code, Data1, Data2, Data3 – See table below
unsigned char flag_port; //Bit 5. Bit 6 Bit 7 unused Bit 0-4: port (0 – host, 1 – aux, 3–Wiegand, 5 – GPI0, 6 – GPI1, 8 – Search)
unsigned char trans_log_data_1;
unsigned char trans_log_data_2;
unsigned char trans_log_data_3;
unsigned char reserved_2;
unsigned char status; //0 if action failed, 1 if action succeeded
char name[16]; // Name field of Template for which log is stored
unsigned short duration; // Enroll / Verify duration in milliseconds
unsigned short template_size; // Size of template in bytes for which log is stored
signed short error_code; // Error code if enroll / verify failed
unsigned char sensor_type; // Sensor type connected to device
unsigned char unit_id; // Unit ID assigned to device, same as net ID (Get/Set command for net ID BII_GET_NETID / BII_SET_NETID)
unsigned char admin_level; // Admin level of template for which log is stored
unsigned char rsz_3; /* Reserved */
unsigned char rsz_4; /* Reserved */
unsigned char rsz_5; /* Reserved */
char ta_msg[16]; /*F1,F2,F3,F4 key message */
}BII_Transaction_Log_Ex;
下面是我在c#中对这个结构的实现。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BII_Transaction_Log_Ex
{
public UInt32 id; // ID of the template whose action was recorded
public Byte reserved_1;
public Byte index; // Index of the template whose action was recorded
public UInt16 year; // Years since 2002 action was recorded
public Byte month; // Months since January action was recorded (0-11) unsigned char
public Byte day; // Day of month action was recorded (1-31)
public Byte hour; // Hour (0-23), Minute and Second (0-59) – Time of action
public Byte min;
public Byte sec;
public Byte trans_code; // Trans_code, Data1, Data2, Data3 – See table below
public Byte flag_port; //Bit 5. Bit 6 Bit 7 unused Bit 0-4: port (0 – host, 1 – aux, 3– Wiegand, 5 – GPI0, 6 – GPI1, 8 – Search)
public Byte trans_log_data_1;
public Byte trans_log_data_2;
public Byte trans_log_data_3;
public Byte reserved_2;
public Byte status; //0 if action failed, 1 if action succeeded
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] name; //char name[16]; // Name field of Template for which log is stored
public UInt16 duration; // Enroll / Verify duration in milliseconds
public UInt16 template_size; // Size of template in bytes for which log is stored
public SByte error_code; // Error code if enroll / verify failed
public Byte sensor_type; // Sensor type connected to device
public Byte unit_id; // Unit ID assigned to device, same as net ID (Get/Set command for net ID BII_GET_NETID / BII_SET_NETID)
public Byte admin_level; // Admin level of template for which log is stored
public Byte rsz_3; /* Reserved */
public Byte rsz_4; /* Reserved */
public Byte rsz_5; /* Reserved */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] ta_msg; /*F1,F2,F3,F4 key message */
}
现在,当我使用调用函数时,它会生成AccessViolationException,并显示以下消息:"试图读取或写入受保护的内存。这通常表明其他内存已损坏。"
int transactionsCount=-1;
BII_Transaction_Log_Ex[] logs = new BII_Transaction_Log_Ex[1000];
int result = GetTransactionLogs(0, 0, ref transactionsCount, ref logs);
我认为我在混淆所涉及的结构时犯了一些错误,但到目前为止我还无法找出确切的问题。任何帮助都将不胜感激。。
编辑:我没有c++源代码。
C++函数的声明如下:
int BII_Read_Transaction_Log_Ex(
int iOption,
int iUpdateFlag,
int *iMaxEntries,
BII_Transaction_Log_Ex *log
);
最后一个参数可以是通过引用传递的单个结构。在这种情况下,C#将是:
[DllImport(@"...", CallingConvention=CallingConvention.Cdecl,
EntryPoint = "BII_Read_Transaction_Log_Ex")]
public static extern int GetTransactionLogs(
int option,
int updateFlag,
ref int maxEntries,
ref BII_Transaction_Log_Ex transactionLogs
);
注意这里不需要unsafe,所以我删除了它。它看起来很像C++函数使用cdecl
。
然而,在transactionLogs
和maxEntries
参数中使用复数会让我怀疑C++代码需要一个数组。在这种情况下,你会写:
[DllImport(@"...", CallingConvention=CallingConvention.Cdecl,
EntryPoint = "BII_Read_Transaction_Log_Ex")]
public static extern int GetTransactionLogs(
int option,
int updateFlag,
ref int maxEntries,
[Out] BII_Transaction_Log_Ex[] transactionLogs
);
我也有点怀疑你在结构定义中使用Pack=1
。是什么让你这么做的。我希望有一个对齐的结构,在这种情况下应该删除Pack
。我认为这无关紧要,因为C++结构将保留成员放在将添加填充的空间中,但我仍然希望看到结构声明为对齐。