#include "StdAfx.h" #include "EventThread.h" #include "Misc.h" #define EXIT_EVENT -1 CEventThread::CEventThread(void) { AddEvent(EXIT_EVENT); m_hEvt = CreateEvent(NULL, FALSE, FALSE, NULL); m_waitTimeout = INFINITE; m_threadRunning = false; m_exitThread = false; m_threadWasStarted = false; } CEventThread::~CEventThread(void) { Stop(); for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++) { CloseHandle(it->first); } } UINT CEventThread::EventThreadFnc(void* thisptr) { CEventThread *threadClass = (CEventThread*)thisptr; threadClass->RunThread(); return 0; } void CEventThread::AddEvent(int eventId) { HANDLE handle = CreateEvent(NULL, FALSE, FALSE, _T("")); m_eventMap[handle] = eventId; } void CEventThread::AddEvent(int eventId, CString name) { //handle creating events cross users/cross process //https://stackoverflow.com/questions/29976596/shared-global-event-between-a-service-user-mode-processes-doesnt-work SECURITY_DESCRIPTOR sd; InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); SECURITY_ATTRIBUTES sa = { 0 }; sa.nLength = sizeof(sa); sa.bInheritHandle = FALSE; sa.lpSecurityDescriptor = &sd; HANDLE handle = CreateEvent(&sa, FALSE, FALSE, name); m_eventMap[handle] = eventId; } bool CEventThread::FireEvent(int eventId) { //Log(StrF(_T("Begin FireEvent, eventId: %d"), eventId)); bool ret = false; HANDLE eventHandle = NULL; for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++) { if(it->second == eventId) { eventHandle = it->first; break; } } if(eventHandle != NULL) { SetEvent(eventHandle); ret = true; } //Log(StrF(_T("End FireEvent, eventId: %d"), eventId)); return false; } bool CEventThread::UndoFireEvent(int eventId) { HANDLE eventHandle = NULL; for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++) { if(it->second == eventId) { eventHandle = it->first; break; } } if(eventHandle != NULL) { ResetEvent(eventHandle); return true; } return false; } void CEventThread::Start(void *param) { if(m_threadRunning == false) { ResetEvent(m_hEvt); m_exitThread = false; m_param = param; m_thread = (HANDLE)_beginthreadex(NULL, 0, EventThreadFnc, this, 0, &m_threadID); // now wait until the thread is up and really running WaitForSingleObject(m_hEvt, 1000); } else { UndoFireEvent(EXIT_EVENT); } } void CEventThread::WaitForThreadToExit(int waitTime) { WaitForSingleObject(m_hEvt, waitTime); } void CEventThread::Stop(int waitTime) { Log(StrF(_T("Start of CEventThread::Stop(int waitTime) %d - Name: %s"), waitTime, m_threadName)); if(m_threadRunning) { m_exitThread = true; FireEvent(EXIT_EVENT); if(waitTime > 0) { if (WAIT_OBJECT_0 != WaitForSingleObject(m_hEvt, waitTime)) { Log(_T("Start of TerminateThread CEventThread::Stop(int waitTime) ")); TerminateThread(m_thread, 0); Log(_T("End of TerminateThread CEventThread::Stop(int waitTime) ")); m_threadRunning = false; } } } Log(StrF(_T("End of CEventThread::Stop(int waitTime) %d - Name: %s"), waitTime, m_threadName)); }; void CEventThread::RunThread() { Log(StrF(_T("Start of CEventThread::RunThread() Name: %s"), m_threadName)); m_threadRunning = true; m_threadWasStarted = true; HANDLE *pHandleArray = new HANDLE[m_eventMap.size()]; int indexPos = 0; for(EventMapType::iterator it = m_eventMap.begin(); it != m_eventMap.end(); it++) { if (it->first != 0) { pHandleArray[indexPos] = it->first; indexPos++; } } SetEvent(m_hEvt); ResetEvent(m_hEvt); while(m_exitThread == false) { DWORD event = WaitForMultipleObjects((DWORD)m_eventMap.size(), pHandleArray, FALSE, m_waitTimeout); if(event == WAIT_FAILED) { LPVOID lpMsgBuf = NULL; DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL); ASSERT(!lpMsgBuf); LocalFree(lpMsgBuf); Sleep(1000); } else if(event == WAIT_TIMEOUT) { OnTimeOut(m_param); } else { HANDLE firedHandle = pHandleArray[event - WAIT_OBJECT_0]; int eventId = m_eventMap[firedHandle]; if(eventId == EXIT_EVENT) { break; } else { Log(StrF(_T("Start of CEventThread::RunThread() - OnEvent %d - Name %s"), eventId, m_threadName)); OnEvent(eventId, m_param); Log(StrF(_T("End of CEventThread::RunThread() - OnEvent %d - Name: %d"), eventId, m_threadName)); } } } UndoFireEvent(EXIT_EVENT); SetEvent(m_hEvt); Log(StrF(_T("End of CEventThread::RunThread() Name: %s"), m_threadName)); m_threadRunning = false; }