0

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 links:

_http://www.pinvoke.net/default.aspx/kernel32.clearcommerror _http://www.pinvoke.net/default.aspx/Structures/COMSTAT.html

Native signatures from 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;
2
  • Can you show the other side of the interface, the unmanaged side Commented Nov 26, 2013 at 18:23
  • I added the pinvoke links as well as the struct def from msdn and unmanaged call defination from msdn as well Commented Nov 26, 2013 at 18:35

1 Answer 1

3

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**.

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

Sign up to request clarification or add additional context in comments.

2 Comments

Wouldn't that cause the method call to never work? It appears to be returning the majority of the time and it populates the cbInQue with data that seems to match what I would be expecting
There's no guarantee that you get an AV, the pointer has a knack for pointing to writable memory. That cbInQue has a good value is harder to explain, except that it usually ought to be 0 which isn't hard to come by. But it is clearly wrong, use [Out] instead of out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.