342 lines
8.6 KiB
C++
342 lines
8.6 KiB
C++
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: MTA Callback
|
|
|
|
File: mtacb.cpp
|
|
|
|
Owner: DmitryR
|
|
|
|
This file contains the implementation of MTA callbacks
|
|
===================================================================*/
|
|
|
|
#include <w3p.hxx>
|
|
#include <process.h>
|
|
#pragma hdrstop
|
|
|
|
#include "MTAcb.h"
|
|
|
|
/*===================================================================
|
|
MTA Callback Thread
|
|
|
|
Worker thread that implements the MTA callback functionality
|
|
===================================================================*/
|
|
class CMTACallbackThread
|
|
{
|
|
private:
|
|
DWORD m_fInited : 1; // inited?
|
|
DWORD m_fCSInited : 1; // critical section inited?
|
|
DWORD m_fShutdown : 1; // shutdown?
|
|
|
|
CRITICAL_SECTION m_csLock; // callback critical section
|
|
HANDLE m_hDoItEvent; // callback requested event
|
|
HANDLE m_hDoneEvent; // callback done event
|
|
HANDLE m_hThread; // thread handle
|
|
|
|
PMTACALLBACK m_pMTACallback; // callback function ptr
|
|
void *m_pvContext; // arg1
|
|
void *m_pvContext2; // arg2
|
|
HRESULT m_hrResult; // return code
|
|
|
|
// The call callback from MTA thread
|
|
void DoCallback()
|
|
{
|
|
DBG_ASSERT(m_pMTACallback);
|
|
m_hrResult = (*m_pMTACallback)(m_pvContext, m_pvContext2);
|
|
}
|
|
|
|
// The thread function
|
|
static unsigned Thread(void *pvArg)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DBG_ASSERT(pvArg);
|
|
CMTACallbackThread *pThread = (CMTACallbackThread *)pvArg;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // MTA
|
|
if (FAILED(hr))
|
|
{
|
|
// Bug 87857: Handle failure from CoInitialize
|
|
if (hr == E_INVALIDARG)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
// This shouldnt actually fail. Not entirely clear what to do if it does
|
|
DBG_ASSERT(FALSE);
|
|
return hr;
|
|
}
|
|
|
|
while (!pThread->m_fShutdown)
|
|
{
|
|
DWORD dwRet = MsgWaitForMultipleObjects
|
|
(
|
|
1,
|
|
&(pThread->m_hDoItEvent),
|
|
FALSE,
|
|
INFINITE,
|
|
QS_ALLINPUT
|
|
);
|
|
|
|
if (pThread->m_fShutdown)
|
|
break;
|
|
|
|
if (dwRet == WAIT_OBJECT_0)
|
|
{
|
|
// Event -> do the callback
|
|
pThread->DoCallback();
|
|
SetEvent(pThread->m_hDoneEvent);
|
|
}
|
|
else
|
|
{
|
|
// Do messages
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
// Constructor
|
|
CMTACallbackThread()
|
|
: m_fInited(FALSE), m_fCSInited(FALSE), m_fShutdown(FALSE),
|
|
m_hDoItEvent(NULL), m_hDoneEvent(NULL), m_hThread(NULL),
|
|
m_pMTACallback(NULL)
|
|
{
|
|
}
|
|
|
|
// Destructor
|
|
~CMTACallbackThread()
|
|
{
|
|
// Real cleanup is in UnInit()
|
|
// This is to cleanup after a bad Init()
|
|
if (m_fCSInited)
|
|
DeleteCriticalSection(&m_csLock);
|
|
if (m_hDoItEvent)
|
|
CloseHandle(m_hDoItEvent);
|
|
if (m_hDoneEvent)
|
|
CloseHandle(m_hDoneEvent);
|
|
}
|
|
|
|
// Init (real constructor)
|
|
HRESULT Init()
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INITIALIZE_CRITICAL_SECTION(&m_csLock);
|
|
m_fCSInited = TRUE;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_hDoItEvent = IIS_CREATE_EVENT(
|
|
"CMTACallbackThread::m_hDoItEvent",
|
|
this,
|
|
FALSE,
|
|
FALSE
|
|
);
|
|
if (!m_hDoItEvent)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_hDoneEvent = IIS_CREATE_EVENT(
|
|
"CMTACallbackThread::m_hDoneEvent",
|
|
this,
|
|
FALSE,
|
|
FALSE
|
|
);
|
|
if (!m_hDoneEvent)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Launch the MTA thread
|
|
|
|
unsigned threadId;
|
|
uintptr_t ulThread = _beginthreadex(NULL,
|
|
0,
|
|
CMTACallbackThread::Thread,
|
|
this,
|
|
0,
|
|
&threadId);
|
|
if (ulThread == 0xffffffff || ulThread == 0)
|
|
hr = E_OUTOFMEMORY;
|
|
else
|
|
m_hThread = (HANDLE)ulThread;
|
|
|
|
if (SUCCEEDED(hr))
|
|
m_fInited = TRUE;
|
|
return hr;
|
|
}
|
|
|
|
// UnInit (real destructor)
|
|
HRESULT UnInit()
|
|
{
|
|
DBG_ASSERT(m_fInited);
|
|
|
|
if (m_hThread)
|
|
{
|
|
// Kill the MTA thread
|
|
m_fShutdown = TRUE;
|
|
SetEvent(m_hDoItEvent);
|
|
WaitForSingleObject(m_hThread, INFINITE);
|
|
CloseHandle(m_hThread);
|
|
m_hThread = NULL;
|
|
}
|
|
|
|
if (m_fCSInited)
|
|
{
|
|
DeleteCriticalSection(&m_csLock);
|
|
m_fCSInited = FALSE;
|
|
}
|
|
|
|
if (m_hDoItEvent)
|
|
{
|
|
CloseHandle(m_hDoItEvent);
|
|
m_hDoItEvent = NULL;
|
|
}
|
|
|
|
if (m_hDoneEvent)
|
|
{
|
|
CloseHandle(m_hDoneEvent);
|
|
m_hDoneEvent = NULL;
|
|
}
|
|
|
|
m_fInited = FALSE;
|
|
return NOERROR;
|
|
}
|
|
|
|
// Execute callback
|
|
HRESULT CallCallback
|
|
(
|
|
PMTACALLBACK pMTACallback,
|
|
void *pvContext,
|
|
void *pvContext2
|
|
)
|
|
{
|
|
if (m_fShutdown)
|
|
return E_FAIL;
|
|
|
|
DBG_ASSERT(m_fInited);
|
|
DBG_ASSERT(pMTACallback);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
EnterCriticalSection(&m_csLock);
|
|
|
|
DBG_ASSERT(m_pMTACallback == NULL);
|
|
m_pMTACallback = pMTACallback;
|
|
m_pvContext = pvContext;
|
|
m_pvContext2 = pvContext2;
|
|
m_hrResult = E_FAIL;
|
|
|
|
// Tell MTA thread to call back
|
|
SetEvent(m_hDoItEvent);
|
|
|
|
// Wait till done
|
|
WaitForSingleObject(m_hDoneEvent, INFINITE);
|
|
|
|
// remember HRESULT
|
|
hr = m_hrResult;
|
|
|
|
// to make sure we never do it twice
|
|
m_pMTACallback = NULL;
|
|
|
|
LeaveCriticalSection(&m_csLock);
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
// Sole instance of the above
|
|
static CMTACallbackThread *g_pMTACallbackThread = NULL;
|
|
|
|
/*===================================================================
|
|
E x t e r n a l A P I
|
|
===================================================================*/
|
|
|
|
/*===================================================================
|
|
InitMTACallbacks
|
|
|
|
To be called from DllInit()
|
|
Inits the MTA callback processing
|
|
Launches the MTA thread
|
|
|
|
Parameters
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT InitMTACallbacks()
|
|
{
|
|
g_pMTACallbackThread = new CMTACallbackThread;
|
|
if (g_pMTACallbackThread == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return g_pMTACallbackThread->Init();
|
|
}
|
|
|
|
/*===================================================================
|
|
UnInitMTACallbacks
|
|
|
|
To be called from DllUnInit()
|
|
Stops the MTA callback processing
|
|
Kills the MTA thread
|
|
|
|
Parameters
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT UnInitMTACallbacks()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (g_pMTACallbackThread != NULL)
|
|
{
|
|
hr = g_pMTACallbackThread->UnInit();
|
|
delete g_pMTACallbackThread;
|
|
g_pMTACallbackThread = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CallMTACallback
|
|
|
|
Calls the hack.
|
|
|
|
Parameters
|
|
PMTACALLBACK pMTACallback call this function
|
|
void *pvContext pass this to it
|
|
void *pvContext2 extra arg
|
|
|
|
Returns:
|
|
HRESULT
|
|
===================================================================*/
|
|
HRESULT CallMTACallback
|
|
(
|
|
PMTACALLBACK pMTACallback,
|
|
void *pvContext,
|
|
void *pvContext2
|
|
)
|
|
{
|
|
return g_pMTACallbackThread->CallCallback
|
|
(
|
|
pMTACallback,
|
|
pvContext,
|
|
pvContext2
|
|
);
|
|
}
|