Skip to content

Instantly share code, notes, and snippets.

@meuchel
Created July 6, 2022 16:46
Show Gist options
  • Save meuchel/6cb3f59d2ccacfa7dbd7b551b279dd0d to your computer and use it in GitHub Desktop.
Save meuchel/6cb3f59d2ccacfa7dbd7b551b279dd0d to your computer and use it in GitHub Desktop.
Access com port on Win9x WinNT systems or may be others. One of my very first contributions to the www :D It ends up somewhere on a server in China. To not loose this hot piece of hightec here it is again and may help the yogurt.
////////////////////////////////////////////////////////////////////////////////////////
//
// Project: Class ComAccess
// Overlapped serial IO communication class
// System: Win9x WinNT
// File: comaccess.cpp
// Start date: 17.11.1997
// Update: 31.07.1998
// Version: 1.2
// Author: Patrick F. pat@* Germany
//
////////////////////////////////////////////////////////////////////////////////////////
#include "comaccess.h"
////////////////////////////////////////////////////////////////////////////////////////
//
// Constructors
//
ComAccess::ComAccess(VOID)
{
m_hCom = 0;
m_lpszErrorMessage[0] = '\0';
ZeroMemory(&m_ov, sizeof(m_ov));
}
ComAccess::ComAccess(LPCSTR lpszPortNum)
{
ComAccess::ComAccess();
ComAccess::Open(lpszPortNum);
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: Open(LPCSTR lpszPortNum,
// DWORD dwBaudRate,
// BYTE byParity,
// BYTE byStopBits,
// BYTE byByteSize)
//
// Return value: BOOL TRUE or FALSE
//
BOOL ComAccess::Open(LPCSTR lpszPortNum,
DWORD dwBaudRate,
BYTE byParity,
BYTE byStopBits,
BYTE byByteSize)
{
DCB dcb; // structure that defines the control setting for a serial communications device
BOOL bSuccess;
m_hCom = CreateFile(lpszPortNum, // pointer to name of the file
GENERIC_READ|GENERIC_WRITE, // access mode
0, // comm devices must be opened w/exclusive-access
NULL, // no security attributs
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL); // hTemplate must be NULL for comm devices
if ( m_hCom == INVALID_HANDLE_VALUE )
{
// handle the error
ComAccess::ErrorToString("Open(): CreateFile() failed, invalid handle value");
return FALSE;
}
//
// Omit the call to SetupComm to use the default queue sizes.
// Get the current configuration.
//
bSuccess = GetCommState(m_hCom, &dcb);
if ( ! bSuccess )
{
// Handle the error.
ComAccess::ErrorToString("Open(): GetCommState() failed");
ComAccess::Close();
return FALSE;
}
//
// Fill in the DCB: baud=9600, 8 data bits, no parity, 1 stop bit are default parameters
//
dcb.BaudRate = dwBaudRate;
dcb.ByteSize = byByteSize;
dcb.Parity = byParity;
dcb.StopBits = byStopBits;
bSuccess = SetCommState(m_hCom, &dcb);
if ( ! bSuccess )
{
// Handle the error.
ComAccess::ErrorToString("Open(): SetCommState() failed");
ComAccess::Close();
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: Close(VOID)
//
// Return value: VOID
//
VOID ComAccess::Close(VOID)
{
if ( m_hCom > 0 )
{
CloseHandle(m_hCom);
}
m_hCom = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: WriteData(LPCVOID pdata,
// DWORD len)
//
// Return value: DWORD -1 failed, above, num written bytes
//
DWORD ComAccess::WriteData(LPCVOID pdata,
DWORD len)
{
BOOL bSuccess;
DWORD written = 0;
if ( len < 1 )
return(0);
// create event for overlapped I/O
m_ov.hEvent = CreateEvent(NULL, // pointer to security attributes
FALSE, // flag for manual-reset event
FALSE, // flag for initial state
""); // pointer to event-object name
if ( m_ov.hEvent == INVALID_HANDLE_VALUE )
{
// Handle the error.
ComAccess::ErrorToString("WriteData(): CreateEvent() failed");
return(-1);
}
bSuccess = WriteFile(m_hCom, // handle to file to write to
pdata, // pointer to data to write to file
len, // number of bytes to write
&written, // pointer to number of bytes written
&m_ov); // pointer to structure needed for overlapped I/O
if ( ComAccess::IsNT() )
{
bSuccess = GetOverlappedResult(m_hCom, &m_ov, &written, TRUE);
if ( ! bSuccess )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("WriteData(): GetOverlappedResult() failed");
return(-1);
}
}
else
if ( len != written )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("WriteData(): WriteFile() failed");
return(-1);
}
CloseHandle(m_ov.hEvent);
return written;
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: ReadData(LPVOID pdest,
// DWORD len,
// DWORD dwMaxWait)
//
// Return value: DWORD -1 failed, above, num read bytes
//
DWORD ComAccess::ReadData(LPVOID pdest,
DWORD len,
DWORD dwMaxWait)
{
BOOL bSuccess;
DWORD result = 0,
read = 0, // num read bytes
mask = 0; // a 32-bit variable that receives a mask
// indicating the type of event that occurred
if ( len < 1 ) return(0);
// create event for overlapped I/O
m_ov.hEvent = CreateEvent(NULL, // pointer to security attributes
FALSE, // flag for manual-reset event
FALSE, // flag for initial state
""); // pointer to event-object name
if ( m_ov.hEvent == INVALID_HANDLE_VALUE )
{
// Handle the error.
ComAccess::ErrorToString("ReadData(): CreateEvent() failed");
return(-1);
}
// Specify here the event to be enabled
bSuccess = SetCommMask(m_hCom, EV_RXCHAR);
if ( ! bSuccess )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("ReadData(): SetCommMask() failed");
return(-1);
}
// WaitForSingleObject
bSuccess = WaitCommEvent(m_hCom, &mask, &m_ov);
if ( ! bSuccess )
{
int err = GetLastError();
if ( err == ERROR_IO_PENDING)
{
result = WaitForSingleObject(m_ov.hEvent, dwMaxWait); //wait dwMaxWait
// milli seconds before returning
if ( result == WAIT_FAILED )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("ReadData(): WaitForSingleObject() failed");
return(-1);
}
}
}
// The specified event occured?
if ( mask & EV_RXCHAR)
{
bSuccess = ReadFile(m_hCom, // handle of file to read
pdest, // address of buffer that receives data
len, // number of bytes to read
&read, // address of number of bytes read
&m_ov); // address of structure for data
if ( ComAccess::IsNT() )
{
bSuccess = GetOverlappedResult(m_hCom, &m_ov, &read, TRUE);
if ( ! bSuccess )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("WriteData(): GetOverlappedResult() failed");
return(-1);
}
}
else
if ( ! bSuccess )
{
// Handle the error.
CloseHandle(m_ov.hEvent);
ComAccess::ErrorToString("ReadData(): ReadFile() failed");
return(-1);
}
}
else
{
// Handle the error.
CloseHandle(m_ov.hEvent);
wsprintf(m_lpszErrorMessage, "Error ReadData(): No EV_RXCHAR occured\n");
return(-1);
}
CloseHandle(m_ov.hEvent);
return read;
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: ErrorToString(LPCSTR lpszMessage)
//
// Return value: VOID
//
VOID ComAccess::ErrorToString(LPCSTR lpszMessage)
{
LPVOID lpMessageBuffer;
DWORD error = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, // source and processing options
NULL, // pointer to message source
error, // requested message identifie
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // the user default language.
(LPTSTR) &lpMessageBuffer, // pointer to message buffer
0, // maximum size of message buffer
NULL); // address of array of message inserts
// and copy it in our error string
wsprintf(m_lpszErrorMessage,"%s: (%d) %s\n", lpszMessage, error, lpMessageBuffer);
LocalFree(lpMessageBuffer);
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Function: IsNT(VOID)
//
// Return value: BOOL True or False
//
BOOL ComAccess::IsNT(VOID)
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
return TRUE;
}
else
{
return FALSE;
}
}
////////////////////////////////////////////////////////////////////////////////////////
//
// Project: Class ComAccess
// Overlapped serial IO communication class
// System: Win9x WinNT
// File: comaccess.h
// Start date: 17.11.1997
// Update: 31.07.1998
// Version: 1.2
// Author: Patrick F. pat@* Germany
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef _COMACCESS_H_
#define _COMACCESS_H_
#include <windows.h>
class ComAccess
{
private:
HANDLE m_hCom; // Device handle
OVERLAPPED m_ov; // A structure that contains informations which are
// used for asynchronous input and output operations
TCHAR m_lpszErrorMessage[256];
public:
ComAccess(VOID);
ComAccess(LPCSTR lpszPortNum);
~ComAccess() { Close(); }
// For more definitions see <winbase.h>
BOOL Open(LPCSTR lpszPortNum = "com1",
DWORD dwBaudRate = CBR_19200,
BYTE byParity = NOPARITY,
BYTE byStopBits = ONESTOPBIT,
BYTE byByteSize = 8);
VOID Close(VOID);
DWORD WriteData(LPCVOID pdata, DWORD len);
DWORD ReadData(LPVOID pdest, DWORD len, DWORD dwMaxWait = 500);
LPSTR GetErrorMessage(VOID) { return m_lpszErrorMessage; }
private:
VOID ErrorToString(LPCSTR lpszMessage);
BOOL IsNT(VOID);
};
#endif // _COMACCESS_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment