Serielle Kommunikation via USB (PC zu Arduino)



  • Hallo zusammen!

    Für ein kleines Projekt möchte ich eine Serielle Kommunikation zwischen meinem Computer und einem Arduino aufbauen. Via USB sollen sie Strings austauschen. Ich hab mich hierzu schon etwas belesen (siehe unten).

    Im ersten Schritt habe ich ein Programm geschrieben, mit dem ich eine Verbindung zum COM-Port, an dem der Arduino angeschlossen ist, herstellen und die DCB Konfiguration auslesen möchte.

    Das Problem:
    Alle Werte, bis auf „DCBlength = 28“, sind = 0. Mit einem Kontrollprogramm, dass ich aus Windwos Docs kopiert habe, bekomme ich allerdings „richtige Werte“ (Baudrate 9600 usw.).

    Frage:
    Anscheinend habe ich also doch keine Verbindung zum COM-Port aufgebaut? Oder gibt es Probleme beim Speichern der Werte? Kurz: ich hoffe, dass mir jemand meinen Fehler aufzeigen und erklären kann, wie ich ihn beheben muss 🙂

    Hier der Code meiner Quelldatei und der Main-Datei. Im Header sind nur die Attribute und die Konstruktoren:

    Serialport.cpp

    #include "Serialport.h"
    #include "pch.h"
    
    using namespace std;
    
    
    
    void SerialPort_Oeffnen(HANDLE CommPort) {
    
    	const wchar_t *Port = TEXT("COM4");
    
    
    	CommPort = CreateFile(Port,
    		GENERIC_READ | GENERIC_WRITE,
    		0,
    		NULL,
    		OPEN_EXISTING,
    		0,
    		NULL);
    
    }
    
    
    void PrintCommState(DCB dcb)
    {
    	int BaudRate = dcb.BaudRate;
    	int ByteSize = dcb.ByteSize;
    	int DCBlength = dcb.DCBlength;
    	int EofChar = dcb.EofChar;
    	int ErrorChar = dcb.ErrorChar;
    	int EvtChar = dcb.EvtChar;
    	int fDtrControl = dcb.fDtrControl;
    	int fDsrSensitivity = dcb.fDsrSensitivity;
    	int fDummy2 = dcb.fDummy2;
    	int fOutX = dcb.fOutX;
    	int fOutxCtsFlow = dcb.fOutxCtsFlow;
    	int fRtsControl = dcb.fRtsControl;
    	int fOutxDsrFlow = dcb.fOutxDsrFlow;
    	int fTXContinueOnXoff = dcb.fTXContinueOnXoff;
    	int wReserved = dcb.wReserved;
    	int XoffChar = dcb.XoffChar;
    	int XoffLim = dcb.XoffLim;
    	int XonChar = dcb.XonChar;
    	int XonLim = dcb.XonLim;
    
    	cout <<
    		"BaudRate = " << BaudRate << "\n" <<
    		"ByteSize = " << ByteSize << "\n" <<
    		"DCBlength = " << DCBlength << "\n" <<
    		"EofChar = " << EofChar << "\n" <<
    		"ErrorChar = " << ErrorChar << "\n" <<
    		"fDtrControl = " << fDtrControl << "\n" <<
    		"fDsrSensitivity = " << fDsrSensitivity << "\n" <<
    		"fDummy2 = " << fDummy2 << "\n" <<
    		"fOutX = " << fOutX << "\n" <<
    		"fOutxCtsFlow = " << fOutxCtsFlow << "\n" <<
    		"fRtsControl = " << fRtsControl << "\n" <<
    		"fOutxDsrFlow = " << fOutxDsrFlow << "\n" <<
    		"fTXContinueOnXoff = " << fTXContinueOnXoff << "\n" <<
    		"wReserved = " << wReserved << "\n" <<
    		"XoffChar = " << XoffChar << "\n" <<
    		"XoffLim = " << XonChar << "\n" <<
    		"XonLim = " << XonLim << endl;
    
    }
    
    
    

    Main.cpp

    #include "pch.h"
    #include "Serialport.h"
    #include <iostream>
    
    
    
    int main()
    {
    
    
    	SerialPort_Oeffnen(hcomm);
    
    	SecureZeroMemory(&dcb_1, sizeof(DCB));
    
    	dcb_1.DCBlength = sizeof(DCB);
    
    	GetCommState(hcomm, &dcb_1);
    
    	PrintCommState(dcb_1);
    
    	CloseHandle(hcomm);
    
    
    
    	system("Pause");
    
    }
    
    

    Ich freue mich auf eure Hilfe! Vielen Dank und euch ein gutes Wochenende!

    P.S.:
    Hier meine Quellen. Als Referenz nehme ich den Code aus (1).
    (1) https://docs.microsoft.com/de-de/windows/desktop/DevIO/configuring-a-communications-resource
    (2) https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498
    Falls noch wichtig, hier näheres zu meinem Hintergrund: Bin Student, hatte jetzt ein Semester Informatik und möchte gern das gelernte nebenher vertiefen / auffrischen. Vielleicht mag deshalb einiges sehr umständlich erscheinen.



  • Deine Funktion SerialPort_Oeffnen ist falsch, da du den Parameter CommPort nur lokal beschreibst (und nicht den übergebenen Parameter hcomm).
    Entweder als Referenz übergeben oder noch besser gleich als Rückgabewert (denn einen Eingabeparameter brauchst du dafür ja nicht):

    HANDLE SerialPort_Oeffnen()
    {
        HANDLE commPort = ...;
      
        return commPort;
    }
    

    Und dann entsprechend den Aufruf abändern.

    Edit: Und bei Systemfunktionen wie GetCommState immer den Rückgabewert (-> Fehlercode) prüfen.



  • Hi Jon,

    die Sachen mit dem rs232 sind wesentlich komplexer als man zu vermuten glaubt, gerade im Zusammenhang mit all den möglichen Konfigurationen.

    Über Jahrzehnte hat sich unter Windows folgendes bewährt:

    CVersions::DbgMsg(false, kannst Du durch TRACE( ersetzen..

    
    #include "StdAfx.h"
    #include "serialio.h"
    #include <process.h>
    
    //*************************************************************** SERIAL IO TEMPLATE ****************************************************
    
    CSerialIO::CSerialIO(void) : 
    	m_pcallback(0), 
    	m_UserDat(0), 
    	m_bConnected(false),
    	m_lLastError(ERROR_SUCCESS), 
    	m_hFile(0),
    	m_eEvent(EEventNone),
    	m_dwEventMask(0),
    	m_fStopping(false),
    	m_hThread(0), 
    	m_hevtOverlapped(0),
    	m_hevtOverlappedWorkerThread(0)
    {
    
    }
    
    CSerialIO::~CSerialIO(void)
    {
    	Delete();
    }
    
    bool CSerialIO::IsConnected(void)
    {
    	return m_bConnected;
    }
    
    CStringList *CSerialIO::GetPortLst(void)
    {
    	CString str;
    	CHAR    TargetPath[MAX_PATH];
    
    	m_strPortLst.RemoveAll();
    
    	for (int i = 0; i < 255; i++)
    	{
    		str.Format(_T("COM%d"), i);
    		if (QueryDosDevice(str, (LPSTR)&TargetPath[0], sizeof(TargetPath)))
    			m_strPortLst.AddTail(str);
    	}
    
    	return &m_strPortLst;
    }
    
    DWORD WINAPI CSerialIO::ThreadProc(LPVOID lpArg)
    {
    	CSerialIO *pThis = (CSerialIO *)lpArg;
    	return pThis->ThreadProc();
    }
    
    DWORD CSerialIO::ThreadProc(void)
    {
    	LPOVERLAPPED lpOverlapped = 0;
    
    	do
    	{
    		::ResetEvent(m_hevtOverlappedWorkerThread);
    	
    		OVERLAPPED ovInternal = { 0 };
    		ovInternal.hEvent = m_hevtOverlappedWorkerThread;
    
    		DWORD ti(GetTickCount());
    
    		if (WaitEvent(&ovInternal) != ERROR_SUCCESS)
    			return m_lLastError;
    
    		if (::WaitForSingleObject(m_hevtOverlappedWorkerThread, INFINITE) != WAIT_OBJECT_0)
    		{
    			m_lLastError = ::GetLastError();
    			return m_lLastError;
    		}
    
    		if (!m_fStopping)
    		{
    			EEvent eEvent = GetEventType();
    			DWORD dwErrors = 0;
    			if (!::ClearCommError(m_hFile, &dwErrors, 0))
    			{
    				m_lLastError = ::GetLastError();
    			}
    
    			EError eError = EError(dwErrors);
    			if (eEvent)
    				OnEvent(eError, eEvent);		
    		}
    
    	} while (!m_fStopping);
    
    	return 0;
    }
    
    
    LRESULT CSerialIO::OnEvent(EError eError, EEvent eEvent)
    {
    	if (eError)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  An internal error occurred.");
    
    	if (eEvent & CSerialIO::EEventBreak)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  Break detected on input.");
    
    	if (eEvent & CSerialIO::EEventError)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  A line-status error occurred.");
    
    	if (eEvent & CSerialIO::EEventRcvEv)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  Event character has been received.");
    
    	if (eEvent & CSerialIO::EEventRing)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  Ring detected");
    
    	if (eEvent & CSerialIO::EEventSend)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  All data is send");
    
    	if (eEvent & CSerialIO::EEventCTS)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  CTS signal change %s %d", "CTS", GetCTS());
    
    	if (eEvent & CSerialIO::EEventDSR)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  DSR signal change %s %d", "DSR", GetDSR());
    
    	if (eEvent & CSerialIO::EEventRLSD)
    		CVersions::DbgMsg(false,"CSerialIO::OnEvent  RLSD signal change %s %d", "RLSD", GetRLSD());
    
    	if (eEvent & CSerialIO::EEventRecv)
    	{
    		DWORD dwRead;
    		char szData[256];
    		const int nBuflen = sizeof(szData) - 1;
    		do
    		{
    			if (!Read(szData, nBuflen, &dwRead))
    			{
    				if (dwRead > 0 && !m_pcallback(szData, dwRead, m_UserDat, this))
    					;
    			}
    
    		} while (dwRead == nBuflen);
    	}
    
    	return 0;
    }
    
    LONG CSerialIO::StartListener(void)
    {
    	if (m_hThread == 0)
    	{
    		DWORD dwThreadId = 0;
    		m_hThread = ::CreateThread(0, 0, ThreadProc, LPVOID(this), 0, &dwThreadId);
    		if (m_hThread == 0)
    		{
    			m_lLastError = ::GetLastError();
    			return m_lLastError;
    		}
    	}
    
    	m_lLastError = ERROR_SUCCESS;
    	return m_lLastError;
    }
    
    LONG CSerialIO::StopListener(DWORD dwTimeout)
    {
    	if (m_hThread)
    	{
    		m_fStopping = true;
    
    		SetMask(GetEventMask());
    
    		if (m_hevtOverlappedWorkerThread)
    			SetEvent(m_hevtOverlappedWorkerThread);
    
    		::WaitForSingleObject(m_hThread, dwTimeout);
    
    		m_fStopping = false;
    
    		::CloseHandle(m_hThread);
    		m_hThread = 0;
    	}
    
    	m_lLastError = ERROR_SUCCESS;
    
    	return m_lLastError;
    }
    
    
    
    void CSerialIO::Delete(void)
    {
    	//if (!m_fStopping)
    	Close();
    }
    
    bool CSerialIO::Create(int comport, int baud,SERCALLBACK pC,DWORD UserDat, DWORD HandShake/*=0*/)
    {
    	if (!pC || !comport || !baud)
    		return false;
    
        Delete();
    
    	m_pcallback = pC;
    	m_UserDat   = UserDat;
    
    	CString comStr; comStr.Format("COM%d",comport);
    
    	if (CheckPort(comStr))
    		return false;
    
    	if (Open(comStr, 0, 0))
    		return false;
    
    	LONG stat = Setup((EBaudrate)baud/*EBaud115200*/, EData8, EParNone, EStop1);
    	SetupHandshaking(HandShake);// EHandshakeOff);
    
    	return (m_bConnected=true);
    }
    
    LONG CSerialIO::Open(LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue)
    {
    	bool fOverlapped = true;
    
    	m_lLastError = ERROR_SUCCESS;
    
    	if (m_hFile)
    	{
    		m_lLastError = ERROR_ALREADY_INITIALIZED;
    		return m_lLastError;
    	}
    
    	m_hFile = ::CreateFile(lpszDevice, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, fOverlapped ? FILE_FLAG_OVERLAPPED : 0, 0);
    	if (m_hFile == INVALID_HANDLE_VALUE)
    	{
    		m_hFile = 0;
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	if (fOverlapped)
    	{
    		m_hevtOverlapped = ::CreateEvent(0, true, false, 0);
    		if (m_hevtOverlapped == 0)
    		{
    			m_lLastError = ::GetLastError();
    
    			::CloseHandle(m_hFile);
    			m_hFile = 0;
    
    			return m_lLastError;
    		}
    	}
    
    	if (dwInQueue || dwOutQueue)
    	{
    		if (!::SetupComm(m_hFile, dwInQueue, dwOutQueue))
    		{
    
    			long lLastError = ::GetLastError();
    
    			Close();
    
    			m_lLastError = lLastError;
    			return m_lLastError;
    		}
    	}
    
    	SetMask();
    
    	SetupReadTimeouts(EReadTimeoutNonblocking);
    
    	COMMCONFIG commConfig = { 0 };
    	DWORD dwSize = sizeof(commConfig);
    	commConfig.dwSize = dwSize;
    	if (::GetDefaultCommConfig(lpszDevice, &commConfig, &dwSize))
    	{
    		if (!::SetCommConfig(m_hFile, &commConfig, dwSize))
    		{
    			;
    		}
    	}
    	else
    	{
    		;
    	}
    
    	if (m_lLastError != ERROR_SUCCESS)
    		return m_lLastError;
    
    	m_hevtOverlappedWorkerThread = ::CreateEvent(0, true, false, 0);
    	if (m_hevtOverlappedWorkerThread == 0)
    	{
    		m_lLastError = ::GetLastError();
    		Close();
    		return m_lLastError;
    	}
    
    	
    	m_lLastError = StartListener();
    	if (m_lLastError != ERROR_SUCCESS)
    		return m_lLastError;
    	
    	return m_lLastError;
    }
    
    inline BOOL CSerialIO::CancelCommIo(void)
    {	
    	return ::CancelIo(m_hFile);
    }
    
    CSerialIO::EPort CSerialIO::CheckPort(LPCTSTR lpszDevice)
    {
    	HANDLE hFile = ::CreateFile(lpszDevice,GENERIC_READ | GENERIC_WRITE,0,0,	OPEN_EXISTING,0,0);
    
    	if (hFile == INVALID_HANDLE_VALUE)
    	{
    		switch (::GetLastError())
    		{
    		case ERROR_FILE_NOT_FOUND:
    			return EPortNotAvailable;
    		case ERROR_ACCESS_DENIED:
    			return EPortInUse;
    		default:
    			return EPortUnknownError;
    		}
    	}
    
    	::CloseHandle(hFile);
    
    	return EPortAvailable;
    }
    
    LONG CSerialIO::Close(void)
    {
    	StopListener(100);// INFINITE);
    
    	if (m_hevtOverlappedWorkerThread)
    	{
    		::CloseHandle(m_hevtOverlappedWorkerThread);
    		m_hevtOverlappedWorkerThread = 0;
    	}
    
    	if (m_hevtOverlapped)
    	{
    		::CloseHandle(m_hevtOverlapped);
    		m_hevtOverlapped = 0;
    	}
    
    	m_lLastError = ERROR_SUCCESS;
    
    	if (m_hFile == 0)
    		return m_lLastError;
    
    	::CloseHandle(m_hFile);
    	m_hFile = 0;
    
    	m_bConnected = false;
    	
    	return m_lLastError;
    }
    
    LONG CSerialIO::Setup(EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
    {
    	m_lLastError = ERROR_SUCCESS;
    
    	if (m_hFile == 0)
    	{
    		m_lLastError = ERROR_INVALID_HANDLE;
    		return m_lLastError;
    	}
    
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	dcb.BaudRate = DWORD(eBaudrate);
    	dcb.ByteSize = BYTE(eDataBits);
    	dcb.Parity = BYTE(eParity);
    	dcb.StopBits = BYTE(eStopBits);
    	dcb.fParity = (eParity != EParNone);
    
    	if (!::SetCommState(m_hFile, &dcb))
    	{
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	return m_lLastError;
    }
    
    LONG CSerialIO::SetEventChar(BYTE bEventChar, bool fAdjustMask)
    {
    	m_lLastError = ERROR_SUCCESS;
    
    	if (m_hFile == 0)
    	{
    		m_lLastError = ERROR_INVALID_HANDLE;
    		return m_lLastError;
    	}
    
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{	
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	dcb.EvtChar = char(bEventChar);
    
    	if (fAdjustMask)
    	{
    		SetMask(GetEventMask() | EEventRcvEv);
    	}
    
    	if (!::SetCommState(m_hFile, &dcb))
    	{
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	return m_lLastError;
    }
    
    LONG CSerialIO::SetMask(DWORD dwEventMask)
    {
    	m_lLastError = ERROR_SUCCESS;
    
    	if (m_hFile == 0)
    	{
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		_RPTF0(_CRT_WARN, "CSerialIO::SetMask - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	if (!::SetCommMask(m_hFile, dwEventMask))
    	{
    		m_lLastError = ::GetLastError();
    		return m_lLastError;
    	}
    
    	m_dwEventMask = dwEventMask;
    	return m_lLastError;
    }
    
    LONG CSerialIO::WaitEvent(LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::WaitEvent - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (!lpOverlapped && m_hevtOverlapped)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal, 0, sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    
    	// Wait for the COM event
    	if (!::WaitCommEvent(m_hFile, LPDWORD(&m_eEvent), lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN, "CSerialIO::WaitEvent - Unable to wait for COM event\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent, dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN, "CSerialIO::WaitEvent - Unable to wait until COM event has arrived\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    
    	// Return successfully
    	return m_lLastError;
    }
    
    
    LONG CSerialIO::SetupHandshaking(int eHandshake)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupHandshaking - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupHandshaking - Unable to obtain DCB information\n");
    		return m_lLastError;
    	}
    
    	// Set the handshaking flags
    	switch (eHandshake)
    	{
    	case EHandshakeOff:
    		dcb.fOutxCtsFlow = false;					// Disable CTS monitoring
    		dcb.fOutxDsrFlow = false;					// Disable DSR monitoring
    		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR monitoring
    		dcb.fOutX = false;							// Disable XON/XOFF for transmission
    		dcb.fInX = false;							// Disable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
    		break;
    
    	case EHandshakeHardware:
    		dcb.fOutxCtsFlow = true;					// Enable CTS monitoring
    		dcb.fOutxDsrFlow = true;					// Enable DSR monitoring
    		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;	// Enable DTR handshaking
    		dcb.fOutX = false;							// Disable XON/XOFF for transmission
    		dcb.fInX = false;							// Disable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	// Enable RTS handshaking
    		break;
    
    	case EHandshakeSoftware:
    		dcb.fOutxCtsFlow = false;					// Disable CTS (Clear To Send)
    		dcb.fOutxDsrFlow = false;					// Disable DSR (Data Set Ready)
    		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR (Data Terminal Ready)
    		dcb.fOutX = true;							// Enable XON/XOFF for transmission
    		dcb.fInX = true;							// Enable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
    		break;
    
    	default:
    		// This shouldn't be possible
    		_ASSERTE(false);
    		m_lLastError = E_INVALIDARG;
    		return m_lLastError;
    	}
    
    	// Set the new DCB structure
    	if (!::SetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupHandshaking - Unable to set DCB information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerialIO::SetupReadTimeouts(EReadTimeout eReadTimeout)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupReadTimeouts - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Determine the time-outs
    	COMMTIMEOUTS cto;
    	if (!::GetCommTimeouts(m_hFile, &cto))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupReadTimeouts - Unable to obtain timeout information\n");
    		return m_lLastError;
    	}
    
    	// Set the new timeouts
    	switch (eReadTimeout)
    	{
    	case EReadTimeoutBlocking:
    		cto.ReadIntervalTimeout = 0;
    		cto.ReadTotalTimeoutConstant = 0;
    		cto.ReadTotalTimeoutMultiplier = 0;
    		break;
    	case EReadTimeoutNonblocking:
    		cto.ReadIntervalTimeout = MAXDWORD;
    		cto.ReadTotalTimeoutConstant = 0;
    		cto.ReadTotalTimeoutMultiplier = 0;
    		break;
    	default:
    		// This shouldn't be possible
    		_ASSERTE(false);
    		m_lLastError = E_INVALIDARG;
    		return m_lLastError;
    	}
    
    	// Set the new DCB structure
    	if (!::SetCommTimeouts(m_hFile, &cto))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::SetupReadTimeouts - Unable to set timeout information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    CSerialIO::EBaudrate CSerialIO::GetBaudrate(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetBaudrate - Device is not opened\n");
    		return EBaudUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetBaudrate - Unable to obtain DCB information\n");
    		return EBaudUnknown;
    	}
    
    	// Return the appropriate baudrate
    	return EBaudrate(dcb.BaudRate);
    }
    
    CSerialIO::EDataBits CSerialIO::GetDataBits(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetDataBits - Device is not opened\n");
    		return EDataUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetDataBits - Unable to obtain DCB information\n");
    		return EDataUnknown;
    	}
    
    	// Return the appropriate bytesize
    	return EDataBits(dcb.ByteSize);
    }
    
    CSerialIO::EParity CSerialIO::GetParity(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetParity - Device is not opened\n");
    		return EParUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetParity - Unable to obtain DCB information\n");
    		return EParUnknown;
    	}
    
    	// Check if parity is used
    	if (!dcb.fParity)
    	{
    		// No parity
    		return EParNone;
    	}
    
    	// Return the appropriate parity setting
    	return EParity(dcb.Parity);
    }
    
    CSerialIO::EStopBits CSerialIO::GetStopBits(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetStopBits - Device is not opened\n");
    		return EStopUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetStopBits - Unable to obtain DCB information\n");
    		return EStopUnknown;
    	}
    
    	// Return the appropriate stopbits
    	return EStopBits(dcb.StopBits);
    }
    
    DWORD CSerialIO::GetEventMask(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetEventMask - Device is not opened\n");
    		return 0;
    	}
    
    	// Return the event mask
    	return m_dwEventMask;
    }
    
    BYTE CSerialIO::GetEventChar(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetEventChar - Device is not opened\n");
    		return 0;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetEventChar - Unable to obtain DCB information\n");
    		return 0;
    	}
    
    	// Set the new event character
    	return BYTE(dcb.EvtChar);
    }
    
    CSerialIO::EHandshake CSerialIO::GetHandshaking(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetHandshaking - Device is not opened\n");
    		return EHandshakeUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile, &dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetHandshaking - Unable to obtain DCB information\n");
    		return EHandshakeUnknown;
    	}
    
    	// Check if hardware handshaking is being used
    	if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
    		return EHandshakeHardware;
    
    	// Check if software handshaking is being used
    	if (dcb.fOutX && dcb.fInX)
    		return EHandshakeSoftware;
    
    	// No handshaking is being used
    	return EHandshakeOff;
    }
    
    LONG CSerialIO::Write(const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Use our own variable for read count
    	DWORD dwWritten;
    	if (pdwWritten == 0)
    	{
    		pdwWritten = &dwWritten;
    	}
    
    	// Reset the number of bytes written
    	*pdwWritten = 0;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Write - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Write - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (!lpOverlapped && m_hevtOverlapped)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal, 0, sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    	
    	// Write the data
    	if (!::WriteFile(m_hFile, pData, iLen, pdwWritten, lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN, "CSerialIO::Write - Unable to write the data\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent, dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				if (!::GetOverlappedResult(m_hFile, lpOverlapped, pdwWritten, FALSE))
    				{
    					// Set the internal error code
    					m_lLastError = ::GetLastError();
    
    					_RPTF0(_CRT_WARN, "CSerialIO::Write - Overlapped completed without result\n");
    					return m_lLastError;
    				}
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN, "CSerialIO::Write - Unable to wait until data has been sent\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerialIO::Read(void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Use our own variable for read count
    	DWORD dwRead;
    	if (pdwRead == 0)
    	{
    		pdwRead = &dwRead;
    	}
    
    	// Reset the number of bytes read
    	*pdwRead = 0;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Read - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Read - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (lpOverlapped == 0)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal, 0, sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    
    	// Read the data
    	if (!::ReadFile(m_hFile, pData, iLen, pdwRead, lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN, "CSerialIO::Read - Unable to read the data\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent, dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				if (!::GetOverlappedResult(m_hFile, lpOverlapped, pdwRead, FALSE))
    				{
    					// Set the internal error code
    					m_lLastError = ::GetLastError();
    
    					_RPTF0(_CRT_WARN, "CSerialIO::Read - Overlapped completed without result\n");
    					return m_lLastError;
    				}
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN, "CSerialIO::Read - Unable to wait until data has been read\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    
    
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerialIO::Purge()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Purge - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    		_RPTF0(_CRT_WARN, "CSerialIO::Purge - Overlapped completed without result\n");
    	}
    
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerialIO::Break(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::Break - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Set the RS-232 port in break mode for a little while
    	::SetCommBreak(m_hFile);
    	::Sleep(100);
    	::ClearCommBreak(m_hFile);
    
    	// Return successfully
    	return m_lLastError;
    }
    
    CSerialIO::EEvent CSerialIO::GetEventType(void)
    {
    	// Obtain the event (mask unwanted events out)
    	EEvent eEvent = EEvent(m_eEvent & m_dwEventMask);
    
    	// Reset internal event type
    	m_eEvent = EEventNone;
    
    	// Return the current cause
    	return eEvent;
    }
    
    CSerialIO::EError CSerialIO::GetError(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetError - Device is not opened\n");
    		return EErrorUnknown;
    	}
    
    	// Obtain COM status
    	DWORD dwErrors = 0;
    	if (!::ClearCommError(m_hFile, &dwErrors, 0))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN, "CSerialIO::GetError - Unable to obtain COM status\n");
    		return EErrorUnknown;
    	}
    
    	// Return the error
    	return EError(dwErrors);
    }
    
    bool CSerialIO::GetCTS(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile, &dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetCTS - Unable to obtain the modem status\n");
    		return false;
    	}
    
    	// Determine if CTS is on
    	return (dwModemStat & MS_CTS_ON) != 0;
    }
    
    bool CSerialIO::GetDSR(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile, &dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetDSR - Unable to obtain the modem status\n");
    		return false;
    	}
    
    	// Determine if DSR is on
    	return (dwModemStat & MS_DSR_ON) != 0;
    }
    
    bool CSerialIO::GetRing(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile, &dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetRing - Unable to obtain the modem status");
    		return false;
    	}
    
    	// Determine if Ring is on
    	return (dwModemStat & MS_RING_ON) != 0;
    }
    
    bool CSerialIO::GetRLSD(void)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile, &dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN, "CSerialIO::GetRLSD - Unable to obtain the modem status");
    		return false;
    	}
    
    	// Determine if RLSD is on
    	return (dwModemStat & MS_RLSD_ON) != 0;
    }
    
    
    bool CSerialIO::SetDTR(bool Stat)
    {
    	if (!EscapeCommFunction(m_hFile, Stat ? SETDTR : CLRDTR))
    		return false;
    
    	return true;
    }
    
    bool CSerialIO::SetRTS(bool Stat)
    {
    	if (!EscapeCommFunction(m_hFile, Stat ? SETRTS : CLRRTS))
    		return false;
    
    	return true;
    }
    
    
    Header Zusatz:
    
    #include "y:\\Common\Versions\Versions.h"
    #pragma once
    #ifdef _DEBUG
    #pragma comment(lib, "seriod.lib")
    #else
    #pragma comment(lib, "serio.lib")
    #endif
    
    
    /******************************* SERIAL EXCESS ***********************************/
    class CSerialIO;
    typedef int (AFX_CDECL *SERCALLBACK)(void *,int,DWORD,CSerialIO *);
    class CSerialIO
    {
    public:
    	CSerialIO(void);
    	~CSerialIO(void);
    public:
    	bool IsConnected(void);
    	void Delete(void);
    	bool Create(int comport, int baud, SERCALLBACK pC,DWORD UserDat, DWORD HandShake=0);
    	CStringList *GetPortLst(void);
    protected:
    	bool           m_bConnected;
    	
    	DWORD          m_UserDat;
    	SERCALLBACK    m_pcallback;
    	CStringList    m_strPortLst;
    
    public:
    	typedef enum
    	{
    		EEventUnknown = -1,
    		EEventNone = 0,
    		EEventBreak = EV_BREAK,
    		EEventCTS = EV_CTS,
    		EEventDSR = EV_DSR,
    		EEventError = EV_ERR,
    		EEventRing = EV_RING,
    		EEventRLSD = EV_RLSD,
    		EEventRecv = EV_RXCHAR,
    		EEventRcvEv = EV_RXFLAG,
    		EEventSend = EV_TXEMPTY,
    		EEventPrinterError = EV_PERR,
    		EEventRx80Full = EV_RX80FULL,
    		EEventProviderEvt1 = EV_EVENT1,
    		EEventProviderEvt2 = EV_EVENT2,
    	}
    	EEvent;
    
    	typedef enum
    	{
    		EBaudUnknown = -1,
    		EBaud110 = CBR_110,
    		EBaud300 = CBR_300,
    		EBaud600 = CBR_600,
    		EBaud1200 = CBR_1200,
    		EBaud2400 = CBR_2400,
    		EBaud4800 = CBR_4800,
    		EBaud9600 = CBR_9600,
    		EBaud14400 = CBR_14400,
    		EBaud19200 = CBR_19200,
    		EBaud38400 = CBR_38400,
    		EBaud56000 = CBR_56000,
    		EBaud57600 = CBR_57600,
    		EBaud115200 = CBR_115200,
    		EBaud128000 = CBR_128000,
    		EBaud256000 = CBR_256000,
    	}
    	EBaudrate;
    
    	typedef enum
    	{
    		EDataUnknown = -1,
    		EData5 = 5,
    		EData6 = 6,
    		EData7 = 7,
    		EData8 = 8
    	}
    	EDataBits;
    
    	typedef enum
    	{
    		EParUnknown = -1,
    		EParNone = NOPARITY,
    		EParOdd = ODDPARITY,
    		EParEven = EVENPARITY,
    		EParMark = MARKPARITY,
    		EParSpace = SPACEPARITY
    	}
    	EParity;
    
    
    	typedef enum
    	{
    		EStopUnknown = -1,
    		EStop1 = ONESTOPBIT,
    		EStop1_5 = ONE5STOPBITS,
    		EStop2 = TWOSTOPBITS
    	}
    	EStopBits;
    
    	typedef enum
    	{
    		EHandshakeUnknown = -1,
    		EHandshakeOff = 0,
    		EHandshakeHardware = 1,
    		EHandshakeSoftware = 2
    	}
    	EHandshake;
    
    	typedef enum
    	{
    		EReadTimeoutUnknown = -1,
    		EReadTimeoutNonblocking = 0,
    		EReadTimeoutBlocking = 1
    	}
    	EReadTimeout;
    
    	typedef enum
    	{
    		EErrorUnknown = 0,
    		EErrorBreak = CE_BREAK,
    		EErrorFrame = CE_FRAME,
    		EErrorIOE = CE_IOE,
    		EErrorMode = CE_MODE,
    		EErrorOverrun = CE_OVERRUN,
    		EErrorRxOver = CE_RXOVER,
    		EErrorParity = CE_RXPARITY,
    		EErrorTxFull = CE_TXFULL
    	}
    	EError;
    
    	typedef enum
    	{
    		EPortUnknownError = -1,
    		EPortAvailable = 0,
    		EPortNotAvailable = 1,
    		EPortInUse = 2
    
    	}
    	EPort;
    
    public:
    	static DWORD WINAPI ThreadProc(LPVOID lpArg);
    	static EPort CheckPort(LPCTSTR lpszDevice);
    	long Open(LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0);
    	LONG Close(void);
    	LONG Setup(EBaudrate eBaudrate = EBaud9600, EDataBits eDataBits = EData8, EParity   eParity = EParNone, EStopBits eStopBits = EStop1);
    	LONG SetEventChar(BYTE bEventChar, bool fAdjustMask = true);
    	LONG SetMask(DWORD dwMask = EEventBreak | EEventError | EEventRecv);
    	LONG WaitEvent(LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    	LONG SetupHandshaking(int eHandshake);
    	LONG SetupReadTimeouts(EReadTimeout eReadTimeout);
    	EBaudrate  GetBaudrate(void);
    	EDataBits  GetDataBits(void);
    	EParity    GetParity(void);
    	EStopBits  GetStopBits(void);
    	EHandshake GetHandshaking(void);
    	DWORD      GetEventMask(void);
    	BYTE       GetEventChar(void);
    	LONG Write(const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    	LONG Read(void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    	LONG Break(void);
    	EEvent GetEventType(void);
    	EError GetError(void);
    	HANDLE GetCommHandle(void) { return m_hFile; }
    	bool IsOpen(void) const { return (m_hFile != 0); }
    	LONG GetLastError(void) const { return m_lLastError; }
    	bool GetCTS(void);
    	bool GetDSR(void);
    	bool GetRing(void);
    	bool GetRLSD(void);
    	LONG Purge(void);
    	bool SetDTR(bool Stat);
    	bool SetRTS(bool Stat);
    protected:
    	class CDCB : public DCB{public:CDCB() { DCBlength = sizeof(DCB); }};
    	BOOL CancelCommIo(void);
    	LRESULT OnEvent(EError eError, EEvent eEvent);
    	LONG StartListener(void);
    	LONG StopListener(DWORD dwTimeout = INFINITE);
    	DWORD ThreadProc(void);
    	LONG	m_lLastError;
    	HANDLE	m_hFile;
    	EEvent	m_eEvent;
    	DWORD	m_dwEventMask;
    	HANDLE	m_hevtOverlapped;
    	bool	m_fStopping;
    	HANDLE	m_hThread;
    	HANDLE	m_hevtOverlappedWorkerThread;
    };
    
    
    


  • @KahnSoft: Über Jahrzehnte hat sich in diesem Forum folgendes bewährt: Code-Tags setzen ;- )



  • Funktioniert leider nicht mehr so wie früher, ist halt neu. Konnte ich auch nachträglich nicht aktivieren, scheinen Spezialkenntnisse nötig zu sein.



  • Du wirst ja wohl den Code markieren und den "</>"-Button drücken können?
    Ansonsten ist dein Beitrag nämlich so komplett sinnlos.



  • Ah funktioniert mit Edge, IE Scheint unterdrückt zu werden , sinnlos ist vieles. Und genau das macht den Sinn aus.


Anmelden zum Antworten