C#PInvoke结构与类访问冲突
调用PInvoke时,我一直在随机获取访问冲突异常,该结构版本似乎可以正常工作.该类版本将随机给我访问冲突异常.问题是我在类版本中有多余的字段,而结构版本与合同所期望的完全匹配吗?我认为多余的字段无关紧要,因为非托管代码无论如何都只能访问前三个UInt32.
I have been randoming getting a Access Violation Exception when calling PInvoke, the struct version seems to work. The class version will randomly give me the Access Violation Exception. Is the issue that I have extra fields in the class version and the struct version matches exactly what the contract is expecting? I would assume extra fields shouldn't matter as the unmanaged code should only be accessing the first 3 UInt32's anyway.
我担心的是结构版本仍然存在访问冲突问题,但这种情况并不常见.
What I'm afraid of is the access violation problem still exists with the struct version but just not as often.
任何帮助将不胜感激 谢谢
Any help would be appreciated Thanks
[StructLayout(LayoutKind.Sequential)]
public class TStat
{
private UInt32 bitfield;
public UInt32 cbInQue;
public UInt32 cbOutQue;
private readonly UInt32 fCtsHoldMask = 0x00000001;
private readonly Int32 fCtsHoldShift = 0;
private readonly UInt32 fDsrHoldMask = 0x00000002;
private readonly Int32 fDsrHoldShift = 1;
private readonly UInt32 fRlsdHoldMask = 0x00000004;
private readonly Int32 fRlsdHoldShift = 2;
private readonly UInt32 fXoffHoldMask = 0x00000008;
private readonly Int32 fXoffHoldShift = 3;
private readonly UInt32 fXoffSentMask = 0x00000010;
private readonly Int32 fXoffSentShift = 4;
private readonly UInt32 fEofMask = 0x00000020;
private readonly Int32 fEofShift = 5;
private readonly UInt32 fTximMask = 0x00000040;
private readonly Int32 fTximShift = 6;
public bool fCtsHold
{
get { return ((bitfield & fCtsHoldMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fCtsHoldShift); }
}
public bool fDsrHold
{
get { return ((bitfield & fDsrHoldMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fDsrHoldShift); }
}
public bool fRlsdHold
{
get { return ((bitfield & fRlsdHoldMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fRlsdHoldShift); }
}
public bool fXoffHold
{
get { return ((bitfield & fXoffHoldMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fXoffHoldShift); }
}
public bool fXoffSent
{
get { return ((bitfield & fXoffSentMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fXoffSentShift); }
}
public bool fEof
{
get { return ((bitfield & fEofMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fEofShift); }
}
public bool fTxim
{
get { return ((bitfield & fTximMask) != 0); }
set { bitfield |= (Convert.ToUInt32(value) << fTximShift); }
}
}
[StructLayout(LayoutKind.Sequential)]
public struct TStat
{
private UInt32 bitfield;
public UInt32 cbInQue;
public UInt32 cbOutQue;
}
[DllImport("coredll.dll", EntryPoint = "ClearCommError", SetLastError = true)]
private static extern Boolean ClearCommError(IntPtr hPort, out UInt32 Errors, out TStat Stat);
PInvoke链接:
PInvoke links:
_http://www.pinvoke.net/default.aspx/kernel32.clearcommerror _http://www.pinvoke.net/default.aspx/Structures/COMSTAT.html
_http://www.pinvoke.net/default.aspx/kernel32.clearcommerror _http://www.pinvoke.net/default.aspx/Structures/COMSTAT.html
msdn的本机签名
http://msdn .microsoft.com/en-us/library/windows/desktop/aa363180(v = vs.85).aspx
BOOL WINAPI ClearCommError(
_In_ HANDLE hFile,
_Out_opt_ LPDWORD lpErrors,
_Out_opt_ LPCOMSTAT lpStat
);
http://msdn .microsoft.com/en-us/library/windows/desktop/aa363200(v = vs.85).aspx
typedef struct _COMSTAT {
DWORD fCtsHold :1;
DWORD fDsrHold :1;
DWORD fRlsdHold :1;
DWORD fXoffHold :1;
DWORD fXoffSent :1;
DWORD fEof :1;
DWORD fTxim :1;
DWORD fReserved :25;
DWORD cbInQue;
DWORD cbOutQue;
} COMSTAT, *LPCOMSTAT;
在PInvoke签名中使用class
类型时,它实际上是作为指向该值的指针传递的. ref / out
也是如此.因此,当TStat
是class
时的out TStat
通过双指针传递值.仅当本机参数类型为TStat**
时才有意义.
When you use a class
type in a PInvoke signature it is essentially passed as a pointer to the value. The same is true for ref / out
. Hence out TStat
when TStat
is a class
is passing the value by double pointer. It only makes sense if the native parameter type is TStat**
.
我猜测本机签名实际上是TStat*
.这就是为什么通过struct
进行传递的原因,因为out struct
具有与PInvoke中的TStat*
相同的数据语义
I'm guessing that the native signature is actually TStat*
. This is why passing as a struct
works because out struct
has the same data semantics as TStat*
in PInvoke