You are on page 1of 6

9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

14,352,613 members Sign in

Search for articles, questions,


articles Q&A forums stuff lounge ?

Ask a Question All Unanswered FAQ

Change DCB fields from SerialPort instance C#


See more: C# .NET serial-port .NET4.5 Comms Rate this:

I am trying to emulate communication between an existing piece of software and hardware, using Advanced Serial Port Monitor I
was able to come up with this information about the communication.

Hide   Copy Code

In/out queue size 1024/512


Purge the serial port: RXABORT, RXCLEAR, TXABORT, TXCLEAR
Set timeouts: ReadInterval=-1, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0,
WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=5000
Baud rate 115200
RTS on
DTR off
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x1A, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(), FlowReplace=(TRANSMIT_TOGGLE, RTS_CONTROL), XonLimit=256,
XoffLimit=256

First I tried using the built in SerialPort class on it's own, but it lacks the versatility to be able to complete such a task, I then tried
using System.Reflection to set the DCB fields, but whenever I come to a field that begins with a lowercase f, such as "fParity" or
"fDtrControl", it gives me a NullReferenceException.

Is there any other way that I can modify these values to match the above?

This is the extension method I wrote enabling the modification of DCB fields
Hide   Expand   Copy Code

internal static class SerialPortExtensions


{
[SecurityPermission(SecurityAction.LinkDemand, Flags =
SecurityPermissionFlag.UnmanagedCode)]
public static void SetFlag(this SerialPort port, string flag, object value)
{
if (port == null)
throw new NullReferenceException();
if (port.BaseStream == null)
throw new InvalidOperationException("Cannot change X chars until after the
port has been opened.");

try
{
// Get the base stream and its type which is System.IO.Ports.SerialStream
object baseStream = port.BaseStream;
Type baseStreamType = baseStream.GetType();

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 1/6
9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

// Get the Win32 file handle for the port


SafeFileHandle portFileHandle =
(SafeFileHandle)baseStreamType.GetField("_handle", BindingFlags.NonPublic |
BindingFlags.Instance).GetValue(baseStream);

// Get the value of the private DCB field (a value type)


FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb",
BindingFlags.NonPublic | BindingFlags.Instance);
object dcbValue dcbFieldInfo GetValue(baseStream);

And this is where I initialize all the values:


Hide   Copy Code
COM.Open();
COM.SetFlag("BaudRate", (UInt32)115200);
COM.SetFlag("StopBits", (byte)0);
COM.SetFlag("ByteSize", (byte)8);
COM.SetFlag("Parity", (byte)0);
COM.SetFlag("fDtrControl", 0x00);
COM.SetFlag("fRtsControl", 0x01);
COM.SetFlag("XonChar", 0x11);
COM.SetFlag("XoffChar", 0x13);
COM.SetFlag("XonLim", (ushort)256);
COM.SetFlag("XoffLim", (ushort)256);

EDIT
Upon further investigation it appears that the fields prefixed with f are not in the DCB structure used by SerialPort for some odd
reason. However there is a flags field, but it is of type UInt32, so I'm unsure of how to use it, if anyone has further information on
how to use this field, please submit it as an answer or comment.

Posted 23-Dec-14 16:53pm Updated 23-Nov-17 10:14am v3


Sicppy

Add a Solution

1 solution

Solution 1 Rate this:

Alright I solved my problem, I'll post the code and explanation here if anyone is interested.

The DCB struct requires a C++ class known as a bitfield, which C# does not have, so instead they have a field called "Flags" stored
as a UInt32. They have their own melarchy set up there as to how it's stored and read from, but they did put a method in the
SerialStream called SetDcbFlag which accepts two ints. After digging through the .net source a bit, I managed to
come up with a set of constants equating to the original DCB Fields and their new int code, I haven't yet made a list of values for
these flags, but those can be easily found in the DCB Documentation. I used system.reflection to gain access to the method as it
was an internal method only to be used by internal .NET source.

So here it is, the code, it's an extension class for the SerialPort class which is shipped stock with .NET 2.0+. My extension
class adds three methods, SetField(string name, object value) which will set any of the fields that aren't
prefixed with "f", SetFlag(int Flag, int Value) which will take care of those fields prefixed with "f" (I'll provide a list
of constants for use with the Flag parameter), and finally UpdateComm() this will update the serial connection once you have

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 2/6
9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

changed all of your values, it was originally part of the SetField method, but it takes slightly longer to complete things if it's
calling that every single time during initialization.

NOTE:
The serial port must be opened before using any of these methods!

Usage:
Hide   Copy Code

SerialPort COM = new SerialPort("COM7");


COM.Open();
COM.DiscardInBuffer();
COM.DiscardOutBuffer();
COM.SetFlag(FBINARY, 1);
COM.SetFlag(FPARITY, 0);
COM.SetFlag(FDTRCONTROL, 0x00);
COM.SetFlag(FRTSCONTROL, 0x01);
COM.SetField("BaudRate", (UInt32)115200);
COM.SetField("StopBits", (byte)0);
COM.SetField("ByteSize", (byte)8);
COM.SetField("Parity", (byte)0);
COM.SetField("XonChar", (byte)0x11);
COM.SetField("XoffChar", (byte)0x13);
COM.SetField("EvtChar", (byte)0x1A);
COM.SetField("XonLim", (ushort)256);
COM.SetField("XoffLim", (ushort)256);
COM.UpdateComm();
/* Do Stuff */
COM.Close();

Constants:
Hide   Copy Code
internal const int FBINARY = 0;
internal const int FPARITY = 1;
internal const int FOUTXCTSFLOW = 2;
internal const int FOUTXDSRFLOW = 3;
internal const int FDTRCONTROL = 4;
internal const int FDSRSENSITIVITY = 6;
internal const int FTXCONTINUEONXOFF = 7;
internal const int FOUTX = 8;
internal const int FINX = 9;
internal const int FERRORCHAR = 10;
internal const int FNULL = 11;
internal const int FRTSCONTROL = 12;
internal const int FABORTONOERROR = 14;
internal const int FDUMMY2 = 15;

And finally, the extension class:


Hide   Expand   Copy Code

internal static class SerialPortExtensions


{
[SecurityPermission(SecurityAction.LinkDemand, Flags =
SecurityPermissionFlag.UnmanagedCode)]
public static void SetField(this SerialPort port, string field, object value)
{
if (port == null)
throw new NullReferenceException();
if (port.BaseStream == null)
throw new InvalidOperationException("Cannot change fields until after the port
has been opened.");

try
{

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 3/6
9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

object baseStream = port.BaseStream;


Type baseStreamType = baseStream.GetType();

FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic |


BindingFlags.Instance);
object dcbValue = dcbFieldInfo.GetValue(baseStream);

Type dcbType = dcbValue.GetType();


dcbType.GetField(field).SetValue(dcbValue, value);
dcbFieldInfo.SetValue(baseStream, dcbValue);
}
catch (SecurityException) { throw; }
catch (OutOfMemoryException) { throw; }

Posted 24-Dec-14 12:09pm


Sicppy

Comments

NikolaB 19-Dec-16 14:57pm   


Thanks! I could not find a better explanation and example. For me it is very useful. Вork perfectly and will use it immediately.

Sicppy 13-Jan-17 15:50pm   


No problem, it took me like a week of digging to get all this so I figured I'd post it here and save someone the trouble, glad
someone got use out of it!

DuanChengHua 1-Apr-17 3:01am   


Good job!help me a lot.

Add your solution here

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 4/6
9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

Preview

Existing Members ...or Join us


Sign in to your account Download, Vote, Comment, Publish.

Your Email     Your Email    

Password   Optional Password  

Forgot your password?

I have read and agree to the Terms of Service


and Privacy Policy
Please subscribe me to the CodeProject
newsletters

Submit your solution!

When answering a question please:

1. Read the question carefully.

2. Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.

3. If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem.
Insults are not welcome.

4. Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the
next question.

Let's work to help developers, not make them feel stupid.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 5/6
9/11/2019 [Solved] Change DCB fields from SerialPort instance C# - CodeProject

Advertise Layout: fixed | fluid Copyright © CodeProject, 1999-2019


Privacy All Rights Reserved.
Cookies
Terms of Use Web04 2.8.191108.1
Last Updated 23 Nov 2017

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100

https://www.codeproject.com/Questions/856414/Change-DCB-fields-from-SerialPort-instance-Csharp 6/6

You might also like