C++ style Bit Fields in VB.NET

  • Thread starter Thread starter Charles Law
  • Start date Start date
C

Charles Law

I have the following structure (for example) that I wish to convert for use
in VB.NET. What would be the best way to do it? Ideally, it would convert
directly to allow access to the bit fields in the same way as in C++, but I
cannot see any mention of bit field declarations in VB.NET.

<structure>
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;
</structure>

TIA

Charles
 
There is no bit field access in VB.Net (or C#). I've found that the best
representation is something like this:

Public Class Test
Private DCBInstance As DCB
Public Sub SomeSub()
If (DCBInstance.DCBFlags And DCBFlagsMask.TXContinueOnXoff) =
DCBFlagsMask.TXContinueOnXoff Then
'Bit Set
End If
Dim fDtrControlBits As Integer = DCBInstance.DCBFlags And
DCBFlagsMask.DtrControl
'Do something
'Etc.
End Sub
End Class

<Flags()> Public Enum DCBFlagsMask
Binary = &H1
Parity = &H2
OutxCtsFlow = &H4
OutxDsrFlow = &H8
DtrControl = &H10 Or &H20
DsrSensitivity = &H40
TXContinueOnXoff = &H80
OutX = &H100
InX = &H200
ErrorChar = &H400
Null = &H800
RtsControl = &H1000 Or &H2000
AbortOnError = &H4000
Dummy = &HFFFF8000
End Enum

<StructLayout(LayoutKind.Sequential)> _
Public Structure DCB
Public DCBlength As Integer
Public BaudRate As Integer
Public DCBFlags As DCBFlagsMask
'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;
Public wReserved As Short
Public XonLim As Short
Public XoffLim As Short
Public ByteSize As Byte
Public Parity As Byte
Public StopBits As Byte
Public XonChar As Byte
Public XoffChar As Byte
Public ErrorChar As Byte
Public EofChar As Byte
Public EvtChar As Byte
Public wReserved1 As Short
End Structure
 
Hi Stephen

Thanks for the suggestion. It has set me thinking. I am now wondering about
adding functions to the DCB structure for manipulating the bit fields, for
example

Public Function IsSet(ByVal Value As DCBFlagsMask) As Boolean
Return (DCBFlags And Value) = Value
End Function

and similar functions called Set and Reset.

Charles
 
Charles,
As Stephen stated, there is not bit field access in C# or VB.NET per se.
There is however a System.Collections.BitVector32 class that gives you
access to bit fields.

When I implemented the DCB structure in VB.NET I defined Flags as a Private
BitVector32. Then used Property procedures that extracted the individual
values, using the methods of BitVector32.

Public enum RtsControl As Byte
Disable = 0
Enable = 1
Handshake = 2
Toggle = 3
End Enum

Public Structure DBC
...
Private Flags As BitVector32
...

Private Shared Readonly m_fBinary As Integer
Private Shared Readonly m_Parity As Integer
...
Private Shared Readonly m_fRtsControl As BitVector32.Section
...

Shared Sub New()
' create boolean masks
m_fBinary = BitVector32.CreateMask()
...
m_fParity = BitVector32.CreateMask(m_fBinary)
...
' create section masks
Dim previousSection As BitVector32.Section
previousSection = BitVector32.CreateSection(1)
...
m_fRtsControl = BitVector32.CreateSection(3,
previousSection)
...
End Sub

Public Property Binary As Boolean
Get
Return Flags.Item(m_fBinary)
End Get
Set(ByVal value As Boolean)
Flags.Item(m_fBinary) = value
End Set
End Property

...

Public Property RtsControl As RtsControl
Get
Return CType(Flags.Item(m_fRtsControl), RtsControl)
End Get
Set(ByVal value As RtsControl)
Flags.Item(m_fRtsControl) = value
End Set
End Property

...

End Structure

BitVector32 is marshaled as an Integer (DWORD) so you can use them
interchangeably.

I made Flags Private as its an implementation detail.

The property procedures expose the flags as the respective types, For
example RtsControl & DtrControl as enums with valid values, others as
Boolean. I had to change a couple names as there is a field & a flag
(ErrorChar).

For the BitVector32 masks I had to make two passes, once for the boolean
values, then a second one for the section (enum) values.

Using the BitVector32 class simplified my property procedures at the
"expense" of a little extra setup (the shared constructor).

I have not posted my class on got dot net yet, as I am still working on
making the WaitEvent async.

Hope this helps
Jay
 
Hi Charles,

Depending on how you want to use the structure that could be a good approach. Jay's suggestion is also good, I don't use it more
from personal preference than anything. I find using a flags enum and masking to be more readable but that may just be me. I'd
probably do it something along these lines:

<StructLayout(LayoutKind.Sequential)> _
Public Structure DCB
Public DCBlength As Integer
Public BaudRate As Integer
Private DCBFlags As DCBFlagsMask
'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;
Public wReserved As Short
Public XonLim As Short
Public XoffLim As Short
Public ByteSize As Byte
Public Parity As Byte
Public StopBits As Byte
Public XonChar As Byte
Public XoffChar As Byte
Public ErrorChar As Byte
Public EofChar As Byte
Public EvtChar As Byte
Public wReserved1 As Short

Public Property fBinary() As Boolean
Get
Return ((DCBFlags And DCBFlagsMask.Binary) = DCBFlagsMask.Binary)
End Get
Set(ByVal Value As Boolean)
If Value Then
DCBFlags = DCBFlags Or DCBFlagsMask.Binary
Else
DCBFlags = DCBFlags And (Not DCBFlagsMask.Binary)
End If
End Set
End Property

Public Property fParity() As Boolean
Get
Return ((DCBFlags And DCBFlagsMask.Parity) = DCBFlagsMask.Parity)
End Get
Set(ByVal Value As Boolean)
If Value Then
DCBFlags = DCBFlags Or DCBFlagsMask.Parity
Else
DCBFlags = DCBFlags And (Not DCBFlagsMask.Parity)
End If
End Set
End Property

'Etc.
 
Thanks for the ideas Stephen. I've now got plenty to think about.

Cheers

Charles


Stephen Martin said:
Hi Charles,

Depending on how you want to use the structure that could be a good
approach. Jay's suggestion is also good, I don't use it more
from personal preference than anything. I find using a flags enum and
masking to be more readable but that may just be me. I'd
 
Back
Top