#include "pch.h"
#include "..\Inc\TCLib.h"
#include "TCThread.h"
TCThread::TCThread() :
m_pThreadParams(NULL),
m_pfnThreadProc(NULL),
m_hThread(NULL)
{
CommonConstruct();
}
TCThread::TCThread(TC_THREADPROC pfnThreadProc, LPVOID pParam) :
m_pThreadParams(pParam),
m_pfnThreadProc(pfnThreadProc)
{
CommonConstruct();
}
void TCThread::CommonConstruct()
{
m_hThread = NULL;
m_nThreadID = 0;
m_bAutoDelete = true;
m_bError = false;
m_bMsgQueue = false;
}
TCThread::~TCThread()
{
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); 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;
}
m_hThread = (HANDLE)_beginthreadex(pSecurityAttrs, nStackSize,
(m_bMsgQueue = bMsgQueue) ? TCMsgThreadEntry : TCThreadEntry, this,
dwCreateFlags | CREATE_SUSPENDED, (UINT*)&m_nThreadID);
if (NULL == m_hThread)
return false;
PRIVATE_VERIFYE(ResumeThread() != (DWORD)-1);
PRIVATE_VERIFYE(::WaitForSingleObject(m_hEvent, INFINITE) == WAIT_OBJECT_0);
m_hEvent = NULL;
if (dwCreateFlags & CREATE_SUSPENDED)
PRIVATE_VERIFYE(DWORD(-1) != ::SuspendThread(m_hThread));
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;
}
::SetEvent(m_hEvent2);
return true;
}
void TCThread::Delete()
{
if (m_bAutoDelete)
delete this;
}
void TCThread::EndThread(UINT nExitCode, bool bDelete)
{
if (bDelete)
Delete();
_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());
BOOL bSucceeded = ::SetEvent(pThread->m_hEvent);
PRIVATE_ASSERTE(bSucceeded);
DWORD dwWait = ::WaitForSingleObject(pThread->m_hEvent2, INFINITE);
PRIVATE_ASSERTE(WAIT_OBJECT_0 == dwWait);
pThread->m_hEvent2 = NULL;
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; }
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());
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
BOOL bSucceeded = ::SetEvent(pThread->m_hEvent);
PRIVATE_ASSERTE(bSucceeded);
DWORD dwWait = ::WaitForSingleObject(pThread->m_hEvent2, INFINITE);
PRIVATE_ASSERTE(WAIT_OBJECT_0 == dwWait);
pThread->m_hEvent2 = NULL;
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; }