CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jul 2007
    Location
    Illinois
    Posts
    517

    [RESOLVED] Marshalling Structure to kernel32.dll

    Very simple example but I cant seem to get it to work accurately, I have created a managed version of the DCB structure within the Windows.h header file:

    Code:
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 8, Size = 28)]
        internal struct DCB
        {
            public DWORD DCBlength; // sizeof(DCB)
            public DWORD BaudRate; // current baud rate
            public DWORD fBinary; // binary mode, no EOF check
            public DWORD fParity; // enable parity checking
            public DWORD fOutxCtsFlow; // CTS output flow control
            public DWORD fOutxDsrFlow; // DSR output flow control
            public DWORD fDtrControl; // DTR flow control type
            public DWORD fDsrSensitivity; // DSR sensitivity
            public DWORD fTXContinueOnXoff; // XOFF continues Tx
            public DWORD fOutX; // XON/XOFF out flow control
            public DWORD fInX; // XON/XOFF in flow control
            public DWORD fErrorChar; // enable error replacement
            public DWORD fNull; // enable null stripping
            public DWORD fRtsControl; // RTS flow control
            public DWORD fAbortOnError; // abort on error
            public DWORD fDummy2; // reserved
            public WORD wReserved; // not currently used
            public WORD XonLim; // transmit XON threshold
            public WORD XoffLim; // transmit XOFF threshold
            public BYTE ByteSize; // number of bits/byte, 4-8
            public BYTE Parity; // 0-4=no,odd,even,mark,space
            public BYTE StopBits; // 0,1,2 = 1, 1.5, 2
            public CHAR XonChar; // Tx and Rx XON character
            public CHAR XoffChar; // Tx and Rx XOFF character
            public CHAR ErrorChar; // error replacement character
            public CHAR EofChar; // end of input character
            public CHAR EvtChar; // received event character
            public WORD wReserved1; // reserved; do not use
        }
    The datatypes have been coerced with "using" statements to be as close to the Win32 data types Microsoft has been using when developing Win32 C++ application. ex. DWORD = System.UInt32 and CHAR = System.SByte.

    Here is my function "prototype" for the function I am attempting to use:

    Code:
            [DllImport("kernel32.dll", SetLastError = true)]
            private static unsafe extern bool GetCommState(SafeFileHandle hFile, DCB* lpDCB);
    Seems ok to me... But when you call the GetCommState function passing in a handle to an open serial port, you end up getting back a DCB structure which has the first few fields properly set (BaudRate, DCBlength) but a few of the fields are really odd. For example:

    fBinary = 6161
    fParity = 134217728
    fOutxCtsFlow = 524800

    At first I thought it may have been a data misalignment problem. But I set the LayoutKind to Explicit and went through the structure and set the FieldOffset attribute for each member manually and it STILL was messed up. I cant seem to set the Parity, StopBits, and some of the other fields using the function SetCommState either since my DCB structure is messed up. Anyone got anyone ideas?
    R.I.P. 3.5" Floppy Drives
    "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

  2. #2
    Join Date
    May 2007
    Posts
    1,546

    Re: Marshalling Structure to kernel32.dll

    Leave out the Pack = 8 and Size=28 parameters unless you *really* know what you're doing and fully understand exactly what they do. My guess is you're forcing a packing which you shouldn't be using which is making the data be stored in the wrong location.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  3. #3
    Join Date
    Jul 2007
    Location
    Illinois
    Posts
    517

    Re: Marshalling Structure to kernel32.dll

    I did that beforehand and it still didn't work. They're there as one of my flailing attempts to try to get it working. I keep thinking its a data misalignment problem but I don't see how... All of the data types are precise CLR substitutes for Win32 data types. Could you try the code on your own machine and see if it works? I'm using a CP-US-03 adapter but I dont know if that will make a difference. Stupid USB serial adapters... theyve always been problematic for us even before I came along 2 years ago. Ugh!
    Last edited by RaleTheBlade; August 31st, 2009 at 05:23 PM.
    R.I.P. 3.5" Floppy Drives
    "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

  4. #4
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Marshalling Structure to kernel32.dll

    DCB is defined as :

    Code:
    typedef struct _DCB {
      DWORD DCBlength;
      DWORD BaudRate;
      DWORD fBinary  :1;
      DWORD fParity  :1;
      DWORD fOutxCtsFlow  :1;
      DWORD fOutxDsrFlow  :1;
      DWORD fDtrControl  :2;
      DWORD fDsrSensitivity  :1;
      DWORD fTXContinueOnXoff  :1;
      DWORD fOutX  :1;
      DWORD fInX  :1;
      DWORD fErrorChar  :1;
      DWORD fNull  :1;
      DWORD fRtsControl  :2;
      DWORD fAbortOnError  :1;
      DWORD fDummy2  :17;
      WORD  wReserved;
      WORD  XonLim;
      WORD  XoffLim;
      BYTE  ByteSize;
      BYTE  Parity;
      BYTE  StopBits;
      char  XonChar;
      char  XoffChar;
      char  ErrorChar;
      char  EofChar;
      char  EvtChar;
      WORD  wReserved1;
    }DCB, *LPDCB;
    Note the ':' after some of the members. This indicates it is a bitfield - which is why you're getting peculiar results.

    See here for more information about bitfields.

    I'd normally give a solution for the pinvoke, but in this case since it'd take quite a while to explain how to properly marshal these try going here.

    There's a free download of a full pinvoke interface for kernel32.dll available which should be of help.

    Darwen.
    Last edited by darwen; August 31st, 2009 at 05:33 PM.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  5. #5
    Join Date
    Jul 2007
    Location
    Illinois
    Posts
    517

    Re: Marshalling Structure to kernel32.dll

    Here is the contents of the DCB structure when reading from a REAL RS-232 serial port:

    Code:
     --- DCB --- 
    DCBlength = 28
    BaudRate = 9600
    fBinary = 1
    fParity = 134217728
    fOutxCtsFlow = 459264
    fOutxDsrFlow = 1249536
    fDtrControl = 0
    fDsrSensitivity = 0
    fTXContinueOnXoff = 0
    fOutX = 0
    fInX = 0
    fErrorChar = 0
    fNull = 0
    fRtsControl = 0
    fAbortOnError = 0
    fDummy2 = 0
    wReserved = 0
    XonLim = 0
    XoffLim = 0
    ByteSize = 0
    Parity = 0
    StopBits = 0
    XonChar = 0
    XoffChar = 0
    ErrorChar = 0
    EofChar = 0
    EvtChar = 0
    wReserved1 = 0
     --- END ---
    And here are the contents of the structure when reading from a serial port which is emulated with a CP-US-03 adapter:

    Code:
     --- DCB --- 
    DCBlength = 28
    BaudRate = 9600
    fBinary = 6161
    fParity = 134217728
    fOutxCtsFlow = 524800
    fOutxDsrFlow = 2
    fDtrControl = 0
    fDsrSensitivity = 0
    fTXContinueOnXoff = 0
    fOutX = 0
    fInX = 0
    fErrorChar = 0
    fNull = 0
    fRtsControl = 0
    fAbortOnError = 0
    fDummy2 = 0
    wReserved = 0
    XonLim = 0
    XoffLim = 0
    ByteSize = 0
    Parity = 0
    StopBits = 0
    XonChar = 0
    XoffChar = 0
    ErrorChar = 0
    EofChar = 0
    EvtChar = 0
    wReserved1 = 0
     --- END ---
    I cant figure this out, Ive been working on it for days. If I build a small test project in C++ and call GetCommState, passing in a pointer to a DCB structure it works perfectly. Something is going bad when I try to invoke those same functions across the P/Invoke layer from C# to Win32.
    R.I.P. 3.5" Floppy Drives
    "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

  6. #6
    Join Date
    Jul 2007
    Location
    Illinois
    Posts
    517

    Re: Marshalling Structure to kernel32.dll

    Quote Originally Posted by darwen View Post
    DCB is defined as :

    Code:
    typedef struct _DCB {
      DWORD DCBlength;
      DWORD BaudRate;
      DWORD fBinary  :1;
      DWORD fParity  :1;
      DWORD fOutxCtsFlow  :1;
      DWORD fOutxDsrFlow  :1;
      DWORD fDtrControl  :2;
      DWORD fDsrSensitivity  :1;
      DWORD fTXContinueOnXoff  :1;
      DWORD fOutX  :1;
      DWORD fInX  :1;
      DWORD fErrorChar  :1;
      DWORD fNull  :1;
      DWORD fRtsControl  :2;
      DWORD fAbortOnError  :1;
      DWORD fDummy2  :17;
      WORD  wReserved;
      WORD  XonLim;
      WORD  XoffLim;
      BYTE  ByteSize;
      BYTE  Parity;
      BYTE  StopBits;
      char  XonChar;
      char  XoffChar;
      char  ErrorChar;
      char  EofChar;
      char  EvtChar;
      WORD  wReserved1;
    }DCB, *LPDCB;
    Note the ':' after some of the members. This indicates it is a bitfield - which is why you're getting peculiar results.

    See here for more information about bitfields.

    I wouldn't normally do this, but since it'd take quite a while to explain how to properly marshal these try going here.

    There's a free download of a full pinvoke interface for kernel32.dll available which should be of help.

    Darwen.
    Thanks Darwen, I knew those items after the : may have had something to do with it but I wasnt fully sure of what they meant. I dont interop but once a blue moon!
    R.I.P. 3.5" Floppy Drives
    "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

  7. #7
    Join Date
    Jul 2007
    Location
    Illinois
    Posts
    517

    Re: Marshalling Structure to kernel32.dll

    Ok, after realizing that I was WAY overreaching my memory when my DCB structure was getting marshalled over the P/Invoke layer I got to thinking that I could just use a BitVector32 object and store all of the bits from fBinary through fDummy and it worked! Now whenever I need to change some of the individual bits I read in the DCB structure from a call to GetCommState, set the bits I need in the BitVector32 object in the DCB structure, and pass it back to SetCommState and it worked like a charm =D Heres the code I used to get this to work:

    The DCB structure:

    Code:
        [StructLayout(LayoutKind.Explicit, Size = 28, CharSet = CharSet.Ansi)]
        internal struct DCB
        {
            [FieldOffset(0)]
            public DWORD DCBlength; // sizeof(DCB)
            [FieldOffset(4)]
            public DWORD BaudRate; // current baud rate
            [FieldOffset(8)]
            [MarshalAs(UnmanagedType.U4)]
            public BitVector32 bitField; // bit fields
            [FieldOffset(12)]
            public WORD wReserved; // not currently used
            [FieldOffset(14)]
            public WORD XonLim; // transmit XON threshold
            [FieldOffset(16)]
            public WORD XoffLim; // transmit XOFF threshold
            [FieldOffset(18)]
            public BYTE ByteSize; // number of bits/byte, 4-8
            [FieldOffset(19)]
            public BYTE Parity; // 0-4=no,odd,even,mark,space
            [FieldOffset(20)]
            public BYTE StopBits; // 0,1,2 = 1, 1.5, 2
            [FieldOffset(21)]
            public CHAR XonChar; // Tx and Rx XON character
            [FieldOffset(22)]
            public CHAR XoffChar; // Tx and Rx XOFF character
            [FieldOffset(23)]
            public CHAR ErrorChar; // error replacement character
            [FieldOffset(24)]
            public CHAR EofChar; // end of input character
            [FieldOffset(25)]
            public CHAR EvtChar; // received event character
            [FieldOffset(26)]
            public WORD wReserved1; // reserved; do not use
        }
    And the code to set the bits:

    Code:
    // 4113 = 000000000000000000001000000010001 in binary
    dcb.bitField = new BitVector32(4113);
    
    // You can set them individually by using the decimal values of each
    // binary digit too:
    
                        dcb.bitField[1] = true;     // fBinary
                        dcb.bitField[2] = false;    // fParity
                        dcb.bitField[4] = false;    // fOutxCtsFlow
                        dcb.bitField[8] = false;    // fOutxRtsFlow
                        dcb.bitField[16] = false;    // fDtrControl
                        dcb.bitField[32] = false;   // fDtrControl (always false)
                        dcb.bitField[64] = false;   // fDsrSensitivity
                        dcb.bitField[128] = false;  // fTxContinueOnXOff
                        dcb.bitField[256] = false;  // fOutX
                        dcb.bitField[512] = false;  // fInX
                        dcb.bitField[1024] = false; // fErrorChar
                        dcb.bitField[2048] = false; // fNull
                        dcb.bitField[4096] = false;  // fRtsControl
                        dcb.bitField[8192] = false; // fRtsControl (always false)
                        dcb.bitField[16384] = false;// fAbortOnError
    
    // This creates a bit field of 32 bits and represents the number 4113 in decimal.
    Thanks for the help Darwin, without knowing that the C implementation made the use of bit fields I would probably have been stuck on this STILL
    Last edited by RaleTheBlade; September 1st, 2009 at 01:20 PM. Reason: Spelling
    R.I.P. 3.5" Floppy Drives
    "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured