Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2598 lines
71 KiB

//
// marshal.cpp
//
#include "private.h"
#include "globals.h"
#include "marshal.h"
#include "thdutil.h"
#include "cicmutex.h"
#include "helpers.h"
#include "mstub.h"
#include "mproxy.h"
#include "ithdmshl.h"
#include "transmit.h"
#include "smblock.h"
#include "utb.h"
#include "nuimgr.h"
#include "timlist.h"
#define WIN9X_SRCTHREADID 0x0001
inline HRESULT MAKE_WIN32( HRESULT status )
{
return MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, status );
}
#ifdef DEBUG
ULONG g_ulMarshalTimeOut = DEFAULTMARSHALTIMEOUT;
#endif
//////////////////////////////////////////////////////////////////////////////
//
// CSendReceiveEvent
//
//////////////////////////////////////////////////////////////////////////////
class CSendReceiveEvent : public CCicEvent
{
public:
CSendReceiveEvent(DWORD dwThreadId, ULONG ulBlockId) : CCicEvent()
{
if (SetName2(sz, ARRAYSIZE(sz), SZRPCSENDRECEIVEEVENT, dwThreadId, ulBlockId))
_psz = sz;
}
private:
char sz[MAX_PATH];
};
//////////////////////////////////////////////////////////////////////////////
//
// CSendReceiveConnectionEvent
//
//////////////////////////////////////////////////////////////////////////////
class CSendReceiveConnectionEvent : public CCicEvent
{
public:
CSendReceiveConnectionEvent(DWORD dwThreadId, ULONG ulBlockId) : CCicEvent()
{
if (SetName2(sz, ARRAYSIZE(sz), SZRPCSENDRECEIVECONNECTIONEVENT, dwThreadId, ulBlockId))
_psz = sz;
}
private:
char sz[MAX_PATH];
};
//////////////////////////////////////////////////////////////////////////////
//
// CCheckThreadInputIdle
//
//////////////////////////////////////////////////////////////////////////////
#define SZCHECKTHREADINPUTIDLE __TEXT("MSCTF.CheckThreadInptIdle.Event.")
class CCheckThreadInputIdle : public CCicEvent
{
public:
CCheckThreadInputIdle(DWORD dwThreadId, DWORD dw) : CCicEvent()
{
if (SetName2(sz, ARRAYSIZE(sz), SZCHECKTHREADINPUTIDLE, dwThreadId, dw))
_psz = sz;
}
private:
char sz[MAX_PATH];
};
//--------------------------------------------------------------------------
//
// GetOleMainThreadWindow
//
//--------------------------------------------------------------------------
BOOL IsOleMainThreadWindow(HWND hwnd)
{
char szClassName[32];
if (!GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName)))
return FALSE;
if (!lstrcmp(szClassName, TEXT("OleMainThreadWndClass")))
return TRUE;
return FALSE;
}
HWND FindOleMainThredWindow(DWORD dwThreadId)
{
HWND hwnd = FindWindowEx(IsOnNT5() ? HWND_MESSAGE : NULL,
NULL,
TEXT("OleMainThreadWndClass"), NULL);
while (hwnd)
{
if (dwThreadId == GetWindowThreadProcessId(hwnd, NULL))
{
if (IsOleMainThreadWindow(hwnd))
return hwnd;
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
return NULL;
}
HWND GetOleMainThreadWindow(SYSTHREAD *psfn)
{
HWND hwndOle = NULL;
if (psfn->hwndOleMainThread)
{
if (IsWindow(psfn->hwndOleMainThread) &&
IsOleMainThreadWindow(psfn->hwndOleMainThread))
return psfn->hwndOleMainThread;
psfn->hwndOleMainThread = NULL;
}
hwndOle = FindOleMainThredWindow(GetCurrentThreadId());
psfn->hwndOleMainThread = hwndOle;
return hwndOle;
}
//--------------------------------------------------------------------------
//
// FindStub
//
//--------------------------------------------------------------------------
int FindStub(CPtrArray<CStub> *prgStub, ULONG ulStubId)
{
int nMin = 0;
int nMax = prgStub->Count();
int nMid = -1;
while (nMin < nMax)
{
ULONG ulMidStubId;
nMid = (nMin + nMax) / 2;
ulMidStubId = prgStub->Get(nMid)->_ulStubId;
if (ulMidStubId > ulStubId)
nMax = nMid;
else if (ulMidStubId < ulStubId)
nMin = nMid + 1;
else
return nMid;
}
return -1;
}
//--------------------------------------------------------------------------
//
// FindStubId
//
//--------------------------------------------------------------------------
BOOL FindStubId(SYSTHREAD *psfn, ULONG *pulStubId, ULONG *pulInsert)
{
Assert(psfn->prgStub);
int i;
int nCnt = psfn->prgStub->Count();
BOOL fFound;
if (nCnt >= 0x7fffffff)
{
Assert(0);
return FALSE;
}
*pulStubId = 0;
*pulInsert = 0;
if (!nCnt)
return TRUE;
//
// max is 0x7ffffffff....
//
*pulStubId = 0x7fffffff;
fFound = FALSE;
for (i = nCnt - 1; i >= 0; i--)
{
CStub *pStub = psfn->prgStub->Get(i);
if (*pulStubId > pStub->_ulStubId)
{
i++;
*pulStubId = pStub->_ulStubId + 1;
fFound = TRUE;
break;
}
*pulStubId = pStub->_ulStubId - 1;
}
//
// we should be able to find any number in 32bit value.
//
Assert(fFound);
Assert(*pulStubId <= 0x7fffffff);
#ifdef DEBUG
Assert(FindStub(psfn->prgStub, *pulStubId) == -1);
#endif
*pulInsert = i;
return fFound;
}
#ifdef DEBUG
void dbg_CheckStubIds(SYSTHREAD *psfn)
{
Assert(psfn->prgStub);
int i;
int nCnt = psfn->prgStub->Count();
CStub *pStubPrev = psfn->prgStub->Get(0);
for (i = 1; i < nCnt; i++)
{
CStub *pStub = psfn->prgStub->Get(i);
Assert(pStubPrev->_ulStubId < pStub->_ulStubId);
pStubPrev = pStub;
}
}
#else
#define dbg_CheckStubIds(psfn)
#endif
//--------------------------------------------------------------------------
//
// CicCoMarshalInterface
//
//--------------------------------------------------------------------------
HRESULT CicCoMarshalInterface(REFIID riid, IUnknown *punk, ULONG *pulStubId, DWORD *pdwStubTime, DWORD dwSrcThreadId)
{
HRESULT hr = E_OUTOFMEMORY;
SYSTHREAD *psfn = GetSYSTHREAD();
CStub *pStub = NULL;
DWORD dwThreadId = GetCurrentThreadId();
MARSHALINTERFACE *pmi = NULL;
ULONG ulStubId;
ULONG ulInsert;
DWORD dwStubTime;
CCicSecAttr sa;
if (!psfn)
return E_FAIL;
if (!psfn->prgStub)
{
psfn->prgStub = new CPtrArray<CStub>;
if (!psfn->prgStub)
{
goto Exit;
}
}
if (!FindStubId(psfn, &ulStubId, &ulInsert))
{
Assert(0);
hr = E_FAIL;
goto Exit;
}
dwStubTime = GetTickCount();
pStub = StubCreator(riid, punk, ulStubId, dwStubTime, psfn->dwThreadId, psfn->dwProcessId, dwSrcThreadId);
if (!pStub)
{
Assert(0);
goto Exit;
}
if (!psfn->prgStub->Insert(ulInsert, 1))
{
goto Exit;
}
psfn->prgStub->Set(ulInsert, pStub);
dbg_CheckStubIds(psfn);
pStub->_pfm = new CMarshalInterfaceFileMapping(dwThreadId, ulStubId, dwStubTime);
if (pStub->_pfm == NULL)
{
goto Exit;
}
pmi = (MARSHALINTERFACE *)pStub->_pfm->Create(sa, sizeof(MARSHALINTERFACE), NULL);
if (!pmi)
{
goto Exit;
}
pmi->iid = riid;
pmi->dwStubTime = dwStubTime;
*pulStubId = ulStubId;
*pdwStubTime = dwStubTime;
hr = S_OK;
Exit:
if (hr != S_OK && pStub != NULL)
{
// pStub dtor will remove stub from psfn->prgStub
pStub->_Release();
}
return hr;
}
//--------------------------------------------------------------------------
//
// CicCoUnmarshalInterface
//
//--------------------------------------------------------------------------
HRESULT CicCoUnmarshalInterface(REFIID riid, DWORD dwStubThreadId, ULONG ulStubId, DWORD dwStubTime, void **ppv)
{
HRESULT hr = E_FAIL;
SYSTHREAD *psfn = GetSYSTHREAD();
IUnknown *punkProxy = NULL;
MARSHALINTERFACE *pmi;
CMarshalInterfaceFileMapping fm(dwStubThreadId, ulStubId, dwStubTime);
*ppv = NULL;
if (!psfn)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
pmi = (MARSHALINTERFACE *)fm.Open();
if (!pmi)
{
// Assert(0);
hr = MAKE_WIN32(RPC_S_SERVER_UNAVAILABLE);
goto Exit;
}
if (!IsEqualIID(pmi->iid, riid))
{
// Assert(0);
hr = E_FAIL;
goto Exit;
}
punkProxy = ProxyCreator(psfn,
pmi->iid,
ulStubId,
dwStubTime,
dwStubThreadId,
psfn->dwThreadId,
psfn->dwProcessId);
if (!punkProxy)
{
Assert(0);
hr = E_OUTOFMEMORY;
goto Exit;
}
*ppv = punkProxy;
hr = S_OK;
Exit:
fm.Close();
return hr;
}
//--------------------------------------------------------------------------
//
// HandleSendReceive
//
//--------------------------------------------------------------------------
void HandleSendReceiveMsg(DWORD dwSrcThreadId, ULONG ulBlockId)
{
MARSHALMSG *pMsg = NULL;
SYSTHREAD *psfn = GetSYSTHREAD();
int nTarget;
CStub *pStub = NULL;
HRESULT hr;
CSharedBlock *psb;
if (!psfn)
{
Assert(0);
return;
}
Assert(IsOnNT() || (dwSrcThreadId == WIN9X_SRCTHREADID));
CSendReceiveEvent event(dwSrcThreadId, ulBlockId);
CSendReceiveConnectionEvent eventc(dwSrcThreadId, ulBlockId);
if (eventc.Open())
eventc.Set();
if (psfn->pti && (psfn->dwThreadId == psfn->pti->dwThreadId))
psfn->pti->ulInMarshal++;
else
Assert(0);
psb = EnsureSharedBlockForThread(psfn, dwSrcThreadId);
if (!psb)
{
TraceMsg(TF_EVENT, "HandleSendReceive no Shared Block Ptr");
goto Exit;
}
pMsg = (MARSHALMSG *)psb->GetPtrFromBlockId(ulBlockId);
if (!pMsg)
{
TraceMsg(TF_EVENT, "HandleSendReceive no Msg Ptr");
goto Exit;
}
if (!psfn->prgStub)
{
TraceMsg(TF_EVENT, "HandleSendReceive no more sink");
goto Exit;
}
nTarget = FindStub(psfn->prgStub, pMsg->ulStubId);
if (nTarget == -1)
{
TraceMsg(TF_EVENT, "HandleSendReceive no Stub");
goto Exit;
}
pStub = psfn->prgStub->Get(nTarget);
if (!pStub)
{
TraceMsg(TF_EVENT, "HandleSendReceive no Stub Ptr");
goto Exit;
}
if (pStub->_dwStubTime != pMsg->dwStubTime)
{
TraceMsg(TF_EVENT, "HandleSendReceive old proxy was used");
goto Exit;
}
Assert(IsEqualIID(pStub->_iid, pMsg->iid));
#ifdef DEBUG
TCHAR _szModule[MAX_PATH];
::GetModuleFileName(NULL, _szModule, sizeof(_szModule)/sizeof(TCHAR));
TraceMsg(TF_EVENT, "%s HandleSendReceive Invoke", _szModule);
#endif
//
// we check the file map handle to marshal this interface itself.
//
pStub->ClearFileMap();
_try
{
hr = pStub->Invoke(pMsg, psb);
}
_except(1)
{
#ifdef DEBUG
TraceMsg(TF_EVENT, "%s HandleSendReceive Except", _szModule);
#endif
Assert(0);
goto Exit;
}
if (FAILED(hr))
{
#ifdef DEBUG
TraceMsg(TF_EVENT, "%s HandleSendReceive Error", _szModule);
#endif
Assert(0);
goto Exit;
}
#ifdef DEBUG
TraceMsg(TF_EVENT, "%s HandleSendReceive OK", _szModule);
#endif
#if 0
if (IsOnNT5())
{
//
// for Office10 beta.
//
// we want to allow SetForegroundWindow always when marshalling
// call happens. Thus we may have non-necessary calls here.
// Needs to find a good place to call this.
//
ALLOWSETFOREGROUNDWINDOW fnAllowSetForeground;
fnAllowSetForeground = EnsureAllowSetForeground();
if (fnAllowSetForeground)
fnAllowSetForeground(pMsg->dwSrcProcessId);
}
#endif
Exit:
if (psfn->pti && (psfn->dwThreadId == psfn->pti->dwThreadId))
psfn->pti->ulInMarshal--;
else
Assert(0);
if (event.Open())
event.Set();
}
//////////////////////////////////////////////////////////////////////////////
//
// CModalLoop
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CModalLoop::CModalLoop(SYSTHREAD *psfn) : CSysThreadRef(psfn)
{
_wQuitCode = 0;
_fQuitReceived = FALSE;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CModalLoop::~CModalLoop()
{
if (_fQuitReceived)
PostQuitMessage(_wQuitCode);
}
//--------------------------------------------------------------------------
//
// WaitHandleWndMessage
//
//--------------------------------------------------------------------------
#define WRM_MARSHALWND 0x0001
#define WRM_DISPATCH 0x0002
#define WRM_OLEWINDOW 0x0004
#define WRM_MARSHALWNDDISPATCH (WRM_DISPATCH | WRM_MARSHALWND)
void CModalLoop::WaitHandleWndMessages(DWORD dwQueueFlags)
{
// Try to clear the queue as best we can of any messages that
// might be holding off some other modal loop from executing.
// So we eat all mouse and key events.
if (dwQueueFlags & QS_KEY)
{
WaitRemoveMessage(WM_KEYFIRST, WM_KEYLAST, 0);
}
// Clear mouse releated messages if there are any
if (dwQueueFlags & QS_MOUSE)
{
WaitRemoveMessage(WM_MOUSEMOVE, WM_MOUSEMOVE, 0);
WaitRemoveMessage(WM_NCMOUSEFIRST, WM_NCMOUSELAST, 0);
WaitRemoveMessage(WM_QUEUESYNC, WM_QUEUESYNC, 0);
}
if (dwQueueFlags & QS_POSTMESSAGE)
{
WaitRemoveMessage(WM_DDE_FIRST, WM_DDE_LAST, WRM_DISPATCH);
WaitRemoveMessage(g_msgThreadMarshal,
g_msgThreadMarshal,
WRM_MARSHALWNDDISPATCH);
WaitRemoveMessage(g_msgCheckThreadInputIdel,
g_msgCheckThreadInputIdel,
WRM_MARSHALWNDDISPATCH);
#ifdef POINTER_MARSHAL
WaitRemoveMessage(g_msgPointerMarshal,
g_msgPointerMarshal,
WRM_MARSHALWNDDISPATCH);
#endif
#ifdef DEBUG
TCHAR _szModule[MAX_PATH];
::GetModuleFileName(NULL, _szModule, sizeof(_szModule)/sizeof(TCHAR));
TraceMsg(TF_EVENT, "%s CModalLoop::WaitHandleWndMessage:: MSUIM.Msg.RpcSendReceive", _szModule);
#endif
WaitRemoveMessage(g_msgRpcSendReceive,
g_msgRpcSendReceive,
WRM_MARSHALWNDDISPATCH);
// WaitRemoveMessage(g_msgPrivate, g_msgPrivate, WRM_DISPATCH);
WaitRemoveMessage(g_msgPrivate, g_msgPrivate, 0);
if (!_psfn->fInmsgSetFocus)
WaitRemoveMessage(g_msgSetFocus, g_msgSetFocus, 0);
if (!_psfn->fInmsgThreadItemChange)
WaitRemoveMessage(g_msgThreadItemChange, g_msgThreadItemChange, 0);
if (!_psfn->fInmsgThreadTerminate)
WaitRemoveMessage(g_msgThreadTerminate, g_msgThreadTerminate, 0);
WaitRemoveMessage(g_msgLBarModal, g_msgLBarModal, 0);
WaitRemoveMessage(WM_USER, (UINT)(-1), WRM_OLEWINDOW | WRM_DISPATCH);
}
// Get rid of paint message if we can as well -- this makes
// the screen look so much better.
if (dwQueueFlags & QS_PAINT)
{
WaitRemoveMessage(WM_PAINT, WM_PAINT, WRM_DISPATCH);
}
}
//--------------------------------------------------------------------------
//
// MyPeekMessage
//
//--------------------------------------------------------------------------
BOOL CModalLoop::MyPeekMessage(MSG *pMsg, HWND hwnd, UINT min, UINT max, WORD wFlag)
{
BOOL fRet = PeekMessage(pMsg, hwnd, min, max, wFlag);
while (fRet)
{
if (pMsg->message != WM_QUIT)
{
break;
}
_wQuitCode = (ULONG)(pMsg->wParam);
_fQuitReceived = TRUE;
if (!(wFlag & PM_REMOVE))
{
// quit message is still on queue so pull it off
PeekMessage(pMsg, hwnd, WM_QUIT, WM_QUIT, PM_REMOVE | PM_NOYIELD);
}
// peek again to see if there is another message
fRet = PeekMessage(pMsg, hwnd, min, max, wFlag);
}
return fRet;
}
//--------------------------------------------------------------------------
//
// WaitRemoveMessage
//
//--------------------------------------------------------------------------
BOOL CModalLoop::WaitRemoveMessage(UINT uMsgFirst, UINT uMsgLast, DWORD dwFlags)
{
MSG msg;
HWND hwnd = NULL;
BOOL fRet = FALSE;
if (dwFlags & WRM_MARSHALWND)
{
hwnd = _psfn->hwndMarshal;
}
if (dwFlags & WRM_OLEWINDOW)
{
hwnd = GetOleMainThreadWindow(_psfn);
if (!hwnd)
return FALSE;
}
while (MyPeekMessage(&msg, hwnd, uMsgFirst, uMsgLast,
PM_REMOVE | PM_NOYIELD))
{
if (dwFlags & WRM_DISPATCH)
DispatchMessage(&msg);
fRet = TRUE;
}
return fRet;
}
//--------------------------------------------------------------------------
//
// BlockFn
//
//--------------------------------------------------------------------------
HRESULT CModalLoop::BlockFn(CCicEvent *pevent, DWORD dwWaitingThreadId, DWORD &dwWaitFlags)
{
DWORD dwReason;
HRESULT hr = S_FALSE;
//
// if the event is already set, we don't need to wait.
//
dwReason = pevent->EventCheck();
if (dwReason == WAIT_OBJECT_0)
return S_OK;
if (dwReason == WAIT_TIMEOUT)
{
//
// we just check the our target send marshaling message to
// our thread. If so, just handle it.
//
DWORD dwStatus = GetQueueStatus(QS_POSTMESSAGE);
WORD wNew = (WORD)dwStatus | HIWORD(dwStatus);
if (wNew & QS_POSTMESSAGE)
{
//
// handle ThreadMarshaling.
//
if (WaitRemoveMessage(g_msgThreadMarshal,
g_msgThreadMarshal,
WRM_MARSHALWNDDISPATCH))
return S_FALSE;
//
// handle another rpc cal.
//
#ifdef DEBUG
TCHAR _szModule[MAX_PATH];
::GetModuleFileName(NULL, _szModule, sizeof(_szModule)/sizeof(TCHAR));
TraceMsg(TF_EVENT, "%s CModalLoop::BlockFn:: MSUIM.Msg.RpcSendReceive", _szModule);
#endif
if (WaitRemoveMessage(g_msgRpcSendReceive,
g_msgRpcSendReceive,
WRM_MARSHALWNDDISPATCH))
return S_FALSE;
}
dwReason = pevent->MsgWait(500, dwWaitFlags);
}
if (dwReason == WAIT_OBJECT_0)
{
return S_OK;
}
else if (dwReason == WAIT_OBJECT_0 + 1)
{
//
// now we handle only new messages.
//
DWORD dwStatus = GetQueueStatus(dwWaitFlags);
WORD wNew = (WORD)dwStatus | HIWORD(dwStatus);
WaitHandleWndMessages((DWORD)wNew);
//
// need to review this later.
// we want to check the thread was terminated or not.
//
goto CheckThread;
}
else
{
//
// Cic#4516
//
// The target thread seems to be busy. Check the current queue to
// see if we have a message sent. The target thread may be in
// SendMessage() and waiting for the reply of this thread.
//
//
DWORD dwStatus = GetQueueStatus(QS_SENDMESSAGE);
WORD wNew = HIWORD(dwStatus);
if (wNew & QS_SENDMESSAGE)
{
MSG msg;
//
// Maybe PeekMessage is better than ReplyMessage().
//
PeekMessage(&msg, NULL, 0, 0,
((IsOnNT5() || IsOn98()) ? PM_QS_SENDMESSAGE : 0) | PM_NOREMOVE);
}
CheckThread:
if (!g_timlist.IsThreadId(dwWaitingThreadId))
{
TraceMsg(TF_EVENT, "CProxy::SendReceive No Thread");
hr = MAKE_WIN32(RPC_S_SERVER_UNAVAILABLE);
goto Exit;
}
}
Exit:
return hr;
}
//+---------------------------------------------------------------------------
//
// FreeStubs
//
//+---------------------------------------------------------------------------
void FreeMarshaledStubs(SYSTHREAD *psfn)
{
if (psfn->prgStub)
{
int nCnt = psfn->prgStub->Count();
int i = 0;
for (i = 0; i < nCnt; i++)
{
CStub *pStub = psfn->prgStub->Get(i);
pStub->_fNoRemoveInDtor = TRUE;
delete pStub;
}
psfn->prgStub->Clear();
delete psfn->prgStub;
psfn->prgStub = NULL;
}
}
//+---------------------------------------------------------------------------
//
// FreeStubsForThread
//
//+---------------------------------------------------------------------------
void FreeMarshaledStubsForThread(SYSTHREAD *psfn, DWORD dwThread)
{
if (psfn->prgStub)
{
int nCnt = psfn->prgStub->Count();
int i = 0;
for (i = nCnt; i > 0; i--)
{
CStub *pStub = psfn->prgStub->Get(i - 1);
if (!pStub)
continue;
if (pStub->_dwSrcThreadId == dwThread)
delete pStub;
}
}
}
//--------------------------------------------------------------------------
//
// StubCleanUp
//
//--------------------------------------------------------------------------
void StubCleanUp(DWORD dwStubTime, ULONG ulStubId)
{
SYSTHREAD *psfn = GetSYSTHREAD();
CStub *pStub;
int nRemove;
if (psfn == NULL)
return;
// Assert(psfn->prgStub);
if (!psfn->prgStub)
return;
dbg_CheckStubIds(psfn);
nRemove = FindStub(psfn->prgStub, ulStubId);
if (nRemove == -1)
return;
pStub = psfn->prgStub->Get(nRemove);
//
// check stub created time.
//
// Requested Stub ID seems to be destroyed long time ago and
// newer stub is using same ID.
//
if (pStub->_dwStubTime != dwStubTime)
return;
psfn->prgStub->Remove(nRemove, 1);
delete pStub;
}
//+---------------------------------------------------------------------------
//
// CicMarshalWndProc
//
//+---------------------------------------------------------------------------
LRESULT CALLBACK CicMarshalWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SYSTHREAD *psfn;
if (uMsg == WM_DESTROY)
{
g_timlist.SetMarshalWnd(GetCurrentThreadId(), NULL);
if (psfn = GetSYSTHREAD())
{
Assert(!psfn->hwndMarshal || (psfn->hwndMarshal == hWnd));
psfn->hwndMarshal = NULL;
//
// #507248
//
// need to reset the dirty flag.
//
if (psfn->plbim)
psfn->plbim->ResetDirtyUpdate();
}
}
else if ((uMsg == WM_CLOSE) || (uMsg == WM_QUERYENDSESSION))
{
if (psfn = GetSYSTHREAD())
{
Assert(!psfn->hwndMarshal || (psfn->hwndMarshal == hWnd));
DestroyWindow(hWnd);
psfn->hwndMarshal = NULL;
}
}
else if (uMsg == g_msgNuiMgrDirtyUpdate)
{
goto CallOnUpdateHandler;
}
else if (uMsg == WM_TIMER)
{
if (wParam == MARSHALWND_TIMER_UPDATEKANACAPS)
{
KillTimer(hWnd, MARSHALWND_TIMER_UPDATEKANACAPS);
if (psfn = GetSYSTHREAD())
{
KanaCapsUpdate(psfn);
}
}
else if (wParam == MARSHALWND_TIMER_NUIMGRDIRTYUPDATE)
{
KillTimer(hWnd, MARSHALWND_TIMER_NUIMGRDIRTYUPDATE);
CallOnUpdateHandler:
if (IsCTFMONBusy() || IsInPopupMenuMode())
{
TryOnUpdatehandlerAgain:
SetTimer(hWnd, MARSHALWND_TIMER_NUIMGRDIRTYUPDATE, 100, NULL);
}
else
{
if (psfn = GetSYSTHREAD())
{
if (psfn->plbim)
{
if (psfn->plbim->IsInOnUpdateHandler())
goto TryOnUpdatehandlerAgain;
psfn->plbim->OnUpdateHandler();
}
}
}
}
else if (wParam == MARSHALWND_TIMER_WAITFORINPUTIDLEFORSETFOCUS)
{
KillTimer(hWnd, MARSHALWND_TIMER_WAITFORINPUTIDLEFORSETFOCUS);
PostThreadMessage(GetCurrentThreadId(), g_msgSetFocus, 0, 0);
}
}
else if (uMsg == g_msgRpcSendReceive)
{
HandleSendReceiveMsg((ULONG)wParam, (ULONG)lParam);
}
#ifdef POINTER_MARSHAL
else if (uMsg == g_msgPointerMarshal)
{
switch (LOWORD(wParam))
{
case MP_MARSHALINTERFACE:
PointerMarshalInterfaceHandler(lParam);
break;
case MP_UNMARSHALINTERFACEERROR:
PointerUnMarshalInterfaceErrorHandler(lParam);
break;
}
}
#endif
else if (uMsg == g_msgThreadMarshal)
{
switch (LOWORD(wParam))
{
case MP_MARSHALINTERFACE:
ThreadMarshalInterfaceHandler((int)lParam);
break;
case MP_UNMARSHALINTERFACEERROR:
ThreadUnMarshalInterfaceErrorHandler((int)lParam);
break;
}
}
else if (uMsg == g_msgStubCleanUp)
{
StubCleanUp((DWORD)wParam, (ULONG)lParam);
}
else if (uMsg == g_msgCheckThreadInputIdel)
{
DWORD dwThreadId = GetCurrentThreadId();
CCheckThreadInputIdle event(dwThreadId, (DWORD)lParam);
if (event.Open())
event.Set();
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
ATOM g_atomMarshalClass = 0;
//+---------------------------------------------------------------------------
//
// EnsureMarshalWnd
//
//+---------------------------------------------------------------------------
HWND EnsureMarshalWnd()
{
SYSTHREAD *psfn;
if ((psfn = GetSYSTHREAD()) == NULL)
return NULL;
if (!EnsureTIMList(psfn))
return NULL;
if (IsWindow(psfn->hwndMarshal))
{
if (psfn->hwndMarshal != g_timlist.GetMarshalWnd(psfn->dwThreadId))
{
g_timlist.SetMarshalWnd(psfn->dwThreadId, psfn->hwndMarshal);
}
return psfn->hwndMarshal;
}
//
// we can not support marshaling after process detach.
//
if (g_fDllProcessDetached)
return NULL;
//
// Win98 has a bug in FindWindow() with HWND_MESSAGE, so we need to have
// unique windiw text for each thread.
//
char sz[MAX_PATH];
if (!SetName(sz, ARRAYSIZE(sz), c_szCicMarshalWnd, GetCurrentThreadId()))
return NULL;
//
// We want to hide this window from EnumWindow() API.
// So we use HWND_MESSAGE for Win98 and NT5.
//
// For Beta.
//
// Under NT4, we destroy every time the popup window is destroyed in
// WndProcHook. However we should
//
psfn->hwndMarshal = CreateWindowEx(0,
c_szCicMarshalClass,
sz,
WS_DISABLED | WS_POPUP,
0,
0,
0,
0,
IsOn98orNT5() ? HWND_MESSAGE : NULL,
0,
g_hInst,
0);
g_timlist.SetMarshalWnd(psfn->dwThreadId, psfn->hwndMarshal);
Assert(psfn->hwndMarshal);
return psfn->hwndMarshal;
}
//+---------------------------------------------------------------------------
//
// RegisterMarshalWndClass
//
//+---------------------------------------------------------------------------
void RegisterMarshalWndClass()
{
WNDCLASSEX wndclass;
memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.hInstance = g_hInst;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.lpfnWndProc = CicMarshalWndProc;
wndclass.lpszClassName = c_szCicMarshalClass;
g_atomMarshalClass = RegisterClassEx(&wndclass);
}
//////////////////////////////////////////////////////////////////////////////
//
// CThreadMarshalWnd
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CThreadMarshalWnd::CThreadMarshalWnd()
{
_dwThreadId = 0;
_hwnd = 0;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CThreadMarshalWnd::~CThreadMarshalWnd()
{
}
//--------------------------------------------------------------------------
//
// Init
//
//--------------------------------------------------------------------------
BOOL CThreadMarshalWnd::Init(DWORD dwThreadId)
{
HWND hwndTemp = NULL;
_dwThreadId = dwThreadId;
//
// clear _hwnd out first.
//
_hwnd = NULL;
if (hwndTemp = GetThreadMarshalWnd(dwThreadId))
{
if (GetWindowThreadProcessId(hwndTemp, NULL) == dwThreadId)
{
_hwnd = hwndTemp;
}
}
return _hwnd ? TRUE : FALSE;
}
//+---------------------------------------------------------------------------
//
// PostMarshalThreadMessage
//
//+---------------------------------------------------------------------------
BOOL CThreadMarshalWnd::PostMarshalThreadMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Assert(g_atomMarshalClass);
if (!_hwnd || !IsWindow())
{
//
// Was the window destroyed?
//
TraceMsg(TF_GENERAL, "CThreadmarshalWnd::PostMarshalThreadMessage marshal window could not be found");
return FALSE;
}
#ifdef DEBUG
TCHAR _szModule[MAX_PATH];
::GetModuleFileName(NULL, _szModule, sizeof(_szModule)/sizeof(TCHAR));
TraceMsg(TF_EVENT, "%s CThreadMarshalWnd::PostMarshalThreadMessage hWnd - %x uMsg - %x wParam - %x lParam - %x", _szModule, _hwnd, uMsg, wParam, lParam);
#endif
return PostMessage(_hwnd, uMsg, wParam, lParam);
}
//--------------------------------------------------------------------------
//
// DestroyAll
//
//--------------------------------------------------------------------------
BOOL CThreadMarshalWnd::DestroyAll()
{
ULONG ulNum;
SYSTHREAD *psfn = GetSYSTHREAD();
if (!psfn)
return FALSE;
EnsureTIMList(psfn);
ulNum = g_timlist.GetNum();
if (ulNum)
{
DWORD *pdw = new DWORD[ulNum + 1];
if (pdw)
{
if (g_timlist.GetList(pdw, ulNum+1, &ulNum, 0, 0, FALSE))
{
ULONG ul;
for (ul = 0; ul < ulNum; ul++)
{
if (pdw[ul])
DestroyThreadMarshalWnd(pdw[ul]);
}
}
delete [] pdw;
}
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// DestroyThreadMarshalWnd
//
//+---------------------------------------------------------------------------
BOOL CThreadMarshalWnd::DestroyThreadMarshalWnd(DWORD dwThread)
{
HWND hwndTemp;
if (hwndTemp = GetThreadMarshalWnd(dwThread))
{
//
// #425375.
//
// SendMessageTimeout() makes shut-down slower.
// instead, we use SendNotifyMessage() and this is safer since
// the queue of the thread does not miss WM_CLOSE message for the
// window.
//
SendNotifyMessage(hwndTemp, WM_CLOSE, 0, 0);
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// ClearMarshalWndProc
//
//+---------------------------------------------------------------------------
void CThreadMarshalWnd::ClearMarshalWndProc(DWORD dwProcessId)
{
ULONG ulNum;
if (!g_timlist.IsInitialized())
return;
ulNum = g_timlist.GetNum();
//
// MSCTF.DLL will be unloaded so we may need to make all existing marshal
// windows in the current process a ghost. We wanted to destroy them
// but we missed a chance to destroy them.
//
// It may be ok to call DestroyWindow() in process detach since
// it is known window. But making them a ghost seems to be safer.
//
if (ulNum)
{
DWORD *pdw = new DWORD[ulNum + 1];
if (pdw)
{
if (g_timlist.GetListInProcess(pdw, &ulNum, dwProcessId))
{
ULONG ul;
for (ul = 0; ul < ulNum; ul++)
{
if (pdw[ul])
{
HWND hwnd = GetThreadMarshalWnd(pdw[ul]);
if (hwnd)
{
SetWindowLongPtr(hwnd,
GWLP_WNDPROC,
(LONG_PTR)DefWindowProc);
}
}
}
}
delete [] pdw;
}
}
}
//+---------------------------------------------------------------------------
//
// GetThreadMarshalWnd
//
//+---------------------------------------------------------------------------
HWND CThreadMarshalWnd::GetThreadMarshalWnd(DWORD dwThread)
{
HWND hwnd = g_timlist.GetMarshalWnd(dwThread);
if (::IsWindow(hwnd))
{
if (dwThread == GetWindowThreadProcessId(hwnd, NULL))
{
ATOM atomClass = (ATOM)GetClassLongPtr(hwnd, GCW_ATOM);
if (g_atomMarshalClass == atomClass)
return hwnd;
}
g_timlist.SetMarshalWnd(dwThread, NULL);
}
return NULL;
}
//+---------------------------------------------------------------------------
//
// EnumThreadWndProc
//
//+---------------------------------------------------------------------------
BOOL CThreadMarshalWnd::EnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
*(BOOL *)lParam = TRUE;
return FALSE;
}
//+---------------------------------------------------------------------------
//
// IsThreadWindow
//
//+---------------------------------------------------------------------------
BOOL CThreadMarshalWnd::IsThreadWindow()
{
BOOL fFound = FALSE;
EnumThreadWindows(_dwThreadId,
EnumThreadWndProc,
(LPARAM)&fFound);
return fFound;
}
//////////////////////////////////////////////////////////////////////////////
//
// CProxy
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CProxy::CProxy(SYSTHREAD *psfn) : CSysThreadRef(psfn)
{
_ulProxyId = 0;
_ulStubId = (ULONG)(-1);
_dwStubThreadId = 0;
_dwSrcThreadId = 0;
_dwSrcProcessId = 0;
_cRef = 1;
#ifdef DEBUG
_fInLoop = FALSE;
#endif
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CProxy::~CProxy()
{
#ifdef DEBUG
Assert(!_fInLoop);
#endif
if (g_timlist.IsThreadId(_dwStubThreadId))
_tmw.PostMarshalThreadMessage(g_msgStubCleanUp, _dwStubTime, _ulStubId);
}
ULONG CProxy::InternalAddRef()
{
_cRef++;
return _cRef;
}
ULONG CProxy::InternalRelease()
{
_cRef--;
if (!_cRef)
{
delete this;
return 0;
}
return _cRef;
}
//--------------------------------------------------------------------------
//
// Init
//
//--------------------------------------------------------------------------
void CProxy::Init(REFIID riid, ULONG ulProxyId, ULONG ulStubId, DWORD dwStubTime, DWORD dwStubThreadId, DWORD dwCurThreadId, DWORD dwCurProcessId)
{
_iid = riid;
_ulProxyId = ulProxyId;
_ulStubId = ulStubId;
_dwStubTime = dwStubTime;
_dwStubThreadId = dwStubThreadId;
_dwSrcThreadId = dwCurThreadId;
_dwSrcProcessId = dwCurProcessId;
_tmw.Init(_dwStubThreadId);
}
//--------------------------------------------------------------------------
//
// SendReceive
//
//--------------------------------------------------------------------------
HRESULT CProxy::SendReceive(MARSHALMSG *pMsg, ULONG ulBlockId)
{
HRESULT hr = E_FAIL;
CCicTimer timer(MARSHALTIMEOUT, FALSE);
DWORD dwWaitFlags;
DWORD dwThreadId = _dwStubThreadId;
CModalLoop modalloop(_psfn);
DWORD dwSrcThreadId;
TL_THREADINFO *pti;
DWORD dwPrevWaitingThread;
CCicSecAttr sa;
#ifdef DEBUG
TCHAR _szModule[MAX_PATH];
::GetModuleFileName(NULL, _szModule, sizeof(_szModule)/sizeof(TCHAR));
TraceMsg(TF_EVENT, "%s CProxy::SendReceive Start _ThreadId - %x _uStubId - %x, msg size - %x", _szModule, _dwStubThreadId, _ulStubId, pMsg->cbSize);
#endif
pti = g_timlist.IsThreadId(_dwStubThreadId);
if (!pti)
{
TraceMsg(TF_EVENT, "CProxy::SendReceive Invalid ThreadId %x", _dwStubThreadId);
return E_FAIL;
}
Assert(pti->dwThreadId == _dwStubThreadId);
if (pti->dwFlags & TLF_INSFW)
{
TraceMsg(TF_EVENT, "CProxy::SendReceive Thread is in SetForegroundWindow %08x", _dwStubThreadId);
return E_FAIL;
}
//
// for Win9x, we can identify the event and shared block by ulBlockId.
//
if (IsOnNT())
dwSrcThreadId = pMsg->dwSrcThreadId;
else
dwSrcThreadId = WIN9X_SRCTHREADID;
//
// Event for marshaling
//
CSendReceiveEvent event(dwSrcThreadId, ulBlockId);
if (!event.Create(sa))
return E_FAIL;
CSendReceiveConnectionEvent eventc(dwSrcThreadId, ulBlockId);
BOOL fSendReceiveConnection = FALSE;
if (!eventc.Create(sa))
return E_FAIL;
// Win98 QS_EVENT hack.
// Win98's Event QueueItem could cause inter thread sendmessage
// We want to clean up Event QueueItem before Marshaling happens.
//
// because CTFMON.EXE may call AttatchThreadInput() and this event
// could be handled in CTFMON's thread and this make the event queue item
// to do inter thread SendMessage.
//
if (!IsOnNT())
{
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
}
//
// save previous waiting thread.
//
if (_psfn->pti)
{
dwPrevWaitingThread = _psfn->pti->dwMarshalWaitingThread;
_psfn->pti->dwMarshalWaitingThread = _dwStubThreadId;
}
//
// update marshal window handle from PTI.
// the window handle in _tmw may be destroyed on NT4.
//
_tmw.SetMarshalWindow(pti->hwndMarshal);
if (!_tmw.PostMarshalThreadMessage(g_msgRpcSendReceive,
dwSrcThreadId,
ulBlockId))
{
TraceMsg(TF_EVENT, "CProxy::SendReceive PostThreadMessage failed");
goto Exit;
}
#ifdef DEBUG
_fInLoop = TRUE;
#endif
timer.Start();
dwWaitFlags = QS_DEFAULTWAITFLAG;
while (!timer.IsTimerAtZero())
{
if (!fSendReceiveConnection &&
timer.IsTimerPass(DEFAULTMARSHALCONNECTIONTIMEOUT))
{
DWORD dwReason = eventc.EventCheck();
if (dwReason != WAIT_OBJECT_0)
{
hr = E_FAIL;
break;
}
fSendReceiveConnection = TRUE;
}
hr = modalloop.BlockFn(&event, dwThreadId, dwWaitFlags);
if (hr == S_OK)
goto EventOK;
if (FAILED(hr))
break;
if (!_tmw.IsWindow())
{
hr = E_FAIL;
break;
}
if (!_tmw.IsThreadWindow())
{
CThreadMarshalWnd::DestroyThreadMarshalWnd(_dwStubThreadId);
hr = E_FAIL;
break;
}
}
#ifdef DEBUG
TraceMsg(TF_EVENT, "%s CProxy::SendReceive Time Out", _szModule);
#endif
goto Exit;
EventOK:
#ifdef DEBUG
TraceMsg(TF_EVENT, "%s CProxy::SendReceive OK", _szModule);
#endif
hr = S_OK;
Exit:
#ifdef DEBUG
_fInLoop = FALSE;
#endif
//
// restore previous waiting thread.
//
if (_psfn->pti)
_psfn->pti->dwMarshalWaitingThread = dwPrevWaitingThread;
return hr;
}
//--------------------------------------------------------------------------
//
// proxy_Param
//
//--------------------------------------------------------------------------
HRESULT CProxy::proxy_Param(ULONG ulMethodId, ULONG ulParamNum, CPROXY_PARAM *pProxyParam)
{
HRESULT hr = E_FAIL;
ULONG i;
MARSHALMSG *pMsgMap = NULL;
ULONG cbBufSize;
CMarshalParamCreator cparam;
ULONG ulBlockId;
HRESULT hrMarshalOutParam = S_OK;
ULONG cbPadMemSize = 0;
CSharedHeap *psheap = EnsureSharedHeap(_psfn);
if (!psheap)
return hr;
InternalAddRef();
TryAgain:
cbBufSize = sizeof(MARSHALMSG) + ulParamNum * sizeof(MARSHALPARAM);
LENGTH_ALIGN(cbBufSize, CIC_ALIGNMENT);
cbBufSize += cbPadMemSize;
LENGTH_ALIGN(cbBufSize, CIC_ALIGNMENT);
for (i = 0; i < ulParamNum; i++)
{
ULONG cbUnitSize = sizeof(ULONG_PTR);
LENGTH_ALIGN(cbUnitSize, CIC_ALIGNMENT);
if (pProxyParam[i].dwFlags & MPARAM_INTERFACE)
cbUnitSize += sizeof(MARSHALINTERFACEPARAM);
else if (pProxyParam[i].dwFlags & MPARAM_HICON)
{
if (!(pProxyParam[i].dwFlags & MPARAM_IN))
{
cbUnitSize += 0x2000;
}
else
{
Assert(pProxyParam[i].ulCount == 1);
HICON *picon = (HICON *)pProxyParam[i].pv;
cbUnitSize += Cic_HICON_UserSize(picon);
}
}
else if (pProxyParam[i].dwFlags & MPARAM_HBITMAP)
{
if (!(pProxyParam[i].dwFlags & MPARAM_IN))
{
cbUnitSize += 0x1000;
}
else
{
Assert(pProxyParam[i].ulCount == 1);
HBITMAP *pbmp = (HBITMAP *)pProxyParam[i].pv;
cbUnitSize += Cic_HBITMAP_UserSize(pbmp);
}
}
else if (pProxyParam[i].dwFlags & MPARAM_BSTR)
cbUnitSize += 0x1000;
// else if (pProxyParam[i].dwFlags & MPARAM_POINTER)
// cbUnitSize += 0x1000;
else if (pProxyParam[i].dwFlags & MPARAM_TF_LBBALLOONINFO)
cbUnitSize += 0x1000;
else
cbUnitSize += pProxyParam[i].cbUnitSize;
LENGTH_ALIGN(cbUnitSize, CIC_ALIGNMENT);
cbBufSize += (cbUnitSize * pProxyParam[i].ulCount);
LENGTH_ALIGN(cbBufSize, CIC_ALIGNMENT);
}
if (!psheap->GetBlock()->GetMutex()->Enter())
{
hr = E_FAIL;
goto Exit;
}
pMsgMap = (MARSHALMSG *)psheap->Alloc(cbBufSize);
if (!pMsgMap)
{
hr = E_OUTOFMEMORY;
goto FinishParamCreation;
}
ulBlockId = psheap->GetBlockId(pMsgMap);
cparam.Set(pMsgMap, cbBufSize);
cparam.Init(_dwSrcThreadId,
_dwSrcProcessId,
_iid,
ulMethodId,
ulParamNum,
_ulStubId,
_dwStubTime);
hr = S_OK;
for (i = 0; i < ulParamNum; i++)
{
if (!(pProxyParam[i].dwFlags & MPARAM_IN))
{
hr = cparam.Add(pProxyParam[i].GetBufSize(),
pProxyParam[i].dwFlags,
NULL);
if (FAILED(hr))
goto FinishParamCreation;
continue;
}
if (pProxyParam[i].dwFlags & MPARAM_INTERFACE)
{
if (pProxyParam[i].ulCount == 1)
{
MARSHALINTERFACEPARAM miparam;
if ((IUnknown **)pProxyParam[i].pv &&
(*(IUnknown **)pProxyParam[i].pv))
{
CicCoMarshalInterface(*pProxyParam[i].piid,
*(IUnknown **)pProxyParam[i].pv,
&miparam.ulStubId,
&miparam.dwStubTime,
_dwStubThreadId);
miparam.fNULLPointer = FALSE;
miparam.fNULLStack = FALSE;
}
else
{
miparam.ulStubId = 0;
miparam.fNULLPointer = TRUE;
if (!(IUnknown **)pProxyParam[i].pv)
miparam.fNULLStack = TRUE;
else
miparam.fNULLStack = FALSE;
}
hr = cparam.Add(sizeof(miparam),
pProxyParam[i].dwFlags,
&miparam);
}
else
{
MARSHALINTERFACEPARAM *pmiparam;
pmiparam = new MARSHALINTERFACEPARAM[pProxyParam[i].ulCount];
if (pmiparam)
{
ULONG ul;
for (ul = 0; ul < pProxyParam[i].ulCount; ul++)
{
IUnknown **ppunk = (IUnknown **)pProxyParam[i].pv;
if (ppunk && ppunk[ul])
{
CicCoMarshalInterface(*pProxyParam[i].piid,
ppunk[ul],
&pmiparam[ul].ulStubId,
&pmiparam[ul].dwStubTime,
_dwStubThreadId);
pmiparam[ul].fNULLPointer = FALSE;
pmiparam[ul].fNULLStack = FALSE;
}
else
{
pmiparam[ul].ulStubId = 0;
pmiparam[ul].fNULLPointer = TRUE;
if (!ppunk)
pmiparam[ul].fNULLStack = TRUE;
else
pmiparam[ul].fNULLStack = FALSE;
}
}
hr = cparam.Add(sizeof(*pmiparam) * pProxyParam[i].ulCount,
pProxyParam[i].dwFlags,
pmiparam);
delete [] pmiparam;
}
}
}
else if (pProxyParam[i].dwFlags & MPARAM_POINTER)
{
hr = cparam.Add(pProxyParam[i].GetBufSize(),
pProxyParam[i].dwFlags,
pProxyParam[i].pv);
}
else if (pProxyParam[i].dwFlags & MPARAM_ULONG)
{
Assert(pProxyParam[i].ulCount == 1);
hr = cparam.Add(pProxyParam[i].cbUnitSize,
pProxyParam[i].dwFlags,
&pProxyParam[i].ul);
}
else if (pProxyParam[i].dwFlags & MPARAM_BSTR)
{
Assert(pProxyParam[i].ulCount == 1);
hr = cparam.Add(pProxyParam[i].cbUnitSize,
pProxyParam[i].dwFlags,
pProxyParam[i].pv);
}
else if (pProxyParam[i].dwFlags & MPARAM_STRUCT)
{
hr = cparam.Add(pProxyParam[i].GetBufSize(),
pProxyParam[i].dwFlags,
pProxyParam[i].pv);
}
else if (pProxyParam[i].dwFlags & MPARAM_HICON)
{
Assert(pProxyParam[i].ulCount == 1);
HICON *picon = (HICON *)pProxyParam[i].pv;
ULONG cbSize = Cic_HICON_UserSize(picon);
BYTE *pBufOrg = NULL;
BYTE *pBuf = NULL;
BYTE *pBufEnd = NULL;
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
pBufEnd = pBuf + cbSize;
}
if (pBuf && Cic_HICON_UserMarshal(pBuf, pBufEnd, picon))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_HICON_UserFree(picon);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else if (pProxyParam[i].dwFlags & MPARAM_HBITMAP)
{
Assert(pProxyParam[i].ulCount == 1);
HBITMAP *pbmp = (HBITMAP *)pProxyParam[i].pv;
ULONG cbSize = Cic_HBITMAP_UserSize(pbmp);
BYTE *pBufOrg = NULL;
BYTE *pBuf = NULL;
BYTE *pBufEnd = NULL;
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
pBufEnd = pBuf + cbSize;
}
if (pBuf && Cic_HBITMAP_UserMarshal(pBuf, pBufEnd, pbmp))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_HBITMAP_UserFree(pbmp);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else if (pProxyParam[i].dwFlags & MPARAM_TF_LBBALLOONINFO)
{
Assert(pProxyParam[i].ulCount == 1);
TF_LBBALLOONINFO *pInfo = (TF_LBBALLOONINFO *)pProxyParam[i].pv;
BYTE *pBufOrg = NULL;
BYTE *pBuf = NULL;
ULONG cbSize = Cic_TF_LBBALLOONINFO_UserSize(pInfo);
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
}
if (pBuf && Cic_TF_LBBALLOONINFO_UserMarshal(pBuf, pInfo))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_TF_LBBALLOONINFO_UserFree(pInfo);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else
{
Assert(0);
hr = E_FAIL;
}
if (FAILED(hr))
{
Assert(0);
goto FinishParamCreation;
}
}
FinishParamCreation:
psheap->GetBlock()->GetMutex()->Leave();
if (FAILED(hr))
{
Assert(0);
goto Exit;
}
hr = cparam.SendReceive(this, ulBlockId);
if (FAILED(hr))
goto Exit;
hrMarshalOutParam = pMsgMap->hrMarshalOutParam;
if (hrMarshalOutParam != S_OK)
{
hr = E_FAIL;
goto Exit;
}
if (!psheap->GetBlock()->GetMutex()->Enter())
{
hr = E_FAIL;
goto Exit;
}
for (i = 0; i < ulParamNum; i++)
{
MARSHALPARAM *pParam;
if (!(pProxyParam[i].dwFlags & MPARAM_OUT))
continue;
if (!pProxyParam[i].pv)
continue;
pParam = cparam.GetMarshalParam(i);
hr = S_OK;
if (pProxyParam[i].dwFlags & MPARAM_POINTER)
{
if (pParam->cbBufSize)
{
memcpy(pProxyParam[i].pv,
ParamToBufferPointer(pParam),
pProxyParam[i].GetBufSize());
}
else
{
memset(pProxyParam[i].pv, 0, pProxyParam[i].GetBufSize());
}
}
else if (pProxyParam[i].dwFlags & MPARAM_INTERFACE)
{
MARSHALMSG *pMsg = cparam.Get();
MARSHALINTERFACEPARAM *pmiparam = (MARSHALINTERFACEPARAM *)ParamToBufferPointer(pParam);
ULONG ul;
IUnknown **ppunk = (IUnknown **)pProxyParam[i].pv;
if (ppunk)
{
for (ul = 0; ul < pProxyParam[i].ulCount; ul++)
{
if (pmiparam->fNULLPointer)
{
*ppunk = NULL;
}
else
{
hr = CicCoUnmarshalInterface(*pProxyParam[i].piid,
pMsg->dwSrcThreadId,
pmiparam->ulStubId,
pmiparam->dwStubTime,
(void **)ppunk);
}
ppunk++;
pmiparam++;
}
}
}
else if (pProxyParam[i].dwFlags & MPARAM_BSTR)
{
Assert(pProxyParam[i].ulCount == 1);
if (pParam->cbBufSize)
{
void *pv = ParamToBufferPointer(pParam);
if ((*(BSTR *)pProxyParam[i].pv = SysAllocString((BSTR)pv)) == NULL)
{
hr = E_OUTOFMEMORY;
}
}
else
{
*(BSTR *)pProxyParam[i].pv = NULL;
}
}
else if (pProxyParam[i].dwFlags & MPARAM_STRUCT)
{
if (pParam->cbBufSize)
{
memcpy(pProxyParam[i].pv,
ParamToBufferPointer(pParam),
pProxyParam[i].GetBufSize());
}
else
{
memset(pProxyParam[i].pv, 0, pProxyParam[i].GetBufSize());
}
}
else if (pProxyParam[i].dwFlags & MPARAM_HICON)
{
Assert(pProxyParam[i].ulCount == 1);
HICON hicon = NULL;
if (pParam->cbBufSize)
{
BYTE *pBuf = (BYTE *)ParamToBufferPointer(pParam);
Cic_HICON_UserUnmarshal(pBuf, &hicon);
}
*(HICON *)pProxyParam[i].pv = hicon;
}
else if (pProxyParam[i].dwFlags & MPARAM_HBITMAP)
{
Assert(pProxyParam[i].ulCount == 1);
HBITMAP hbmp = NULL;
if (pParam->cbBufSize)
{
BYTE *pBuf = (BYTE *)ParamToBufferPointer(pParam);
Cic_HBITMAP_UserUnmarshal(pBuf, &hbmp);
}
*(HBITMAP *)pProxyParam[i].pv = hbmp;
}
else if (pProxyParam[i].dwFlags & MPARAM_TF_LBBALLOONINFO)
{
Assert(pProxyParam[i].ulCount == 1);
if (pParam->cbBufSize)
{
BYTE *pBuf = (BYTE *)ParamToBufferPointer(pParam);
hr = Cic_TF_LBBALLOONINFO_UserUnmarshal(pBuf, (TF_LBBALLOONINFO *)pProxyParam[i].pv);
}
}
else
{
Assert(0);
hr = E_FAIL;
}
if (FAILED(hr))
break;
}
if (SUCCEEDED(hr))
hr = cparam.GetHresult();
psheap->GetBlock()->GetMutex()->Leave();
Exit:
if (pMsgMap)
psheap->Free(pMsgMap);
if ((cbPadMemSize == 0) && (hrMarshalOutParam == E_OUTOFMEMORY))
{
cbPadMemSize = cbBufSize * 2;
cparam.Clear();
goto TryAgain;
}
InternalRelease();
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// CStub
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CStub::CStub()
{
_pfm = NULL;
_fNoRemoveInDtor = FALSE;
_cRef = 1;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CStub::~CStub()
{
//
// #489905
//
// we can not call sink anymore after DLL_PROCESS_DETACH.
//
if (!DllShutdownInProgress())
{
if (_punk && !IsBadReadPtr(_punk, 1))
{
_try {
_punk->Release();
_punk = NULL;
}
_except(1)
{
//
// Tips may not do DllAddRef() for LangBarItems so
// _punk could be bad pointer. We need to have a
// way to clean up CStub.
//
; // TraceMsg(TF_GENERAL, "CStub punk is gone.");
}
}
}
ClearFileMap();
if (_fNoRemoveInDtor)
{
//
// we're in FreeMarshaledStubs() so we don't have to
// remove itself. GetSYSTEMTHREAD() may not work when it is called
// in UninitProcess().
//
return;
}
SYSTHREAD *psfn = GetSYSTHREAD();
Assert(psfn != NULL && psfn->prgStub != NULL);
if (psfn == NULL || psfn->prgStub == NULL)
return;
dbg_CheckStubIds(psfn);
int i;
int nCnt = psfn->prgStub->Count();
for (i = 0; i < nCnt; i++)
{
if (this == psfn->prgStub->Get(i))
{
psfn->prgStub->Remove(i, 1);
break;
}
}
}
//--------------------------------------------------------------------------
//
// _AddRef
//
//--------------------------------------------------------------------------
ULONG CStub::_AddRef()
{
_cRef++;
return _cRef;
}
//--------------------------------------------------------------------------
//
// _Release
//
//--------------------------------------------------------------------------
ULONG CStub::_Release()
{
_cRef--;
if (!_cRef)
{
delete this;
return 0;
}
return _cRef;
}
//--------------------------------------------------------------------------
//
// stub_OutParam
//
//--------------------------------------------------------------------------
HRESULT CStub::stub_OutParam(CStub *_this, MARSHALMSG *pMsg, ULONG ulMethodId, ULONG ulParamNum, CPROXY_PARAM *pProxyParam, CSharedBlock *psb)
{
ULONG i;
HRESULT hr = E_FAIL;
CMarshalParamCreator cparam;
if (!psb->GetMutex()->Enter())
{
Assert(0);
return E_FAIL;
}
if (!CSharedHeap::IsValidBlock(psb, pMsg))
{
Assert(0);
goto Exit;
}
if (!IsEqualIID(pMsg->iid, _this->_iid))
{
Assert(0);
goto Exit;
}
if (pMsg->ulMethodId != ulMethodId)
{
Assert(0);
goto Exit;
}
if (pMsg->ulParamNum != ulParamNum)
{
Assert(0);
goto Exit;
}
if (pMsg->ulStubId != _this->_ulStubId)
{
Assert(0);
goto Exit;
}
if (pMsg->dwStubTime != _this->_dwStubTime)
{
Assert(0);
goto Exit;
}
hr = S_OK;
cparam.Set(pMsg, pMsg->cbBufSize);
cparam.Init(_this->_dwStubThreadId,
_this->_dwStubProcessId,
_this->_iid,
ulMethodId,
ulParamNum,
_this->_ulStubId,
_this->_dwStubTime);
for (i = 0; i < ulParamNum; i++)
{
if (!(pProxyParam[i].dwFlags & MPARAM_OUT))
{
cparam.Add(0, pProxyParam[i].dwFlags, NULL);
continue;
}
if (!pProxyParam[i].pv && !(pProxyParam[i].dwFlags & MPARAM_INTERFACE))
{
cparam.Add(0, pProxyParam[i].dwFlags, NULL);
continue;
}
if (pProxyParam[i].dwFlags & MPARAM_INTERFACE)
{
#if 0
MARSHALINTERFACEPARAM miparam;
if (pProxyParam[i].pv)
{
CicCoMarshalInterface(*pProxyParam[i].piid,
*(IUnknown **)pProxyParam[i].pv,
&miparam.ulStubId,
&miparam.dwStubTime,
_this->_dwSrcThreadId);
miparam.fNULLPointer = FALSE;
}
else
{
miparam.ulStubId = 0;
miparam.fNULLPointer = TRUE;
}
hr = cparam.Add(sizeof(miparam),
pProxyParam[i].dwFlags,
&miparam);
#else
if (pProxyParam[i].ulCount == 1)
{
MARSHALINTERFACEPARAM miparam;
if ((IUnknown **)pProxyParam[i].pv &&
(*(IUnknown **)pProxyParam[i].pv))
{
CicCoMarshalInterface(*pProxyParam[i].piid,
*(IUnknown **)pProxyParam[i].pv,
&miparam.ulStubId,
&miparam.dwStubTime,
_this->_dwSrcThreadId);
miparam.fNULLPointer = FALSE;
miparam.fNULLStack = FALSE;
}
else
{
miparam.ulStubId = 0;
miparam.fNULLPointer = TRUE;
if (!(IUnknown **)pProxyParam[i].pv)
miparam.fNULLStack = TRUE;
else
miparam.fNULLStack = FALSE;
}
hr = cparam.Add(sizeof(miparam),
pProxyParam[i].dwFlags,
&miparam);
}
else
{
MARSHALINTERFACEPARAM *pmiparam;
pmiparam = new MARSHALINTERFACEPARAM[pProxyParam[i].ulCount];
if (pmiparam)
{
ULONG ul;
for (ul = 0; ul < pProxyParam[i].ulCount; ul++)
{
IUnknown **ppunk = (IUnknown **)pProxyParam[i].pv;
if (ppunk && ppunk[ul])
{
CicCoMarshalInterface(*pProxyParam[i].piid,
ppunk[ul],
&pmiparam[ul].ulStubId,
&pmiparam[ul].dwStubTime,
_this->_dwSrcThreadId);
pmiparam[ul].fNULLPointer = FALSE;
pmiparam[ul].fNULLStack = FALSE;
}
else
{
pmiparam[ul].ulStubId = 0;
pmiparam[ul].fNULLPointer = TRUE;
if (!ppunk)
pmiparam[ul].fNULLStack = TRUE;
else
pmiparam[ul].fNULLStack = FALSE;
}
}
hr = cparam.Add(sizeof(*pmiparam) * pProxyParam[i].ulCount,
pProxyParam[i].dwFlags,
pmiparam);
delete [] pmiparam;
}
}
#endif
}
else if (pProxyParam[i].dwFlags & MPARAM_POINTER)
{
hr = cparam.Add(pProxyParam[i].GetBufSize(),
pProxyParam[i].dwFlags,
pProxyParam[i].pv);
}
else if (pProxyParam[i].dwFlags & MPARAM_ULONG)
{
Assert(pProxyParam[i].ulCount == 1);
hr = cparam.Add(pProxyParam[i].cbUnitSize,
pProxyParam[i].dwFlags,
&pProxyParam[i].ul);
}
else if (pProxyParam[i].dwFlags & MPARAM_BSTR)
{
Assert(pProxyParam[i].ulCount == 1);
if (pProxyParam[i].pv)
{
hr = cparam.Add(SysStringByteLen((BSTR)pProxyParam[i].pv) + 2,
pProxyParam[i].dwFlags,
pProxyParam[i].pv);
SysFreeString((BSTR)pProxyParam[i].pv);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
}
else if (pProxyParam[i].dwFlags & MPARAM_HICON)
{
Assert(pProxyParam[i].ulCount == 1);
HICON *picon = (HICON *)pProxyParam[i].pv;
ULONG cbSize = Cic_HICON_UserSize(picon);
BYTE *pBuf = NULL;
BYTE *pBufOrg = NULL;
BYTE *pBufEnd = NULL;
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
pBufEnd = pBuf + cbSize;
}
if (pBuf && Cic_HICON_UserMarshal(pBuf, pBufEnd, picon))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_HICON_UserFree(picon);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else if (pProxyParam[i].dwFlags & MPARAM_HBITMAP)
{
Assert(pProxyParam[i].ulCount == 1);
HBITMAP *pbmp = (HBITMAP *)pProxyParam[i].pv;
ULONG cbSize = Cic_HBITMAP_UserSize(pbmp);
BYTE *pBuf = NULL;
BYTE *pBufOrg = NULL;
BYTE *pBufEnd = NULL;
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
pBufEnd = pBuf + cbSize;
}
if (pBuf && Cic_HBITMAP_UserMarshal(pBuf, pBufEnd, pbmp))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_HBITMAP_UserFree(pbmp);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else if (pProxyParam[i].dwFlags & MPARAM_TF_LBBALLOONINFO)
{
Assert(pProxyParam[i].ulCount == 1);
TF_LBBALLOONINFO *pInfo = (TF_LBBALLOONINFO *)pProxyParam[i].pv;
ULONG cbSize = Cic_TF_LBBALLOONINFO_UserSize(pInfo);
BYTE *pBuf = NULL;
BYTE *pBufOrg = NULL;
if (cbSize)
{
pBufOrg = (BYTE *)cicMemAlloc(cbSize + CIC_ALIGNMENT + 1);
pBuf = pBufOrg;
POINTER_ALIGN( pBuf, CIC_ALIGNMENT);
}
if (pBuf && Cic_TF_LBBALLOONINFO_UserMarshal(pBuf, pInfo))
{
hr = cparam.Add(cbSize,
pProxyParam[i].dwFlags,
pBuf);
Cic_TF_LBBALLOONINFO_UserFree(pInfo);
}
else
{
hr = cparam.Add(0,
pProxyParam[i].dwFlags,
NULL);
}
if (pBufOrg)
cicMemFree(pBufOrg);
}
else
Assert(0);
if (hr != S_OK)
{
break;
}
}
Exit:
pMsg->hrMarshalOutParam = hr;
psb->GetMutex()->Leave();
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// TF_CCheckThreadInputIdle
//
//////////////////////////////////////////////////////////////////////////////
extern "C" DWORD WINAPI TF_CheckThreadInputIdle(DWORD dwThreadId, DWORD dwTimeOut)
{
if (dwThreadId == GetCurrentThreadId())
return 0;
HWND hwndTemp = CThreadMarshalWnd::GetThreadMarshalWnd(dwThreadId);
if (!hwndTemp)
{
return WAIT_FAILED;
}
DWORD dwTime = GetTickCount();
CCheckThreadInputIdle event(dwThreadId, dwTime);
CCicSecAttr sa;
if (!event.Create(sa))
{
Assert(0);
return WAIT_FAILED;
}
PostMessage(hwndTemp, g_msgCheckThreadInputIdel, 0, (LPARAM)dwTime);
DWORD dwReason = event.EventCheck();
if (dwReason == WAIT_OBJECT_0)
return 0;
if (event.Wait(dwTimeOut))
return 0;
return WAIT_TIMEOUT;
}