I am trying to write an MFC dialog based application that reads the information from the serial COMM port of your PC and then write some information back to the serial COMM port. Any idea as to where do I start from?
Thanks in advance.
Does this help? :-)
SerialPort.h
/* /////////////////// Macros / Structs etc ////////////////////////// */
#ifndef __SERIALPORT_H__
#define __SERIALPORT_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vector>
/* ///////////////////////// Classes /////////////////////////////////////////// */
/* //// Serial port exception class //////////////////////////////////////////// */
void AfxThrowSerialException(DWORD dwError = 0);
class CSerialException : public CException
{
public:
/* Constructors / Destructors */
CSerialException (DWORD dwError);
~CSerialException ();
/* Methods */
#ifdef _DEBUG
virtual void Dump(CDumpContext & dc) const;
#endif
virtual BOOL GetErrorMessage(LPTSTR lpstrError, UINT nMaxError, PUINT pnHelpContext = NULL);
CString GetErrorMessage();
/* Data members */
DWORD m_dwError;
protected:
DECLARE_DYNAMIC(CSerialException)
};
/* // The actual serial port class ///////////////////////////////////////////// */
class CSerialPort : public CObject
{
public:
/* Enums */
enum FlowControl {
NoFlowControl,
CtsRtsFlowControl,
CtsDtrFlowControl,
DsrRtsFlowControl,
DsrDtrFlowControl,
XonXoffFlowControl
};
enum Parity {
EvenParity,
MarkParity,
NoParity,
OddParity,
SpaceParity
};
enum StopBits {
OneStopBit,
OnePointFiveStopBits,
TwoStopBits
};
/* Constructors / Destructors */
CSerialPort ();
~CSerialPort ();
/* General Methods */
static std::vector<CString> EnumSerialPorts( void );
void Open(int nPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8,
StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
void Open(LPCTSTR szPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8,
StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
void Close();
void Attach(HANDLE hComm);
HANDLE Detach();
operator HANDLE() const { return m_hComm; }
BOOL IsOpen() const { return m_hComm != INVALID_HANDLE_VALUE; }
#ifdef _DEBUG
void CSerialPort::Dump(CDumpContext & dc) const;
#endif
/* Reading / Writing Methods */
DWORD Read(void *lpBuf, DWORD dwCount);
BOOL Read(void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped);
void ReadEx(void *lpBuf, DWORD dwCount);
DWORD Write(const void *lpBuf, DWORD dwCount);
BOOL Write(const void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped);
void WriteEx(const void *lpBuf, DWORD dwCount);
void TransmitChar(char cChar);
void GetOverlappedResult(OVERLAPPED & overlapped,
DWORD & dwBytesTransferred,
BOOL bWait);
void CancelIo();
/* Configuration Methods */
void GetConfig(COMMCONFIG & config);
static void GetDefaultConfig(int nPort, COMMCONFIG & config);
void SetConfig(COMMCONFIG & Config);
static void SetDefaultConfig(int nPort, COMMCONFIG & config);
/* Misc RS232 Methods */
void ClearBreak();
void SetBreak();
void ClearError(DWORD & dwErrors);
void GetStatus(COMSTAT & stat);
void GetState(DCB & dcb);
void SetState(DCB & dcb, BOOL bClosePortOnErr = FALSE);
void Escape(DWORD dwFunc);
void ClearDTR();
void ClearRTS();
void SetDTR();
void SetRTS();
void SetXOFF();
void SetXON();
void GetProperties(COMMPROP & properties);
void GetModemStatus(DWORD & dwModemStatus);
/* Timeouts */
void SetTimeouts(const COMMTIMEOUTS& timeouts);
void GetTimeouts(COMMTIMEOUTS& timeouts);
void Set0Timeout();
void Set0WriteTimeout();
void Set0ReadTimeout();
/* Event Methods */
void SetMask(DWORD dwMask);
void GetMask(DWORD & dwMask);
void WaitEvent(DWORD & dwMask);
void WaitEvent(DWORD & dwMask, OVERLAPPED & overlapped);
/* Queue Methods */
void Flush();
void Purge(DWORD dwFlags);
void TerminateOutstandingWrites();
void TerminateOutstandingReads();
void ClearWriteBuffer();
void ClearReadBuffer();
void Setup(DWORD dwInQueue, DWORD dwOutQueue);
/* Overridables */
virtual void OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped);
protected:
HANDLE m_hComm; /* Handle to the comms port */
BOOL m_bOverlapped; /* Is the port open in overlapped IO */
static void WINAPI _OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped);
DECLARE_DYNAMIC(CSerialPort)
private:
void OpenComm(LPCTSTR szPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8,
StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
};
#endif /* __SERIALPORT_H__ */
SerialPort.cpp
/* /////////////////////////////// Includes ////////////////////////////////// */
#include "stdafx.h"
#include <winspool.h>
#include "serialport.h"
#include "winerror.h"
/* /////////////////////////////// defines ///////////////////////////////////// */
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/* ////////////////////////////// Implementation /////////////////////////////// */
/* Class which handles CancelIo function which must be constructed at run time
* since it is not imeplemented on NT 3.51 or Windows 95. To avoid the loader
* bringing up a message such as "Failed to load due to missing export...", the
* function is constructed using GetProcAddress. The CSerialPort::CancelIo
* function then checks to see if the function pointer is NULL and if it is it
* throws an exception using the error code ERROR_CALL_NOT_IMPLEMENTED which
* is what 95 would have done if it had implemented a stub for it in the first
* place !!
*/
class _SERIAL_PORT_DATA
{
public:
/* Constructors /Destructors */
_SERIAL_PORT_DATA ();
~_SERIAL_PORT_DATA ();
HINSTANCE m_hKernel32;
typedef BOOL ( CANCELIO )( HANDLE );
typedef CANCELIO *LPCANCELIO;
LPCANCELIO m_lpfnCancelIo;
};
_SERIAL_PORT_DATA::_SERIAL_PORT_DATA ()
{
m_hKernel32 = LoadLibrary( _T("KERNEL32.DLL") );
VERIFY(m_hKernel32 != NULL);
m_lpfnCancelIo = (LPCANCELIO)GetProcAddress(m_hKernel32, "CancelIo");
}
_SERIAL_PORT_DATA::~_SERIAL_PORT_DATA ()
{
FreeLibrary(m_hKernel32);
m_hKernel32 = NULL;
}
/* The local variable which handle the function pointers */
_SERIAL_PORT_DATA _SerialPortData;
/* //////// Exception handling code */
void AfxThrowSerialException(DWORD dwError /* = 0 */)
{
if(dwError == 0) {
dwError = ::GetLastError();
}
CSerialException *pException = new CSerialException(dwError);
TRACE( _T("Warning: throwing CSerialException for error %d\n"), dwError );
THROW( pException );
}
BOOL CSerialException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
ASSERT( pstrError != NULL && AfxIsValidString(pstrError, nMaxError) );
if(pnHelpContext != NULL) {
*pnHelpContext = 0;
}
LPTSTR lpBuffer;
BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, m_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
(LPTSTR)&lpBuffer, 0, NULL);
if(bRet == FALSE) {
*pstrError = '\0';
} else {
lstrcpyn(pstrError, lpBuffer, nMaxError);
bRet = TRUE;
LocalFree(lpBuffer);
}
return bRet;
} /* GetErrorMessage */
CString CSerialException::GetErrorMessage()
{
CString rVal;
LPTSTR pstrError = rVal.GetBuffer(4096);
GetErrorMessage(pstrError, 4096, NULL);
rVal.ReleaseBuffer();
return rVal;
}
CSerialException::CSerialException (DWORD dwError)
{
m_dwError = dwError;
}
CSerialException::~CSerialException ()
{}
IMPLEMENT_DYNAMIC(CSerialException, CException)
#ifdef _DEBUG
void CSerialException::Dump(CDumpContext & dc) const
{
CObject::Dump(dc);
dc << "m_dwError = " << m_dwError;
}
#endif
/* //////// The actual serial port code */
CSerialPort::CSerialPort ()
{
m_hComm = INVALID_HANDLE_VALUE;
m_bOverlapped = FALSE;
}
CSerialPort::~CSerialPort ()
{
Close();
}
IMPLEMENT_DYNAMIC(CSerialPort, CObject)
#ifdef _DEBUG
void CSerialPort::Dump(CDumpContext & dc) const
{
CObject::Dump(dc);
dc << _T("m_hComm = ") << m_hComm << _T("\n");
dc << _T("m_bOverlapped = ") << m_bOverlapped;
}
#endif
std::vector<CString> CSerialPort::EnumSerialPorts(void)
{
/* Clear existing list of COMM ports */
std::vector<CString> commPortList;
/* COM ports can be numbered from 1 to 255, loop through all possibilities and add the ones we
* find.
*/
for( UINT i = 1; i < 256; i++ ) {
//Form the Raw device name
CString sPort;
sPort.Format( _T("COM%d"), i );
COMMCONFIG cc;
DWORD dwSize = sizeof(cc);
if( GetDefaultCommConfig(sPort, &cc, &dwSize) != 0 ) {
commPortList.push_back( (LPCTSTR)sPort );
}
}
return commPortList;
}
void CSerialPort::Open(int nPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopBits,
FlowControl fc, BOOL bOverlapped)
{
/* Validate our parameters */
ASSERT(nPort > 0 && nPort <= 255);
/* Call CreateFile to open up the comms port */
CString sPort;
sPort.Format(_T("\\\\.\\COM%d"), nPort);
OpenComm(sPort, dwBaud, parity, dataBits, stopBits, fc, bOverlapped);
}
void CSerialPort::Open(LPCTSTR szPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopBits,
FlowControl fc, BOOL bOverlapped)
{
OpenComm(szPort, dwBaud, parity, dataBits, stopBits, fc, bOverlapped);
}
void CSerialPort::OpenComm(LPCTSTR szPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopbits,
FlowControl fc, BOOL bOverlapped)
{
m_hComm = CreateFile(szPort, (GENERIC_READ | GENERIC_WRITE), 0, NULL, OPEN_EXISTING,
bOverlapped ? FILE_FLAG_OVERLAPPED : 0, NULL);
if(m_hComm == INVALID_HANDLE_VALUE) {
TRACE( _T("Failed to open up the comms port\n") );
AfxThrowSerialException();
}
m_bOverlapped = bOverlapped;
/* Get the current state prior to changing it */
DCB dcb;
GetState(dcb);
/* Setup the baud rate */
dcb.BaudRate = dwBaud;
/* Setup the Parity */
switch(parity) {
case EvenParity:
dcb.Parity = EVENPARITY; break;
case MarkParity:
dcb.Parity = MARKPARITY; break;
case NoParity:
dcb.Parity = NOPARITY; break;
case OddParity:
dcb.Parity = ODDPARITY; break;
case SpaceParity:
dcb.Parity = SPACEPARITY; break;
default:
ASSERT(FALSE); break;
}
/* Setup the data bits */
dcb.ByteSize = dataBits;
/* Setup the stop bits */
switch(stopbits) {
case OneStopBit:
dcb.StopBits = ONESTOPBIT; break;
case OnePointFiveStopBits:
dcb.StopBits = ONE5STOPBITS; break;
case TwoStopBits:
dcb.StopBits = TWOSTOPBITS; break;
default:
ASSERT(FALSE); break;
}
/* Setup the flow control */
dcb.fDsrSensitivity = FALSE;
switch(fc) {
case NoFlowControl:
{
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
break;
}
case CtsRtsFlowControl:
{
dcb.fOutxCtsFlow = TRUE;
dcb.fOutxDsrFlow = FALSE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
break;
}
case CtsDtrFlowControl:
{
dcb.fOutxCtsFlow = TRUE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
break;
}
case DsrRtsFlowControl:
{
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = TRUE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
break;
}
case DsrDtrFlowControl:
{
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = TRUE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
break;
}
case XonXoffFlowControl:
{
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutX = TRUE;
dcb.fInX = TRUE;
dcb.XonChar = 0x11;
dcb.XoffChar = 0x13;
dcb.XoffLim = 100;
dcb.XonLim = 100;
break;
}
default:
{
ASSERT(FALSE);
break;
}
}
/* Now that we have all the settings in place, make the changes */
SetState(dcb);
} /* Open */
void CSerialPort::Close()
{
if( IsOpen() ) {
BOOL bSuccess = CloseHandle(m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
if(!bSuccess) {
TRACE( _T("Failed to close up the comms port, GetLastError:%d\n"), GetLastError() );
}
m_bOverlapped = FALSE;
}
}
void CSerialPort::Attach(HANDLE hComm)
{
Close();
m_hComm = hComm;
}
HANDLE CSerialPort::Detach()
{
HANDLE hrVal = m_hComm;
m_hComm = INVALID_HANDLE_VALUE;
return hrVal;
}
DWORD CSerialPort::Read(void *lpBuf, DWORD dwCount)
{
ASSERT( IsOpen() );
ASSERT(!m_bOverlapped);
DWORD dwBytesRead = 0;
if( !ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, NULL) ) {
TRACE( _T("Failed in call to ReadFile\n") );
AfxThrowSerialException();
}
return dwBytesRead;
}
BOOL CSerialPort::Read(void *lpBuf, DWORD dwCount, OVERLAPPED & overlapped)
{
ASSERT( IsOpen() );
ASSERT(m_bOverlapped);
ASSERT(overlapped.hEvent);
DWORD dwBytesRead = 0;
BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
if(!bSuccess) {
if(GetLastError() != ERROR_IO_PENDING) {
TRACE( _T("Failed in call to ReadFile\n") );
AfxThrowSerialException();
}
}
return bSuccess;
}
DWORD CSerialPort::Write(const void *lpBuf, DWORD dwCount)
{
ASSERT( IsOpen() );
ASSERT(!m_bOverlapped);
DWORD dwBytesWritten = 0;
if( !WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, NULL) ) {
TRACE( _T("Failed in call to WriteFile\n") );
AfxThrowSerialException();
}
return dwBytesWritten;
}
BOOL CSerialPort::Write(const void *lpBuf, DWORD dwCount, OVERLAPPED & overlapped)
{
ASSERT( IsOpen() );
ASSERT(m_bOverlapped);
ASSERT(overlapped.hEvent);
DWORD dwBytesWritten = 0;
BOOL bSuccess = WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, &overlapped);
if(!bSuccess) {
if(GetLastError() != ERROR_IO_PENDING) {
TRACE( _T("Failed in call to WriteFile\n") );
AfxThrowSerialException();
}
}
return bSuccess;
}
void CSerialPort::GetOverlappedResult(OVERLAPPED & overlapped,
DWORD & dwBytesTransferred,
BOOL bWait)
{
ASSERT( IsOpen() );
ASSERT(m_bOverlapped);
ASSERT(overlapped.hEvent);
//DWORD dwBytesWritten = 0;
if( !::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait) ) {
if(GetLastError() != ERROR_IO_PENDING) {
TRACE( _T("Failed in call to GetOverlappedResult\n") );
AfxThrowSerialException();
}
}
}
void CSerialPort::_OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped)
{
/* Validate our parameters */
ASSERT(lpOverlapped);
/* Convert back to the C++ world */
CSerialPort *pSerialPort = (CSerialPort *)lpOverlapped->hEvent;
ASSERT( pSerialPort->IsKindOf( RUNTIME_CLASS(CSerialPort) ) );
/* Call the C++ function */
pSerialPort->OnCompletion(dwErrorCode, dwCount, lpOverlapped);
}
void CSerialPort::OnCompletion(DWORD /*dwErrorCode*/, DWORD /*dwCount*/, LPOVERLAPPED lpOverlapped)
{
/* Just free up the memory which was previously allocated for the OVERLAPPED structure */
delete lpOverlapped;
/* Your derived classes can do something useful in OnCompletion, but don't forget to
* call CSerialPort::OnCompletion to ensure the memory is freed up
*/
}
void CSerialPort::CancelIo()
{
ASSERT( IsOpen() );
if(_SerialPortData.m_lpfnCancelIo == NULL) {
TRACE( _T(
"CancelIo function is not supported on this OS. You need to be running at least NT 4 or Win 98 to use this function\n") );
AfxThrowSerialException(ERROR_CALL_NOT_IMPLEMENTED);
}
if( !::_SerialPortData.m_lpfnCancelIo(m_hComm) ) {
TRACE( _T("Failed in call to CancelIO\n") );
AfxThrowSerialException();
}
}
void CSerialPort::WriteEx(const void *lpBuf, DWORD dwCount)
{
ASSERT( IsOpen() );
OVERLAPPED *pOverlapped = new OVERLAPPED;
ZeroMemory( pOverlapped, sizeof(OVERLAPPED) );
pOverlapped->hEvent = (HANDLE) this;
if( !WriteFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion) ) {
delete pOverlapped;
TRACE( _T("Failed in call to WriteFileEx\n") );
AfxThrowSerialException();
}
}
void CSerialPort::ReadEx(void *lpBuf, DWORD dwCount)
{
ASSERT( IsOpen() );
OVERLAPPED *pOverlapped = new OVERLAPPED;
ZeroMemory( pOverlapped, sizeof(OVERLAPPED) );
pOverlapped->hEvent = (HANDLE) this;
if( !ReadFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion) ) {
delete pOverlapped;
TRACE( _T("Failed in call to ReadFileEx\n") );
AfxThrowSerialException();
}
}
void CSerialPort::TransmitChar(char cChar)
{
ASSERT( IsOpen() );
if( !TransmitCommChar(m_hComm, cChar) ) {
TRACE( _T("Failed in call to TransmitCommChar\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetConfig(COMMCONFIG & config)
{
ASSERT( IsOpen() );
DWORD dwSize = sizeof(COMMCONFIG);
if( !GetCommConfig(m_hComm, &config, &dwSize) ) {
TRACE( _T("Failed in call to GetCommConfig\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetConfig(COMMCONFIG & config)
{
ASSERT( IsOpen() );
DWORD dwSize = sizeof(COMMCONFIG);
if( !SetCommConfig(m_hComm, &config, dwSize) ) {
TRACE( _T("Failed in call to SetCommConfig\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetBreak()
{
ASSERT( IsOpen() );
if( !SetCommBreak(m_hComm) ) {
TRACE( _T("Failed in call to SetCommBreak\n") );
AfxThrowSerialException();
}
}
void CSerialPort::ClearBreak()
{
ASSERT( IsOpen() );
if( !ClearCommBreak(m_hComm) ) {
TRACE( _T("Failed in call to SetCommBreak\n") );
AfxThrowSerialException();
}
}
void CSerialPort::ClearError(DWORD & dwErrors)
{
ASSERT( IsOpen() );
if( !ClearCommError(m_hComm, &dwErrors, NULL) ) {
TRACE( _T("Failed in call to ClearCommError\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetDefaultConfig(int nPort, COMMCONFIG & config)
{
/* Validate our parameters */
ASSERT(nPort > 0 && nPort <= 255);
/* Create the device name as a string */
CString sPort;
sPort.Format(_T("COM%d"), nPort);
DWORD dwSize = sizeof(COMMCONFIG);
if( !GetDefaultCommConfig(sPort, &config, &dwSize) ) {
TRACE( _T("Failed in call to GetDefaultCommConfig\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetDefaultConfig(int nPort, COMMCONFIG & config)
{
/* Validate our parameters */
ASSERT(nPort > 0 && nPort <= 255);
/* Create the device name as a string */
CString sPort;
sPort.Format(_T("COM%d"), nPort);
DWORD dwSize = sizeof(COMMCONFIG);
if( !SetDefaultCommConfig(sPort, &config, dwSize) ) {
TRACE( _T("Failed in call to GetDefaultCommConfig\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetStatus(COMSTAT & stat)
{
ASSERT( IsOpen() );
DWORD dwErrors;
if( !ClearCommError(m_hComm, &dwErrors, &stat) ) {
TRACE( _T("Failed in call to ClearCommError\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetState(DCB& dcb)
{
ASSERT( IsOpen() );
if( !GetCommState(m_hComm, &dcb) ) {
TRACE( _T("Failed in call to GetCommState\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetState(DCB& dcb, BOOL bClosePortOnErr)
{
ASSERT( IsOpen() );
if( !SetCommState(m_hComm, &dcb) ) {
if( bClosePortOnErr == TRUE ) {
Close();
}
TRACE( _T("Failed in call to SetCommState\n") );
AfxThrowSerialException();
}
}
void CSerialPort::Escape(DWORD dwFunc)
{
ASSERT( IsOpen() );
if( !EscapeCommFunction(m_hComm, dwFunc) ) {
TRACE( _T("Failed in call to EscapeCommFunction\n") );
AfxThrowSerialException();
}
}
void CSerialPort::ClearDTR()
{
Escape(CLRDTR);
}
void CSerialPort::ClearRTS()
{
Escape(CLRRTS);
}
void CSerialPort::SetDTR()
{
Escape(SETDTR);
}
void CSerialPort::SetRTS()
{
Escape(SETRTS);
}
void CSerialPort::SetXOFF()
{
Escape(SETXOFF);
}
void CSerialPort::SetXON()
{
Escape(SETXON);
}
void CSerialPort::GetProperties(COMMPROP & properties)
{
ASSERT( IsOpen() );
if( !GetCommProperties(m_hComm, &properties) ) {
TRACE( _T("Failed in call to GetCommProperties\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetModemStatus(DWORD & dwModemStatus)
{
ASSERT( IsOpen() );
if( !GetCommModemStatus(m_hComm, &dwModemStatus) ) {
TRACE( _T("Failed in call to GetCommModemStatus\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetMask(DWORD dwMask)
{
ASSERT( IsOpen() );
if( !SetCommMask(m_hComm, dwMask) ) {
TRACE( _T("Failed in call to SetCommMask\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetMask(DWORD & dwMask)
{
ASSERT( IsOpen() );
if( !GetCommMask(m_hComm, &dwMask) ) {
TRACE( _T("Failed in call to GetCommMask\n") );
AfxThrowSerialException();
}
}
void CSerialPort::Flush()
{
ASSERT( IsOpen() );
if( !FlushFileBuffers(m_hComm) ) {
TRACE( _T("Failed in call to FlushFileBuffers\n") );
AfxThrowSerialException();
}
}
void CSerialPort::Purge(DWORD dwFlags)
{
ASSERT( IsOpen() );
if( !PurgeComm(m_hComm, dwFlags) ) {
TRACE( _T("Failed in call to PurgeComm\n") );
AfxThrowSerialException();
}
}
void CSerialPort::TerminateOutstandingWrites()
{
Purge(PURGE_TXABORT);
}
void CSerialPort::TerminateOutstandingReads()
{
Purge(PURGE_RXABORT);
}
void CSerialPort::ClearWriteBuffer()
{
Purge(PURGE_TXCLEAR);
}
void CSerialPort::ClearReadBuffer()
{
Purge(PURGE_RXCLEAR);
}
void CSerialPort::Setup(DWORD dwInQueue, DWORD dwOutQueue)
{
ASSERT( IsOpen() );
if( !SetupComm(m_hComm, dwInQueue, dwOutQueue) ) {
TRACE( _T("Failed in call to SetupComm\n") );
AfxThrowSerialException();
}
}
void CSerialPort::SetTimeouts(const COMMTIMEOUTS& timeouts)
{
ASSERT( IsOpen() );
if( !SetCommTimeouts(m_hComm, (LPCOMMTIMEOUTS)&timeouts) ) {
TRACE( _T("Failed in call to SetCommTimeouts\n") );
AfxThrowSerialException();
}
}
void CSerialPort::GetTimeouts(COMMTIMEOUTS & timeouts)
{
ASSERT( IsOpen() );
if( !GetCommTimeouts(m_hComm, &timeouts) ) {
TRACE( _T("Failed in call to GetCommTimeouts\n") );
AfxThrowSerialException();
}
}
void CSerialPort::Set0Timeout()
{
COMMTIMEOUTS Timeouts;
ZeroMemory( &Timeouts, sizeof(COMMTIMEOUTS) );
Timeouts.ReadIntervalTimeout = MAXDWORD;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 0;
Timeouts.WriteTotalTimeoutMultiplier = 0;
Timeouts.WriteTotalTimeoutConstant = 0;
SetTimeouts(Timeouts);
}
void CSerialPort::Set0WriteTimeout()
{
COMMTIMEOUTS Timeouts;
GetTimeouts(Timeouts);
Timeouts.WriteTotalTimeoutMultiplier = 0;
Timeouts.WriteTotalTimeoutConstant = 0;
SetTimeouts(Timeouts);
}
void CSerialPort::Set0ReadTimeout()
{
COMMTIMEOUTS Timeouts;
GetTimeouts(Timeouts);
Timeouts.ReadIntervalTimeout = MAXDWORD;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 0;
SetTimeouts(Timeouts);
}
void CSerialPort::WaitEvent(DWORD & dwMask)
{
ASSERT( IsOpen() );
ASSERT(!m_bOverlapped);
if( !WaitCommEvent(m_hComm, &dwMask, NULL) ) {
TRACE( _T("Failed in call to WaitCommEvent\n") );
AfxThrowSerialException();
}
}
void CSerialPort::WaitEvent(DWORD & dwMask, OVERLAPPED & overlapped)
{
ASSERT( IsOpen() );
ASSERT(m_bOverlapped);
ASSERT(overlapped.hEvent);
if( !WaitCommEvent(m_hComm, &dwMask, &overlapped) ) {
if(GetLastError() != ERROR_IO_PENDING) {
TRACE( _T("Failed in call to WaitCommEvent\n") );
AfxThrowSerialException();
}
}
}
Related
Pipe is being used, If server call WriteFile/ReadFile, client have to call ReadFile/WriteFile for synchronize each other.I implemented it like this.
Example :
**COMMON : **
BOOL RecvData(DWORD &dwScore)
{
DWORD dwRead = 0;
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
return FALSE;
if (sizeof(DWORD) != dwRead)
return FALSE;
return TRUE;
}
BOOL SendData(DWORD dwScore)
{
DWORD dwSend = 0;
if(0 == WriteFile(g_hPipe, &dwScore, sizeof(DWORD), &dwSend, 0))
return FALSE;
if (sizeof(DWORD) != dwSend)
return FALSE;
return TRUE;
}
**SERVER : **
VOID StartServerManager()
{
DWORD dwScore = 0;
while (TRUE)
{
if(FALSE == RecvData(dwScore))
continue;
//.... do something dwScore + dwSkill ...
if(FALSE == SendData(dwScore))
continue;
}
}
**CLIENT : **
#define VILLA_READ_MODE 0xDEDC
#define VILLA_WRITE_MODE 0xCDEC
VOID StartClientManager()
{
DWORD dwScore = 4;
DWORD dwMode = VILLA_WRITE_MODE;
while(TRUE)
{
switch(dwMode)
{
case VILLA_WRITE_MODE:
SendData(dwScore);
dwMode = VILLA_READ_MODE;
break;
case VILLA_READ_MODE:
RecvData(dwScore);
dwMode = VILLA_WRITE_MODE;
break;
}
}
}
If I change StartServerManager() into like this
VOID StartServerManager()
{
DWORD dwScore = 0;
while (TRUE)
{
if(FALSE == RecvData(dwScore))
continue;
//.... do something dwScore + dwSkill ...
if(FALSE == SendData(dwScore))
continue;
if(FALSE == RecvData(dwScore))
continue;
if(FALSE == RecvData(dwScore))
continue;
}
}
Function will block at ReadFile()
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
BOOL RecvData(DWORD &dwScore)
{
DWORD dwRead = 0;
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
return FALSE;
if (sizeof(DWORD) != dwRead)
return FALSE;
return TRUE;
}
Implemented with threads, too.
Is there any method pass block on ReadFile?
I thought about this...
#define VILLA_READ_MODE 0xDEDC
#define VILLA_WRITE_MODE 0xCDEC
VOID StartClientManager()
{
HANDLE hThread[2];
DWORD dwModeRead = VILLA_READ_MODE;
DWORD dwModeWrite = VILLA_WRITE_MODE;
hThread[1] = CreateThread(NULL, 0, SYNCTHREAD, &dwModeRead, 0, 0);
hThread[2] = CreateThread(NULL, 0, SYNCTHREAD, &dwModeWrite, 0, 0);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
}
DWORD WINAPI SYNCTHREAD(DWORD &dwMode)
{
switch (dwMode)
{
case VILLA_READ_MODE:
RecvData(dwScore);
break;
case VILLA_WRITE_MODE:
SendData(dwScore);
break;
}
}
I'm working in a small antirootkit and i need add a functionality that is:
Delete all files on directory of rootkit and in yours possible subdiretories.
So, firstly is necessary know all these directories and files, right?
To this, i have code below that already make half of this task. He enumerate all directories and files of a specific directory but not "see" subdirectories ( files and folders).
Eg:
Output:
Code:
#include <ntifs.h>
typedef unsigned int UINT;
NTSTATUS EnumFilesInDir()
{
HANDLE hFile = NULL;
UNICODE_STRING szFileName = { 0 };
OBJECT_ATTRIBUTES Oa = { 0 };
NTSTATUS ntStatus = 0;
IO_STATUS_BLOCK Iosb = { 0 };
UINT uSize = sizeof(FILE_BOTH_DIR_INFORMATION);
FILE_BOTH_DIR_INFORMATION *pfbInfo = NULL;
BOOLEAN bIsStarted = TRUE;
RtlInitUnicodeString(&szFileName, L"\\??\\C:\\MyDirectory");
InitializeObjectAttributes(&Oa, &szFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
ntStatus = ZwCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &Oa, &Iosb, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(ntStatus)) { return ntStatus; }
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000');
if (pfbInfo == NULL)
{
ZwClose(hFile); return STATUS_NO_MEMORY;
}
while (TRUE)
{
lbl_retry:
RtlZeroMemory(pfbInfo, uSize);
ntStatus = ZwQueryDirectoryFile(hFile, 0, NULL, NULL, &Iosb, pfbInfo, uSize, FileBothDirectoryInformation, FALSE, NULL, bIsStarted);
if (STATUS_BUFFER_OVERFLOW == ntStatus) {
ExFreePoolWithTag(pfbInfo, '000');
uSize = uSize * 2;
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000');
if (pfbInfo == NULL) { ZwClose(hFile); return STATUS_NO_MEMORY; }
goto lbl_retry;
}
else if (STATUS_NO_MORE_FILES == ntStatus)
{
ExFreePoolWithTag(pfbInfo, '000');
ZwClose(hFile); return STATUS_SUCCESS;
}
else if (STATUS_SUCCESS != ntStatus)
{
ExFreePoolWithTag(pfbInfo, '000');
ZwClose(hFile);
return ntStatus;
}
if (bIsStarted)
{
bIsStarted = FALSE;
}
while (TRUE)
{
WCHAR * szWellFormedFileName = ExAllocatePoolWithTag(PagedPool, (pfbInfo->FileNameLength + sizeof(WCHAR)), '0001');
if (szWellFormedFileName)
{
RtlZeroMemory(szWellFormedFileName, (pfbInfo->FileNameLength + sizeof(WCHAR)));
RtlCopyMemory(szWellFormedFileName, pfbInfo->FileName, pfbInfo->FileNameLength);
//KdPrint(("File name is: %S\n", szWellFormedFileName));
KdPrint((" %S\n", szWellFormedFileName));
ExFreePoolWithTag(szWellFormedFileName, '000');
}
if (pfbInfo->NextEntryOffset == 0) { break; }
pfbInfo += pfbInfo->NextEntryOffset;
}
}
ZwClose(hFile);
ExFreePoolWithTag(pfbInfo, '000');
return ntStatus;
}
So, how do this?
Thank in advance by any help or suggestion.
--------------------------------------------------------EDIT:--------------------------------------------------------------------
I found a possible solution, but i'm getting a BSOD in this line:
if ( (*pDir)->NextEntryOffset)
In KernelFindNextFile method.
Some suggestion?
Here is the code that i found:
#include <ntifs.h>
#include <stdlib.h>
HANDLE KernelCreateFile(IN PUNICODE_STRING pstrFile,IN BOOLEAN bIsDir)
{
HANDLE hFile = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK StatusBlock = {0};
ULONG ulShareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
ULONG ulCreateOpt = FILE_SYNCHRONOUS_IO_NONALERT;
OBJECT_ATTRIBUTES objAttrib = {0};
ULONG ulAttributes = OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE;
InitializeObjectAttributes(&objAttrib,pstrFile,ulAttributes,NULL,NULL);
ulCreateOpt |= bIsDir?FILE_DIRECTORY_FILE:FILE_NON_DIRECTORY_FILE;
Status = ZwCreateFile(
&hFile,
GENERIC_ALL,
&objAttrib,
&StatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
ulShareAccess,
FILE_OPEN_IF,
ulCreateOpt,
NULL,
0);
if (!NT_SUCCESS(Status))
{
return (HANDLE)-1;
}
return hFile;
}
PFILE_BOTH_DIR_INFORMATION KernelFindFirstFile(IN HANDLE hFile,IN ULONG ulLen,OUT PFILE_BOTH_DIR_INFORMATION pDir)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK StatusBlock = {0};
PFILE_BOTH_DIR_INFORMATION pFileList = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,ulLen);
Status = ZwQueryDirectoryFile(
hFile,NULL,NULL,NULL,
&StatusBlock,
pDir,
ulLen,
FileBothDirectoryInformation,
TRUE,
NULL,
FALSE);
RtlCopyMemory(pFileList,pDir,ulLen);
Status = ZwQueryDirectoryFile(
hFile,NULL,NULL,NULL,
&StatusBlock,
pFileList,
ulLen,
FileBothDirectoryInformation,
FALSE,
NULL,
FALSE);
return pFileList;
}
NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir)
{
if ( (*pDir)->NextEntryOffset)
{
(*pDir)=(PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir)+(*pDir)->NextEntryOffset);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
void Traversal()
{
UNICODE_STRING ustrFolder = {0};
WCHAR szSymbol[0x512] = L"\\??\\";
UNICODE_STRING ustrPath = RTL_CONSTANT_STRING(L"C:\\MyDirectory");
HANDLE hFile = NULL;
SIZE_T nFileInfoSize = sizeof(FILE_BOTH_DIR_INFORMATION)+270*sizeof(WCHAR);
SIZE_T nSize = nFileInfoSize*0x256;
char strFileName[0x256] = {0};
PFILE_BOTH_DIR_INFORMATION pFileListBuf = NULL;
PFILE_BOTH_DIR_INFORMATION pFileList = NULL;
PFILE_BOTH_DIR_INFORMATION pFileDirInfo = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,nSize);
wcscat_s(szSymbol,_countof(szSymbol),ustrPath.Buffer);
RtlInitUnicodeString(&ustrFolder,szSymbol);
hFile = KernelCreateFile(&ustrFolder,TRUE);
pFileList = pFileListBuf;
KernelFindFirstFile(hFile,nSize,pFileDirInfo);
if (pFileList)
{
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileDirInfo->FileName,pFileDirInfo->FileNameLength);
if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0)
{
if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
}
}
while (NT_SUCCESS(KernelFindNextFile(&pFileList)))
{
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileList->FileName,pFileList->FileNameLength);
if (strcmp(strFileName,"..")==0 || strcmp(strFileName,".")==0)
{
continue;
}
if (pFileList->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
}
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileListBuf->FileName,pFileListBuf->FileNameLength);
if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0)
{
if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
ExFreePool(pFileListBuf);
ExFreePool(pFileDirInfo);
}
}
BSOD:
FAULTING_SOURCE_LINE_NUMBER: 263
FAULTING_SOURCE_CODE:
259: }
260:
261: NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir)
262: {
> 263: if ((*pDir)->NextEntryOffset)
264: {
265: (*pDir) = (PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir) + (*pDir)->NextEntryOffset);
266: return STATUS_SUCCESS;
267: }
268:
ok, here code which tested and works. if somebody can not use it or got BSOD - probably problem not in code but in somebody skills
several notes - if you have previous mode kernel - use Nt* api (when exported) but not Zw* api. or Io* api. if you not understand why, or what is your previous mode - better even not try programming in kernel.
mandatory use FILE_OPEN_REPARSE_POINT option or even not try run this code if not understand what is this and why need use
for delete - open files with FILE_DELETE_ON_CLOSE option, for dump only - with FILE_DIRECTORY_FILE option instead.
code yourself used <= 0x1800 bytes of stack in x64 in deepest folders, like c:\Users - so this is ok for kernel, but always check stack space with IoGetRemainingStackSize
i will be not correct every comma in your code, if you can not do this yourself
#define ALLOCSIZE PAGE_SIZE
#ifdef _REAL_DELETE_
#define USE_DELETE_ON_CLOSE FILE_DELETE_ON_CLOSE
#define FILE_ACCESS FILE_GENERIC_READ|DELETE
#else
#define USE_DELETE_ON_CLOSE FILE_DIRECTORY_FILE
#define FILE_ACCESS FILE_GENERIC_READ
#endif
// int nLevel, PSTR prefix for debug only
void ntTraverse(POBJECT_ATTRIBUTES poa, ULONG FileAttributes, int nLevel, PSTR prefix)
{
if (IoGetRemainingStackSize() < PAGE_SIZE)
{
DbgPrint("no stack!\n");
return ;
}
if (!nLevel)
{
DbgPrint("!nLevel\n");
return ;
}
NTSTATUS status;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
DbgPrint("%s[<%wZ>]\n", prefix, poa->ObjectName);
#ifdef _REAL_DELETE_
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
{
if (0 <= NtOpenFile(&oa.RootDirectory, FILE_WRITE_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT|FILE_OPEN_REPARSE_POINT))
{
static FILE_BASIC_INFORMATION fbi = { {}, {}, {}, {}, FILE_ATTRIBUTE_NORMAL };
NtSetInformationFile(oa.RootDirectory, &iosb, &fbi, sizeof(fbi), FileBasicInformation);
NtClose(oa.RootDirectory);
}
}
#endif//_REAL_DELETE_
if (0 <= (status = NtOpenFile(&oa.RootDirectory, FILE_ACCESS, poa, &iosb, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|USE_DELETE_ON_CLOSE)))
{
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (PVOID buffer = ExAllocatePool(PagedPool, ALLOCSIZE))
{
union {
PVOID pv;
PBYTE pb;
PFILE_DIRECTORY_INFORMATION DirInfo;
};
while (0 <= (status = NtQueryDirectoryFile(oa.RootDirectory, NULL, NULL, NULL, &iosb,
pv = buffer, ALLOCSIZE, FileDirectoryInformation, 0, NULL, FALSE)))
{
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
ObjectName.Buffer = DirInfo->FileName;
switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength)
{
case 2*sizeof(WCHAR):
if (ObjectName.Buffer[1] != '.') break;
case sizeof(WCHAR):
if (ObjectName.Buffer[0] == '.') continue;
}
ObjectName.MaximumLength = ObjectName.Length;
#ifndef _REAL_DELETE_
if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
#endif
{
ntTraverse(&oa, DirInfo->FileAttributes, nLevel - 1, prefix - 1);
}
#ifndef _REAL_DELETE_
else
#endif
{
DbgPrint("%s%8I64u <%wZ>\n", prefix, DirInfo->EndOfFile.QuadPart, &ObjectName);
}
} while (NextEntryOffset = DirInfo->NextEntryOffset);
}
ExFreePool(buffer);
if (status == STATUS_NO_MORE_FILES)
{
status = STATUS_SUCCESS;
}
}
}
NtClose(oa.RootDirectory);
}
if (0 > status)
{
DbgPrint("---- %x %wZ\n", status, poa->ObjectName);
}
}
void ntTraverse()
{
char prefix[MAXUCHAR + 1];
memset(prefix, '\t', MAXUCHAR);
prefix[MAXUCHAR] = 0;
STATIC_OBJECT_ATTRIBUTES(oa, "\\??\\c:\\users");
//STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot");
ntTraverse(&oa, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_READONLY, MAXUCHAR, prefix + MAXUCHAR);
}
It is not easy to write a iocp console server,socket pool and thread pool works well,but after some times leater, the server can not connect again,though nothing wrong happens, why? I use procexp_16.05.1446001339.exe to check the process properties, I found lots of close_wait status, after some times again, close_wait status disappears, but the server still can not connect.Why is that? And how to fix it ?
#include "stdafx.h"
#include "Winsock2.h"
#include "Windows.h"
#include "Winbase.h"
#include "tlhelp32.h"
#include "tchar.h"
#include "Psapi.h"
#include "Winternl.h"
#include "Shlwapi.h"
#include "mstcpip.h"
#include
#include "ws2tcpip.h"
#include "time.h"
#pragma comment( lib, "Kernel32.lib" )
#pragma comment( lib, "Shlwapi.lib" )
#pragma comment( lib, "Psapi.lib" )
#pragma comment( lib, "Winmm.lib" )
#pragma comment( lib, "Ws2_32.lib" )
#define DATA_BUFSIZE 10240
#define OP_ACCEPT 1
#define OP_RECV 2
#define OP_SEND 3
#define OP_DIS 4
#define OP_ONACCEPT 5
//iocp struct
struct iocp_overlapped{
OVERLAPPED m_ol; //
int m_iOpType; //do type
SOCKET m_skServer; //server socket
SOCKET m_skClient; //client
DWORD m_recvBytes; //recv msg bytes
char m_pBuf[DATA_BUFSIZE]; //recv buf
WSABUF m_DataBuf; //recv data buf
int m_recv_timeout; //recv timeout
int m_send_timeout;
SOCKADDR_IN m_addrClient; //client address
SOCKADDR_IN m_addrServer; //server address
int m_isUsed; //client is active 1 yes 0 not
time_t m_active; //the last active time
int m_isCrashed; //is crashed? 0 not 1 yes
int m_online; //is online 1 yes 0 not
int m_usenum; //
//void (*handler)(int,struct tag_socket_data*); data->handler(res, data);
};
static SOCKET m_sock_listen = INVALID_SOCKET; //the server listen socket
class WingIOCP{
private:
char* m_listen_ip; //listen ip
int m_port; //listen port
int m_max_connect; //max connection
int m_recv_timeout; //recv timeout
int m_send_timeout; //send timeout
unsigned long* m_povs; //clients
//iocp worker
static VOID CALLBACK worker(
DWORD dwErrorCode,
DWORD dwBytesTrans,
LPOVERLAPPED lpOverlapped
);
//accept ex
static BOOL accept(
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
);
//disconnect a client socket and reuse it
static BOOL disconnect( SOCKET client_socket , LPOVERLAPPED lpOverlapped , DWORD dwFlags = TF_REUSE_SOCKET , DWORD reserved = 0);
//event callbacks
static void onconnect( iocp_overlapped *&povl );
static void ondisconnect( iocp_overlapped *&povl );
static void onclose( iocp_overlapped *&povl );
static void onrecv( iocp_overlapped *&povl );
static void onsend( iocp_overlapped *&povl );
static void onrun( iocp_overlapped *&povl, DWORD errorcode, int last_error );
static void onaccept(iocp_overlapped *&pOL);
public:
WingIOCP(
const char* listen = "0.0.0.0",
const int port = 6998,
const int max_connect = 10,
const int recv_timeout = 3000,
const int send_timeout = 3000
);
~WingIOCP();
BOOL start();
void wait();
};
/**
* # construct
*/
WingIOCP::WingIOCP(
const char* listen, //listen ip
const int port, //listen port
const int max_connect, //max connect
const int recv_timeout,//recv timeout in milliseconds
const int send_timeout //send timeout in milliseconds
)
{
this->m_listen_ip = _strdup(listen); //listen ip
this->m_port = port; //listen port
this->m_max_connect = max_connect; //max connect
this->m_recv_timeout = recv_timeout; //recv timeout
this->m_send_timeout = send_timeout; //send timeout
this->m_povs = new unsigned long[max_connect];//clients
}
/**
* # destruct
*/
WingIOCP::~WingIOCP(){
if( this->m_listen_ip )
{
free(this->m_listen_ip );
this->m_listen_ip = NULL;
}
if( this->m_povs )
{
delete[] this->m_povs;
this->m_povs = NULL;
}
if( m_sock_listen != INVALID_SOCKET )
{
closesocket( m_sock_listen );
m_sock_listen = INVALID_SOCKET;
}
WSACleanup();
}
/**
*#wait
*/
void WingIOCP::wait(){
while( true ){
Sleep(10);
}
}
//event callbacks
void WingIOCP::onconnect( iocp_overlapped *&pOL ){
printf("%ld onconnect\r\n",pOL->m_skClient);
pOL->m_online = 1;
pOL->m_active = time(NULL);
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_UPDATE_ACCEPT_CONTEXT,(const char *)&pOL->m_skServer,sizeof(pOL->m_skServer) ) != 0 )
{
//setsockopt fail
//printf("1=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
WSASetLastError(0);
return;
}
// set send timeout
if( pOL->m_send_timeout > 0 )
{
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_SNDTIMEO, (const char*)&pOL->m_send_timeout,sizeof(pOL->m_send_timeout)) !=0 )
{
//setsockopt fail
// printf("2=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
}
if( pOL->m_recv_timeout > 0 )
{
if( setsockopt( pOL->m_skClient, SOL_SOCKET,SO_RCVTIMEO, (const char*)&pOL->m_recv_timeout,sizeof(pOL->m_recv_timeout)) != 0 )
{
//setsockopt fail
// printf("3=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
}
linger so_linger;
so_linger.l_onoff = TRUE;
so_linger.l_linger = 0; // without close wait status
if( setsockopt( pOL->m_skClient,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(so_linger) ) != 0 ){
// printf("31=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
//get client ip and port
int client_size = sizeof(pOL->m_addrClient);
ZeroMemory( &pOL->m_addrClient , sizeof(pOL->m_addrClient) );
if( getpeername( pOL->m_skClient , (SOCKADDR *)&pOL->m_addrClient , &client_size ) != 0 )
{
//getpeername fail
// printf("4=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
// printf("%s %d connect\r\n",inet_ntoa(pOL->m_addrClient.sin_addr), pOL->m_addrClient.sin_port);
//keepalive open
int dt = 1;
DWORD dw = 0;
tcp_keepalive live ;
live.keepaliveinterval = 5000; //连接之后 多长时间发现无活动 开始发送心跳吧 单位为毫秒
live.keepalivetime = 1000; //多长时间发送一次心跳包 1分钟是 60000 以此类推
live.onoff = TRUE; //是否开启 keepalive
if( setsockopt( pOL->m_skClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&dt, sizeof(dt) ) != 0 )
{
//setsockopt fail
// printf("5=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
if( WSAIoctl( pOL->m_skClient, SIO_KEEPALIVE_VALS, &live, sizeof(live), NULL, 0, &dw, &pOL->m_ol , NULL ) != 0 )
{
//WSAIoctl error
// printf("6=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
}
memset(pOL->m_pBuf,0,DATA_BUFSIZE);
//post recv
pOL->m_DataBuf.buf = pOL->m_pBuf;
pOL->m_DataBuf.len = DATA_BUFSIZE;
pOL->m_iOpType = OP_RECV;
DWORD RecvBytes = 0;
DWORD Flags = 0;
int code = WSARecv(pOL->m_skClient,&(pOL->m_DataBuf),1,&RecvBytes,&Flags,&(pOL->m_ol),NULL);
int error_code = WSAGetLastError();
if( 0 != code )
{
if( WSA_IO_PENDING != error_code )
{
// printf("7=>onconnect some error happened , error code %d \r\n", WSAGetLastError());
return;
}
}
else
{
//recv complete
onrecv( pOL );
}
}
void WingIOCP::ondisconnect( iocp_overlapped *&pOL ){
// printf("ondisconnect error %d\r\n",WSAGetLastError());
WSASetLastError(0);
pOL->m_online = 0; //set offline
pOL->m_active = time(NULL); //the last active time
pOL->m_iOpType = OP_ONACCEPT; //reset status
pOL->m_isUsed = 0; //
ZeroMemory(pOL->m_pBuf,sizeof(char)*DATA_BUFSIZE); //clear buf
if( !BindIoCompletionCallback( (HANDLE)pOL->m_skClient ,worker,0) ){
// printf("BindIoCompletionCallback error %ld\r\n",WSAGetLastError());
}
//post acceptex
int error_code = accept( pOL->m_skClient,pOL->m_pBuf,0,sizeof(SOCKADDR_IN)+16,sizeof(SOCKADDR_IN)+16,NULL, (LPOVERLAPPED)pOL );
//printf("accept error %d\r\n",WSAGetLastError());
int last_error = WSAGetLastError() ;
if( !error_code && ERROR_IO_PENDING != last_error ){
}
//printf("2=>ondisconnect some error happened , error code %d \r\n================================================\r\n\r\n", WSAGetLastError());
//printf("21=>ondisconnect some error happened , error code %d \r\n================================================\r\n\r\n", WSAGetLastError());
WSASetLastError(0);
}
void WingIOCP::onaccept(iocp_overlapped *&pOL){
pOL->m_active = time(NULL); //the last active time
pOL->m_iOpType = OP_ACCEPT; //reset status
printf("%ld reuse socket real complete , error code %d \r\n", pOL->m_skClient,WSAGetLastError());
WSASetLastError(0);
}
void WingIOCP::onclose( iocp_overlapped *&pOL ){
// printf("%ld close\r\n", pOL->m_skClient);
SOCKET m_sockListen = pOL->m_skServer;
SOCKET m_client = pOL->m_skClient;
int send_timeout = pOL->m_send_timeout;
int recv_timeout = pOL->m_recv_timeout;
pOL->m_iOpType = OP_DIS;
shutdown( pOL->m_skClient, SD_BOTH );
//socket reuse
if( !disconnect( pOL->m_skClient , &pOL->m_ol ) && WSA_IO_PENDING != WSAGetLastError()) {
// printf("1=>onclose some error happened , error code %d \r\n", WSAGetLastError());
}
//printf("onclose complete %d \r\n", WSAGetLastError());
}
void WingIOCP::onrecv( iocp_overlapped *&pOL ){
pOL->m_active = time(NULL);
// printf("recv:\r\n%s\r\n\r\n",pOL->m_pBuf);
ZeroMemory(pOL->m_pBuf,DATA_BUFSIZE);
}
void WingIOCP::onsend( iocp_overlapped *&povl ){
}
void WingIOCP::onrun( iocp_overlapped *&povl, DWORD errorcode, int last_error ){}
/**
* # acceptex
*/
BOOL WingIOCP::accept(
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
)
{
WSASetLastError(0);
if( m_sock_listen == INVALID_SOCKET || !lpOverlapped )
{
return 0;
}
GUID guidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes = 0;
LPFN_ACCEPTEX lpfnAcceptEx;
int res= WSAIoctl( m_sock_listen, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx,
sizeof(guidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL );
if( 0 != res )
{
return 0;
}
return lpfnAcceptEx( m_sock_listen, sAcceptSocket, lpOutputBuffer, dwReceiveDataLength,
dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped );
}
/**
* # disconnect socket and reuse the socket
*/
BOOL WingIOCP::disconnect( SOCKET client_socket , LPOVERLAPPED lpOverlapped , DWORD dwFlags , DWORD reserved )
{
WSASetLastError(0);
if( client_socket == INVALID_SOCKET || !lpOverlapped )
{
return 0;
}
GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
DWORD dwBytes = 0;
LPFN_DISCONNECTEX lpfnDisconnectEx;
if( 0 != WSAIoctl( client_socket,SIO_GET_EXTENSION_FUNCTION_POINTER,&GuidDisconnectEx,
sizeof(GuidDisconnectEx),&lpfnDisconnectEx,sizeof(lpfnDisconnectEx),&dwBytes,NULL,NULL))
{
return 0;
}
return lpfnDisconnectEx(client_socket,lpOverlapped,/*TF_REUSE_SOCKET*/dwFlags,reserved);
}
/**
* # iocp worker thread
*/
VOID CALLBACK WingIOCP::worker( DWORD dwErrorCode,DWORD dwBytesTrans,LPOVERLAPPED lpOverlapped )
{
//why here get the error code 87 ?
//printf("worker error %d\r\n",WSAGetLastError());
if( NULL == lpOverlapped )
{
//not real complete
SleepEx(20,TRUE);//set warn status
WSASetLastError(0);
return;
}
//get overlapped data
iocp_overlapped* pOL = CONTAINING_RECORD(lpOverlapped, iocp_overlapped, m_ol);
//just a test
onrun( pOL, dwErrorCode, WSAGetLastError() );
switch( pOL->m_iOpType )
{
case OP_DIS:
ondisconnect(pOL);
break;
case OP_ONACCEPT:
onaccept(pOL);
break;
case OP_ACCEPT:
{
//new client connect
onconnect( pOL );
}
break;
case OP_RECV:
{
pOL->m_recvBytes = dwBytesTrans;
//check client offline
if( 0 == dwBytesTrans || WSAECONNRESET == WSAGetLastError() || ERROR_NETNAME_DELETED == WSAGetLastError()){
onclose( pOL );
}
else
{ //recv msg from client
pOL->m_recvBytes = dwBytesTrans;
onrecv( pOL );
}
}
break;
case OP_SEND:
{
}
break;
}
WSASetLastError(0);
}
BOOL WingIOCP::start(){
do{
WSADATA wsaData;
if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 )
{
return FALSE;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
break;
}
m_sock_listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == m_sock_listen )
{
break;
}
//bind the worker thread
BOOL bReuse = TRUE;
BOOL bind_status = ::BindIoCompletionCallback((HANDLE)( m_sock_listen ), worker, 0 );
if( !bind_status )
{
break;
}
//set option SO_REUSEADDR
if( 0 != ::setsockopt( m_sock_listen, SOL_SOCKET, SO_REUSEADDR,(LPCSTR)&bReuse, sizeof(BOOL) ) )
{
//some error happened
break;
}
struct sockaddr_in ServerAddress;
ZeroMemory(&ServerAddress, sizeof(ServerAddress));
ServerAddress.sin_family = AF_INET;
ServerAddress.sin_addr.s_addr = inet_addr( this->m_listen_ip );
ServerAddress.sin_port = htons( this->m_port );
if ( SOCKET_ERROR == bind( m_sock_listen, (struct sockaddr *) &ServerAddress, sizeof( ServerAddress ) ) )
{
break;
}
if( 0 != listen( m_sock_listen , SOMAXCONN ) )
{
break;
}
//printf("1=>start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
//socket pool
for( int i = 0 ; i m_max_connect ; i++ )
{
SOCKET client = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == client )
{
continue;
}
if( !BindIoCompletionCallback( (HANDLE)client ,worker,0) )
{
closesocket(client);
continue;
}
iocp_overlapped *povl = new iocp_overlapped();
if( NULL == povl )
{
closesocket(client);
continue;
}
DWORD dwBytes = 0;
ZeroMemory(povl,sizeof(iocp_overlapped));
povl->m_iOpType = OP_ACCEPT;
povl->m_skServer = m_sock_listen;
povl->m_skClient = client;
povl->m_recv_timeout = m_recv_timeout;
povl->m_isUsed = 0;
povl->m_active = 0;
povl->m_isCrashed = 0;
povl->m_online = 0;
povl->m_usenum = 1;
int server_size = sizeof(povl->m_addrServer);
ZeroMemory(&povl->m_addrServer,server_size);
getpeername(povl->m_skServer,(SOCKADDR *)&povl->m_addrServer,&server_size);
int error_code = accept( povl->m_skClient, povl->m_pBuf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, NULL, (LPOVERLAPPED)povl );
int last_error = WSAGetLastError() ;
if( !error_code && ERROR_IO_PENDING != last_error )
{
closesocket( client );
client = povl->m_skClient = INVALID_SOCKET;
delete povl;
povl = NULL;
//printf("client=>crate error %d\r\n",WSAGetLastError());
}else{
this->m_povs[i] = (unsigned long)povl;
}
//here all the last error is 997 , means nothing error happened
//printf("client=>start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
}
//printf("last start get error %d\r\n",WSAGetLastError());
WSASetLastError(0);
return TRUE;
} while( 0 );
if( m_sock_listen != INVALID_SOCKET )
{
closesocket( m_sock_listen );
m_sock_listen = INVALID_SOCKET;
}
WSACleanup();
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
WingIOCP *iocp = new WingIOCP();
iocp->start();
iocp->wait();
delete iocp;
return 0;
}
The solution to any CLOSE_WAIT issue is to close the socket. Evidently you are leaking sockets at end of stream or on an error.
Correct setsockopt usage like MS sample.
[EDIT] After some search I find this issue about AcceptEx.
Good lock.
My Windows has several accounts like "test1", "test2" and "test3" that belong to the Administrators group. I am developing an application program and I want that program to know if itself is run under an account that belong to the Administrators group by designing a boolean function: isCurrentUserAdminMember(), the isCurrentUserAdminMember() funtion should only return TRUE if the process is run by "test1", "test2", "test3" or the built-in Administrator account no matter whether the process is elevated.
I found some code in http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime as below, but it seems only to check if the current process is elevated as an Administrator. I don't care if the process is elevated, I just want to know if the start account of the process is a member of Administrators group. And I hope the determination itself is not privilege required. Is that possible? thanks.
BOOL IsAppRunningAsAdminMode()
{
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
dwError = GetLastError();
goto Cleanup;
}
// Determine whether the SID of administrators group is enabled in
// the primary access token of the process.
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
dwError = GetLastError();
goto Cleanup;
}
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
// Throw the error if something failed in the function.
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
return fIsRunAsAdmin;
}
At last, we achieved the goal to check the Administrators group membership as the code below, however it is USELESS as the answer and comment said, just leave here for reference in case anybody needs it for other use.
// PermTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
BOOL IsUserInGroup(const wchar_t* groupe)
{
BOOL result = FALSE;
SID_NAME_USE snu;
WCHAR szDomain[256];
DWORD dwSidSize = 0;
DWORD dwSize = sizeof szDomain / sizeof * szDomain;
if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
&& (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
SID* pSid = (SID*)malloc(dwSidSize);
if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
{
BOOL b;
if (CheckTokenMembership(NULL, pSid, &b))
{
if (b == TRUE)
{
result = TRUE;
}
}
else
{
result = FALSE;
}
}
//Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
//avec le bon operateur.
free(pSid);
}
return result;
}
void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
LPUSER_INFO_3 pBuf = NULL;
int j = 0;
DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);
LPUSER_INFO_2 pBuf2 = NULL;
pBuf2 = (LPUSER_INFO_2) pBuf;
if (pBuf)
{
wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name);
wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
}
// wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
// wprintf(L"\tPassword age (seconds): %d\n",
// pBuf2->usri2_password_age);
// wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST 0
// #define USER_PRIV_USER 1
// #define USER_PRIV_ADMIN 2
// wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
// wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
// wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
// wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
// wprintf(L"\tAuth flags (in hex): %x\n",
// pBuf2->usri2_auth_flags);
// wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
// wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
// wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
// wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
// wprintf
// (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logon);
// wprintf
// (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logoff);
// wprintf
// (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_acct_expires);
// wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
// wprintf(L"\tUnits per week: %d\n",
// pBuf2->usri2_units_per_week);
// wprintf(L"\tLogon hours:");
// for (j = 0; j < 21; j++)
// {
// printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
// }
// wprintf(L"\n");
// wprintf(L"\tBad password count: %d\n",
// pBuf2->usri2_bad_pw_count);
// wprintf(L"\tNumber of logons: %d\n",
// pBuf2->usri2_num_logons);
// wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
// wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
// wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
// printf( "Current user is %s\\%s\n",
// lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
//HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
HANDLE hProcess = GetCurrentProcess();
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
int _tmain(int argc, _TCHAR* argv[])
{
//cout << IsUserInGroup(L"administrators");
getUserInfo(L"adtest.net", L"Administrator");
getUserInfo(NULL, L"Administrator");
getUserInfo(NULL, L"test");
getUserInfo(NULL, L"test2");
getUserInfo(NULL, L"testnormal");
_bstr_t username;
_bstr_t domain;
GetUserFromProcess(username, domain);
cout << "Current account running this program is: " << endl << domain << "\\" << username << endl;
getchar();
return 0;
}
You can do this by opening your process token (OpenProcessToken, listing the SIDs using GetTokenInformation and comparing each SID to the Administrators SID.
Microsoft have sample code here: Searching for a SID in an Access Token in C++
However, this is rarely a useful thing to do. Even if the user is not a member of the Administrators group, they can still elevate by providing an administrative username and password, so you should not (for example) only offer elevation if the user is in the Administrators group.
bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;
HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
&hToken);
if ( bSuccess )
{
DWORD dwSizeToken=0;
DWORD dwSizeName=0;
DWORD dwSizeReferencedDomainName = 0;
// Get group information:
GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
{
const int MAX_NAME = 256;
char *psName = new char[MAX_NAME];
char *psDomain = new char[MAX_NAME];
char *pBuf = new char[dwSizeToken+10];
TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
if ( bSuccess )
{
// find the group name we are looking for
for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
{
SID_NAME_USE SidType;
dwSizeName = MAX_NAME;
dwSizeReferencedDomainName = MAX_NAME;
bSuccess = LookupAccountSid(NULL, // local system,
pGroupInfo->Groups[uiGroupNdx].Sid,
psName,
&dwSizeName,
psDomain,
&dwSizeReferencedDomainName,
&SidType);
if ( bSuccess )
{
if ( SidTypeGroup == SidType )
{
if ( !lstrcmpi(pszGroupName, psName) )
{
bFound = true;
}
}
}
}
}
delete [] pBuf;
delete [] psName;
delete [] psDomain;
}
CloseHandle(hToken);
}
return bFound;
}
In the following code the call to SetupDiEnumDeviceInfo() causes the subsequent CreateFile to return ERROR_SHARING_VIOLATION instead of opening the file. I was able to pinpoint the line by commenting out the other pieces of code until I hit one line that would cause the CreateFile to fail.
String SerialATDT::getComPortId()
{
#if 1
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
String comPort = "";
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_MODEM,
0, // Enumerator
0,
DIGCF_PRESENT );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return "";
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
int offset = 0;
while ( SetupDiEnumDeviceInfo(hDevInfo, offset++, &DeviceInfoData) )
{
DWORD DataT;
#if 1
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
// Look for identifying info in the name
if ( mComPortIdentifier.size() > 0 ) {
const char *temp = strstr(buffer, mComPortIdentifier.c_str());
if ( temp == 0 ) {
continue;
}
}
// Now find out the port number
DWORD nSize=0 ;
TCHAR buf[MAX_PATH];
if ( SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, buf, MAX_PATH, &nSize) )
{
HKEY devKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
DWORD size = 0;
DWORD type;
RegQueryValueEx(devKey, TEXT("PortName"), NULL, NULL, NULL, & size);
BYTE* buff = new BYTE[size];
String result;
if( RegQueryValueEx(devKey, TEXT("PortName"), NULL, &type, buff, & size) == ERROR_SUCCESS ) {
comPort = (char*)buff;
if ( comPort.size() > 0 ) {
RegCloseKey(devKey);
break;
}
}
RegCloseKey(devKey);
delete [] buff;
}
#else
comPort = "COM44";
#endif
}
// Cleanup
SetupDiDestroyDeviceInfoList (hDevInfo);
if (buffer) {
LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS &&
GetLastError() != ERROR_INVALID_HANDLE )
{
TRACE_L("ATDT error after free %ld", GetLastError() );
// Insert error handling here.
return "";
}
return comPort;
#else
return "COM44";
#endif
}
bool SerialATDT::getComPort(HANDLE *hFile)
{
String comPort = getComPortId();
*hFile = INVALID_HANDLE_VALUE;
if ( comPort.size() > 0 ) {
String comPortStr;
comPortStr.Format("\\\\.\\%s", comPort.c_str());
*hFile = ::CreateFile( comPortStr.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
if ( *hFile == INVALID_HANDLE_VALUE ) {
TRACE_L("AT file open error %ld", GetLastError());
}
}
return *hFile != INVALID_HANDLE_VALUE;
}
I have been looking but have not found a reason why the DeviceInfoData needs to be cleared (nor have I found a method to do it). Has anybody run into this before?