// // 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 *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; 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; }