///////////////////////////////////////////////////////////////////////////// // TCThread.cpp | Implementation of the TCThread class. // #include "pch.h" #include "..\Inc\TCLib.h" #include "TCThread.h" ///////////////////////////////////////////////////////////////////////////// // TCThread ///////////////////////////////////////////////////////////////////////////// // Group=Construction / Destruction TCThread::TCThread() : m_pThreadParams(NULL), m_pfnThreadProc(NULL), m_hThread(NULL) { // Perform common construction CommonConstruct(); } TCThread::TCThread(TC_THREADPROC pfnThreadProc, LPVOID pParam) : m_pThreadParams(pParam), m_pfnThreadProc(pfnThreadProc) { // Perform common construction CommonConstruct(); } void TCThread::CommonConstruct() { m_hThread = NULL; m_nThreadID = 0; m_bAutoDelete = true; m_bError = false; m_bMsgQueue = false; } TCThread::~TCThread() { // free thread object if (NULL != m_hThread) CloseHandle(m_hThread); } TCThread* TCThread::BeginThread(TC_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES pSecurityAttrs) { PRIVATE_ASSERTE(pfnThreadProc); if (pfnThreadProc) { TCThread* pThread = new TCThread(pfnThreadProc, pParam); if (!pThread->CreateThread(false, dwCreateFlags | CREATE_SUSPENDED, nStackSize, pSecurityAttrs)) { pThread->Delete(); return NULL; } PRIVATE_VERIFYE(pThread->SetThreadPriority(nPriority)); if (!(dwCreateFlags & CREATE_SUSPENDED)) PRIVATE_VERIFYE(pThread->ResumeThread() != (DWORD)-1); return pThread; } return NULL; } TCThread* TCThread::BeginMsgThread(TC_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES pSecurityAttrs) { PRIVATE_ASSERTE(pfnThreadProc); if (pfnThreadProc) { TCThread* pThread = new TCThread(pfnThreadProc, pParam); if (!pThread->CreateThread(true, dwCreateFlags | CREATE_SUSPENDED, nStackSize, pSecurityAttrs)) { pThread->Delete(); return NULL; } PRIVATE_VERIFYE(pThread->SetThreadPriority(nPriority)); if (!(dwCreateFlags & CREATE_SUSPENDED)) PRIVATE_VERIFYE(pThread->ResumeThread() != (DWORD)-1); return pThread; } return NULL; } bool TCThread::CreateThread(bool bMsgQueue, DWORD dwCreateFlags, UINT nStackSize, LPSECURITY_ATTRIBUTES pSecurityAttrs) { PRIVATE_ASSERTE(m_hThread == NULL); // already created? m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_hEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_hEventExit = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_dwCreateFlags = dwCreateFlags; if (!m_hEvent || !m_hEvent2 || !m_hEventExit) { _TRACE0("Warning: CreateEvent failed in TCThread::CreateThread.\n"); m_hEvent = NULL; m_hEvent2 = NULL; m_hEventExit = NULL; return false; } // create the thread (it may or may not start to run) m_hThread = (HANDLE)_beginthreadex(pSecurityAttrs, nStackSize, (m_bMsgQueue = bMsgQueue) ? TCMsgThreadEntry : TCThreadEntry, this, dwCreateFlags | CREATE_SUSPENDED, (UINT*)&m_nThreadID); if (NULL == m_hThread) return false; // start the thread just for initialization PRIVATE_VERIFYE(ResumeThread() != (DWORD)-1); PRIVATE_VERIFYE(::WaitForSingleObject(m_hEvent, INFINITE) == WAIT_OBJECT_0); m_hEvent = NULL; // if created suspended, suspend it until resume thread wakes it up if (dwCreateFlags & CREATE_SUSPENDED) PRIVATE_VERIFYE(DWORD(-1) != ::SuspendThread(m_hThread)); // if error during startup, shut things down if (m_bError) { PRIVATE_VERIFYE(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hThread, INFINITE)); m_hEvent = NULL; m_hEvent2 = NULL; m_hEventExit = NULL; m_hThread = NULL; return false; } // allow thread to continue, once resumed (it may already be resumed) ::SetEvent(m_hEvent2); return true; } void TCThread::Delete() { // delete thread if it is auto-deleting if (m_bAutoDelete) delete this; } void TCThread::EndThread(UINT nExitCode, bool bDelete) { if (bDelete) Delete(); // allow C-runtime to cleanup, and exit the thread _endthreadex(nExitCode); } UINT __stdcall TCThread::TCThreadEntry(void* pParam) { TCThread* pThread = (TCThread*)pParam; PRIVATE_ASSERTE(NULL != pThread); PRIVATE_ASSERTE(!pThread->m_hEvent.IsNull()); PRIVATE_ASSERTE(!pThread->m_bError); PRIVATE_ASSERTE(!pThread->m_hEventExit.IsNull()); // allow the creating thread to return from TCThread::CreateThread BOOL bSucceeded = ::SetEvent(pThread->m_hEvent); PRIVATE_ASSERTE(bSucceeded); // wait for thread to be resumed DWORD dwWait = ::WaitForSingleObject(pThread->m_hEvent2, INFINITE); PRIVATE_ASSERTE(WAIT_OBJECT_0 == dwWait); pThread->m_hEvent2 = NULL; // Call the passed in thread proc DWORD nResult = 0; if (NULL != pThread->m_pfnThreadProc) { nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams); PRIVATE_ASSERTE(pThread); pThread->EndThread(nResult, pThread->m_bAutoDelete); } return 0; // not reached } UINT __stdcall TCThread::TCMsgThreadEntry(void* pParam) { TCThread* pThread = (TCThread*)pParam; PRIVATE_ASSERTE(NULL != pThread); PRIVATE_ASSERTE(!pThread->m_hEvent.IsNull()); PRIVATE_ASSERTE(!pThread->m_bError); PRIVATE_ASSERTE(!pThread->m_hEventExit.IsNull()); // Force a message queue to be created MSG msg; PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); // allow the creating thread to return from TCThread::CreateMsgThread BOOL bSucceeded = ::SetEvent(pThread->m_hEvent); PRIVATE_ASSERTE(bSucceeded); // wait for thread to be resumed DWORD dwWait = ::WaitForSingleObject(pThread->m_hEvent2, INFINITE); PRIVATE_ASSERTE(WAIT_OBJECT_0 == dwWait); pThread->m_hEvent2 = NULL; // Call the passed in thread proc DWORD nResult = 0; if (NULL != pThread->m_pfnThreadProc) { nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams); PRIVATE_ASSERTE(pThread); pThread->EndThread(nResult, pThread->m_bAutoDelete); } return 0; // not reached }