542 lines
14 KiB
C++
542 lines
14 KiB
C++
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
// WorkThrd.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
// Implementation of the CWorkerThread class.
|
||
|
//
|
||
|
// Author:
|
||
|
// David Potter (davidp) November 17, 1997
|
||
|
//
|
||
|
// Revision History:
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "AdmCommonRes.h"
|
||
|
#include "WorkThrd.h"
|
||
|
#include <process.h>
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Global Variables
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
TCHAR g_szOldWndProc[] = _T("CLADMWIZ_OldWndProc");
|
||
|
TCHAR g_szThreadObj[] = _T("CLADMWIZ_ThreadObj");
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// class CWorkerThread
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// CWorkerThread::CreateThread
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Create the thread.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// None.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// Any error values returned by CreateMutex(), CreateEvent(), or
|
||
|
// CreateThread().
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
DWORD CWorkerThread::CreateThread( void )
|
||
|
{
|
||
|
ATLASSERT( m_hThread == NULL );
|
||
|
ATLASSERT( m_hMutex == NULL );
|
||
|
ATLASSERT( m_hInputEvent == NULL );
|
||
|
ATLASSERT( m_hOutputEvent == NULL );
|
||
|
ATLASSERT( m_idThread == 0 );
|
||
|
|
||
|
DWORD _sc = ERROR_SUCCESS;
|
||
|
|
||
|
// Loop to avoid goto's.
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Create the mutex.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CreateThread() - Calling CreateMutex()\n") );
|
||
|
m_hMutex = CreateMutex(
|
||
|
NULL, // lpMutexAttributes
|
||
|
FALSE, // bInitialOwner
|
||
|
NULL // lpName
|
||
|
);
|
||
|
if ( m_hMutex == NULL )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error creating the mutex
|
||
|
|
||
|
//
|
||
|
// Create the input event.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CreateThread() - Calling CreateEvent() for input event\n") );
|
||
|
m_hInputEvent = CreateEvent(
|
||
|
NULL, // lpEventAttributes
|
||
|
TRUE, // bManualReset
|
||
|
FALSE, // bInitialState
|
||
|
NULL // lpName
|
||
|
);
|
||
|
if ( m_hInputEvent == NULL )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error creating the input event
|
||
|
|
||
|
//
|
||
|
// Create the output event.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CreateThread() - Calling CreateEvent() for output event\n") );
|
||
|
m_hOutputEvent = CreateEvent(
|
||
|
NULL, // lpEventAttributes
|
||
|
TRUE, // bManualReset
|
||
|
FALSE, // bInitialState
|
||
|
NULL // lpName
|
||
|
);
|
||
|
if ( m_hOutputEvent == NULL )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error creating the output event
|
||
|
|
||
|
//
|
||
|
// Create the thread.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CreateThread() - Calling CreateThread()\n") );
|
||
|
m_hThread = reinterpret_cast< HANDLE >( _beginthreadex(
|
||
|
NULL, // security
|
||
|
0, // stack_size
|
||
|
S_ThreadProc, // start_address,
|
||
|
(LPVOID) this, // arglist
|
||
|
0, // initflag
|
||
|
&m_idThread // thrdaddr
|
||
|
) );
|
||
|
if ( m_hThread == NULL )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error creating the thread
|
||
|
|
||
|
} while ( 0 );
|
||
|
|
||
|
//
|
||
|
// Handle errors by cleaning up objects we created.
|
||
|
//
|
||
|
if ( _sc != ERROR_SUCCESS )
|
||
|
{
|
||
|
Cleanup();
|
||
|
} // if: error occurred
|
||
|
|
||
|
return _sc;
|
||
|
|
||
|
} //*** CWorkerThread::CreateThread()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// CWorkerThread::PrepareWindowToWait
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Prepare to wait for a long operation. This involves disabling the
|
||
|
// window and displaying a wait cursor.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [IN] Handle for the window to disable while the
|
||
|
// operation is being performed.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// None.
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
void CWorkerThread::PrepareWindowToWait( IN HWND hwnd )
|
||
|
{
|
||
|
m_hCurrentCursor = GetCursor();
|
||
|
|
||
|
if ( hwnd != NULL )
|
||
|
{
|
||
|
//
|
||
|
// Subclass the window procedure so we can set the cursor properly.
|
||
|
//
|
||
|
m_pfnOldWndProc = reinterpret_cast< WNDPROC >( GetWindowLongPtr( hwnd, GWLP_WNDPROC ) );
|
||
|
SetProp( hwnd, g_szOldWndProc, m_pfnOldWndProc );
|
||
|
SetProp( hwnd, g_szThreadObj, this );
|
||
|
SetWindowLongPtr( hwnd, GWLP_WNDPROC, reinterpret_cast< LONG_PTR >( S_ParentWndProc ) );
|
||
|
|
||
|
//
|
||
|
// Disable property sheet and wizard buttons.
|
||
|
//
|
||
|
EnableWindow( hwnd, FALSE );
|
||
|
|
||
|
} // if: parent window specified
|
||
|
|
||
|
} //*** CWorkerThread::PrepareWindowToWait()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// CWorkerThread::CleanupWindowAfterWait
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Prepare to wait for a long operation. This involves disabling the
|
||
|
// window and displaying a wait cursor.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [IN] Handle for the window to disable while the
|
||
|
// operation is being performed.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// None.
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
void CWorkerThread::CleanupWindowAfterWait( IN HWND hwnd )
|
||
|
{
|
||
|
if ( hwnd != NULL )
|
||
|
{
|
||
|
//
|
||
|
// Unsubclass the window procedure.
|
||
|
//
|
||
|
SetWindowLongPtr( hwnd, GWLP_WNDPROC, reinterpret_cast< LONG_PTR >( m_pfnOldWndProc ) );
|
||
|
m_pfnOldWndProc = NULL;
|
||
|
RemoveProp( hwnd, g_szOldWndProc );
|
||
|
RemoveProp( hwnd, g_szThreadObj );
|
||
|
|
||
|
//
|
||
|
// Re-enable property sheet and wizard buttons.
|
||
|
//
|
||
|
EnableWindow( hwnd, TRUE );
|
||
|
} // if: parent window specified
|
||
|
|
||
|
m_hCurrentCursor = NULL;
|
||
|
|
||
|
} //*** CWorkerThread::CleanupWindowAfterWait()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// CWorkerThread::CallThreadFunction
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Call a function supported by the thread.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [IN] Handle for the window to disable while the
|
||
|
// operation is being performed.
|
||
|
// nFunction [IN] Code representing the function to perform.
|
||
|
// pvParam1 [IN OUT] Parameter 1 with function-specific data.
|
||
|
// pvParam2 [IN OUT] Parameter 2 with function-specific data.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// Any error values returned by AtlWaitWithMessageLoop() or PulseEvent().
|
||
|
// Status return from the function.
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
DWORD CWorkerThread::CallThreadFunction(
|
||
|
IN HWND hwnd,
|
||
|
IN LONG nFunction,
|
||
|
IN OUT PVOID pvParam1, // = NULL,
|
||
|
IN OUT PVOID pvParam2 // = NULL
|
||
|
)
|
||
|
{
|
||
|
ATLASSERT( m_hThread != NULL ); // Thread must already be created.
|
||
|
ATLASSERT( m_hMutex != NULL ); // Mutex must already be created.
|
||
|
ATLASSERT( m_hInputEvent != NULL ); // Input event must already be created.
|
||
|
ATLASSERT( m_hOutputEvent != NULL ); // Output event must already be created.
|
||
|
ATLASSERT( m_pfnOldWndProc == NULL ); // Parent window not already subclassed.
|
||
|
|
||
|
DWORD _sc;
|
||
|
CWaitCursor _wc;
|
||
|
|
||
|
//
|
||
|
// Prepare the window to wait for the thread operation.
|
||
|
//
|
||
|
PrepareWindowToWait( hwnd );
|
||
|
|
||
|
// Loop to avoid goto's.
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Wait for the thread to become available.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CallThreadFunction() - Waiting on mutex\n") );
|
||
|
if ( ! AtlWaitWithMessageLoop( m_hMutex ) )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error waiting on the mutex
|
||
|
|
||
|
// Loop to avoid using goto's.
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Pass this caller's data to the thread.
|
||
|
//
|
||
|
ATLASSERT( m_nFunction == 0 );
|
||
|
ATLASSERT( m_pvParam1 == NULL );
|
||
|
ATLASSERT( m_pvParam2 == NULL );
|
||
|
ATLASSERT( m_dwOutputStatus == ERROR_SUCCESS );
|
||
|
m_nFunction = nFunction;
|
||
|
m_pvParam1 = pvParam1;
|
||
|
m_pvParam2 = pvParam2;
|
||
|
|
||
|
//
|
||
|
// Signal the thread that there is work to do.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CallThreadFunction() - Setting input event\n") );
|
||
|
if ( ! SetEvent( m_hInputEvent ) )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error pulsing the event
|
||
|
|
||
|
//
|
||
|
// Wait for the thread to complete the function.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::CallThreadFunction() - Waiting on output event\n") );
|
||
|
if ( ! AtlWaitWithMessageLoop( m_hOutputEvent ) )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error waiting for the event
|
||
|
ATLTRACE( _T("CWorkerThread::CallThreadFunction() - Resetting output event\n") );
|
||
|
ResetEvent( m_hOutputEvent );
|
||
|
|
||
|
//
|
||
|
// Retrieve the results of the function to return
|
||
|
// to the caller.
|
||
|
//
|
||
|
_sc = m_dwOutputStatus;
|
||
|
|
||
|
//
|
||
|
// Clear input parameters.
|
||
|
//
|
||
|
m_nFunction = WTF_NONE;
|
||
|
m_pvParam1 = NULL;
|
||
|
m_pvParam2 = NULL;
|
||
|
m_dwOutputStatus = ERROR_SUCCESS;
|
||
|
|
||
|
} while ( 0 );
|
||
|
|
||
|
ATLTRACE( _T("CWorkerThread::CallThreadFunction() - Releasing mutex\n") );
|
||
|
ReleaseMutex( m_hMutex );
|
||
|
|
||
|
} while ( 0 );
|
||
|
|
||
|
//
|
||
|
// Cleanup windows after the wait operation.
|
||
|
//
|
||
|
CleanupWindowAfterWait( hwnd );
|
||
|
|
||
|
return _sc;
|
||
|
|
||
|
} //*** CWorkerThread::CallThreadFunction()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// CWorkerThread::WaitForThreadToExit
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Wait for the thread to exit.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [IN] Handle for the window to disable while the
|
||
|
// operation is being performed.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// ERROR_SUCCESS Operation completed successfully.
|
||
|
// Any error values returned by AtlWaitWithMessageLoop().
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
DWORD CWorkerThread::WaitForThreadToExit( IN HWND hwnd )
|
||
|
{
|
||
|
ATLASSERT( m_hThread != NULL ); // Thread must already be created.
|
||
|
|
||
|
DWORD _sc = ERROR_SUCCESS;
|
||
|
CWaitCursor _wc;
|
||
|
|
||
|
//
|
||
|
// Prepare the window to wait for the thread operation.
|
||
|
//
|
||
|
PrepareWindowToWait( hwnd );
|
||
|
|
||
|
//
|
||
|
// Wait for the thread to exit.
|
||
|
//
|
||
|
AtlWaitWithMessageLoop( m_hThread );
|
||
|
if ( ! AtlWaitWithMessageLoop( m_hThread ) )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
} // if: error waiting for the thread to exit
|
||
|
|
||
|
//
|
||
|
// Cleanup windows after the wait operation.
|
||
|
//
|
||
|
CleanupWindowAfterWait( hwnd );
|
||
|
|
||
|
return _sc;
|
||
|
|
||
|
} //*** CWorkerThread::WaitForThreadToExit()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// static
|
||
|
// CWorkerThread::S_ParentWndProc
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Static parent window procedure. This procedure handles the
|
||
|
// WM_SETCURSOR message while the thread is processing a request.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [IN] Identifies the window.
|
||
|
// uMsg [IN] Specifies the message.
|
||
|
// wParam [IN] Specifies additional information based on uMsg.
|
||
|
// lParam [IN] Specifies additional information based on uMsg.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// The result of the message processing.
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
LRESULT WINAPI CWorkerThread::S_ParentWndProc(
|
||
|
IN HWND hwnd,
|
||
|
IN UINT uMsg,
|
||
|
IN WPARAM wParam,
|
||
|
IN LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
LRESULT lResult = 0;
|
||
|
CWorkerThread * pthread = reinterpret_cast< CWorkerThread * >( GetProp( hwnd, g_szThreadObj ) );
|
||
|
|
||
|
ATLASSERT( pthread != NULL );
|
||
|
|
||
|
if ( pthread != NULL )
|
||
|
{
|
||
|
if ( uMsg == WM_SETCURSOR )
|
||
|
{
|
||
|
if ( GetCursor() != pthread->m_hCurrentCursor )
|
||
|
{
|
||
|
SetCursor( pthread->m_hCurrentCursor );
|
||
|
} // if: cursor is different
|
||
|
lResult = TRUE;
|
||
|
} // if: set cursor message
|
||
|
else
|
||
|
{
|
||
|
lResult = (*pthread->m_pfnOldWndProc)( hwnd, uMsg, wParam, lParam );
|
||
|
} // else: other message
|
||
|
} // if: thread is non-null
|
||
|
|
||
|
return lResult;
|
||
|
|
||
|
} //*** CWorkerThread::S_ParentWndProc()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//++
|
||
|
//
|
||
|
// static
|
||
|
// CWorkerThread::S_ThreadProc
|
||
|
//
|
||
|
// Routine Description:
|
||
|
// Static thread procedure.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pvThis [IN OUT] this pointer for the CWorkerThread instance.
|
||
|
//
|
||
|
// Return Value:
|
||
|
// None (ignored).
|
||
|
//
|
||
|
//--
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
UINT __stdcall CWorkerThread::S_ThreadProc( IN OUT LPVOID pvThis )
|
||
|
{
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Beginning thread\n") );
|
||
|
|
||
|
DWORD _sc;
|
||
|
LONG _nFunction;
|
||
|
CWorkerThread * _pThis = reinterpret_cast< CWorkerThread * >( pvThis );
|
||
|
|
||
|
ATLASSERT( pvThis != NULL );
|
||
|
ATLASSERT( _pThis->m_hMutex != NULL );
|
||
|
ATLASSERT( _pThis->m_hInputEvent != NULL );
|
||
|
ATLASSERT( _pThis->m_hOutputEvent != NULL );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Wait for work.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Waiting on input event\n") );
|
||
|
_sc = WaitForSingleObject( _pThis->m_hInputEvent, INFINITE );
|
||
|
if ( _sc == WAIT_FAILED )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error waiting for the event
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Resetting input event\n") );
|
||
|
ResetEvent( _pThis->m_hInputEvent );
|
||
|
|
||
|
//
|
||
|
// Handle the exit request.
|
||
|
//
|
||
|
if ( _pThis->m_nFunction == WTF_EXIT )
|
||
|
{
|
||
|
_pThis->m_bThreadExiting = TRUE;
|
||
|
} // if: exiting
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Call the function handler.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Calling thread function handler\n") );
|
||
|
ATLASSERT( _pThis->m_nFunction != 0 );
|
||
|
_pThis->m_dwOutputStatus = _pThis->ThreadFunctionHandler(
|
||
|
_pThis->m_nFunction,
|
||
|
_pThis->m_pvParam1,
|
||
|
_pThis->m_pvParam2
|
||
|
);
|
||
|
} // else: not exiting
|
||
|
|
||
|
//
|
||
|
// Save locally data that we need to access once we have signalled
|
||
|
// the caller's event. If we don't do this, we won't be referencing
|
||
|
// the proper function code after that point.
|
||
|
//
|
||
|
_nFunction = _pThis->m_nFunction;
|
||
|
|
||
|
//
|
||
|
// Signal the calling thread that the work has been completed.
|
||
|
//
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Setting output event\n") );
|
||
|
if ( ! SetEvent( _pThis->m_hOutputEvent ) )
|
||
|
{
|
||
|
_sc = GetLastError();
|
||
|
break;
|
||
|
} // if: error pulsing
|
||
|
|
||
|
//
|
||
|
// Set the status in case we are exiting.
|
||
|
//
|
||
|
_sc = ERROR_SUCCESS;
|
||
|
|
||
|
} while ( _nFunction != WTF_EXIT );
|
||
|
|
||
|
ATLTRACE( _T("CWorkerThread::S_ThreadProc() - Exiting thread\n") );
|
||
|
// Sleep( 10000 ); // Test thread synchronization
|
||
|
return _sc;
|
||
|
|
||
|
} //*** CWorkerThread::S_ThreadProc()
|