|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: Hndlrq.cpp
//
// Contents: Implements class for keeping track of handlers
// and the UI associated with them
//
// Classes: CHndlrQueue
//
// Notes:
//
// History: 05-Nov-97 rogerg Created.
//
//--------------------------------------------------------------------------
#include "precomp.h"
#define HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE 10
// called to set up the JobInfo on a choice queue.
STDMETHODIMP CHndlrQueue::AddQueueJobInfo(DWORD dwSyncFlags,DWORD cbNumConnectionNames, TCHAR **ppConnectionNames, TCHAR *pszScheduleName,BOOL fCanMakeConnection ,JOBINFO **pJobInfo)
{ HRESULT hr = E_UNEXPECTED; TCHAR *pszConnectionName; TCHAR **pszConnectionNameArray; CLock clockqueue(this);
*pJobInfo = NULL;
Assert(m_QueueType == QUEUETYPE_CHOICE);
if (m_QueueType != QUEUETYPE_CHOICE) { return E_UNEXPECTED; }
clockqueue.Enter();
Assert(NULL == m_pFirstJobInfo);
// fix up connections so have at least one connection/job.
// this currently happens on an UpdateItems.
if (NULL == ppConnectionNames || 0 == cbNumConnectionNames ) { cbNumConnectionNames = 1; pszConnectionName = TEXT(""); pszConnectionNameArray = &pszConnectionName; } else { pszConnectionName = *ppConnectionNames; pszConnectionNameArray = ppConnectionNames; }
// create a job requesting size for the number of connections passed in.
hr = CreateJobInfo(&m_pFirstJobInfo,cbNumConnectionNames);
if (S_OK == hr) { DWORD dwConnectionIndex;
Assert(cbNumConnectionNames >= 1); // Review assert for debugging to test when have multiple connections for first time.
m_pFirstJobInfo->cbNumConnectionObjs = 0;
// add a connectionObject for each connection
for (dwConnectionIndex = 0; dwConnectionIndex < cbNumConnectionNames; ++dwConnectionIndex) { hr = ConnectObj_FindConnectionObj(pszConnectionNameArray[dwConnectionIndex], TRUE,&(m_pFirstJobInfo->pConnectionObj[dwConnectionIndex]));
if (S_OK != hr) { break; } else { ++m_pFirstJobInfo->cbNumConnectionObjs; } }
if (S_OK == hr) { m_pFirstJobInfo->dwSyncFlags = dwSyncFlags;
if ((SYNCMGRFLAG_SCHEDULED == (dwSyncFlags & SYNCMGRFLAG_EVENTMASK))) { StringCchCopy(m_pFirstJobInfo->szScheduleName, ARRAYSIZE(m_pFirstJobInfo->szScheduleName), pszScheduleName); m_pFirstJobInfo->fCanMakeConnection = fCanMakeConnection; m_pFirstJobInfo->fTriedConnection = FALSE; } } else { // couldn't create the connectionObj so release our jobID
m_pFirstJobInfo = NULL; } }
*pJobInfo = m_pFirstJobInfo; clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::CHndlrQueue, public
//
// Synopsis: Constructor used to create a progress queue
//
// Arguments: [QueueType] - Type of Queue that should be created.
// [hwndDlg] - Hwnd who owns this queue.
//
// Returns:
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
CHndlrQueue::CHndlrQueue(QUEUETYPE QueueType,CBaseDlg *pDlg) { Assert( (QueueType == QUEUETYPE_PROGRESS) || (QueueType == QUEUETYPE_CHOICE) );
m_pFirstHandler = NULL; m_wHandlerCount = 0; m_dwShowErrororOutCallCount = 0; m_cRefs = 1; m_QueueType = QueueType; m_fItemsMissing = FALSE; m_dwQueueThreadId = GetCurrentThreadId(); m_iNormalizedMax = 0; m_fNumItemsCompleteNeedsARecalc = TRUE;
m_pDlg = pDlg; if (m_pDlg) { m_hwndDlg = m_pDlg->GetHwnd(); Assert(m_hwndDlg); }
m_fInCancelCall = FALSE; m_pFirstJobInfo = NULL; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::~CHndlrQueue, public
//
// Synopsis: Destructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
CHndlrQueue::~CHndlrQueue() { CLock clockqueue(this);
// for a progress queue all the jobInfos should be released
// for the choice queue there should be one JobInfo that has to
// be released that was addref'd in the constructor.
Assert(0 == m_cRefs); Assert(NULL == m_pFirstJobInfo); // review - this should never fire anymore.
Assert(NULL == m_pFirstJobInfo || m_QueueType == QUEUETYPE_CHOICE); // there shouldn't be any unreleased JobInfo
Assert(m_pFirstHandler == NULL); // All Handlers should have been released by now.
}
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AddRef, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 01-June-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CHndlrQueue::AddRef() { DWORD cRefs;
Assert(m_cRefs >= 1); // should never zero bounce.
cRefs = InterlockedIncrement((LONG *)& m_cRefs); return cRefs; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::Release, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 01-June-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CHndlrQueue::Release() { DWORD cRefs;
cRefs = InterlockedDecrement( (LONG *) &m_cRefs);
Assert( ((LONG) cRefs) >= 0); // should never go negative.
if (0 == cRefs) { delete this; }
return cRefs; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AddHandler, public
//
// Synopsis: Adds a new empty handler to the queue and returns it ID
//
// Arguments: [pwHandlerID] - on success contains the assigned Handler ID
// [pJobInfo] - Job this item is associated with
// [dwRegistrationFlags] - Flags the Handler has registered for.
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::AddHandler(HANDLERINFO **ppHandlerId,JOBINFO *pJobInfo,DWORD dwRegistrationFlags) { HRESULT hr = E_OUTOFMEMORY; LPHANDLERINFO pnewHandlerInfo; CLock clockqueue(this);
*ppHandlerId = 0;
pnewHandlerInfo = (LPHANDLERINFO) ALLOC(sizeof(HANDLERINFO));
if (pnewHandlerInfo) { clockqueue.Enter();
m_fNumItemsCompleteNeedsARecalc = TRUE; // need to recalc next GetProgress.
// initialize the new Handler Entry
memset(pnewHandlerInfo, 0, sizeof(HANDLERINFO)); pnewHandlerInfo->HandlerState = HANDLERSTATE_CREATE; pnewHandlerInfo->pHandlerId = pnewHandlerInfo; pnewHandlerInfo->dwRegistrationFlags = dwRegistrationFlags;
// queue should be a choice queue and
// there should already be a jobinfo.
Assert(m_QueueType == QUEUETYPE_CHOICE); Assert(m_pFirstJobInfo); Assert(pJobInfo == m_pFirstJobInfo); // for now job info should always be the first one.
if (m_QueueType == QUEUETYPE_CHOICE && pJobInfo) { AddRefJobInfo(pJobInfo); pnewHandlerInfo->pJobInfo = pJobInfo; }
// add to end of list and set pHandlerId. End of list since in choice dialog want
// first writer wins so don't have to continue searches when setting item state.
if (NULL == m_pFirstHandler) { m_pFirstHandler = pnewHandlerInfo; } else { LPHANDLERINFO pCurHandlerInfo;
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo->pNextHandler) { pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
pCurHandlerInfo->pNextHandler = pnewHandlerInfo; }
*ppHandlerId = pnewHandlerInfo->pHandlerId;
clockqueue.Leave();
hr = S_OK; }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ForceKillHandlers, public
//
// Synopsis: Kills unresponsive handlers after timeout
//
// Returns: Appropriate return codes
//
// History: 20-Nov-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ForceCompleteOutCalls(LPHANDLERINFO pCurHandler) { // need to have lock for argument to be valid.
ASSERT_LOCKHELD(this);
//prepare for sync out call
if (pCurHandler->dwOutCallMessages & ThreadMsg_PrepareForSync) { CallCompletionRoutine(pCurHandler,ThreadMsg_PrepareForSync, HRESULT_FROM_WIN32(ERROR_CANCELLED),0,NULL); }
//Synchronize out call
if (pCurHandler->dwOutCallMessages & ThreadMsg_Synchronize) { CallCompletionRoutine(pCurHandler,ThreadMsg_Synchronize, HRESULT_FROM_WIN32(ERROR_CANCELLED),0,NULL); } //ShowProperties out call
if (pCurHandler->dwOutCallMessages & ThreadMsg_ShowProperties) { CallCompletionRoutine(pCurHandler,ThreadMsg_ShowProperties, HRESULT_FROM_WIN32(ERROR_CANCELLED),0,NULL); } //Show Errors out call
if (pCurHandler->dwOutCallMessages & ThreadMsg_ShowError) { CallCompletionRoutine(pCurHandler,ThreadMsg_ShowError, HRESULT_FROM_WIN32(ERROR_CANCELLED),0,NULL); }
// force handler state to release.
pCurHandler->HandlerState = HANDLERSTATE_RELEASE;
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ForceKillHandlers, public
//
// Synopsis: Kills unresponsive handlers after timeout
//
// Returns: Appropriate return codes
//
// History: 30-Oct-98 susia Created.
// 19-Nov-98 rogerg Change to only kill first unresponsive handler
//
//----------------------------------------------------------------------------
#define BAD_HANDLERSTATE(pHandlerId) \
( (HANDLERSTATE_INSYNCHRONIZE >= pHandlerId->HandlerState) \ || (pHandlerId->dwOutCallMessages & ThreadMsg_SetItemStatus) \ )
STDMETHODIMP CHndlrQueue::ForceKillHandlers(BOOL *pfItemToKill) { HRESULT hr = S_OK; LPHANDLERINFO pCurHandler; CLock clockqueue(this);
*pfItemToKill = TRUE; // if something strange happens make sure timer gets reset.
clockqueue.Enter();
pCurHandler = m_pFirstHandler;
while (pCurHandler) { // if handler is cancelled but still in a noncancelled state or
// is cancelled but stuck in the outcall then terminate.
// need to check both because some handlers may call the callback
// to set the state done but still be stuck in an out call.
if ( pCurHandler->fCancelled && BAD_HANDLERSTATE(pCurHandler) ) { TCHAR pszHandlerName[MAX_SYNCMGRHANDLERNAME + 1];
ConvertString(pszHandlerName, (pCurHandler->SyncMgrHandlerInfo).wszHandlerName, MAX_SYNCMGRHANDLERNAME);
// yield because of message box in Terminate Handler call.
Assert(!pCurHandler->fInTerminateCall); pCurHandler->fInTerminateCall = TRUE; clockqueue.Leave();
hr = pCurHandler->pThreadProxy->TerminateHandlerThread(pszHandlerName,TRUE);
clockqueue.Enter();
pCurHandler->fInTerminateCall = FALSE;
if (hr == S_OK) { LPHANDLERINFO pKilledHandler = pCurHandler;
ForceCompleteOutCalls(pCurHandler);
// now need to loop through remaining instances handlers off the same clsid
// we just killed
// CODE REVIEW: NOTENOTE:
// pCurHandler is being assigned, not compared - its a '=', not a '=='
while(pCurHandler = pCurHandler->pNextHandler) { if (pCurHandler->clsidHandler == pKilledHandler->clsidHandler) { // must meet original kil criteria
if ( pCurHandler->fCancelled && BAD_HANDLERSTATE(pCurHandler) ) { HRESULT hrProxyTerminate;
pCurHandler->fInTerminateCall = TRUE;
clockqueue.Leave(); hrProxyTerminate = pCurHandler->pThreadProxy->TerminateHandlerThread(pszHandlerName,FALSE); clockqueue.Enter();
Assert(S_OK == hrProxyTerminate);// this should never fail.
ForceCompleteOutCalls(pCurHandler);
pCurHandler->fInTerminateCall = FALSE; } } } }
// if handled one , break out and reqiure to be called again.
break; }
pCurHandler = pCurHandler->pNextHandler; }
// finally loop through the queue and see if there are any more items to kill
*pfItemToKill = FALSE;
pCurHandler = m_pFirstHandler;
while (pCurHandler) { // if handler is cancelled but still in a noncancelled state or
// is cancelled but stuck in the outcall then terminate.
// need to check both because some handlers may call the callback
// to set the state done but still be stuck in an out call.
if ( pCurHandler->fCancelled && BAD_HANDLERSTATE(pCurHandler) ) { *pfItemToKill = TRUE; break; }
pCurHandler = pCurHandler->pNextHandler; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::Cancel, public
//
// Synopsis: Set the current Handler Items in the queue
// into cancel mode.
//
// The Different States Are.
// If the item is waiting for <= PrepareForSync place in Release
// If InPrepareForSync Skip Items and then Synchrnoize
// will check the complete value before calling through
// and if set will just release the Handler.
// If Waiting to Synchronize Skip Items then let Synchronize
// Check for complete value and just set release
// If Item is currently In the Synchronize Skip all items
// and then just let synchronize return
//
// Algorithm. If <= PrepareForSync then place in Release, Else if <= InSynchronize
// then SkipTheItems
//
// Note: Relies on Synchronize setting handler state before calling
// through to Handlers Synchronize Method. PrepareForSync should
// also check this in case new PrepareforSync request comes
// in during an out call in this routine.
//
// Arguments:
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::Cancel(void) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pCurHandler; CLock clockqueue(this);
clockqueue.Enter();
// don't do anything is still processing the last cancel request
if (!m_fInCancelCall) { m_fInCancelCall = TRUE;
// first thing set cancel to true on all handler items
// so if sync,PrepareForSyncRequest comes in during SetItemStatus
// out call it will be cancelled immediately.
pCurHandler = m_pFirstHandler;
while (pCurHandler) { pCurHandler->fCancelled = TRUE; pCurHandler = pCurHandler->pNextHandler; }
// now loop through looking for any items that need to have
// their item status set.
// !!!remember new requests can come in so only make out call
// if fCancelled is set.
// !!! items can be removed from queue in between our cancel call
// and when we return.
pCurHandler = m_pFirstHandler;
while (pCurHandler) { CThreadMsgProxy *pThreadProxy = pCurHandler->pThreadProxy;
if (pCurHandler->fCancelled && pThreadProxy && (pCurHandler->HandlerState >= HANDLERSTATE_INPREPAREFORSYNC) && (pCurHandler->HandlerState <= HANDLERSTATE_INSYNCHRONIZE) ) { // could be in a setitemstatus call, if so then don't do another.
// review - dup of SkipCode. should have a general purpose function
// to call after setting what items should be cancelled.
if (!(pCurHandler->dwOutCallMessages & ThreadMsg_SetItemStatus)) { pCurHandler->dwOutCallMessages |= ThreadMsg_SetItemStatus; clockqueue.Leave();
// send a reset to the hwnd we belong to if there is one
if (m_hwndDlg) { SendMessage(m_hwndDlg,WM_PROGRESS_RESETKILLHANDLERSTIMER,0,0); }
hr = pThreadProxy->SetItemStatus(GUID_NULL, SYNCMGRSTATUS_STOPPED);
clockqueue.Enter(); pCurHandler->dwOutCallMessages &= ~ThreadMsg_SetItemStatus; } } else if (pCurHandler->HandlerState < HANDLERSTATE_INPREPAREFORSYNC) { LPITEMLIST pCurItem;
pCurHandler->HandlerState = HANDLERSTATE_RELEASE;
// need to setup HwndCallback so progres gets updated.
// review, after ship why can't setup HwndCallback on transferqueueu
pCurHandler->hWndCallback = m_hwndDlg;
// if handler hansn't been kicked off yet, just reset the items ourselves
pCurItem = pCurHandler->pFirstItem;
while (pCurItem) { if (pCurItem->fIncludeInProgressBar) { SYNCMGRPROGRESSITEM SyncProgressItem;
SyncProgressItem.cbSize = sizeof(SYNCMGRPROGRESSITEM); SyncProgressItem.mask = SYNCMGRPROGRESSITEM_PROGVALUE | SYNCMGRPROGRESSITEM_MAXVALUE | SYNCMGRPROGRESSITEM_STATUSTYPE; SyncProgressItem.iProgValue = HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE; SyncProgressItem.iMaxValue = HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE; SyncProgressItem.dwStatusType = SYNCMGRSTATUS_STOPPED;
// set progress faking we are in an out call so any releasecompleted
// handler that comes through doesn't release us.
// if already in outCall then progress just won't get updated
// until next time.
if (!(pCurHandler->dwOutCallMessages & ThreadMsg_SetItemStatus)) { pCurHandler->dwOutCallMessages |= ThreadMsg_SetItemStatus; clockqueue.Leave();
Progress(pCurHandler->pHandlerId, pCurItem->offlineItem.ItemID,&SyncProgressItem);
clockqueue.Enter(); pCurHandler->dwOutCallMessages &= ~ThreadMsg_SetItemStatus; } }
pCurItem = pCurItem->pnextItem; }
}
pCurHandler = pCurHandler->pNextHandler; }
m_fInCancelCall = FALSE; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::MoveHandler, public
//
// Synopsis: Moves the Handler from a queue into this queue.
//
// Arguments: [pQueueMoveFrom] - Queue the handler is being moved from.
// [pHandlerInfoMoveFrom] - Handler that is being moved
// [ppHandlerId] - On Success contains the new HandlerID
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::MoveHandler(CHndlrQueue *pQueueMoveFrom, LPHANDLERINFO pHandlerInfoMoveFrom, HANDLERINFO **ppHandlerId, CLock *pclockQueue) { LPITEMLIST pCurItem = NULL; JOBINFO *pJobInfo = NULL; BOOL fHasItemsToSync = FALSE;
ASSERT_LOCKHELD(this); // items should already be locked when this function is called.
ASSERT_LOCKHELD(pQueueMoveFrom);
if ( (QUEUETYPE_PROGRESS != m_QueueType) && (QUEUETYPE_CHOICE != m_QueueType) ) { Assert(QUEUETYPE_CHOICE == m_QueueType); Assert(QUEUETYPE_PROGRESS == m_QueueType); return E_UNEXPECTED; // review error code.
}
*ppHandlerId = 0; ++m_wHandlerCount;
// pHandlerInfoMoveFrom->pHandlerId = m_wHandlerCount;
pHandlerInfoMoveFrom->pNextHandler = NULL;
*ppHandlerId = pHandlerInfoMoveFrom->pHandlerId;
// now fix up the items duplicate flag information.
pCurItem = pHandlerInfoMoveFrom->pFirstItem;
while (pCurItem) { LPHANDLERINFO pHandlerMatched; LPITEMLIST pItemListMatch;
// setup the information for the UI depending on if this item is check and
// the state it is in.
// if item is now within a valid range then uncheck it.
if (SYNCMGRITEMSTATE_CHECKED == pCurItem->offlineItem.dwItemState && ( (pHandlerInfoMoveFrom->HandlerState < HANDLERSTATE_PREPAREFORSYNC) || (pHandlerInfoMoveFrom->HandlerState >= HANDLERSTATE_RELEASE) ) ) { Assert(pHandlerInfoMoveFrom->HandlerState >= HANDLERSTATE_PREPAREFORSYNC); // this should never happen.
pCurItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED; }
// setup the UI information based on if the item is checked.
// or if its a hidden item.
if ( (SYNCMGRITEMSTATE_UNCHECKED == pCurItem->offlineItem.dwItemState) || pCurItem->fHiddenItem) { SetItemProgressValues(pCurItem,HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE,HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE); pCurItem->fIncludeInProgressBar = FALSE; } else { fHasItemsToSync = TRUE; SetItemProgressValues(pCurItem,0,HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE); pCurItem->fIncludeInProgressBar = TRUE; }
if (IsItemAlreadyInList(pHandlerInfoMoveFrom->clsidHandler, (pCurItem->offlineItem.ItemID), pHandlerInfoMoveFrom->pHandlerId, &pHandlerMatched,&pItemListMatch) ) { pCurItem->fDuplicateItem = TRUE; } else { Assert(FALSE == pCurItem->fDuplicateItem); // catch case of duplicate getting lost
pCurItem->fDuplicateItem = FALSE; }
pCurItem = pCurItem->pnextItem; }
// if the item we are moving has a Proxy then update the proxy to the new queue.
// We update this when the item is not attached to either queue.
if (pHandlerInfoMoveFrom->pThreadProxy) { HANDLERINFO *pHandlerInfoArg = pHandlerInfoMoveFrom->pHandlerId;
// set the proxy to point to the new information
pHandlerInfoMoveFrom->pThreadProxy->SetProxyParams(m_hwndDlg ,m_dwQueueThreadId ,this ,pHandlerInfoArg); }
// Add the handler to this list.
if (NULL == m_pFirstHandler) { m_pFirstHandler = pHandlerInfoMoveFrom; // Assert(1 == m_wHandlerCount); // Review = HandlerCount doesn't have to be 1 if ReleaseCompltedHandlers has been called.
} else { LPHANDLERINFO pCurHandlerInfo;
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo->pNextHandler) { pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
pCurHandlerInfo->pNextHandler = pHandlerInfoMoveFrom; }
// if this is a progress queue and there are not items to sync for the
// handler or the HandlerState isn't in PrepareForSync then set
// the state to TransferRelease since it can be freed.
if ((QUEUETYPE_PROGRESS == m_QueueType && !fHasItemsToSync ) || (pHandlerInfoMoveFrom->HandlerState != HANDLERSTATE_PREPAREFORSYNC)) { pHandlerInfoMoveFrom->HandlerState = HANDLERSTATE_TRANSFERRELEASE; }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::TransferQueueData, public
//
// Synopsis: Moves the Items from one queue to another. Currently we only
// support transferrring items from a choice queueu to a choice or
// progress queue. Only handlers in the PREPAREFORSYNC state are moved
// when transferring to a Progress queue. When transferring to a choice
// queue only items in the ADDHANDLERITEMS state are moved.
//
// !!Warning - Cannot release lock during this process
//
// Arguments: [pQueueMoveFrom] - Queue to move items from.
// [dwSyncFlags] - flags that started the sync
// [pszConnectionName] - Connection the sync should be performed on, can be NULL
// [szSchedulName] - Name of Schedule that started this Job. Can be NULL.
// [hRasPendingEvent] - Event to signal when job is complete. Can be NULL.
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::TransferQueueData(CHndlrQueue *pQueueMoveFrom /* ,DWORD dwSyncFlags,TCHAR *pzConnectionName,TCHAR *szScheduleName */) { HRESULT hr = E_UNEXPECTED; HANDLERINFO HandlerInfoMoveFrom; LPHANDLERINFO pHandlerInfoMoveFrom = &HandlerInfoMoveFrom; CLock clockqueue(this); CLock clockqueueMoveFrom(pQueueMoveFrom);
clockqueue.Enter(); clockqueueMoveFrom.Enter();
m_fNumItemsCompleteNeedsARecalc = TRUE; // need to recalc NumItems next time
if ((QUEUETYPE_PROGRESS != m_QueueType && QUEUETYPE_CHOICE != m_QueueType) || QUEUETYPE_CHOICE != pQueueMoveFrom->m_QueueType) { Assert(QUEUETYPE_PROGRESS == m_QueueType || QUEUETYPE_CHOICE == m_QueueType); Assert(QUEUETYPE_CHOICE == pQueueMoveFrom->m_QueueType); } else if (NULL == pQueueMoveFrom->m_pFirstHandler) { // if no job info then there aren't any items to move.
} else { JOBINFO *pMoveFromJobInfo = NULL;
// transfer everything over and then release after done call freecompletedhandlers
// to clean anything up.
// transfer over all jobs
Assert(pQueueMoveFrom->m_pFirstJobInfo); Assert(pQueueMoveFrom->m_pFirstJobInfo->pConnectionObj);
pMoveFromJobInfo = pQueueMoveFrom->m_pFirstJobInfo; pQueueMoveFrom->m_pFirstJobInfo = NULL;
if (NULL == m_pFirstJobInfo) { m_pFirstJobInfo = pMoveFromJobInfo; } else { JOBINFO *pCurLastJob = NULL;
pCurLastJob = m_pFirstJobInfo; while (pCurLastJob->pNextJobInfo) { pCurLastJob = pCurLastJob->pNextJobInfo; }
pCurLastJob->pNextJobInfo = pMoveFromJobInfo; }
// loop through moving items, have to reassign the Handler ID and
// !!Warning - This function does nothing with ListViewData it is up to the
// caller to make sure this is set up properly
// review - should just loop through fixing up necessary items and then
// add entire list onto end. inneficient to do one at a time.
pHandlerInfoMoveFrom->pNextHandler = pQueueMoveFrom->m_pFirstHandler; while (pHandlerInfoMoveFrom->pNextHandler) { LPHANDLERINFO pHandlerToMove; HANDLERINFO *pNewHandlerId;
// Asserts for making sure the UI has been cleared from the queue
Assert(FALSE == pHandlerInfoMoveFrom->pNextHandler->fHasErrorJumps); Assert(pHandlerInfoMoveFrom->pNextHandler->pJobInfo);
// !!! Warning get next handler before transfer or next ptr will be invalid.
pHandlerToMove = pHandlerInfoMoveFrom->pNextHandler; pHandlerInfoMoveFrom->pNextHandler = pHandlerToMove->pNextHandler; MoveHandler(pQueueMoveFrom,pHandlerToMove,&pNewHandlerId,&clockqueue);
// now set the original queues head
pQueueMoveFrom->m_pFirstHandler = HandlerInfoMoveFrom.pNextHandler;
hr = S_OK; } }
clockqueue.Leave(); clockqueueMoveFrom.Leave();
// now free any handlers that came into the queue that we
// don't want to do anything with .
ReleaseHandlers(HANDLERSTATE_TRANSFERRELEASE);
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetQueueHwnd, public
//
// Synopsis: informs the queue os the new dialog owner if any
// queue must also loop through existing proxies
// and reset their hwnd.
//
// Arguments:
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetQueueHwnd(CBaseDlg *pDlg) { LPHANDLERINFO pCurHandlerInfo; CLock clockqueue(this);
clockqueue.Enter();
m_pDlg = pDlg; if (m_pDlg) { m_hwndDlg = m_pDlg->GetHwnd(); } else { m_hwndDlg = NULL; }
m_dwQueueThreadId = GetCurrentThreadId(); // make sure queu threadId is updated.
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { if (pCurHandlerInfo->pThreadProxy) { pCurHandlerInfo->pThreadProxy->SetProxyParams(m_hwndDlg ,m_dwQueueThreadId ,this ,pCurHandlerInfo->pHandlerId);
}
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ReleaseCompletedHandlers, public
//
// Synopsis: Releases any Handlers that are in the Release or free
// dead state from the queue.
//
// Arguments:
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ReleaseCompletedHandlers() { return ReleaseHandlers(HANDLERSTATE_RELEASE); }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FreeAllHandlers, public
//
// Synopsis: Releases all handlers from the queue.
//
// Arguments:
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FreeAllHandlers(void) { return ReleaseHandlers(HANDLERSTATE_NEW); // release handlers in all states.
}
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ReleaseHandlers, public
//
// Synopsis: Releases any Handlers are in a state >= the requested state
//
// Arguments: HandlerState - Frees all handlers that have a state >= the requested state.
//
// !!Warning: This should be the only place the proxy if freed and
// the handler is removed from the list.
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ReleaseHandlers(HANDLERSTATE HandlerState) { HANDLERINFO HandlerInfoStart; LPHANDLERINFO pPrevHandlerInfo = &HandlerInfoStart; LPHANDLERINFO pCurHandlerInfo = NULL; LPHANDLERINFO pHandlerFreeList = NULL; LPITEMLIST pCurItem = NULL; LPITEMLIST pNextItem = NULL; CLock clockqueue(this);
ASSERT_LOCKNOTHELD(this); // shouldn't be any out calls in progress when this is called.
clockqueue.Enter();
m_fNumItemsCompleteNeedsARecalc = TRUE; // need to recalc next GetProgress.
// loop through the handlers finding the one that match the criteria
// removing them from list and adding them to the free list
// we do this so don't have to worry about someone else accessing
// handlers we are freeing during an out call.
if (HANDLERSTATE_NEW == HandlerState) { // Release should only be called on this state if caller is sure no out
// calls are in progress or else handler may not exist when
// they come back
pHandlerFreeList = m_pFirstHandler; m_pFirstHandler = NULL; } else { Assert(HandlerState >= HANDLERSTATE_RELEASE); // if in release no out calls are in progress.
pPrevHandlerInfo->pNextHandler = m_pFirstHandler;
while (pPrevHandlerInfo->pNextHandler) { pCurHandlerInfo = pPrevHandlerInfo->pNextHandler;
// if meet handler state criteria and not in any out calls then can
// remove from list.
// if request for HANDLERSTATE_NEW then assert than there shouldn't be
// any out calls in progress or terminating.
Assert(!(HandlerState == HANDLERSTATE_NEW) || (0 == pCurHandlerInfo->dwOutCallMessages && !pCurHandlerInfo->fInTerminateCall));
if ( (HandlerState <= pCurHandlerInfo->HandlerState) && (0 == pCurHandlerInfo->dwOutCallMessages) && !(pCurHandlerInfo->fInTerminateCall)) { Assert (HANDLERSTATE_RELEASE == pCurHandlerInfo->HandlerState || HANDLERSTATE_TRANSFERRELEASE == pCurHandlerInfo->HandlerState || HANDLERSTATE_HASERRORJUMPS == pCurHandlerInfo->HandlerState || HANDLERSTATE_DEAD == pCurHandlerInfo->HandlerState);
// remove from queue list and add to free.
pPrevHandlerInfo->pNextHandler = pCurHandlerInfo->pNextHandler;
pCurHandlerInfo->pNextHandler = pHandlerFreeList; pHandlerFreeList = pCurHandlerInfo; } else { // if no match then just continue.
pPrevHandlerInfo = pCurHandlerInfo; }
}
// update the queue head.
m_pFirstHandler = HandlerInfoStart.pNextHandler; }
// now loop through the free list freeing the items.
while (pHandlerFreeList) { pCurHandlerInfo = pHandlerFreeList; pHandlerFreeList = pHandlerFreeList->pNextHandler;
// if the item has a job info release the reference on it.
if (pCurHandlerInfo->pJobInfo) { ReleaseJobInfo(pCurHandlerInfo->pJobInfo); pCurHandlerInfo->pJobInfo = NULL; }
if (pCurHandlerInfo->pThreadProxy) { CThreadMsgProxy *pThreadProxy = pCurHandlerInfo->pThreadProxy; HWND hwndCallback;
Assert(HANDLERSTATE_DEAD != pCurHandlerInfo->HandlerState);
pCurHandlerInfo->HandlerState = HANDLERSTATE_DEAD; pThreadProxy = pCurHandlerInfo->pThreadProxy; pCurHandlerInfo->pThreadProxy = NULL;
hwndCallback = pCurHandlerInfo->hWndCallback; pCurHandlerInfo->hWndCallback = NULL;
clockqueue.Leave(); // release lock when making the OutCall.
pThreadProxy->Release(); // review, don't release proxy to try to catch race condition.
clockqueue.Enter(); }
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { pNextItem = pCurItem->pnextItem; FREE(pCurItem); pCurItem = pNextItem; }
FREE(pCurHandlerInfo); }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetHandlerInfo, public
//
// Synopsis: Gets Data associated with the HandlerID and ItemID
//
// Arguments: [clsidHandler] - ClsiId Of Handler the Item belongs too
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetHandlerInfo(REFCLSID clsidHandler, LPSYNCMGRHANDLERINFO pSyncMgrHandlerInfo) { HRESULT hr = S_FALSE; LPHANDLERINFO pCurHandlerInfo = NULL; CLock clockqueue(this);
clockqueue.Enter();
// find first handler that matches the request CLSID
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo ) { if (clsidHandler == pCurHandlerInfo->clsidHandler) { *pSyncMgrHandlerInfo = pCurHandlerInfo->SyncMgrHandlerInfo; hr = S_OK; break; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetHandlerInfo, public
//
// Synopsis: Gets Data associated with the HandlerID and ItemID
//
// Arguments: [wHandlerId] - Id Of Handler the Item belongs too
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetHandlerInfo(HANDLERINFO *pHandlerId, LPSYNCMGRHANDLERINFO pSyncMgrHandlerInfo) { HRESULT hr = S_FALSE; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { *pSyncMgrHandlerInfo = pHandlerInfo->SyncMgrHandlerInfo; hr = S_OK; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetItemDataAtIndex, public
//
// Synopsis: Gets Data associated with the HandlerID and ItemID
//
// Arguments: [wHandlerId] - Id Of Handler the Item belongs too
// [wItemID] - Identifies the Item in the Handler
// [pclsidHandler] - on return contains a pointer to the clsid of the Handler
// [offlineItem] - on returns contains a pointer to the OfflineItem for the item.
// [pfHiddenItem] - On return is a bool indicating if this item is hidden.
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetItemDataAtIndex(HANDLERINFO *pHandlerId,WORD wItemID, CLSID *pclsidHandler,SYNCMGRITEM *offlineItem,BOOL *pfHiddenItem)
{ BOOL fFoundMatch = FALSE; LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo && !fFoundMatch) { // only valid if Hanlder is in the PrepareForSync state.
if (pHandlerId == pCurHandlerInfo->pHandlerId) // see if CLSID matches
{ // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (wItemID == pCurItem->wItemId) { fFoundMatch = TRUE; break; }
pCurItem = pCurItem->pnextItem; } }
if (!fFoundMatch) pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
if (fFoundMatch) { if (pclsidHandler) { *pclsidHandler = pCurHandlerInfo->clsidHandler; } if (offlineItem) { *offlineItem = pCurItem->offlineItem; } if (pfHiddenItem) { *pfHiddenItem = pCurItem->fHiddenItem; }
}
clockqueue.Leave();
return fFoundMatch ? S_OK : S_FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetItemDataAtIndex, public
//
// Synopsis: Gets Data associated with the HandlerID and OfflineItemID
//
// Arguments: [wHandlerId] - Id Of Handler the Item belongs too
// [ItemID] - identifies the Item by its OfflineItemID
// [pclsidHandler] - on return contains a pointer to the clsid of the Handler
// [offlineItem] - on returns contains a pointer to the OfflineItem for the item.
// [pfHiddenItem] - On return is a bool indicating if this item is a hidden item.
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetItemDataAtIndex(HANDLERINFO *pHandlerId,REFSYNCMGRITEMID ItemID,CLSID *pclsidHandler, SYNCMGRITEM *offlineItem,BOOL *pfHiddenItem) { BOOL fFoundMatch = FALSE; LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo && !fFoundMatch) { // only valid if handler is in the PrepareForSync state.
if (pHandlerId == pCurHandlerInfo->pHandlerId) // see if CLSID matches
{ // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (ItemID == pCurItem->offlineItem.ItemID) { fFoundMatch = TRUE; break; }
pCurItem = pCurItem->pnextItem; } }
if (!fFoundMatch) pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
if (fFoundMatch) { *pclsidHandler = pCurHandlerInfo->clsidHandler; *offlineItem = pCurItem->offlineItem; *pfHiddenItem = pCurItem->fHiddenItem;
}
clockqueue.Leave();
return fFoundMatch ? S_OK : S_FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FindFirstItemInState, public
//
// Synopsis: Finds the first Item in the queue that matches the given state.
//
// Arguments:
// [hndlrState] - specifies matching state we are looking for.
// [pwHandlerId] - on return contains the HandlerID of the Item
// [pwItemID] - on returns contains the ItemID of the item in the queue.
//
// Returns: S_OK if an Item was found with an unassigned ListView.
// S_FALSE - if no Item was found.
// Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FindFirstItemInState(HANDLERSTATE hndlrState, HANDLERINFO **ppHandlerId,WORD *pwItemID) { return FindNextItemInState(hndlrState,0,0,ppHandlerId,pwItemID); }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FindNextItemInState, public
//
// Synopsis: Finds the first Item in the queue that matches the given state.
// after the specified item.
//
// Arguments:
// [hndlrState] - specifies matching state we are looking for.
// [pOfflineItemID] - on returns contains a pointer to the OfflineItem for the item.
// [pwHandlerId] - on return contains the HandlerID of the Item
// [pwItemID] - on returns contains the ItemID of the item in the queue.
//
// Returns: S_OK if an Item was found with an unassigned ListView.
// S_FALSE - if no Item was found.
// Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FindNextItemInState(HANDLERSTATE hndlrState, HANDLERINFO *pLastHandlerId,WORD wLastItemID, HANDLERINFO **ppHandlerId,WORD *pwItemID) { BOOL fFoundMatch = FALSE; LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
clockqueue.Enter(); pCurHandlerInfo = m_pFirstHandler;
if (pLastHandlerId) { // loop until find the specified handler or hit end of list.
while(pCurHandlerInfo && pLastHandlerId != pCurHandlerInfo->pHandlerId) { pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
if (NULL == pCurHandlerInfo) // reached end of list without finding the Handler
{ Assert(0); // user must have passed an invalid start HandlerID.
clockqueue.Leave(); return S_FALSE; }
// loop until find item or end of item list
pCurItem = pCurHandlerInfo->pFirstItem; while (pCurItem && pCurItem->wItemId != wLastItemID) { pCurItem = pCurItem->pnextItem; }
if (NULL == pCurItem) // reached end of item list without finding the specified item
{ Assert(0); // user must have passed an invalid start ItemID.
clockqueue.Leave(); return S_FALSE; }
// now we found the Handler and item. loop through remaining items for this handler
// if it still has another item then just return that.
pCurItem = pCurItem->pnextItem; if (pCurItem) { Assert(hndlrState == pCurHandlerInfo->HandlerState); // should only be called in PrepareForSyncState
fFoundMatch = TRUE; }
if (!fFoundMatch) pCurHandlerInfo = pCurHandlerInfo->pNextHandler; // increment to next handler if no match
}
if (!fFoundMatch) { // in didn't find a match in the
while (pCurHandlerInfo) { if ((hndlrState == pCurHandlerInfo->HandlerState) && (pCurHandlerInfo->pFirstItem) ) { pCurItem = pCurHandlerInfo->pFirstItem; fFoundMatch = TRUE; break; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; } }
if (fFoundMatch) { *ppHandlerId = pCurHandlerInfo->pHandlerId; *pwItemID = pCurItem->wItemId; }
clockqueue.Leave();
return fFoundMatch ? S_OK : S_FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetItemState, public
//
// Synopsis: Set the Item state for the first item finds that it
// matches in the Queue. Sets all other matches to unchecked.
//
// Arguments:
//
// Returns: Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetItemState(REFCLSID clsidHandler,REFSYNCMGRITEMID ItemID,DWORD dwState) { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; BOOL fFoundMatch = FALSE; CLock clockqueue(this);
if (QUEUETYPE_CHOICE != m_QueueType) { Assert(QUEUETYPE_CHOICE == m_QueueType); return E_UNEXPECTED; }
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { if (clsidHandler == pCurHandlerInfo->clsidHandler) { pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (ItemID == pCurItem->offlineItem.ItemID) { // if the handlerstate is not prepareforsync or not first match then uncheck
if ((HANDLERSTATE_PREPAREFORSYNC != pCurHandlerInfo->HandlerState) || fFoundMatch) { pCurItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED; } else { pCurItem->offlineItem.dwItemState = dwState; fFoundMatch = TRUE; } }
pCurItem = pCurItem->pnextItem; } }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
Assert(fFoundMatch); // we should have found at least one match.
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SkipItem, public
//
// Synopsis: loop through handler and mark the items appropriately that match..
//
// Arguments: [iItem] - List View Item to skip.
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SkipItem(REFCLSID clsidHandler,REFSYNCMGRITEMID ItemID) { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this); HRESULT hr = S_OK;
if (QUEUETYPE_PROGRESS != m_QueueType) { Assert(QUEUETYPE_PROGRESS == m_QueueType); return E_UNEXPECTED; }
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo ) { if (clsidHandler == pCurHandlerInfo->clsidHandler) { pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { // if item is cancelled then also treat as a match to
// handle case cancel came in while in an out call.
if ( ItemID == pCurItem->offlineItem.ItemID) { // found an item, now if it hasn't started the sync or
// is not already complete set the value.
if ((pCurHandlerInfo->HandlerState < HANDLERSTATE_RELEASE) ) { pCurItem->fItemCancelled = TRUE;
// If haven't called PrepareforSync yet then
// set uncheck the item so it isn't passed to PrepareForSync
// If PrepareForSync has already been called, call the items
// SkipMethod. if already in a setItemstatus call for this handler don't
// do anything.
// if not in another setitemstatus call loop through freeing all
// the items that have the cancel set.
// essentially a dup of cance and also handle case cancel
// comes win while this handler is in an out call.
if (!(pCurHandlerInfo->dwOutCallMessages & ThreadMsg_SetItemStatus)) { pCurHandlerInfo->dwOutCallMessages |= ThreadMsg_SetItemStatus;
if (pCurHandlerInfo->HandlerState >= HANDLERSTATE_INPREPAREFORSYNC && pCurItem->fSynchronizingItem ) { CThreadMsgProxy *pThreadProxy; SYNCMGRITEMID ItemId;
pThreadProxy = pCurHandlerInfo->pThreadProxy; ItemId = pCurItem->offlineItem.ItemID; clockqueue.Leave();
if (pThreadProxy) { hr = pThreadProxy->SetItemStatus(ItemId, SYNCMGRSTATUS_SKIPPED); }
clockqueue.Enter(); } else { // once done skipping handler if state is <= preparefor sync we set the state accordingly.
// if were syncing up to handler.
if ( (pCurHandlerInfo->HandlerState <= HANDLERSTATE_PREPAREFORSYNC) && (pCurItem->fIncludeInProgressBar) ) { SYNCMGRPROGRESSITEM SyncProgressItem;
// unheck the state so PrepareForsync doesn't include
// this item.
pCurItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED;
SyncProgressItem.cbSize = sizeof(SYNCMGRPROGRESSITEM); SyncProgressItem.mask = SYNCMGRPROGRESSITEM_PROGVALUE | SYNCMGRPROGRESSITEM_MAXVALUE | SYNCMGRPROGRESSITEM_STATUSTYPE; SyncProgressItem.iProgValue = HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE; SyncProgressItem.iMaxValue = HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE; SyncProgressItem.dwStatusType = SYNCMGRSTATUS_SKIPPED;
// need to setup HwndCallback so progres gets updated.
// review, after ship why can't setup HwndCallback on transferqueueu
pCurHandlerInfo->hWndCallback = m_hwndDlg;
clockqueue.Leave();
Progress(pCurHandlerInfo->pHandlerId, pCurItem->offlineItem.ItemID,&SyncProgressItem);
clockqueue.Enter(); } }
pCurHandlerInfo->dwOutCallMessages &= ~ThreadMsg_SetItemStatus; } } }
pCurItem = pCurItem->pnextItem; } }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ItemHasProperties, public
//
// Synopsis: determines if the item in the queue has properties.
// Uses the first item match it finds.
//
// Arguments:
//
// Returns: Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ItemHasProperties(REFCLSID clsidHandler,REFSYNCMGRITEMID ItemID) { LPHANDLERINFO pHandlerInfo; LPITEMLIST pItem; HRESULT hr = S_FALSE; CLock clockqueue(this);
Assert(QUEUETYPE_CHOICE == m_QueueType); ASSERT_LOCKNOTHELD(this);
clockqueue.Enter();
// item is guidNULL this is toplevel so use the getHandlerInfo, else see
// if the item supports showProperties.
if (S_OK == FindItemData(clsidHandler,ItemID, HANDLERSTATE_PREPAREFORSYNC,HANDLERSTATE_PREPAREFORSYNC,&pHandlerInfo,&pItem)) { if (GUID_NULL == ItemID) { Assert(NULL == pItem);
hr = ((pHandlerInfo->SyncMgrHandlerInfo).SyncMgrHandlerFlags & SYNCMGRHANDLER_HASPROPERTIES) ? S_OK : S_FALSE; } else { Assert(pItem); if (pItem) { hr = (pItem->offlineItem).dwFlags & SYNCMGRITEM_HASPROPERTIES ? S_OK : S_FALSE; } else { hr = S_FALSE; } } }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ShowProperties, public
//
// Synopsis: Calls the ShowProperties Method on the first items it finds.
// Uses the first item match it finds.
//
// Arguments:
//
// Returns: Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ShowProperties(REFCLSID clsidHandler,REFSYNCMGRITEMID ItemID,HWND hwndParent) { LPHANDLERINFO pHandlerInfo; LPHANDLERINFO pHandlerId = NULL; LPITEMLIST pItem; HRESULT hr = E_UNEXPECTED; BOOL fHandlerCalled = FALSE; BOOL fHasProperties = FALSE; CThreadMsgProxy *pThreadProxy; CLock clockqueue(this);
Assert(QUEUETYPE_CHOICE == m_QueueType); ASSERT_LOCKNOTHELD(this);
clockqueue.Enter();
if (S_OK == FindItemData(clsidHandler,ItemID, HANDLERSTATE_PREPAREFORSYNC,HANDLERSTATE_PREPAREFORSYNC,&pHandlerInfo,&pItem)) { Assert(HANDLERSTATE_PREPAREFORSYNC == pHandlerInfo->HandlerState);
pThreadProxy = pHandlerInfo->pThreadProxy; pHandlerId = pHandlerInfo->pHandlerId;
Assert(!(ThreadMsg_ShowProperties & pHandlerInfo->dwOutCallMessages)); pHandlerInfo->dwOutCallMessages |= ThreadMsg_ShowProperties;
if (GUID_NULL == ItemID && pHandlerInfo) { Assert(NULL == pItem);
fHasProperties = (pHandlerInfo->SyncMgrHandlerInfo).SyncMgrHandlerFlags & SYNCMGRHANDLER_HASPROPERTIES ? TRUE : FALSE; } else if (pItem) { Assert(SYNCMGRITEM_HASPROPERTIES & pItem->offlineItem.dwFlags); fHasProperties = (pItem->offlineItem).dwFlags & SYNCMGRITEM_HASPROPERTIES ? TRUE : FALSE; } else { fHasProperties = FALSE; } clockqueue.Leave();
// make sure properties flag isn't set.
if (fHasProperties && pThreadProxy ) { fHandlerCalled = TRUE; hr = pThreadProxy->ShowProperties(hwndParent,ItemID); } else { AssertSz(0,"ShowProperties called on an Item without properties"); hr = S_FALSE; }
Assert(pHandlerId);
if ( (fHandlerCalled && (FAILED(hr))) || (!fHandlerCalled) ) { GUID guidCompletion = ItemID; CallCompletionRoutine(pHandlerId,ThreadMsg_ShowProperties,hr,1,&guidCompletion);
// since called completion routine map anything but S_OK to S_FALSE;
// so caller doesn't wait for the callback.
if (S_OK != hr) { hr = S_FALSE; } } } else { Assert(FAILED(hr)); // should return some failure so caller knows callback isn't coming.
clockqueue.Leave(); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ReEnumHandlerItems, public
//
// Synopsis: Deletes any Items associated with any handlers that
// match the clsid of the handler and then
// call the first handlers in the list enumeration method
// again.
//
// Arguments:
//
// Returns: Appropriate error return codes
//
// Modifies:
//
// History: 30-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ReEnumHandlerItems(REFCLSID clsidHandler,REFSYNCMGRITEMID ItemID) { LPHANDLERINFO pCurHandlerInfo = NULL; HANDLERINFO *pHandlerId = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
if (QUEUETYPE_CHOICE != m_QueueType) { Assert(QUEUETYPE_CHOICE == m_QueueType); return E_UNEXPECTED; }
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { if (clsidHandler == pCurHandlerInfo->clsidHandler) { LPITEMLIST pNextItem;
// if first handler we found update the handlerID
if (pHandlerId) { pHandlerId = pCurHandlerInfo->pHandlerId; pCurHandlerInfo->HandlerState = HANDLERSTATE_ADDHANDLERTEMS; // put back to addhandlerItems statest
}
pCurHandlerInfo->wItemCount = 0;
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { pNextItem = pCurItem->pnextItem; FREE(pCurItem); pCurItem = pNextItem; }
pCurHandlerInfo->pFirstItem = NULL; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
// if have a handler id add them back to the queue
if (pHandlerId) { DWORD cbNumItemsAdded;
AddHandlerItemsToQueue(pHandlerId,&cbNumItemsAdded); }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::IsItemCompleted, private
//
// Synopsis: Given an handler item determines if its
// synchronization is completed
//
// !!!This is not efficient. n! solution. If get
// a lot of items may need to have to rewrite
// and cache some information concerning dup
// items.
//
// Arguments: [wHandlerId] - Handler the item belongs too.
// [wItemID] - Identifies the Item
//
// Returns:
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CHndlrQueue::IsItemCompleted(LPHANDLERINFO pHandler,LPITEMLIST pItem) { CLSID clsidHandler; SYNCMGRITEMID ItemId; int iItemNotComplete = 0;
Assert(pHandler); Assert(pItem);
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
clsidHandler = pHandler->clsidHandler; ItemId = pItem->offlineItem.ItemID;
// back up to beginning of handler to simplify logic
// items must be pCurItem->fIncludeInProgressBar && !pCurItem->fProgressBarHandled
// to count toward not being a completion;
while (pHandler) { if (pHandler->clsidHandler == clsidHandler) { // see if handler info has a matching item
pItem = pHandler->pFirstItem;
while (pItem) { if (pItem->offlineItem.ItemID == ItemId) { if (pItem->fIncludeInProgressBar && !pItem->fProgressBarHandled) { if (pItem->iProgValue < pItem->iProgMaxValue) { ++iItemNotComplete; }
pItem->fProgressBarHandled = TRUE; } }
pItem = pItem->pnextItem; } }
pHandler = pHandler->pNextHandler; }
return iItemNotComplete ? FALSE : TRUE; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetItemProgressInfo, public
//
// Synopsis: Updates the stored progress information for the
// Associated Items
//
// Arguments: [wHandlerId] - Handler the item belongs too.
// [wItemID] - Identifies the Item
// [pSyncProgressItem] - Pointer to Progress Information.
// [pfProgressChanged] - returns true if any progress values were changed
// for the item
//
// Returns: S_OK - at least one item with the iItem assigned was found
// S_FALSE - Item does not have properties.
// Appropriate error return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetItemProgressInfo(HANDLERINFO *pHandlerId,WORD wItemID, LPSYNCMGRPROGRESSITEM pSyncProgressItem, BOOL *pfProgressChanged) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; BOOL fFoundMatch = FALSE; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
Assert(pfProgressChanged);
*pfProgressChanged = FALSE;
if (QUEUETYPE_PROGRESS != m_QueueType) { Assert(QUEUETYPE_PROGRESS == m_QueueType); return E_UNEXPECTED; // review error code.
}
clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { // try to find the matching item.
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { if (wItemID == pCurItem->wItemId) { fFoundMatch = TRUE; break; }
pCurItem = pCurItem->pnextItem; } }
if (fFoundMatch) { SetItemProgressInfo(pCurItem,pSyncProgressItem,pfProgressChanged); }
clockqueue.Leave();
return fFoundMatch ? S_OK : S_FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetItemProgressInfo, private
//
// Synopsis: Updates the stored progress information for the
// Associated iTEM
//
// Arguments: [pItem] - Identifies the Item
// [pSyncProgressItem] - Pointer to Progress Information.
// [pfProgressChanged] - returns true if any progress values were changed
// for the item
//
// Returns: S_OK - at least one item with the iItem assigned was found
// Appropriate error return codes
//
// !!Caller must have already taken a lock.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetItemProgressInfo(LPITEMLIST pItem,LPSYNCMGRPROGRESSITEM pSyncProgressItem, BOOL *pfProgressChanged) { BOOL fProgressAlreadyCompleted;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
// progress is considered complete if Values is >= Maxa
fProgressAlreadyCompleted = (pItem->iProgMaxValue <= pItem->iProgValue);
if (SYNCMGRPROGRESSITEM_MAXVALUE & pSyncProgressItem->mask) { // if Progress Max Value is negative then don't set.
if (pSyncProgressItem->iMaxValue >= 0) { if (pItem->iProgMaxValue != pSyncProgressItem->iMaxValue) { *pfProgressChanged = TRUE; pItem->fProgValueDirty = TRUE; pItem->iProgMaxValue = pSyncProgressItem->iMaxValue; } } }
if (SYNCMGRPROGRESSITEM_PROGVALUE & pSyncProgressItem->mask) { // if progress value is negative, don't change it
if (pSyncProgressItem->iProgValue > 0) { if (pItem->iProgValue != pSyncProgressItem->iProgValue) { *pfProgressChanged = TRUE; pItem->fProgValueDirty = TRUE; pItem->iProgValue = pSyncProgressItem->iProgValue; } } }
if (SYNCMGRPROGRESSITEM_STATUSTYPE & pSyncProgressItem->mask) { if (pItem->dwStatusType != pSyncProgressItem->dwStatusType) { *pfProgressChanged = TRUE; pItem->dwStatusType = pSyncProgressItem->dwStatusType;
// if status is complete set the progvalue == to the max
// on behalf of the handler so the Items completed and progress bar
// gets updated.
if (pItem->dwStatusType == SYNCMGRSTATUS_SKIPPED || pItem->dwStatusType == SYNCMGRSTATUS_SUCCEEDED || pItem->dwStatusType == SYNCMGRSTATUS_FAILED ) { pItem->fProgValueDirty = TRUE; pItem->iProgValue = pItem->iProgMaxValue; } } }
// if progressValue is > max then set it to max
if (pItem->iProgValue > pItem->iProgMaxValue) { // AssertSz(0,"Progress Value is > Max");
pItem->iProgValue = pItem->iProgMaxValue; }
// see if need to recalc numItems completed next time
// GetProgressInfo is Called.
BOOL fProgressCompletedNow = (pItem->iProgMaxValue <= pItem->iProgValue);
if (fProgressAlreadyCompleted != fProgressCompletedNow) { m_fNumItemsCompleteNeedsARecalc = TRUE; }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetItemProgressValues, private
//
// Synopsis: Private helper function for updating/initializing
// an items progress bar values.
//
// Arguments: [pItem] - Identifies the Item
// [pSyncProgressItem] - Pointer to Progress Information.
// [pfProgressChanged] - returns true if any progress values were changed
// for the item
//
// Returns: S_OK - at least one item with the iItem assigned was found
// Appropriate error return codes
//
// !!Caller must have already taken a lock.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetItemProgressValues(LPITEMLIST pItem,INT iProgValue,INT iProgMaxValue) { SYNCMGRPROGRESSITEM SyncProgressItem; BOOL fProgressChanged;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
SyncProgressItem.cbSize = sizeof(SYNCMGRPROGRESSITEM); SyncProgressItem.mask = SYNCMGRPROGRESSITEM_PROGVALUE | SYNCMGRPROGRESSITEM_MAXVALUE; SyncProgressItem.iProgValue = iProgValue; SyncProgressItem.iMaxValue = iProgMaxValue;
return SetItemProgressInfo(pItem,&SyncProgressItem,&fProgressChanged); }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetProgressInfo, public
//
// Synopsis: calculates current progress bar values and number of items complete.
//
// Arguments: [piProgValue] - on return contains the new Progress Bar Value.
// [piMaxValue] - on return contains the Progress Bar Max Value
// [piNumItemsComplete] - on returns contains number of items complete.
// [iNumItemsTotal] - on returns contains number of total items.
//
// Returns: Appropriate error codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetProgressInfo(INT *piProgValue,INT *piMaxValue,INT *piNumItemsComplete, INT *piNumItemsTotal) { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; INT iCurValue; BOOL fNormalizedValueChanged = FALSE; CLock clockqueue(this);
if (QUEUETYPE_PROGRESS != m_QueueType) { Assert(QUEUETYPE_PROGRESS == m_QueueType); return E_UNEXPECTED; // review error code.
}
clockqueue.Enter();
// if m_fNumItemsCompleteNeedsARecalc is set need
// to recalc normalized and numItems Comlete and Total Items.
if (m_fNumItemsCompleteNeedsARecalc) { INT iNormalizedMax;
m_ulProgressItemCount = 0;
// get the number of selected items in the queue.
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (pCurItem->fIncludeInProgressBar) { //if this item should be included in the progress, increment the progress bar count.
++m_ulProgressItemCount;
pCurItem->fProgressBarHandled = FALSE; // reset handled
}
pCurItem = pCurItem->pnextItem; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
if (0 == m_ulProgressItemCount) { iNormalizedMax = 0; } else { iNormalizedMax = MAXPROGRESSVALUE/m_ulProgressItemCount;
if (0 == iNormalizedMax) { iNormalizedMax = 1; } }
if (m_iNormalizedMax != iNormalizedMax) { fNormalizedValueChanged = TRUE; m_iNormalizedMax = iNormalizedMax; } }
// now loop thruogh again getting total CurValue and finished items
// we say an item is finished if it is out of the synchronize method or the min==max.
pCurHandlerInfo = m_pFirstHandler; iCurValue = 0;
// if numitemcount needs updated reset the member vars
if (m_fNumItemsCompleteNeedsARecalc) { m_iCompletedItems = 0; m_iItemCount = 0; } while (pCurHandlerInfo) { // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (pCurItem->fIncludeInProgressBar) { // if Progress is dirty or normalized value changed
// need to recalc this items progress value
if (pCurItem->fProgValueDirty || fNormalizedValueChanged) { int iProgValue = pCurItem->iProgValue; int iProgMaxValue = pCurItem->iProgMaxValue; if (iProgValue && iProgMaxValue) { pCurItem->iProgValueNormalized = (int) ((1.0*iProgValue*m_iNormalizedMax)/iProgMaxValue); } else { pCurItem->iProgValueNormalized = 0; }
pCurItem->fProgValueDirty = FALSE; }
iCurValue += pCurItem->iProgValueNormalized;
// Handle NumItems needing to be recalc'd
if (m_fNumItemsCompleteNeedsARecalc && !pCurItem->fProgressBarHandled) { ++m_iItemCount; // now loop through this item and remaining items and if any match
// mark as handled and if complete then incrment the compleated count;
if (IsItemCompleted(pCurHandlerInfo,pCurItem)) { ++m_iCompletedItems; } } }
pCurItem = pCurItem->pnextItem; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
m_fNumItemsCompleteNeedsARecalc = FALSE;
*piProgValue = iCurValue; *piMaxValue = m_iNormalizedMax*m_ulProgressItemCount; *piNumItemsComplete = m_iCompletedItems; *piNumItemsTotal = m_iItemCount;
Assert(*piProgValue <= *piMaxValue);
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::RemoveFinishedProgressItems, public
//
// Synopsis: Loops through handler setting any finished items
// fIncludeInProgressBar value to false
//
// Arguments:
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::RemoveFinishedProgressItems() { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
clockqueue.Enter();
m_fNumItemsCompleteNeedsARecalc = TRUE;
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { // mark any items that have completed their synchronization.
if (HANDLERSTATE_INSYNCHRONIZE < pCurHandlerInfo->HandlerState) { // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { pCurItem->fIncludeInProgressBar = FALSE; pCurItem = pCurItem->pnextItem; }
}
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AreAnyItemsSelectedInQueue, public
//
// Synopsis: Determines if there are any items selected in the queue.
// can be called by choice dialog for example before creating
// progress and doing a transfer since there is no need to
// if nothing to sync anyways.
//
// Arguments:
//
// Returns: TRUE - At least one item is selected inthe queue
// FALSE - No Items are slected in the queue.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CHndlrQueue::AreAnyItemsSelectedInQueue() { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; BOOL fFoundSelectedItem = FALSE; CLock clockqueue(this);
clockqueue.Enter();
// invalidate UI that applies to entire queue
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo && !fFoundSelectedItem) { // if handler state is less than a completion go ahead and
// check the items.
if (HANDLERSTATE_HASERRORJUMPS > pCurHandlerInfo->HandlerState) { pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { // clear Item UI information
if (pCurItem->offlineItem.dwItemState == SYNCMGRITEMSTATE_CHECKED) { fFoundSelectedItem = TRUE; break; }
pCurItem = pCurItem->pnextItem; } }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return fFoundSelectedItem; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::PersistChoices, public
//
// Synopsis: Saves Selected Users choices for the next time
// the choice dialog is brought up. Only should
// be called from a choice queue.
//
// Arguments:
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::PersistChoices(void) { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; CLock clockqueue(this);
if (QUEUETYPE_CHOICE != m_QueueType) { Assert(QUEUETYPE_CHOICE == m_QueueType); return S_FALSE; }
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
// currently only persist on a manual invoke since user
// has to go to settings to change other invoke types and
// that is persisted
// since this is the choice queue we know all handlers have the
// same JobID. if this ever changes, have to set on a case by
// case basis.
if (m_pFirstJobInfo && m_pFirstJobInfo->pConnectionObj && (SYNCMGRFLAG_MANUAL == (m_pFirstJobInfo->dwSyncFlags & SYNCMGRFLAG_EVENTMASK)) ) { TCHAR *pszConnectionName = m_pFirstJobInfo->pConnectionObj[0]->pwszConnectionName; DWORD dwSyncFlags = m_pFirstJobInfo->dwSyncFlags;
Assert(1 == m_pFirstJobInfo->cbNumConnectionObjs); // assert manual only ever has one connectionObj
// delete all previously stored preferences.
// this is valid because only called from choice queue that all ConnectionNames are the same.
if (!m_fItemsMissing) { RegRemoveManualSyncSettings(pszConnectionName); }
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { // only save if Handler is in the PrepareForSync state.
// bug, need to make sure return code from enum wasn't missing items
if (HANDLERSTATE_PREPAREFORSYNC == pCurHandlerInfo->HandlerState ) { // save out these items.
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (!pCurItem->fDuplicateItem) { switch(dwSyncFlags & SYNCMGRFLAG_EVENTMASK) { case SYNCMGRFLAG_MANUAL: RegSetSyncItemSettings(SYNCTYPE_MANUAL, pCurHandlerInfo->clsidHandler, pCurItem->offlineItem.ItemID, pszConnectionName, pCurItem->offlineItem.dwItemState, NULL); break; default: AssertSz(0,"UnknownSyncFlag Event"); break; }; }
pCurItem = pCurItem->pnextItem; } }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; } }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FindFirstHandlerInState, public
//
// Synopsis: Finds the first Handler that matches the specified
// state in the queue.
//
// Arguments: [hndlrState] - Requested handler state.
// [pwHandlerID] - on success filled with HandlerID that was found
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FindFirstHandlerInState(HANDLERSTATE hndlrState, REFCLSID clsidHandler, HANDLERINFO **ppHandlerId,CLSID *pMatchHandlerClsid) { return FindNextHandlerInState(0, clsidHandler,hndlrState, ppHandlerId, pMatchHandlerClsid); }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FindNextHandlerInState, public
//
// Synopsis: Finds next handler after LastHandlerID in the queue that matches
// the requested state. Passing in 0 for the LastHandlerID is the same
// as calling FindFirstHandlerInState
//
// if GUID_NULL is passed in for the clsidHandler the first handler that
// matches the specified state is returned.
//
// Arguments: [wLastHandlerID] - Id of last handler found.
// [clsidHandler] - specific handler classid is requested, only find matches with this clsid
// [hndlrState] - Requested handler state.
// [pwHandlerID] - on success filled with HandlerID that was found
// [pMatchHandlerClsid] - on sucdess clsid of handler found.
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FindNextHandlerInState(HANDLERINFO *pLastHandlerID,REFCLSID clsidHandler, HANDLERSTATE hndlrState,HANDLERINFO **ppHandlerID,CLSID *pMatchHandlerClsid) { HRESULT hr = S_FALSE; LPHANDLERINFO pCurHandler; CLock clockqueue(this);
*ppHandlerID = 0;
clockqueue.Enter();
pCurHandler = m_pFirstHandler;
if (pLastHandlerID) { // loop foward until find the last handlerID we checked or hit the end
while (pCurHandler) { if (pLastHandlerID == pCurHandler->pHandlerId) { break; }
pCurHandler = pCurHandler->pNextHandler; }
if (pCurHandler) { pCurHandler = pCurHandler->pNextHandler; // increment to next handler.
} }
while (pCurHandler) { if ( (hndlrState == pCurHandler->HandlerState) && ((GUID_NULL == clsidHandler) || (clsidHandler == pCurHandler->clsidHandler)) ) { *ppHandlerID = pCurHandler->pHandlerId; *pMatchHandlerClsid = pCurHandler->clsidHandler; hr = S_OK; break; }
pCurHandler = pCurHandler->pNextHandler; }
clockqueue.Leave(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::CreateServer, public
//
// Synopsis: Creates a new proxy then calls proxy to create and instance of the
// specified handler.
//
// Arguments: [wHandlerId] - Id of handler to call.
// [pCLSIDServer] - CLSID of Handler to Create.
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::CreateServer(HANDLERINFO *pHandlerId, const CLSID *pCLSIDServer) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { Assert(HANDLERSTATE_CREATE == pHandlerInfo->HandlerState);
Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
if (HANDLERSTATE_CREATE == pHandlerInfo->HandlerState) { pHandlerInfo->HandlerState = HANDLERSTATE_INCREATE; Assert(NULL == pHandlerInfo->pThreadProxy);
// see if there is already a thread for this handler's
// CLSID.
hr = CreateHandlerThread(&(pHandlerInfo->pThreadProxy), m_hwndDlg, *pCLSIDServer);
if (S_OK == hr) { HANDLERINFO *pHandlerIdArg; CThreadMsgProxy *pThreadProxy;
pHandlerIdArg = pHandlerInfo->pHandlerId; pThreadProxy = pHandlerInfo->pThreadProxy;
clockqueue.Leave();
hr = pThreadProxy->CreateServer(pCLSIDServer,this,pHandlerIdArg);
clockqueue.Enter();
pHandlerInfo->pThreadProxy = pThreadProxy; }
if (S_OK == hr) { pHandlerInfo->clsidHandler = *pCLSIDServer; pHandlerInfo->HandlerState = HANDLERSTATE_INITIALIZE; } else { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; } }
pHandlerInfo->dwCallNestCount--; }
clockqueue.Leave(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::Initialize, public
//
// Synopsis: Calls Hanlder's Initialize method
//
// Arguments: [wHandlerId] - Id of handler to call.
// [dwReserved] - Initialize reserved parameter
// [dwSyncFlags] - Sync flags
// [cbCookie] - size of cookie data
// [lpCookie] - ptr to cookie data
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::Initialize(HANDLERINFO *pHandlerId,DWORD dwReserved,DWORD dwSyncFlags, DWORD cbCookie,const BYTE *lpCooke) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId, &pHandlerInfo)) { Assert(HANDLERSTATE_INITIALIZE == pHandlerInfo->HandlerState); Assert(pHandlerInfo->pThreadProxy);
Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
if ( (HANDLERSTATE_INITIALIZE == pHandlerInfo->HandlerState) && (pHandlerInfo->pThreadProxy) ) { CThreadMsgProxy *pThreadProxy;
Assert(dwSyncFlags & SYNCMGRFLAG_EVENTMASK); // an event should be set
pHandlerInfo->HandlerState = HANDLERSTATE_ININITIALIZE;
pThreadProxy = pHandlerInfo->pThreadProxy;
clockqueue.Leave();
hr = pThreadProxy->Initialize(dwReserved,dwSyncFlags,cbCookie,lpCooke);
clockqueue.Enter();
if (S_OK == hr) { pHandlerInfo->HandlerState = HANDLERSTATE_ADDHANDLERTEMS; } else { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; } }
pHandlerInfo->dwCallNestCount--; }
clockqueue.Leave(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AddHandlerItemsToQueue, public
//
// Synopsis: Calls through to proxy to add items to the queue
//
// Arguments: [wHandlerId] - Id of handler to call.
//
// Returns: Appropriate return codes.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::AddHandlerItemsToQueue(HANDLERINFO *pHandlerId,DWORD *pcbNumItems) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
Assert(pcbNumItems); Assert(QUEUETYPE_CHOICE == m_QueueType); // items should only be added in a choice queue.
*pcbNumItems = 0;
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
Assert(HANDLERSTATE_ADDHANDLERTEMS == pHandlerInfo->HandlerState); Assert(pHandlerInfo->pThreadProxy);
if ( (HANDLERSTATE_ADDHANDLERTEMS == pHandlerInfo->HandlerState) && (pHandlerInfo->pThreadProxy) ) { CThreadMsgProxy *pThreadProxy;
pHandlerInfo->HandlerState = HANDLERSTATE_INADDHANDLERITEMS; pThreadProxy = pHandlerInfo->pThreadProxy;
clockqueue.Leave();
// on return all items should be filled in.
hr = pThreadProxy->AddHandlerItems(NULL /* HWND */,pcbNumItems);
clockqueue.Enter();
if ( (S_OK == hr) || (S_SYNCMGR_MISSINGITEMS == hr) ) { if (S_SYNCMGR_MISSINGITEMS == hr) m_fItemsMissing = TRUE;
hr = S_OK; // review, need to handler missing items in registry.
pHandlerInfo->HandlerState = HANDLERSTATE_PREPAREFORSYNC; } else { // on an error, go ahead and release the proxy if server can't enum
pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; *pcbNumItems = 0; } }
pHandlerInfo->dwCallNestCount--; }
clockqueue.Leave(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetItemObject, public
//
// Synopsis: Calls through to proxy to get an items object pointer
//
// Arguments: [wHandlerId] - Id of handler to call.
// [wItemID] - ID of item to get the object of.
// [riid] - interface requested of the object
// [ppv] - on success is a pointer to the newly created object
//
// Returns: Currently all handlers should return E_NOTIMPL.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::GetItemObject(HANDLERINFO *pHandlerId,WORD wItemID,REFIID riid,void** ppv) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
Assert(QUEUETYPE_PROGRESS == m_QueueType);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { LPITEMLIST pCurItem;
Assert(HANDLERSTATE_PREPAREFORSYNC == pHandlerInfo->HandlerState); Assert(pHandlerInfo->pThreadProxy);
Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
if ( (HANDLERSTATE_PREPAREFORSYNC == pHandlerInfo->HandlerState) && (pHandlerInfo->pThreadProxy)) { // now try to find the item.
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { if (wItemID == pCurItem->wItemId) { CThreadMsgProxy *pThreadProxy; SYNCMGRITEMID ItemID;
pThreadProxy = pHandlerInfo->pThreadProxy; ItemID = pCurItem->offlineItem.ItemID; clockqueue.Leave();
hr = pThreadProxy->GetItemObject(ItemID,riid,ppv);
return hr; }
pCurItem = pCurItem->pnextItem; } }
pHandlerInfo->dwCallNestCount--; }
clockqueue.Leave();
AssertSz(0, "Specified object wasn't found"); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetUpProgressCallback, public
//
// Synopsis: Calls through to proxy to set up the progress callback
//
// Arguments: [wHandlerId] - Id of handler to call.
// [fSet] - TRUE == create, FALSE == destroy.
// [hwnd] - Callback info should be sent to specified window.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetUpProgressCallback(HANDLERINFO *pHandlerId,BOOL fSet,HWND hwnd) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
AssertSz(0,"this function no longer used");
return E_NOTIMPL; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::PrepareForSync, public
//
// Synopsis: Calls through to Handlers PrepareForSync method.
//
// Arguments: [wHandlerId] - Id of handler to call.
// [hWndParent] - Hwnd to use for any displayed dialogs.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::PrepareForSync(HANDLERINFO *pHandlerId,HWND hWndParent) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; ULONG cbNumItems; SYNCMGRITEMID *pItemIDs; BOOL fHandlerCalled = FALSE; CLock clockqueue(this);
Assert(QUEUETYPE_PROGRESS == m_QueueType);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { Assert(HANDLERSTATE_PREPAREFORSYNC == pHandlerInfo->HandlerState); Assert(pHandlerInfo->pThreadProxy);
Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
Assert(!(ThreadMsg_PrepareForSync & pHandlerInfo->dwOutCallMessages)); pHandlerInfo->dwOutCallMessages |= ThreadMsg_PrepareForSync;
if (HANDLERSTATE_PREPAREFORSYNC == pHandlerInfo->HandlerState) { // if item doesn't have a ThreadProxy or it has been cancelled,
// put in the Release State
if ( (NULL == pHandlerInfo->pThreadProxy) || (pHandlerInfo->fCancelled) ) { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; } else { // create a list of the selected items and pass to PrepareForSync
cbNumItems = GetSelectedItemsInHandler(pHandlerInfo,0,NULL); if (0 == cbNumItems) { // if no items selected don't call prepareforsync
// and set the HandlerState so it can be released
pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; hr = S_FALSE; } else { pItemIDs = (SYNCMGRITEMID *) ALLOC(sizeof(SYNCMGRITEMID)*cbNumItems);
if (pItemIDs) { // loop through items filling in the proper data
GetSelectedItemsInHandler(pHandlerInfo,&cbNumItems,pItemIDs);
if (0 == cbNumItems) { hr = S_FALSE; // There are no selected items.
} else { CThreadMsgProxy *pThreadProxy; JOBINFO *pJobInfo = NULL;
pHandlerInfo->HandlerState = HANDLERSTATE_INPREPAREFORSYNC;
pThreadProxy = pHandlerInfo->pThreadProxy; pHandlerInfo->hWndCallback = hWndParent; pJobInfo = pHandlerInfo->pJobInfo;
// if we need to dial to make the connection do
// so now.
clockqueue.Leave();
DWORD dwSyncFlags = pJobInfo->dwSyncFlags & SYNCMGRFLAG_EVENTMASK; BOOL fAutoDialDisable = TRUE; if ( dwSyncFlags == SYNCMGRFLAG_MANUAL || dwSyncFlags == SYNCMGRFLAG_INVOKE ) fAutoDialDisable = FALSE;
//
// Ignore failure return from ApplySyncItemDialState
//
ApplySyncItemDialState( fAutoDialDisable );
hr = OpenConnection(pJobInfo);
if (S_OK == hr) { // if this is on an idle write out the last
// handler id
// review - if don't wait to call PrepareForSync
// on idle the setlastIdlehandler should be called on sync.
if (pJobInfo && (SYNCMGRFLAG_IDLE == (pJobInfo->dwSyncFlags & SYNCMGRFLAG_EVENTMASK)) ) { SetLastIdleHandler(pHandlerInfo->clsidHandler); }
fHandlerCalled = TRUE; hr = pThreadProxy->PrepareForSync(cbNumItems, pItemIDs, hWndParent, 0 /* dwReserved */ );
} else { clockqueue.Enter(); pHandlerInfo->hWndCallback = NULL; clockqueue.Leave(); } }
// on return from PrepareFroSync or error need to free items
clockqueue.Enter(); FREE(pItemIDs); } else { hr = E_OUTOFMEMORY; } } } } }
clockqueue.Leave();
// if the handler returns an errorfrom PrepareForSync we need
// to call the completion routine ourselves and/or we never got to the point
// of making the outcall.
if ( (fHandlerCalled && (S_OK != hr)) || (!fHandlerCalled)) { CallCompletionRoutine(pHandlerId,ThreadMsg_PrepareForSync,hr,0,NULL); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::PrepareForSyncCompleted, public
//
// Synopsis: Called by completion routine on a PrepareForSyncCompleted
//
// Warning: Assume queue is locked and pHandlerInfo has
// already been verified.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 02-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::PrepareForSyncCompleted(LPHANDLERINFO pHandlerInfo,HRESULT hCallResult) { ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
if (S_OK == hCallResult) { pHandlerInfo->HandlerState = HANDLERSTATE_SYNCHRONIZE; } else { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; }
if ( (pHandlerInfo->HandlerState != HANDLERSTATE_SYNCHRONIZE)) { // if handler didn't make it to the synchronize state then fix up the items
LPITEMLIST pCurItem = NULL;
// prepare for sync either doesn't want to handle the
// items or an error occured,
// need to go ahead and mark the items as completed.
// same routine that is after synchronize.
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { SetItemProgressValues(pCurItem, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE);
pCurItem->fSynchronizingItem = FALSE;
pCurItem = pCurItem->pnextItem; } }
pHandlerInfo->dwCallNestCount--; // decrement nestcount put on by PrepareForSync call.
// if the handler state has been released but it has some jumptext, which it can if
// the PrepareForsync was caused by a retry then set the results to HANDLERSTATE_HASERRORJUMPS
if ((HANDLERSTATE_RELEASE == pHandlerInfo->HandlerState) && (pHandlerInfo->fHasErrorJumps)) { pHandlerInfo->HandlerState = HANDLERSTATE_HASERRORJUMPS; }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::Synchronize, public
//
// Synopsis: Calls through to Handlers Synchronize method.
//
// Arguments: [wHandlerId] - Id of handler to call.
// [hWndParent] - Hwnd to use for any displayed dialogs.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::Synchronize(HANDLERINFO *pHandlerId,HWND hWndParent) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; BOOL fHandlerCalled = FALSE; CLock clockqueue(this);
Assert(QUEUETYPE_PROGRESS == m_QueueType);
ASSERT_LOCKNOTHELD(this); clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { Assert(HANDLERSTATE_SYNCHRONIZE == pHandlerInfo->HandlerState); Assert(pHandlerInfo->pThreadProxy);
Assert(0 == pHandlerInfo->dwCallNestCount); pHandlerInfo->dwCallNestCount++;
Assert(!(ThreadMsg_Synchronize & pHandlerInfo->dwOutCallMessages)); pHandlerInfo->dwOutCallMessages |= ThreadMsg_Synchronize;
if ( (HANDLERSTATE_SYNCHRONIZE == pHandlerInfo->HandlerState) && (pHandlerInfo->pThreadProxy) ) { // make sure the handler has a proxy and the item
// wasn't cancelled.
if ( (NULL == pHandlerInfo->pThreadProxy) || (pHandlerInfo->fCancelled)) { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; } else { CThreadMsgProxy *pThreadProxy;
pHandlerInfo->HandlerState = HANDLERSTATE_INSYNCHRONIZE; pThreadProxy= pHandlerInfo->pThreadProxy;
clockqueue.Leave(); fHandlerCalled = TRUE; hr = pThreadProxy->Synchronize(hWndParent); clockqueue.Enter(); } } }
clockqueue.Leave();
// if the handler returns an error from Synchronize we need
// to call the completion routine ourselves and/or we never got to the point
// of making the outcall.
if ( (fHandlerCalled && (S_OK != hr)) || (!fHandlerCalled) ) { CallCompletionRoutine(pHandlerId,ThreadMsg_Synchronize,hr,0,NULL); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SynchronizeCompleted, public
//
// Synopsis: Called by completion routine on a SynchronizeCompleted
//
// Warning: Assume queue is locked and pHandlerInfo has
// already been verified.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 02-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SynchronizeCompleted(LPHANDLERINFO pHandlerInfo,HRESULT hCallResult) { LPITEMLIST pCurItem = NULL; BOOL fRetrySync = FALSE;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
if (pHandlerInfo->fRetrySync) { // if a retry request came in during the sync, retry it.
pHandlerInfo->HandlerState = HANDLERSTATE_PREPAREFORSYNC; pHandlerInfo->fRetrySync = FALSE; // reset the retry sync flag.
fRetrySync = TRUE; } else if (pHandlerInfo->fHasErrorJumps) { pHandlerInfo->HandlerState = HANDLERSTATE_HASERRORJUMPS; } else { pHandlerInfo->HandlerState = HANDLERSTATE_RELEASE; }
// when come out of synchronize we set the items values for them.
// in case they were negligent.
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { SetItemProgressValues(pCurItem, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE);
pCurItem->fSynchronizingItem = FALSE;
pCurItem = pCurItem->pnextItem;
}
pHandlerInfo->dwCallNestCount--; // remove nest count
// if the handler state has been released but it has some jumptext, which it can if
// the sycnrhonize was caused by a retry then set the results to HANDLERSTATE_HASERRORJUMPS
if ((HANDLERSTATE_RELEASE == pHandlerInfo->HandlerState) && (pHandlerInfo->fHasErrorJumps)) { pHandlerInfo->HandlerState = HANDLERSTATE_HASERRORJUMPS; }
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ShowError, public
//
// Synopsis: Calls through to Handlers ShowError method.
//
// Arguments: [wHandlerId] - Id of handler to call.
// [hWndParent] - Hwnd to use for any displayed dialogs.
// [dwErrorID] - Identifies the error to show
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ShowError(HANDLERINFO *pHandlerId,HWND hWndParent,REFSYNCMGRERRORID ErrorID) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; BOOL fHandlerCalled = FALSE; BOOL fAlreadyInShowErrors = TRUE; CLock clockqueue(this);
Assert(QUEUETYPE_PROGRESS == m_QueueType);
clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { Assert(pHandlerInfo->fHasErrorJumps); Assert(pHandlerInfo->pThreadProxy);
// if we are already handling a ShowError for this handler then don't
// start another one
if (!(pHandlerInfo->fInShowErrorCall)) { fAlreadyInShowErrors = FALSE; m_dwShowErrororOutCallCount++; // increment handlers ShowError OutCall Count.
Assert(!(ThreadMsg_ShowError & pHandlerInfo->dwOutCallMessages)); pHandlerInfo->dwOutCallMessages |= ThreadMsg_ShowError;
if (pHandlerInfo->pThreadProxy ) { CThreadMsgProxy *pThreadProxy; ULONG cbNumItems = 0; // review, these are not longer necessary.
SYNCMGRITEMID *pItemIDs = NULL;
pThreadProxy = pHandlerInfo->pThreadProxy; fHandlerCalled = TRUE; pHandlerInfo->fInShowErrorCall = TRUE;
clockqueue.Leave(); hr = pThreadProxy->ShowError(hWndParent,ErrorID,&cbNumItems,&pItemIDs); clockqueue.Enter(); } } }
clockqueue.Leave();
// if the handler returns an error from ShowError we need
// to call the completion routine ourselves and/or we never got to the point
// of making the outcall and there wasn't already an outcall in progress.
if ( (fHandlerCalled && (S_OK != hr)) || (!fHandlerCalled && !fAlreadyInShowErrors) ) { CallCompletionRoutine(pHandlerId,ThreadMsg_ShowError,hr,0,NULL); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ShowErrorCompleted, public
//
// Synopsis: Called by completion routine on a ShowErrorCompleted
//
// Warning: Assume queue is locked and pHandlerInfo has
// already been verified.
//
// Returns:
//
// Modifies:
//
// History: 02-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ShowErrorCompleted(LPHANDLERINFO pHandlerInfo,HRESULT hCallResult, ULONG cbNumItems,SYNCMGRITEMID *pItemIDs) { ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
if (S_SYNCMGR_RETRYSYNC == hCallResult) {
// validate we got something back for cbNumItems and pItemIDs or
// don't do anything
if ( (0 == cbNumItems) || (NULL == pItemIDs)) { Assert(cbNumItems); // assert in debug so can catch handlers.
Assert(pItemIDs); } else { SYNCMGRITEMID *pCurItemItemId; ULONG cbNumItemsIndex;
// if the handler is in the release state then change to prepareForSync
// if it is still in a synchronize just set the fRetrySync flag in the
// handler for it to check when done.
// Cases
// Handlers PrepareForSync Method hasn't been called. Just add items to request
// Handlers is between InPrepareForSync and InSynchronize. Set RetrySyncFlag
// Handler has is done with it synchronize. reset state to PrepareForSync
// when prepareforsync is called on an item it state gets set back to unchecked
// so just need to worry about setting appropriate items to checked.
pCurItemItemId = pItemIDs; for (cbNumItemsIndex = 0 ; cbNumItemsIndex < cbNumItems; cbNumItemsIndex++) { BOOL fFoundMatch = FALSE; LPITEMLIST pHandlerItem;
pHandlerItem = pHandlerInfo->pFirstItem; while (pHandlerItem) { if (*pCurItemItemId == pHandlerItem->offlineItem.ItemID) { pHandlerItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_CHECKED;
SetItemProgressValues(pHandlerItem,0, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE);
pHandlerItem->fIncludeInProgressBar = TRUE; fFoundMatch = TRUE; break; }
pHandlerItem = pHandlerItem->pnextItem; }
if (!fFoundMatch) { LPITEMLIST pNewItem; SYNCMGRITEM syncItem;
// if didn't find a match this must be a new item, add it to the list
// and set up the appropriate states.
// Note: items added like this should not be included in the progress bar.
// first time progress is called on an item it will get included
// in the progress bar.
syncItem.cbSize = sizeof(SYNCMGRITEM); syncItem.dwFlags = SYNCMGRITEM_TEMPORARY; syncItem.ItemID = *pCurItemItemId; syncItem.dwItemState = SYNCMGRITEMSTATE_CHECKED; syncItem.hIcon = NULL; *syncItem.wszItemName = L'\0';
pNewItem = AllocNewHandlerItem(pHandlerInfo,&syncItem);
if (pNewItem) { pNewItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_CHECKED;
SetItemProgressValues(pNewItem, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE);
pNewItem->fHiddenItem = TRUE; // set to indicate not part of UI.
pNewItem->fIncludeInProgressBar = FALSE; } }
++pCurItemItemId; }
if (pHandlerInfo->HandlerState < HANDLERSTATE_INPREPAREFORSYNC) { // don't reset anything. just make sure requested items are added
// to the request.
} else if (pHandlerInfo->HandlerState > HANDLERSTATE_INSYNCHRONIZE) { // if synchronize is complete reset the state to PrepareForSync.
pHandlerInfo->HandlerState = HANDLERSTATE_PREPAREFORSYNC; } else { // retry request came in between the PrepareForSync call and Synchronize
// being complete.
Assert(pHandlerInfo->HandlerState >= HANDLERSTATE_INPREPAREFORSYNC); Assert(pHandlerInfo->HandlerState < HANDLERSTATE_DEAD); pHandlerInfo->fRetrySync = TRUE; }
//
// If the handler has been canceled, uncancel it to enable the retry
//
pHandlerInfo->fCancelled = FALSE; } }
--m_dwShowErrororOutCallCount; // decrement handlers ShowError OutCall Count.
// should never happen but in case out call goes negative fixup to zero.
Assert( ((LONG) m_dwShowErrororOutCallCount) >= 0); if ( ((LONG) m_dwShowErrororOutCallCount) < 0) { m_dwShowErrororOutCallCount = 0; }
pHandlerInfo->fInShowErrorCall = FALSE; // handler is no longer in a ShowError Call
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::FindItemData, private
//
// Synopsis: finds associated handler and item info. caller must be
// holding the lock and access the returned info before
// releasing the lock
//
// !! Only matches items that have a state between or equal
// to the handler state ranges.
//
// !!! If ItemID of GUID_NULL is passed it it returns a match
// of the first handler found and sets pItem out param to NULL
//
// Arguments:
//
// Returns: Appropriate return codes
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::FindItemData(CLSID clsidHandler,REFSYNCMGRITEMID OfflineItemID, HANDLERSTATE hndlrStateFirst,HANDLERSTATE hndlrStateLast, LPHANDLERINFO *ppHandlerInfo,LPITEMLIST *ppItem) { LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; BOOL fNoMatchFound = TRUE; HRESULT hr = S_FALSE;
ASSERT_LOCKHELD(this);
Assert(ppHandlerInfo); Assert(ppItem);
*ppHandlerInfo = NULL; *ppItem = NULL;
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo && fNoMatchFound) { if ( (clsidHandler == pCurHandlerInfo->clsidHandler) && (hndlrStateLast >= pCurHandlerInfo->HandlerState) && (hndlrStateFirst <= pCurHandlerInfo->HandlerState) ) { *ppHandlerInfo = pCurHandlerInfo;
// if top level item tem ppItem to NULL and return okay
if (GUID_NULL == OfflineItemID) { *ppItem = NULL; hr = S_OK; fNoMatchFound = FALSE; } else { pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (OfflineItemID == pCurItem->offlineItem.ItemID) { *ppItem = pCurItem; hr = S_OK; fNoMatchFound = FALSE; break; } pCurItem = pCurItem->pnextItem; } } }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::LookupHandlerFromId, private
//
// Synopsis: Finds associate handler info from the given Id
//
// Arguments: [wHandlerId] - Id of handler to call.
// [pHandlerInfo] - on S_OK pointer to handler info
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::LookupHandlerFromId(HANDLERINFO *pHandlerId,LPHANDLERINFO *pHandlerInfo) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pCurItem;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
*pHandlerInfo = NULL; pCurItem = m_pFirstHandler;
while (pCurItem) { if (pHandlerId == pCurItem->pHandlerId ) { *pHandlerInfo = pCurItem; Assert(pCurItem == pHandlerId); hr = S_OK; break; }
pCurItem = pCurItem->pNextHandler; }
Assert(S_OK == hr); // test assert to see if ever fires.
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AllocNewHandlerItem, public
//
// Synopsis: Adds new item to the specified handler.
//
// Arguments: [wHandlerId] - Id of handler.
// [pOfflineItem] - Points to Items information to add.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 13-May-98 rogerg Created.
//
//----------------------------------------------------------------------------
LPITEMLIST CHndlrQueue::AllocNewHandlerItem(LPHANDLERINFO pHandlerInfo,SYNCMGRITEM *pOfflineItem) { LPITEMLIST pNewItem = NULL;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
Assert(pHandlerInfo); Assert(pOfflineItem);
// Allocate the item.
pNewItem = (LPITEMLIST) ALLOC(sizeof(ITEMLIST));
if (pNewItem) { // set up defaults.
memset(pNewItem, 0, sizeof(ITEMLIST)); pNewItem->wItemId = ++pHandlerInfo->wItemCount; pNewItem->pHandlerInfo = pHandlerInfo; pNewItem->fDuplicateItem = FALSE; pNewItem->fIncludeInProgressBar = FALSE; SetItemProgressValues(pNewItem, 0, HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE); pNewItem->dwStatusType = SYNCMGRSTATUS_PENDING; pNewItem->fHiddenItem = FALSE; pNewItem->fSynchronizingItem = FALSE;
pNewItem->offlineItem = *pOfflineItem;
// stick the item on the end of the list
if (NULL == pHandlerInfo->pFirstItem) { pHandlerInfo->pFirstItem = pNewItem; Assert(1 == pHandlerInfo->wItemCount); } else { LPITEMLIST pCurItem;
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem->pnextItem) pCurItem = pCurItem->pnextItem;
pCurItem->pnextItem = pNewItem;
Assert ((pCurItem->wItemId + 1) == pNewItem->wItemId); } }
return pNewItem; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SetHandlerInfo, public
//
// Synopsis: Adds item to the specified handler.
// Called in context of the handlers thread.
//
// Arguments: [pHandlerId] - Id of handler.
// [pSyncMgrHandlerInfo] - Points to SyncMgrHandlerInfo to be filled in.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 28-Jul-98 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SetHandlerInfo(HANDLERINFO *pHandlerId,LPSYNCMGRHANDLERINFO pSyncMgrHandlerInfo) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; CLock clockqueue(this);
if (!pSyncMgrHandlerInfo) { Assert(pSyncMgrHandlerInfo); return E_INVALIDARG; }
clockqueue.Enter();
Assert(m_QueueType == QUEUETYPE_CHOICE);
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { if (HANDLERSTATE_INADDHANDLERITEMS != pHandlerInfo->HandlerState) { Assert(HANDLERSTATE_INADDHANDLERITEMS == pHandlerInfo->HandlerState); hr = E_UNEXPECTED; } else { // Quick Check of Size here. other paramters should already
// be validated by hndlrmsg
if (pSyncMgrHandlerInfo->cbSize != sizeof(SYNCMGRHANDLERINFO) ) { Assert(pSyncMgrHandlerInfo->cbSize == sizeof(SYNCMGRHANDLERINFO)); hr = E_INVALIDARG; } else { pHandlerInfo->SyncMgrHandlerInfo = *pSyncMgrHandlerInfo; hr = S_OK; } } }
clockqueue.Leave();
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::IsAllHandlerInstancesCancelCompleted, private
//
// Synopsis: Asks queue if all interintances of a Handler CLSID
// are completed, Called in proxy terminate to see
// if after requesting user input there are still items to
// kill.
//
// Note: Only checks instances for this queue.
//
// Arguments:
//
// Returns: S_OK; if all handler instances are done.
// S_FALSE - if still items going that should be killed.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::IsAllHandlerInstancesCancelCompleted(REFCLSID clsidHandler) { HRESULT hr = S_OK; LPHANDLERINFO pCurHandlerInfo; CLock clockqueue(this);
// just loop through handlers matching clsid and if any are <= SynchronizeCompleted
// and the cancelled flag set then an instance of the Handler is still
// stuck in a Cancel.
Assert(m_QueueType == QUEUETYPE_PROGRESS);
clockqueue.Enter();
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo) { if ( (clsidHandler == pCurHandlerInfo->clsidHandler) && (BAD_HANDLERSTATE(pCurHandlerInfo) ) && (pCurHandlerInfo->fCancelled) ) { hr = S_FALSE; break; }
pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
clockqueue.Leave();
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::AddItemToHandler, public
//
// Synopsis: Adds item to the specified handler.
// Called in context of the handlers thread.
//
// Arguments: [wHandlerId] - Id of handler.
// [pOfflineItem] - Points to Items information to add.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::AddItemToHandler(HANDLERINFO *pHandlerId,SYNCMGRITEM *pOfflineItem) { HRESULT hr = E_UNEXPECTED; // review for Lookup failures
LPHANDLERINFO pHandlerInfo = NULL; LPITEMLIST pNewItem = NULL; LPHANDLERINFO pHandlerMatched; LPITEMLIST pItemListMatch; CLock clockqueue(this);
clockqueue.Enter();
Assert(m_QueueType == QUEUETYPE_CHOICE);
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { if (HANDLERSTATE_INADDHANDLERITEMS != pHandlerInfo->HandlerState) { Assert(HANDLERSTATE_INADDHANDLERITEMS == pHandlerInfo->HandlerState); hr = E_UNEXPECTED; } else { // make sure the handler has a jobID and ConnectionObj
// associated with it.
Assert(pHandlerInfo->pJobInfo); Assert(pHandlerInfo->pJobInfo->pConnectionObj);
if (pHandlerInfo->pJobInfo && pHandlerInfo->pJobInfo->pConnectionObj) { DWORD dwSyncFlags = pHandlerInfo->pJobInfo->dwSyncFlags;
// Allocate the item.
pNewItem = AllocNewHandlerItem(pHandlerInfo,pOfflineItem);
if (NULL == pNewItem) { hr = E_OUTOFMEMORY; } else { DWORD dwCheckState; DWORD dwDefaultCheck; // what default for the item should be.
DWORD ConnectionIndex; DWORD dwSyncEvent = dwSyncFlags & SYNCMGRFLAG_EVENTMASK;
// if SyncType is SYNCMGRFLAG_CONNECT, SYNCMGRFLAG_PENDINGDISCONNECT
// or Idle, set the defaults based on registration flags
// If change this logic need to also change logic in dll hndlrq.
dwDefaultCheck = pOfflineItem->dwItemState; if ( ( (dwSyncEvent == SYNCMGRFLAG_IDLE) && !(pHandlerInfo->dwRegistrationFlags & SYNCMGRREGISTERFLAG_IDLE) ) || ( (dwSyncEvent == SYNCMGRFLAG_CONNECT) && !(pHandlerInfo->dwRegistrationFlags & SYNCMGRREGISTERFLAG_CONNECT) ) || ( (dwSyncEvent == SYNCMGRFLAG_PENDINGDISCONNECT) && !(pHandlerInfo->dwRegistrationFlags & SYNCMGRREGISTERFLAG_PENDINGDISCONNECT) ) ) { dwDefaultCheck = SYNCMGRITEMSTATE_UNCHECKED; }
// get appropriate stored setting based on the sync flags
// invoke we just use whatever the handler tells us it should be.
if (SYNCMGRFLAG_INVOKE != dwSyncEvent) { for (ConnectionIndex = 0; ConnectionIndex < pHandlerInfo->pJobInfo->cbNumConnectionObjs; ++ConnectionIndex) { TCHAR *pszConnectionName = pHandlerInfo->pJobInfo->pConnectionObj[ConnectionIndex]->pwszConnectionName;
switch(dwSyncEvent) { case SYNCMGRFLAG_MANUAL: // only support one connection for manual
Assert(pHandlerInfo->pJobInfo->cbNumConnectionObjs == 1);
if (RegGetSyncItemSettings(SYNCTYPE_MANUAL, pHandlerInfo->clsidHandler, pOfflineItem->ItemID, pszConnectionName,&dwCheckState, dwDefaultCheck, NULL)) { pNewItem->offlineItem.dwItemState = dwCheckState; } break;
case SYNCMGRFLAG_CONNECT: case SYNCMGRFLAG_PENDINGDISCONNECT: if (RegGetSyncItemSettings(SYNCTYPE_AUTOSYNC, pHandlerInfo->clsidHandler, pOfflineItem->ItemID, pszConnectionName,&dwCheckState, dwDefaultCheck, NULL)) { // for logon/logoff a checkstate of set wins and
// as soon as it is set break out of the loop
if ( (0 == ConnectionIndex) || (SYNCMGRITEMSTATE_CHECKED == dwCheckState) ) { pNewItem->offlineItem.dwItemState = dwCheckState; }
if (SYNCMGRITEMSTATE_CHECKED == pNewItem->offlineItem.dwItemState) { break; } } break;
case SYNCMGRFLAG_IDLE: if (RegGetSyncItemSettings(SYNCTYPE_IDLE, pHandlerInfo->clsidHandler, pOfflineItem->ItemID, pszConnectionName,&dwCheckState, dwDefaultCheck, NULL)) { // for Idle a checkstate of set wins and
// as soon as it is set break out of the loop
if ( (0 == ConnectionIndex) || (SYNCMGRITEMSTATE_CHECKED == dwCheckState)) { pNewItem->offlineItem.dwItemState = dwCheckState; }
if (SYNCMGRITEMSTATE_CHECKED ==pNewItem->offlineItem.dwItemState) { break; } } break;
case SYNCMGRFLAG_SCHEDULED: // if caused by an invoke, use whatever handler tells us.
// only support one connection for schedule
Assert(pHandlerInfo->pJobInfo->cbNumConnectionObjs == 1);
if (pHandlerInfo->pJobInfo) { if (RegGetSyncItemSettings(SYNCTYPE_SCHEDULED, pHandlerInfo->clsidHandler, pOfflineItem->ItemID, pszConnectionName, &dwCheckState, SYNCMGRITEMSTATE_UNCHECKED, // if don't find item, don't check
pHandlerInfo->pJobInfo->szScheduleName)) { pNewItem->offlineItem.dwItemState = dwCheckState; } else { // If don't find then default is to be unchecked.
pNewItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED; } } break;
case SYNCMGRFLAG_INVOKE: // if caused by an invoke, use whatever handler tells us.
break;
default: AssertSz(0, "UnknownSyncFlag Event"); break; }; } }
// Search and mark duplicate entries.
if (IsItemAlreadyInList(pHandlerInfo->clsidHandler, (pOfflineItem->ItemID),pHandlerInfo->pHandlerId, &pHandlerMatched,&pItemListMatch) ) { Assert(QUEUETYPE_CHOICE == m_QueueType || QUEUETYPE_PROGRESS == m_QueueType);
pNewItem->fDuplicateItem = TRUE;
// duplicate handling
// if a manual sync then first writer to the queue wins,
if (QUEUETYPE_CHOICE == m_QueueType) { pNewItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED; }
}
hr = S_OK; } } } }
clockqueue.Leave(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::Progress, public
//
// Synopsis: Updates items progress information
// Called in the context of the Handlers thread
//
// Arguments: [wHandlerId] - Id of handler.
// [ItemID] - OfflineItemID of the specified item.
// [lpSyncProgressItem] - Pointer to SyncProgressItem.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::Progress(HANDLERINFO *pHandlerId,REFSYNCMGRITEMID ItemID, LPSYNCMGRPROGRESSITEM lpSyncProgressItem) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; BOOL fFoundMatch = FALSE; PROGRESSUPDATEDATA progressData; HWND hwndCallback; CLock clockqueue(this);
progressData.pHandlerID = pHandlerId; progressData.ItemID = ItemID;
Assert(QUEUETYPE_PROGRESS == m_QueueType);
clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { if (ItemID == pCurItem->offlineItem.ItemID) { fFoundMatch = TRUE; break; }
pCurItem = pCurItem->pnextItem; }
if (pHandlerInfo->fCancelled) hr = S_SYNCMGR_CANCELALL; else if (!fFoundMatch || pCurItem->fItemCancelled) { Assert(fFoundMatch); hr = S_SYNCMGR_CANCELITEM; } else hr = S_OK;
}
if (fFoundMatch) // store everyting in local vars.
{ // if found match but shouldn't include in progress bar
// fix it up.
if ( (pCurItem->fHiddenItem) || (FALSE == pCurItem->fIncludeInProgressBar)) { // if found a match it should be included in the progress bar
// Assert(TRUE == pCurItem->fIncludeInProgressBar); // Review if test app hits this.
Assert(FALSE == pCurItem->fHiddenItem); // shouldn't get progress on hidden items.
fFoundMatch = FALSE;
if (S_OK == hr) { hr = S_SYNCMGR_CANCELITEM; // return cancel item just as if item wasn't cancelled.
} } else { progressData.clsidHandler = pHandlerInfo->clsidHandler; progressData.wItemId = pCurItem->wItemId; hwndCallback = pHandlerInfo->hWndCallback; } }
clockqueue.Leave();
if (fFoundMatch) { // send off data to the callback window.
// it is responsible for updating the items progress values.
if (hwndCallback) { // validate the ProgressItem structure before passing it on.
if (IsValidSyncProgressItem(lpSyncProgressItem)) { SendMessage(hwndCallback,WM_PROGRESS_UPDATE, (WPARAM) &progressData,(LPARAM) lpSyncProgressItem); } else { if (S_OK == hr) // CANCEL RESULTS OVERRIDE ARG PROBLEMS
{ hr = E_INVALIDARG; } } } }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::LogError, public
//
// Synopsis: Logs and error for the specified item
// Called in the context of the Handlers thread
//
// Arguments: [wHandlerId] - Id of handler.
// [dwErrorLevel] - ErrorLevel of the Error
// [lpcErrorText] - Text of the Error.
// [lpSyncLogError] - Pointer to SyncLogError structure
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::LogError(HANDLERINFO *pHandlerId,DWORD dwErrorLevel, const WCHAR *lpcErrorText, LPSYNCMGRLOGERRORINFO lpSyncLogError) { HRESULT hr = E_UNEXPECTED; LPHANDLERINFO pHandlerInfo = NULL; LPITEMLIST pCurItem = NULL; BOOL fFoundMatch = FALSE; MSGLogErrors msgLogErrors; HWND hWndCallback = NULL; CLock clockqueue(this);
msgLogErrors.dwErrorLevel = dwErrorLevel; msgLogErrors.lpcErrorText = lpcErrorText; msgLogErrors.ErrorID = GUID_NULL; msgLogErrors.fHasErrorJumps = FALSE; msgLogErrors.mask = 0;
Assert(QUEUETYPE_PROGRESS == m_QueueType);
clockqueue.Enter();
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { hWndCallback = pHandlerInfo->hWndCallback;
// validate the paramaters.
if (NULL == hWndCallback) { hr = E_UNEXPECTED; } else if (!IsValidSyncLogErrorInfo(dwErrorLevel,lpcErrorText,lpSyncLogError)) { hr = E_INVALIDARG; } else { if (lpSyncLogError && (lpSyncLogError->mask & SYNCMGRLOGERROR_ERRORID)) { pHandlerInfo->fHasErrorJumps = TRUE; msgLogErrors.mask |= SYNCMGRLOGERROR_ERRORID; msgLogErrors.ErrorID = lpSyncLogError->ErrorID; }
if (lpSyncLogError && (lpSyncLogError->mask & SYNCMGRLOGERROR_ERRORFLAGS)) { if (SYNCMGRERRORFLAG_ENABLEJUMPTEXT & lpSyncLogError->dwSyncMgrErrorFlags) { pHandlerInfo->fHasErrorJumps = TRUE; msgLogErrors.fHasErrorJumps = TRUE; } }
if (lpSyncLogError && (lpSyncLogError->mask & SYNCMGRLOGERROR_ITEMID)) { msgLogErrors.mask |= SYNCMGRLOGERROR_ITEMID; msgLogErrors.ItemID = lpSyncLogError->ItemID; }
hr = S_OK; } }
clockqueue.Leave();
if (S_OK == hr) { Assert(sizeof(WPARAM) >= sizeof(HANDLERINFO *));
SendMessage(hWndCallback, WM_PROGRESS_LOGERROR, (WPARAM) pHandlerId, (LPARAM) &msgLogErrors); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::DeleteLogError, public
//
// Synopsis: Deletes an Error from the Results pane that was previously logged.
//
// Arguments:
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::DeleteLogError(HANDLERINFO *pHandlerId,REFSYNCMGRERRORID ErrorID,DWORD dwReserved)
{ MSGDeleteLogErrors msgDeleteLogError; HWND hWndCallback = NULL; HANDLERINFO *pHandlerInfo; CLock clockqueue(this);
clockqueue.Enter(); msgDeleteLogError.pHandlerId = pHandlerId; msgDeleteLogError.ErrorID = ErrorID;
if (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) { hWndCallback = pHandlerInfo->hWndCallback; }
// review, if handler doesn't have any more error jumps after the deletelogError we can now
// release it (pHandlerInfo->fHasErrorJumps)
clockqueue.Leave();
if (hWndCallback) { SendMessage(hWndCallback, WM_PROGRESS_DELETELOGERROR, (WPARAM) 0, (LPARAM) &msgDeleteLogError); }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::CallCompletionRoutine, public
//
// Synopsis: Called by callback on handler thread
// to indicate a call with a completion callback
// has completed.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 02-Jun-98 rogerg Created.
//
//----------------------------------------------------------------------------
void CHndlrQueue::CallCompletionRoutine(HANDLERINFO *pHandlerId,DWORD dwThreadMsg,HRESULT hCallResult, ULONG cbNumItems,SYNCMGRITEMID *pItemIDs) { HWND hWndDlg = NULL; HRESULT hrHandlerCall = S_OK; BOOL fCallbackAlreadyCalled = FALSE; HANDLERINFO *pHandlerInfo; CLock clockqueue(this);
if (!pHandlerId) { Assert(pHandlerId); return; } // Note: cbNumItems and pItemIDs is only valid for ShowErrors
// make sure the handlid is valid and then if there
// is a pdlg call its completion routine via the postmessage
// method.
clockqueue.Enter();
hWndDlg = m_hwndDlg; Assert(hWndDlg);
if ( pHandlerId && (S_OK == LookupHandlerFromId(pHandlerId,&pHandlerInfo)) ) { // if flag isn't set for the message
// then it was already handled i.e. handler called
// us even though it returned an error.
if (dwThreadMsg & pHandlerInfo->dwOutCallMessages) { pHandlerInfo->dwOutCallMessages &= ~dwThreadMsg; } else { AssertSz(0,"Callback called twice"); // test apps currently do this.
fCallbackAlreadyCalled = TRUE; }
// if already handled don't call these again.
if (!fCallbackAlreadyCalled) { // fix up internal states before informing caller
// the call is complete.
switch(dwThreadMsg) { case ThreadMsg_ShowProperties: // don't need to do anything on show properties.
break; case ThreadMsg_PrepareForSync: hrHandlerCall = PrepareForSyncCompleted(pHandlerInfo,hCallResult); break; case ThreadMsg_Synchronize: hrHandlerCall = SynchronizeCompleted(pHandlerInfo,hCallResult); break; case ThreadMsg_ShowError: hrHandlerCall = ShowErrorCompleted(pHandlerInfo,hCallResult,cbNumItems,pItemIDs); break; default: AssertSz(0,"Unknown Queue Completion Callback"); break; } }
// possible completion routine comes in before handler has actually
// returned from the original call. Wait until proxy is no longer in an
// out call.
// If switch to COM for messaging need to find a better way of doing this.
if (pHandlerInfo->pThreadProxy && pHandlerInfo->pThreadProxy->IsProxyInOutCall() && hWndDlg) { // tell proxy to post the message whenver it gets done.
// CODE REVIEW:
// NOTENOTE:
// Remove this code..
/*
if ( 0 /* S_OK ==
pHandlerInfo->pThreadProxy->SetProxyCompletion(hWndDlg,WM_BASEDLG_COMPLETIONROUTINE,dwThreadMsg,hCallResult)*) { hWndDlg = NULL; } */ } } else { // on handler lookup assert but still post the message to the hwnd
// so it won't get stuck waiting for the completion routine
// this is only valid for setproperties in the
// case the user clicked on a non-existant item but
// this shouldn't really happen either
AssertSz(dwThreadMsg == ThreadMsg_ShowProperties,"LookupHandler failed in CompletionRoutine"); }
LPCALLCOMPLETIONMSGLPARAM lpCallCompletelParam = (LPCALLCOMPLETIONMSGLPARAM) ALLOC(sizeof(CALLCOMPLETIONMSGLPARAM));
if (lpCallCompletelParam) { lpCallCompletelParam->hCallResult = hCallResult; lpCallCompletelParam->clsidHandler = pHandlerId->clsidHandler;
// itemID is GUID_NULL unless its a ShowProperties completed.
if ((ThreadMsg_ShowProperties == dwThreadMsg) && (1 == cbNumItems)) { lpCallCompletelParam->itemID = *pItemIDs; } else { lpCallCompletelParam->itemID = GUID_NULL; } }
clockqueue.Leave();
if (hWndDlg && !fCallbackAlreadyCalled) // if already out of out call or proxy failed post the messge ourselves.
{ // if alloc of completion lparam fails send message anyways so callback count
// remains accurate.
PostMessage(hWndDlg,WM_BASEDLG_COMPLETIONROUTINE,dwThreadMsg,(LPARAM) lpCallCompletelParam); } else { // if don't post message up to us to free the lpCallCopmlete.
if (lpCallCompletelParam) { FREE(lpCallCompletelParam); } } }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::IsItemAlreadyInList, private
//
// Synopsis: Given a clsid and ItemID determines if a matchin
// item is already in the list
// Called in the context of the Handlers thread
//
// Arguments: [clsidHandler] - clsid of the handler
// [ItemID] - ItemID of the item
// [wHandlerId] - HandlerID of the item.
// [ppHandlerMatched] - on out the handler that matched
// [ppItemIdMatch] - on out Item that matched.
//
// Returns: Appropriate Error code
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
BOOL CHndlrQueue::IsItemAlreadyInList(CLSID clsidHandler,REFSYNCMGRITEMID ItemID, HANDLERINFO *pHandlerId, LPHANDLERINFO *ppHandlerMatched, LPITEMLIST *ppItemListMatch) { BOOL fFoundMatch = FALSE; LPHANDLERINFO pCurHandlerInfo = NULL; LPITEMLIST pCurItem = NULL;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
pCurHandlerInfo = m_pFirstHandler;
while (pCurHandlerInfo && !fFoundMatch) { if (pHandlerId == pCurHandlerInfo->pHandlerId) // when find hander know didn't find any before.
break;
if (clsidHandler == pCurHandlerInfo->clsidHandler) // see if CLSID matches
{ // see if handler info has a matching item
pCurItem = pCurHandlerInfo->pFirstItem;
while (pCurItem) { if (ItemID == pCurItem->offlineItem.ItemID) {
*ppHandlerMatched = pCurHandlerInfo; *ppItemListMatch = pCurItem;
fFoundMatch = TRUE; break; }
pCurItem = pCurItem->pnextItem; } } pCurHandlerInfo = pCurHandlerInfo->pNextHandler; }
return fFoundMatch; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::GetSelectedItemsInHandler, private
//
// Synopsis: Gets the number of selected items for this handler
//
// for our implementation if a cbCount is passed and it doesn't match
// the number of actually selected then assert since we call this routine
// internally.
//
//
// Arguments: [pHandlerInfo] - Pointer to the HandlerInfo to look at.
// [cbcount] - [in] cbCount == number of pItems allocated,
// [out] cbCpimt == number of items actually written.
// if the buffer is too small items written will be zero.
// [pItems] - Pointer to array of SYNCMGRITEMs to be filled in.
//
// Returns: Returns the number of selectd items.
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
DWORD CHndlrQueue::GetSelectedItemsInHandler(LPHANDLERINFO pHandlerInfo,ULONG *cbCount, SYNCMGRITEMID* pItems) { LPITEMLIST pCurItem; DWORD dwSelectCount = 0; DWORD dwArraySizeIndex; DWORD dwArraySize;
ASSERT_LOCKHELD(this); // caller of this function should have already locked the queue.
if (cbCount) { dwArraySizeIndex = *cbCount; dwArraySize = *cbCount; *cbCount = 0; // initialize to zero.
} else { dwArraySizeIndex = 0; dwArraySize = 0; }
if ( dwArraySize && NULL == pItems) { Assert(0 == dwArraySize || pItems); return 0; }
if (NULL == pHandlerInfo) { Assert(pHandlerInfo); return 0; }
pCurItem = pHandlerInfo->pFirstItem;
while (pCurItem) { // dwItemState
if (SYNCMGRITEMSTATE_CHECKED == pCurItem->offlineItem.dwItemState) { ++dwSelectCount;
if (dwArraySizeIndex) { *pItems = pCurItem->offlineItem.ItemID; *cbCount += 1; ++pItems; --dwArraySizeIndex;
if (!pCurItem->fHiddenItem) // if not a hidden item
{ Assert(TRUE == pCurItem->fIncludeInProgressBar); Assert(HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE == pCurItem->iProgMaxValue);
// reset iProgValue back to zero since may not be zero if retry came in while still synchronizing.
SetItemProgressValues(pCurItem,0,HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE); } else { // if item is hidden,a assert it doesn't have UI
Assert(FALSE == pCurItem->fIncludeInProgressBar); Assert(HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE == pCurItem->iProgValue); Assert(HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE == pCurItem->iProgMaxValue); } pCurItem->fSynchronizingItem = TRUE; // item is now synchronizing
// once added to the array uncheck the item so on a retry we can just
// always reset items to checked
pCurItem->offlineItem.dwItemState = SYNCMGRITEMSTATE_UNCHECKED; } } else { Assert(FALSE == pCurItem->fSynchronizingItem); // Assert(FALSE == pCurItem->fIncludeInProgressBar); Can be included in progress bar if retry comes in before RemoveFinished is called.
Assert(HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE == pCurItem->iProgValue); Assert(HNDRLQUEUE_DEFAULT_PROGRESS_MAXVALUE == pCurItem->iProgMaxValue); }
pCurItem = pCurItem->pnextItem; }
// internal call should always request a proper array size.
Assert(dwSelectCount == dwArraySize || 0 == dwArraySize);
return dwSelectCount; }
// job info methods
STDMETHODIMP CHndlrQueue::CreateJobInfo(JOBINFO **ppJobInfo,DWORD cbNumConnectionNames) { HRESULT hr = S_FALSE; JOBINFO *pNewJobInfo = NULL;
ASSERT_LOCKHELD(this);
// create a new job and add it to the the JobInfo list.
// allocate space for JobInfo + number of connection objects that
// will be associated with this job.
Assert(cbNumConnectionNames);
if (cbNumConnectionNames < 1) return S_FALSE;
pNewJobInfo = (JOBINFO *) ALLOC(sizeof(JOBINFO) + sizeof(CONNECTIONOBJ)*(cbNumConnectionNames - 1));
if (pNewJobInfo) { memset(pNewJobInfo, 0, sizeof(JOBINFO));
pNewJobInfo->cRefs = 1; pNewJobInfo->pNextJobInfo = m_pFirstJobInfo; m_pFirstJobInfo = pNewJobInfo;
*ppJobInfo = pNewJobInfo;
hr = S_OK; } else { hr = E_OUTOFMEMORY; }
return hr; }
DWORD CHndlrQueue::ReleaseJobInfoExt(JOBINFO *pJobInfo) { DWORD dwRet; CLock clockqueue(this);
clockqueue.Enter(); dwRet = ReleaseJobInfo(pJobInfo); clockqueue.Leave();
return dwRet; }
DWORD CHndlrQueue::ReleaseJobInfo(JOBINFO *pJobInfo) { DWORD cRefs;
ASSERT_LOCKHELD(this);
--(pJobInfo->cRefs); cRefs = pJobInfo->cRefs;
Assert( ((LONG) cRefs) >= 0);
if (0 == cRefs) { JOBINFO *pCurJobInfo = NULL; DWORD dwConnObjIndex;
// loop through release all connection objs on this job
for (dwConnObjIndex = 0 ; dwConnObjIndex < pJobInfo->cbNumConnectionObjs; dwConnObjIndex++) { Assert(pJobInfo->pConnectionObj[dwConnObjIndex]); if (pJobInfo->pConnectionObj[dwConnObjIndex]) { ConnectObj_ReleaseConnectionObj(pJobInfo->pConnectionObj[dwConnObjIndex]); pJobInfo->pConnectionObj[dwConnObjIndex] = NULL; } }
// remove this JobInfo from the list.
if (pJobInfo == m_pFirstJobInfo) { m_pFirstJobInfo = pJobInfo->pNextJobInfo; } else { pCurJobInfo = m_pFirstJobInfo;
while (pCurJobInfo->pNextJobInfo) { if (pJobInfo == pCurJobInfo->pNextJobInfo) { pCurJobInfo->pNextJobInfo = pJobInfo->pNextJobInfo; break; }
pCurJobInfo = pCurJobInfo->pNextJobInfo; } }
FREE(pJobInfo); }
return cRefs; }
DWORD CHndlrQueue::AddRefJobInfo(JOBINFO *pJobInfo) { DWORD cRefs;
ASSERT_LOCKHELD(this);
++(pJobInfo->cRefs); cRefs = pJobInfo->cRefs;
return cRefs; }
// determines ifthe specified JobInfo's connection can be openned.
// review should really call into connection Object help api.
STDMETHODIMP CHndlrQueue::OpenConnection(JOBINFO *pJobInfo) { CONNECTIONOBJ *pConnectionObj; HRESULT hr;
Assert(pJobInfo);
if (NULL == pJobInfo) // if no job info go ahead and say the connection is open.
return S_OK;
// turn off workOffline during the sync CloseConnection will turn
// it back on if the user had it off.
ConnectObj_SetWorkOffline(FALSE);
// if this is anything but a schedule go ahead and say S_OK;
if (!(SYNCMGRFLAG_SCHEDULED == (pJobInfo->dwSyncFlags & SYNCMGRFLAG_EVENTMASK)) ) { return S_OK; }
// for schedule sink we only support one connection Object.
if (1 != pJobInfo->cbNumConnectionObjs) { Assert(1 == pJobInfo->cbNumConnectionObjs); return E_UNEXPECTED; }
pConnectionObj = pJobInfo->pConnectionObj[0]; if (NULL == pConnectionObj) return S_OK;
// if we aren't suppose to make a connection of there is already
// a hRasConn as part of the connection object then just
// return S_OK;
// if connection is already open and we are on a job that
// has already tried to open it then return S_OK;
if (pJobInfo->pConnectionObj[0]->fConnectionOpen && pJobInfo->fTriedConnection) return S_OK;
// if we haven't already tried to make the connection
// on this job then call OpenConnection to make sure the
// connection is still really open.
if (!pJobInfo->fTriedConnection) { pJobInfo->fTriedConnection = TRUE;
hr = ConnectObj_OpenConnection(pConnectionObj, pJobInfo->fCanMakeConnection, m_pDlg); } else { hr = S_FALSE; }
// if get down to the bottom and still no hRasConn then return S_FALSE
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::ScrambleIdleHandlers, private
//
// Synopsis: Called on an Idle Choice queue just before transfer
// so the lastHandler is placed at the back of the list.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
// History: 17-Nov-97 rogerg Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::ScrambleIdleHandlers(REFCLSID clsidLastHandler) { LPHANDLERINFO pMatchHandler; LPHANDLERINFO pLastHandler; CLock clockqueue(this);
Assert(m_QueueType == QUEUETYPE_CHOICE);
clockqueue.Enter();
// find the first occurance of specified handler and then place that handler
// at the end of the list and everything after at the beginning of the list
// no an error to not find the Handler since may have been deleted or
// no longer has items.
pMatchHandler = m_pFirstHandler;
while (pMatchHandler) { if (pMatchHandler->clsidHandler == clsidLastHandler) { // if there are no items after the match then just break;
if (NULL == pMatchHandler->pNextHandler) { break; }
// loop until find the last handler.
pLastHandler = pMatchHandler->pNextHandler; while (pLastHandler->pNextHandler) { pLastHandler = pLastHandler->pNextHandler; }
// now set the handler after the matchHandler to be the
// head and set the next pointer of the LastHandler in
// the list to point to the MatchHandler.
pLastHandler->pNextHandler = m_pFirstHandler; m_pFirstHandler = pMatchHandler->pNextHandler; pMatchHandler->pNextHandler = NULL; break; }
pMatchHandler = pMatchHandler->pNextHandler; }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::BeginSyncSession
//
// Synopsis: Called to signal the beginning of the core synchronization session
// to setup up dial support.
//
// History: 28-Jul-98 SitaramR Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::BeginSyncSession() { HRESULT hr = ::BeginSyncSession(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::EndSyncSession
//
// Synopsis: Called to signal the end of the core synchronization session
// to teardown dial support.
//
// History: 28-Jul-98 SitaramR Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::EndSyncSession() { HRESULT hr = ::EndSyncSession(); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::SortHandlersByConnection
//
// Synopsis: Moves hanlders that won't establish connection to the end,
// ie after handlers that can establish connectoin.
//
// History: 28-Jul-98 SitaramR Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::SortHandlersByConnection() { CLock clockqueue(this); clockqueue.Enter();
Assert(m_QueueType == QUEUETYPE_CHOICE);
LPHANDLERINFO pFirstCannotDialHandler = NULL; LPHANDLERINFO pLastCannotDialHandler = NULL;
LPHANDLERINFO pPrevHandler = NULL; LPHANDLERINFO pCurHandler = m_pFirstHandler;
while ( pCurHandler ) { if ( pCurHandler->SyncMgrHandlerInfo.SyncMgrHandlerFlags & SYNCMGRHANDLER_MAYESTABLISHCONNECTION ) { //
// Move to next handler
//
pPrevHandler = pCurHandler; pCurHandler = pCurHandler->pNextHandler; } else { //
// Move handler to cannot dial list
//
if ( pPrevHandler == NULL ) { //
// This is the first handler in list
//
m_pFirstHandler = pCurHandler->pNextHandler; pCurHandler->pNextHandler = NULL;
if ( pLastCannotDialHandler == NULL ) { Assert( pFirstCannotDialHandler == NULL ); pFirstCannotDialHandler = pLastCannotDialHandler = pCurHandler; } else { pLastCannotDialHandler->pNextHandler = pCurHandler; pLastCannotDialHandler = pCurHandler; }
pCurHandler = m_pFirstHandler; } else { pPrevHandler->pNextHandler = pCurHandler->pNextHandler; pCurHandler->pNextHandler = NULL;
if ( pLastCannotDialHandler == NULL ) { Assert( pFirstCannotDialHandler == NULL ); pFirstCannotDialHandler = pLastCannotDialHandler = pCurHandler; } else { pLastCannotDialHandler->pNextHandler = pCurHandler; pLastCannotDialHandler = pCurHandler; }
pCurHandler = pPrevHandler->pNextHandler; } } }
//
// Attach cannot dial list at end of m_pFirstHandler list
//
if ( pPrevHandler ) { Assert( pPrevHandler->pNextHandler == NULL ); pPrevHandler->pNextHandler = pFirstCannotDialHandler; } else { //
// Case where the original list became empty
//
Assert( m_pFirstHandler == NULL ); m_pFirstHandler = pFirstCannotDialHandler; }
clockqueue.Leave();
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CHndlrQueue::EstablishConnection
//
// Synopsis: Called by handler to establish a connection.
//
// Arguments: [pHandlerID] -- Ptr to handler
// [lpwszConnection] -- Connection to establish
// [dwReserved] -- Must be zero for now
//
// History: 28-Jul-98 SitaramR Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CHndlrQueue::EstablishConnection( LPHANDLERINFO pHandlerID, WCHAR const * lpwszConnection, DWORD dwReserved ) { HRESULT hr = S_OK;
CLock clockqueue(this);
clockqueue.Enter();
CONNECTIONOBJ *pConnObj = NULL; BOOL fAutoDial = FALSE;
LPHANDLERINFO pHandlerInfo = NULL; hr = LookupHandlerFromId( pHandlerID, &pHandlerInfo );
if ( S_OK == hr ) { JOBINFO *pJobInfo = pHandlerInfo->pJobInfo; DWORD dwSyncFlags = pJobInfo->dwSyncFlags & SYNCMGRFLAG_EVENTMASK; if ( ( dwSyncFlags == SYNCMGRFLAG_MANUAL || dwSyncFlags == SYNCMGRFLAG_INVOKE ) && pHandlerInfo->SyncMgrHandlerInfo.SyncMgrHandlerFlags & SYNCMGRHANDLER_MAYESTABLISHCONNECTION ) { if ( lpwszConnection == NULL ) { //
// Null connection means use the default autodial connection
//
fAutoDial = TRUE; } else { hr = ConnectObj_FindConnectionObj(lpwszConnection,TRUE,&pConnObj); } } else { //
// Either the handler invoke type does not permit establishing connection,
// or GetHandlerInfo flags did not specify the EstablishConnection flag.
//
hr = E_UNEXPECTED; } }
clockqueue.Leave();
if (S_OK == hr) { if (fAutoDial) { hr = ConnectObj_AutoDial(INTERNET_AUTODIAL_FORCE_ONLINE,m_pDlg); } else { Assert( pConnObj ); if ( !pConnObj->fConnectionOpen ) { hr = ConnectObj_OpenConnection(pConnObj, TRUE, m_pDlg ); ConnectObj_ReleaseConnectionObj(pConnObj); } } }
return hr; }
|