//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: Hndlrmsg.cpp // // Contents: Takes care of handler specific messages // // Classes: CHndlrMsg // // Notes: // // History: 05-Nov-97 rogerg Created. // //-------------------------------------------------------------------------- #include "precomp.h" //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::CHndlrMsg, public // // Synopsis: Constructor // // Arguments: // // Returns: // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- CHndlrMsg::CHndlrMsg() { m_pOneStopHandler = NULL; m_pOldOneStopHandler = NULL; m_dwSyncFlags = 0; m_pCallBack = NULL; m_cRef = 1; m_fDead = FALSE; m_fForceKilled = FALSE; m_dwNestCount = 0; m_fThreadInputAttached = FALSE; m_itemIDShowProperties = GUID_NULL; m_dwProxyThreadId = -1; m_dwThreadId = GetCurrentThreadId(); } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::~CHndlrMsg, public // // Synopsis: Destructor // // Arguments: // // Returns: // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- CHndlrMsg::~CHndlrMsg() { Assert(m_dwThreadId == GetCurrentThreadId() || m_fForceKilled); Assert(0 == m_dwNestCount || m_fForceKilled); Assert(0 == m_cRef || m_fForceKilled); } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::QueryInterface, public // // Synopsis: Standard QueryInterface // // Arguments: [iid] - Interface ID // [ppvObj] - Object return // // Returns: Appropriate status code // // Modifies: [ppvObj] // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::QueryInterface(REFIID riid, LPVOID FAR *ppv) { Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::AddRef, public // // Synopsis: Add reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CHndlrMsg::AddRef() { ULONG cRefs; Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); m_dwNestCount++; cRefs = InterlockedIncrement((LONG *)& m_cRef); m_dwNestCount--; return cRefs; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::Release, public // // Synopsis: Release reference // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CHndlrMsg::Release() { ULONG cRefs; Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); m_dwNestCount++; cRefs = InterlockedDecrement( (LONG *) &m_cRef); if (0 == cRefs) { if (m_pCallBack) { SetupCallback(FALSE); } Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler) { LPSYNCMGRSYNCHRONIZE OneStopHandler = m_pOneStopHandler; m_pOneStopHandler = NULL; // if have a callback then revoke it // CODE REVIEW : NOTENOTE : // This is a valid use of try/except, but this would mask real refcounting errors in the handler callbacks, // or elsewhere in our code where m_pOneStopHandler was overwritten.. __try { OneStopHandler->Release(); } __except(QueryHandleException()) { AssertSz(0,"Exception in Handler's release method."); } } if (m_pOldOneStopHandler) { LPOLDSYNCMGRSYNCHRONIZE pOldOneStopHandler = m_pOldOneStopHandler; m_pOldOneStopHandler = NULL; // if have a callback then revoke it __try { pOldOneStopHandler->Release(); } __except(QueryHandleException()) { AssertSz(0,"Exception in Handler's release method."); } } if (m_pHndlrQueue) { m_pHndlrQueue->Release(); m_pHndlrQueue = NULL; } m_fDead = TRUE; m_dwNestCount--; delete this; } else { m_dwNestCount--; } return cRefs; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::Initialize, public // // Synopsis: Calls Initialize method of the Handler // // Arguments: [dwReserved] - Reserved for now is NULL // [dwSyncFlags] - SyncFlags // [cbCookie] - Size of Cookie data if any // [lpCookie] - Pointer to Cookie data // // Returns: Whatever the handler tells us too. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::Initialize(DWORD dwReserved, DWORD dwSyncFlags, DWORD cbCookie, BYTE const* lpCookie) { HRESULT hr = E_UNEXPECTED; Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); m_dwNestCount++; m_dwSyncFlags = dwSyncFlags; Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler) { // CODE REVIEW : NOTENOTE: // QueryHandleException() catches all exceptions - do we want to limit out exception handling code ? __try { hr = m_pOneStopHandler->Initialize(dwReserved,dwSyncFlags,cbCookie,lpCookie); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's Initialize method."); } } if (m_pOldOneStopHandler) { // old handlers can't handle cookie data unless it is their own if (SYNCMGRFLAG_INVOKE != (dwSyncFlags & SYNCMGRFLAG_EVENTMASK)) { cbCookie = 0; lpCookie = NULL; } __try { hr = m_pOldOneStopHandler->Initialize(dwReserved,dwSyncFlags,cbCookie,lpCookie); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's Initialize method."); } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::GetHandlerInfo, public // // Synopsis: Calls GetHandlerInfo method of the Handler // // Arguments: [ppSyncMgrHandlerInfo] - // // Returns: Whatever the handler tells us too. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::GetHandlerInfo(LPSYNCMGRHANDLERINFO *ppSyncMgrHandlerInfo) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->GetHandlerInfo(ppSyncMgrHandlerInfo); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's GetHandlerInfo method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->GetHandlerInfo(ppSyncMgrHandlerInfo); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's GetHandlerInfo method."); } } return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::EnumOfflineItems, public // // Synopsis: PlaceHolder for IOfflineSynchronize Enum method. // This shouldn't be called. AddHandlerItems should be // called instead // // Arguments: [ppenumOfflineItems] - returned enumerator // // Returns: Whatever the handler tells us too. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::EnumSyncMgrItems(ISyncMgrEnumItems** ppenumOffineItems) { Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); m_dwNestCount++; AssertSz(0,"Shouldn't call this Method"); *ppenumOffineItems = NULL; m_dwNestCount--; return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::GetItemObject, public // // Synopsis: Calls Handler's GetItemObject method // // Arguments: [ItemID] - Id of the item // [riid] - requested interface // [ppv] - out pointer for object // // Returns: Whatever the handler tells us too. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::GetItemObject(REFSYNCMGRITEMID ItemID, REFIID riid, void** ppv) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(0 == m_dwNestCount); m_dwNestCount++; Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); // CODE REVIEW: NOTENOTE // MSDN documents that this GetItemObject method is for future use, and that no client // should be implementing it. Notice the ASSERT below if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->GetItemObject(ItemID,riid,ppv); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's GetItemObject method."); } Assert(E_NOTIMPL == hr); // currently no one should be implementing this. } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->GetItemObject(ItemID,riid,ppv); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's GetItemObject method."); } Assert(E_NOTIMPL == hr); // currently noone should be implementing this. } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::ShowProperties, public // // Synopsis: Calls Handler's ShowProperties method // // Arguments: [hwnd] - hwnd to use as parent to dialog // [itemID] - Identifies the Item // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::ShowProperties(HWND hwnd,REFSYNCMGRITEMID ItemID) { HRESULT hr = E_UNEXPECTED; Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); // need to setup calback if showProperties is called // if can't setup callback then fail the ShowProperties call. // Review, ShowPropertiesCompleted doesn't give us the ItemID back so we // have to store it. This is fine but limits us to one ShowPropertiesCall // at a time on the handler. if update main interfaces change // ShowPropertiesCompleted to return the ItemID Assert(GUID_NULL == m_itemIDShowProperties); m_itemIDShowProperties = ItemID; hr = SetupCallback(TRUE); // set up the callback. if (S_OK != hr) return hr; Assert(0 == m_dwNestCount); m_dwNestCount++; Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); AttachThreadInput(TRUE); if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->ShowProperties(hwnd,ItemID); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's ShowProperties method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->ShowProperties(hwnd,ItemID); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's ShowProperties method."); } } m_dwNestCount--; // if old interface need to make the callback ourselves if ( m_pOldOneStopHandler ) { Assert(m_pCallBack); if (m_pCallBack && (S_OK == hr)) { m_pCallBack->ShowPropertiesCompleted(S_OK); } } // if an error is returned set the showProperties guid back if (S_OK != hr) { m_itemIDShowProperties = GUID_NULL; } return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::SetProgressCallback, public // // Synopsis: PlaceHolder for SetProgressCallback. This member is currently // not used. Instead the SetupCallback method is called // // Arguments: [lpCallBack] - Pointer to Callback object // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::SetProgressCallback(ISyncMgrSynchronizeCallback *lpCallBack) { Assert(m_dwThreadId == GetCurrentThreadId()); Assert(0 == m_dwNestCount); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); m_dwNestCount++; AssertSz(0,"Shouldn't call this method"); m_dwNestCount--; return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::PrepareForSync, public // // Synopsis: Calls Handler's ShowProperties method // // Arguments: [cbNumItems] - number of items so sync // [pItemIDs] - Array of Items // [hwnd] - Hwnd to use as the Parent of any dialogs // [dwReserved] - Just a reserved parameter // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::PrepareForSync(ULONG cbNumItems,SYNCMGRITEMID *pItemIDs, HWND hwnd,DWORD dwReserved) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); // Assert(0 == m_dwNestCount);// may not be zero if handler has yielded hr = SetupCallback(TRUE); // set up the callback. if (S_OK != hr) return hr; m_dwNestCount++; Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->PrepareForSync(cbNumItems,pItemIDs,hwnd,dwReserved); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's PrepareForSync method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->PrepareForSync(cbNumItems,pItemIDs,hwnd,dwReserved); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's PrepareForSync method."); } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::Sychronize, public // // Synopsis: Calls Handler's Synchronize method // // Arguments: [hwnd] - hwnd to use as parent to dialog // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::Synchronize(HWND hwnd) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); // Assert(0 == m_dwNestCount); m_dwNestCount++; if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->Synchronize(hwnd); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's Synchronize method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->Synchronize(hwnd); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's Synchronize method."); } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::SetItemStatus, public // // Synopsis: Calls Handler's SetItemStatus method // // Arguments: // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::SetItemStatus(REFSYNCMGRITEMID ItemID,DWORD dwSyncMgrStatus) { HRESULT hr = S_OK; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); m_dwNestCount++; // valid for this to come in when in sync call. if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->SetItemStatus(ItemID,dwSyncMgrStatus); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's SetItemStatus method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->SetItemStatus(ItemID,dwSyncMgrStatus); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's SetItemStatus method."); } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::ShowError, public // // Synopsis: Calls Handler's ShowError method // // Arguments: [hwnd] - hwnd to use as parent to dialog // [dwErrorID] - ErrorID passed in LogError // // Returns: Whatever the handler tells us. // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::ShowError(HWND hWndParent,REFSYNCMGRERRORID ErrorID) { HRESULT hr = E_UNEXPECTED; ULONG cbNumItems; SYNCMGRITEMID *pItemIDs; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); m_dwNestCount++; // on a ShowError enablemodeless in the callback can // return true since user has shown an interest if (m_pCallBack) { m_pCallBack->SetEnableModeless(TRUE); } AttachThreadInput(TRUE); if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->ShowError(hWndParent,ErrorID); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's ShowError method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->ShowError(hWndParent,ErrorID,&cbNumItems,&pItemIDs); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's ShowError method."); } } m_dwNestCount--; // if old interface need to make the callback ourselves if ( m_pOldOneStopHandler ) { Assert(m_pCallBack); if (m_pCallBack && SUCCEEDED(hr)) { m_pCallBack->ShowErrorCompleted(hr,cbNumItems,pItemIDs); if ( (S_SYNCMGR_RETRYSYNC == hr) && pItemIDs) // after completion routine free the pItems since [in] param. { CoTaskMemFree(pItemIDs); } } return SUCCEEDED(hr) ? S_OK : hr; } // New interface won't have the numItems and Items Enum // on new interface ShowError should only return S_OK so if retry or // other success is returned then return S_OK; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::SetupCallback, private // // Synopsis: Sets up the callback for the handler // // Arguments: [fSet] - TRUE sets the Callbac, FALSE removes it // // Returns: S_OK on Success // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::SetupCallback(BOOL fSet) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_dwNestCount <= 1); // 1 since valid to be called from Release method. m_dwNestCount++; // possible to get called with fSet twice of true in the case // a retrysync occurs. If we already have a callback set // when a new request to set one comes in the just return. if ( m_pCallBack && (TRUE == fSet)) { hr = S_OK; } else { Assert( ( (m_pCallBack) && (FALSE == fSet) ) || (TRUE == fSet)); // catch case OneStop calls this twice when already set if (m_pCallBack) { // set the callbacks CHndlrMsg pointer to NULL in case // object tries to call through after the release. m_pCallBack->SetHndlrMsg(NULL,FALSE); m_pCallBack->Release(); m_pCallBack = NULL; } if (TRUE == fSet) { // if allocation fails, progress just gets set to NULL m_pCallBack = new COfflineSynchronizeCallback( this, m_CLSIDServer,m_dwSyncFlags, (SYNCMGRFLAG_MAYBOTHERUSER & m_dwSyncFlags) /* fAllowModeless */ ); } Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler) { __try { hr = m_pOneStopHandler->SetProgressCallback( (LPSYNCMGRSYNCHRONIZECALLBACK) m_pCallBack ); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's SetProgressCallback method."); } } if (m_pOldOneStopHandler) { __try { hr = m_pOldOneStopHandler->SetProgressCallback( (LPOLDSYNCMGRSYNCHRONIZECALLBACK) m_pCallBack ); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's SetProgressCallback method."); } } if ( (S_OK != hr) && (m_pCallBack) ) { m_pCallBack->SetHndlrMsg(NULL,FALSE); m_pCallBack->Release(); // on an error go ahead and release our copy too. m_pCallBack = NULL; } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::SetHandlerInfo, private // // Synopsis: sets up the Handler info // // Arguments: // // Returns: S_OK on Success // // Modifies: // // History: 28-Jul-98 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::SetHandlerInfo() { LPSYNCMGRHANDLERINFO pSyncMgrHandlerInfo = NULL; HRESULT hr = E_UNEXPECTED; Assert(FALSE == m_fForceKilled && FALSE == m_fDead); hr = GetHandlerInfo(&pSyncMgrHandlerInfo); if (S_OK != hr || (NULL == pSyncMgrHandlerInfo)) { return hr; } if (!IsValidSyncMgrHandlerInfo(pSyncMgrHandlerInfo)) { CoTaskMemFree(pSyncMgrHandlerInfo); return E_INVALIDARG; } Assert(m_pHndlrQueue); if (m_pHndlrQueue) { hr = m_pHndlrQueue->SetHandlerInfo(m_pHandlerId,pSyncMgrHandlerInfo); } if (pSyncMgrHandlerInfo) { CoTaskMemFree(pSyncMgrHandlerInfo); } return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::AddtoItemList, private // // Synopsis: Adds a single Items to the queue // // Arguments: [poffItem] - Pointer to Item to add // // Returns: S_OK on Success // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- HRESULT CHndlrMsg::AddToItemList(LPSYNCMGRITEM poffItem) { HRESULT hr = E_UNEXPECTED; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(m_pHndlrQueue); if (!IsValidSyncMgrItem(poffItem)) { return E_INVALIDARG; } if (m_pHndlrQueue) { hr = m_pHndlrQueue->AddItemToHandler(m_pHandlerId,poffItem); } return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::AddHandlerItems, private // // Synopsis: Calls the handlers enumerator and adds each returned item // to the queue // // Arguments: [hwndList] - hwnd of ListView to add items too. (Not Used) // // Returns: Appropriate status code // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::AddHandlerItems(HWND hwndList, DWORD *pcbNumItems) { HRESULT hr = E_UNEXPECTED; LPSYNCMGRENUMITEMS pEnumOffline = NULL; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(pcbNumItems); *pcbNumItems = 0; Assert(0 == m_dwNestCount); m_dwNestCount++; SetHandlerInfo(); // setup the toplevel handler info Assert(m_pOneStopHandler || m_pOldOneStopHandler); Assert( !(m_pOneStopHandler && m_pOldOneStopHandler) ); if (m_pOneStopHandler || m_pOldOneStopHandler) { if ( m_pOneStopHandler ) { __try { hr = m_pOneStopHandler->EnumSyncMgrItems(&pEnumOffline); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's EnumSyncMgrItems method."); } } if ( m_pOldOneStopHandler ) { __try { hr = m_pOldOneStopHandler->EnumSyncMgrItems(&pEnumOffline); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's EnumSyncMgrItems method."); } } // Review - Make sure preferences aren't deleted // in missing items case. if ( (S_OK == hr || S_SYNCMGR_MISSINGITEMS == hr) && pEnumOffline) { SYNCMGRITEMNT5B2 offItem; // temporarily use NT5B2 structure since its bigger ULONG pceltFetched; Assert(sizeof(SYNCMGRITEMNT5B2) > sizeof(SYNCMGRITEM)); // sit in loop getting data of objects to fill list box. // should really set up list in memory for OneStop to fill in or // main thread could pass in a callback interface. if (pEnumOffline) { __try { while(S_OK == pEnumOffline->Next(1,(LPSYNCMGRITEM) &offItem,&pceltFetched)) { if (S_OK == AddToItemList((LPSYNCMGRITEM) &offItem)) { ++(*pcbNumItems); } } pEnumOffline->Release(); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's EnumOffline::Next method."); } } else { hr = E_UNEXPECTED; } } } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::CreateServer, private // // Synopsis: Creates and Instance of the handle // // Arguments: [pCLSIDServer] - CLSID of Handler // [pHndlrQueue] - pointer to queue handler should be added too // [wHandlerID] - ID of Handler in the queue // // Returns: Appropriate status code // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::CreateServer(const CLSID *pCLSIDServer,CHndlrQueue *pHndlrQueue, HANDLERINFO *pHandlerId,DWORD dwProxyThreadId) { HRESULT hr = S_OK; LPUNKNOWN pUnk; LPSYNCMGRENUMITEMS pEnumOffline = NULL; Assert(m_dwThreadId == GetCurrentThreadId()); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); Assert(0 == m_dwNestCount); m_dwNestCount++; m_CLSIDServer = *pCLSIDServer; m_pHndlrQueue = pHndlrQueue; m_dwProxyThreadId = dwProxyThreadId; if (m_pHndlrQueue) { m_pHndlrQueue->AddRef(); } m_pHandlerId = pHandlerId; hr = CoCreateInstance(m_CLSIDServer, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **) &pUnk); if (S_OK == hr) { __try { hr = pUnk->QueryInterface(IID_ISyncMgrSynchronize,(void **) &m_pOneStopHandler); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's IUnknown::QI method."); } __try { pUnk->Release(); } __except(QueryHandleException()) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); AssertSz(0,"Exception in Handler's IUnknown::Release method."); } } if (S_OK != hr) { m_pOneStopHandler = NULL; m_pOldOneStopHandler = NULL; } m_dwNestCount--; return hr; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::SetHndlrQueue, private // // Synopsis: Assigns a new HndlrQueue. // // Arguments: [pHndlrQueue] - Pointer to the Queue // [wHandlerId] - Id assigned to handler in the new queue // // !!!Warning - this is on the callers thread // // Returns: Appropriate status code // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::SetHndlrQueue(CHndlrQueue *pHndlrQueue,HANDLERINFO *pHandlerId,DWORD dwProxyThreadId) { CLock clockCallback(this); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); clockCallback.Enter(); Assert(0 == m_dwNestCount); m_dwNestCount++; if (pHndlrQueue != m_pHndlrQueue) { if (m_pHndlrQueue) { m_pHndlrQueue->Release(); } m_pHndlrQueue = pHndlrQueue; if (m_pHndlrQueue) { m_pHndlrQueue->AddRef(); } } AttachThreadInput(FALSE); // make sure thread input isn't set // update handlr id and proxy which can change even if queue is same // which can happen first queue that gets set in choice. m_pHandlerId = pHandlerId; m_dwProxyThreadId = dwProxyThreadId; m_dwNestCount--; clockCallback.Leave(); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::GetHndlrQueue, private // // Synopsis: Gets current Queue, // Can be called on any thread so progress callback // gets this information. // // Arguments: [ppHndlrQueue] - Out param filled with Pointer to the Queue // [pwHandlerId] - out param filled with Id assigned to handler // in the new queue // // Returns: Appropriate status code // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- void CHndlrMsg::GetHndlrQueue(CHndlrQueue **ppHndlrQueue,HANDLERINFO **ppHandlerId,DWORD *pdwProxyThreadId) { CLock clockCallback(this); Assert(FALSE == m_fForceKilled && FALSE == m_fDead); clockCallback.Enter(); *ppHndlrQueue = m_pHndlrQueue; *ppHandlerId = m_pHandlerId; *pdwProxyThreadId = m_dwProxyThreadId; if (m_pHndlrQueue) { m_pHndlrQueue->AddRef(); } clockCallback.Leave(); } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::AttachThreadInput, private // // Synopsis: Attaches the thread input of this thread // with the calling proxy so UI works correctly. // // Arguments: [fAttach] - Bool to indicate if should attach or not. // // Returns: Appropriate status code // // Modifies: // // History: 05-Nov-97 rogerg Created. // //---------------------------------------------------------------------------- void CHndlrMsg::AttachThreadInput(BOOL fAttach) { Assert(FALSE == m_fForceKilled && FALSE == m_fDead); // if request is same as current state don't do anything. if (m_fThreadInputAttached != fAttach ) { m_fThreadInputAttached = fAttach; ::AttachThreadInput(m_dwProxyThreadId,m_dwThreadId,fAttach); } } //+--------------------------------------------------------------------------- // // Member: CHndlrMsg::ForceKillHandler, private // // Synopsis: called directly by proxy when a thread is not // responding. Does any necessary cleanup of classes in the handler // thread before the proxy kills the thred // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 17-Nov-98 rogerg Created. // //---------------------------------------------------------------------------- STDMETHODIMP CHndlrMsg::ForceKillHandler() { Assert(FALSE == m_fForceKilled && FALSE == m_fDead); m_fForceKilled = TRUE; // if have a callback tell it we terminated but don't // release it in case the handler calls the callback later. if (m_pCallBack) { COfflineSynchronizeCallback* pCallback = m_pCallBack; m_pCallBack = NULL; pCallback->SetHndlrMsg(NULL,TRUE); } // delete our instance since should never be called again. delete this; return S_OK; }