windows-nt/Source/XPSP1/NT/printscan/ui/uicommon/bkthread.h
2020-09-26 16:20:57 +08:00

346 lines
9 KiB
C++

#ifndef __BKTHREAD_H_INCLUDED
#define __BKTHREAD_H_INCLUDED
#include "tspqueue.h"
#include "modlock.h"
// Base class for all messages
class CThreadMessage
{
private:
int m_nMessage;
private:
//
// No implementation
//
CThreadMessage(void);
CThreadMessage( const CThreadMessage & );
CThreadMessage &operator=( const CThreadMessage & );
public:
CThreadMessage( int nMessage )
: m_nMessage(nMessage)
{
}
virtual ~CThreadMessage(void)
{
}
int Message(void) const
{
return(m_nMessage);
}
int Message( int nMessage )
{
return(m_nMessage = nMessage);
}
};
typedef CThreadSafePriorityQueue<CThreadMessage> CThreadMessageQueue;
class CNotifyThreadMessage : public CThreadMessage
{
private:
//
// No implementation
//
CNotifyThreadMessage(void);
CNotifyThreadMessage( const CNotifyThreadMessage & );
CNotifyThreadMessage &operator=( const CNotifyThreadMessage & );
private:
HWND m_hWndNotify;
public:
CNotifyThreadMessage( int nMessage, HWND hWndNotify )
: CThreadMessage(nMessage),
m_hWndNotify(hWndNotify)
{
}
virtual ~CNotifyThreadMessage(void)
{
m_hWndNotify = NULL;
}
HWND NotifyWindow(void) const
{
return(m_hWndNotify);
}
};
typedef BOOL (WINAPI *ThreadMessageHandler)( CThreadMessage *pMsg );
struct CThreadMessageMap
{
int nMessage;
ThreadMessageHandler pfnHandler;
};
class CBackgroundThread
{
private:
HANDLE m_hThread;
DWORD m_dwThreadId;
CThreadMessageQueue *m_pMessageQueue;
CThreadMessageMap *m_pThreadMessageMap;
CSimpleEvent m_CancelEvent;
HINSTANCE m_hInstanceUnlock;
private:
//
// No implementation
//
CBackgroundThread(void);
CBackgroundThread &operator=( const CBackgroundThread & );
CBackgroundThread( const CBackgroundThread & );
private:
//
// Private constructor. This is the only constructor. It is only called from Create.
//
CBackgroundThread( CThreadMessageQueue *pMessageQueue, CThreadMessageMap *pThreadMessageMap, HANDLE hCancelEvent )
: m_pMessageQueue(pMessageQueue),
m_pThreadMessageMap(pThreadMessageMap),
m_CancelEvent(hCancelEvent),
m_hInstanceUnlock(NULL)
{
}
bool HandleMessage( CThreadMessage *pMsg )
{
for (int i=0;pMsg && m_pThreadMessageMap && m_pThreadMessageMap[i].nMessage;i++)
{
if (m_pThreadMessageMap[i].nMessage == pMsg->Message())
{
//
// reset the cancel event
//
m_CancelEvent.Reset();
return (m_pThreadMessageMap[i].pfnHandler(pMsg) != FALSE);
}
}
return(true);
}
HRESULT Run()
{
//
// Make sure we got a good message queue
//
if (!m_pMessageQueue)
{
return E_POINTER;
}
//
// Make sure the event handle is good
//
if (!m_pMessageQueue->QueueEvent())
{
return E_INVALIDARG;
}
//
// Make sure we have a message queue
//
PostThreadMessage( GetCurrentThreadId(), WM_NULL, 0, 0 );
//
// Initialize COM on this thread. As a single threaded apartment.
//
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
//
// We will loop until we get a WM_QUIT message
//
while (true)
{
//
// Wait for a message to be place in the priority queue, or a message to be placed in the thread's queue
//
HANDLE Handles[1] = {m_pMessageQueue->QueueEvent()};
DWORD dwRes = MsgWaitForMultipleObjects(1,Handles,FALSE,INFINITE,QS_ALLINPUT|QS_ALLPOSTMESSAGE);
//
// If the event is signalled, there is a message in the queue
//
if (WAIT_OBJECT_0==dwRes)
{
//
// Pull the message out of the queue
//
CThreadMessage *pMsg = m_pMessageQueue->Dequeue();
if (pMsg)
{
//
// Call the message handler.
//
BOOL bResult = HandleMessage(pMsg);
//
// Delete the message
//
delete pMsg;
//
// If the handler returns false, exit the thread.
//
if (!bResult)
{
break;
}
}
}
else if (WAIT_OBJECT_0+1==dwRes)
{
//
// pull all of the messages out of the queue and process them
//
MSG msg;
while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
{
//
// Break out of the loop
//
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
//
// Shut down COM
//
CoUninitialize();
}
return(hr);
}
static DWORD ThreadProc(PVOID pData)
{
HRESULT hr = E_FAIL;
HINSTANCE hInstUnlock = NULL;
CBackgroundThread *pThread = (CBackgroundThread *)pData;
if (pData)
{
hr = pThread->Run();
hInstUnlock = pThread->m_hInstanceUnlock;
delete pThread;
}
if (hInstUnlock)
{
FreeLibraryAndExitThread( hInstUnlock, static_cast<DWORD>(hr) );
}
else
{
ExitThread( static_cast<DWORD>(hr) );
}
}
public:
~CBackgroundThread(void)
{
//
// Delete the thread handle
//
if (m_hThread)
{
CloseHandle(m_hThread);
m_hThread = 0;
}
//
// Nuke the message queue
//
delete m_pMessageQueue;
}
static HANDLE Create( CThreadMessageQueue *pMessageQueue, CThreadMessageMap *pThreadMessageMap, HANDLE hCancelEvent, HINSTANCE hInstLock )
{
//
// Make sure we have valid arguments
//
if (!pMessageQueue || !pThreadMessageMap)
{
WIA_ERROR((TEXT("!pMessageQueue || !pThreadMessageMap")));
return NULL;
}
//
// The duplicated handle we will be returning
//
HANDLE hReturnHandle = NULL;
//
// Create the thread class
//
CBackgroundThread *pThread = new CBackgroundThread( pMessageQueue, pThreadMessageMap, hCancelEvent );
if (pThread)
{
//
// Lock up before we create the thread
//
HINSTANCE hInstanceUnlock = NULL;
if (hInstLock)
{
//
// Get the module name
//
TCHAR szModule[MAX_PATH];
if (GetModuleFileName( hInstLock, szModule, ARRAYSIZE(szModule)))
{
//
// Increment the reference count
//
pThread->m_hInstanceUnlock = LoadLibrary( szModule );
}
}
pThread->m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, pThread, 0, &pThread->m_dwThreadId );
if (pThread->m_hThread)
{
//
// Copy the handle to return to the caller
//
DuplicateHandle( GetCurrentProcess(), pThread->m_hThread, GetCurrentProcess(), &hReturnHandle, 0, FALSE, DUPLICATE_SAME_ACCESS );
}
else
{
//
// Unlock the module
//
if (pThread->m_hInstanceUnlock)
{
FreeLibrary( hInstanceUnlock );
hInstanceUnlock;
}
//
// Since we can't start the thread, we have to delete the thread info to prevent a leak
//
delete pThread;
WIA_ERROR((TEXT("CreateThread failed")));
}
}
else
{
//
// Since the background thread isn't going to free it, we have to.
//
delete pMessageQueue;
WIA_ERROR((TEXT("new CBackgroundThread failed")));
}
return hReturnHandle;
}
};
#endif //__BKTHREAD_H_INCLUDED