Introduction
Many days ago, I was looking for a class in managed C++ that gives me access to
the COM port. I was surprised I couldn't find anything to use. There
were many classes to use for sockets and files, but none for COM ports.
I tried to use System::IO::File
without any success. Actually File::Open
gave me an exception. So I went ahead and created a class to handle serial COM
ports. Please note I am using DllImport to import the kernel32.dll
__gc class CSerialPort
{
public:
CSerialPort(void);
__nogc struct DCB
{
int DCBlength;
int BaudRate;
int fBinary;
int fParity;
int fOutxCtsFlow;
int fOutxDsrFlow;
int fDtrControl;
int fDsrSensitivity;
int fTXContinueOnXoff;
int fOutX;
int fInX;
int fErrorChar;
int fNull;
int fRtsControl;
int fAbortOnError;
int fDummy2;
unsigned short wReserved;
unsigned short XonLim;
unsigned char ByteSize; unsigned char Parity; unsigned char StopBits; char XonChar;
char XoffChar;
char ErrorChar;
char EofChar;
char EvtChar;
unsigned short wReserved1;
};
bool Open( char *szComPort);
void Write(String __gc * buf);
String *Read();
void Close();
private:
FileStream * m_MyFileStream;
StreamWriter * m_MyStreamWriter;
StreamReader * m_MyStreamReader;
static long GENERIC_READ = 0x80000000L;
static long GENERIC_WRITE = 0x40000000L;
static int OPEN_ALWAYS = 4;
static int FILE_FLAG_NO_BUFFERING = 0x20000000;
static int FILE_FLAG_OVERLAPPED = 0x40000000;
};
namespace MyKernel
{
[DllImport("kernel32.dll")]
extern bool SetCommState(System::IntPtr hFile, CSerialPort::DCB * lpDBC);
[DllImport("kernel32.dll")]
extern int CreateFile( char * lpFileName , int dwDesiredAccess, int dwShareMode,
IntPtr lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, IntPtr hTemplateFile );
}
Also note that I am creating a new namespace to use the imported functions from
kernel32.dll
This is the cpp file:
CSerialPort::CSerialPort(void)
{
}
bool CSerialPort::Open( char *szComPort)
{
int handle;
handle = MyKernel::CreateFile(
szComPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
NULL);
try
{
IntPtr pCom(handle);
m_MyFileStream = new FileStream(pCom,
FileAccess::ReadWrite,
true, 1000, true);
}
catch (Exception * e ) {
Console::WriteLine(e->ToString());
return false;
}
DCB * CommSettings = new DCB();
CommSettings->DCBlength = sizeof(CommSettings);
CommSettings->BaudRate = 38400;
CommSettings->ByteSize = 8;
CommSettings->Parity = 0;
CommSettings->StopBits = 1;
MyKernel::SetCommState(m_MyFileStream->get_Handle(),
CommSettings);
try
{
m_MyStreamReader = new StreamReader(m_MyFileStream);
}
catch (Exception * e ) {
Console::WriteLine(e->ToString());
return false;
}
if ( m_MyFileStream->get_CanWrite() )
{
try
{
m_MyStreamWriter = new StreamWriter(m_MyFileStream);
}
catch (Exception * e ) {
Console::WriteLine(e->ToString());
return false;
}
}
return true;
}
void CSerialPort::Write(String __gc * buf)
{
try
{
m_MyStreamWriter->Write(buf);
m_MyStreamWriter->Flush();
}
catch (Exception * e ) {
Console::WriteLine(e->ToString());
}
}
String * CSerialPort::Read()
{
String *buf;
buf = m_MyStreamReader->ReadLine();
return (buf);
}
void CSerialPort::Close()
{
m_MyStreamWriter->Close();
m_MyStreamReader->Close();
m_MyFileStream->Close();
}
To use it:
CSerialPort * pSerial = new CSerialPort;
pSerial->Open(S"COM2:");
Console::WriteLine(pSerial->Read());
We open COM port 2 and we wait to read a LINE with \r\n or \n. If you waiting
for bytes you need to change m_MyStreamReader->ReadLine()
to m_MyStreamReader->Read()
.