Accessing COM Ports
Environment: C#, .NET
In this column, we'll explore how to communicate with COM ports of your computer. We will cover how to send commands to the port and how to read information from ports.
Background
The whole idea behind this work was to access a GPRS/GSM modem connected to COM port to send and receive SMS messages through Windows XP service.
There is a nice article about Creating a Windows Service in .NET by Mark Strawmyer here.
There are not many possible ways to include this functionality. There were attempts to attach some COMMLIB DLL files. As the application itself is a service, so the use of System.Windows.Forms was to be ignored.
The Approach
The way out was to import the access functions from kernel32. A standard way to access API functions is using DLL Import. So, I decided to import three functions:
- Create File—to open the COM port.
- Write File—to send commands.
- Read File—to read information.
And of course, you won't get away without using the Get Last Error.
//file open masks const uint GENERIC_READ = 0x80000000; const uint GENERIC_WRITE = 0x40000000; const uint OPEN_EXISTING = 3; [DllImport("kernel32", SetLastError=true)] static extern unsafe int CreateFile( string filename, // file name uint desiredAccess, // read? write? uint shareMode, // sharing uint attributes, // SecurityAttributes pointer uint creationDisposition, uint flagsAndAttributes, uint templateFile); [DllImport("kernel32", SetLastError=true)] static extern unsafe bool ReadFile(int hFile, // handle to file void* lpBuffer, // data buffer int nBytesToRead, // number of bytes // to read int* nBytesRead, // number of bytes // read int overlapped); // overlapped buffer [DllImport("kernel32", SetLastError=true)] static extern unsafe bool WriteFile(int hFile, // handle to file void* lpBuffer, // data buffer int nBytesToWrite, // number of bytes // to write int* nBytesWritten, // number of bytes // written int overlapped); // overlapped buffer [DllImport("kernel32", SetLastError=true)] static extern int GetLastError();
The Code
The next step is to use these functions in your code and get the getting going.
Note: I have changed my WriteLogFile function to console.writeline for easy understanding.
/// <summary> /// Connect to the COM Port. /// </summary> private void GetDevice(string Port) { // open the existing port... m_ihandle = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, // comm devices must be opened // w/exclusive-access 0, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING 0, // not overlapped I/O 0); // hTemplate must be NULL for comm devices //if the handle value is -1, that means you got an error.... if(m_ihandle == -1) //write failure log Console.WriteLine("open COM port failed" + GetLastError()); else //write success log Console.WriteLine(Port + " opened successfully!"); } /// <summary> /// Send Command to the COM Port. /// As I am using a modem, I send command like "AT+CGMM" /// </summary> private unsafe void SendCommand(string szCmd) { int i = 0, n = 0; //get string length int Len = szCmd.Length; //use ASCIIEncoding to work with byte and string ASCIIEncoding e = new ASCIIEncoding(); //assign string to byte buffer and add "return" byte[]Buffer = e.GetBytes(szCmd + "\r\n"); //use fixed to avoid more memory allocation fixed (byte* p = Buffer) { i=0; //write command to the port if(!WriteFile(m_ihandle, p + i, Len+1, &n, 0)) //if false, write failure log Console.WriteLine("Send Command " + szCmd + " failed"); else // write success log Console.WriteLine("Send Command Successed"); } } /// <summary> /// Read information from the COM Port. /// </summary> private unsafe void ReadModem() { //set the maximum limit to read int count = 128; //create buffer to store the info byte[] buffer = new byte[count]; //use ASCII encoding to work with string and byte ASCIIEncoding e = new ASCIIEncoding(); //loop through read until done... int index = 0; int n = 1; while (n!=0) { n = 0; fixed (byte* p = buffer) { //read file if(!ReadFile(m_ihandle, p + index, count, &n, 0)) //write the value received in log Console.WriteLine(e.GetString(buffer)); else //write failure log Console.WriteLine("Read Modem Failed"); } } }
Summary
That's it. All the time that was spent to solve this problem gave pretty fine results. This is all that I intended to do and the results are achieved. I hope you now have a rough idea of how to communicate with, write commands to, and read information from ports. You can further try to catch events from ports. I am working on it. That's what you will get next, when I will write another article.
- Anand Saini

Comments
additional changes
Posted by Legacy on 02/17/2004 12:00amOriginally posted by: Daryl
Replym_ihandle
Posted by Legacy on 01/23/2004 12:00amOriginally posted by: marcos
what is m_ihandle?
ReplyModified ReadModem (just nit-picking)
Posted by Legacy on 01/07/2004 12:00amOriginally posted by: Peter Kintu
Hello all, I tried the code so kindly provided, but kept on getting incosistent results. The data from the modem was read only once, (I'm sure the response from the SendCmd function was available in the buffer, but for some reason was not being read.) The SendCmd worked perfect every time.
I modified the code to use System.IO.FileStream and System.IO.StreamReader to read the modem response or data from the modem as below.
private unsafe void ReadModem()
{
Console.WriteLine(m_ihandle); //Recall m_ihandle is system
//file handle for port
System.IntPtr iPtr = new System.IntPtr(m_ihandle);
//Handle has to be passed to FileStream constructor
//wrapped in IntPtr object
System.IO.FileStream fs = new System.IO.FileStream(iPtr,FileAccess.Read);
//Construct FileStream object on file handle with desired
//Read or Write access. Must use FileAccess object //attributes
System.IO.StreamReader sr = new System.IO.StreamReader(fs);
//Open a reader on the stream
String line;
if(fs.CanRead){
ReplyConsole.WriteLine("Can read from port");
while ((line = sr.ReadLine()) != null)
Console.WriteLine(line);
}else{
Console.WriteLine("Cannot read from port");
}
}
Help Me!
Posted by Legacy on 01/06/2004 12:00amOriginally posted by: Arun Pringan Kannan
Hi everyone,
ReplyCould anyone help me?
i have developed a program with windows form in C# to read in address of a location and displaying the map of that locality with the help of MapPoint.Net.
Now i need to interface a GPS through COM port to the program to read in the values provioded by the GPS and display the map accordingly.
And also send some data through COM port to another machine.
But i have no idea how to connect the COM port to the program.
i have read an article in CodeGuru about COM port communication. but it says that Windows form should be ignored.
But that means total shuffling of the present program.
Can anyone suggest me a better way?
thanking you,
Arun
arunpk29@yahoo.com
acces modem
Posted by Legacy on 05/01/2003 12:00amOriginally posted by: arif miftahur
i interest your artikle.but my modem is internal so i can't apply your artikle
Replya little change here!
Posted by Legacy on 04/24/2003 12:00amOriginally posted by: Anand
the code for readfile is using !ReadFile(), so, the console.writeline messages must be interchanged for correct working of the code.
changed code
//read file
if(!ReadFile(m_ihandle, p + index, count, &n, 0))
//write the value received in log
Console.WriteLine("Read Modem Failed");
else
//write failure log
Console.WriteLine(e.GetString(buffer));
Reply