MSGTHRD.H

//==========================================================================; 
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;

// support for a worker thread class to which you can asynchronously post
// messages


// Message class - really just a structure.
//
class CMsg {
public:
UINT uMsg;
DWORD dwFlags;
LPVOID lpParam;
CAMEvent *pEvent;

CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)
: uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}

CMsg()
: uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
};

// This is the actual thread class. It exports all the usual thread control
// functions. The created thread is different from a normal WIN32 thread in
// that it is prompted to perform particaular tasks by responding to messages
// posted to its message queue.
//
class AM_NOVTABLE CMsgThread {
private:
static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);
DWORD m_ThreadId;
HANDLE m_hThread;

protected:

// if you want to override GetThreadMsg to block on other things
// as well as this queue, you need access to this
CGenericList<CMsg> m_ThreadQueue;
CCritSec m_Lock;
HANDLE m_hSem;
LONG m_lWaiting;

public:
CMsgThread()
: m_ThreadId(0),
m_hThread(NULL),
m_lWaiting(0),
m_hSem(NULL),
// make a list with a cache of 5 items
m_ThreadQueue(NAME("MsgThread list"), 5)
{
}

~CMsgThread();
// override this if you want to block on other things as well
// as the message loop
void virtual GetThreadMsg(CMsg *msg);

// override this if you want to do something on thread startup
virtual void OnThreadInit() {
};

BOOL CreateThread();

BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {
if (m_hThread != NULL) {
WaitForSingleObject(m_hThread, INFINITE);
return GetExitCodeThread(m_hThread, lpdwExitCode);
}
return FALSE;
}

DWORD ResumeThread() {
return ::ResumeThread(m_hThread);
}

DWORD SuspendThread() {
return ::SuspendThread(m_hThread);
}

int GetThreadPriority() {
return ::GetThreadPriority(m_hThread);
}

BOOL SetThreadPriority(int nPriority) {
return ::SetThreadPriority(m_hThread, nPriority);
}

HANDLE GetThreadHandle() {
return m_hThread;
}

DWORD GetThreadId() {
return m_ThreadId;
}


void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {
CAutoLock lck(&m_Lock);
CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
m_ThreadQueue.AddTail(pMsg);
if (m_lWaiting != 0) {
ReleaseSemaphore(m_hSem, m_lWaiting, 0);
m_lWaiting = 0;
}
}

// This is the function prototype of the function that the client
// supplies. It is always called on the created thread, never on
// the creator thread.
//
virtual LRESULT ThreadMessageProc(
UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;
};