|
|
//==========================================================================
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright 1998 - 1999 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------
#include "precomp.h"
extern UINT g_cRefThisDll; // Reference count of this DLL.
extern HINSTANCE g_hmodThisDll; // Handle to this DLL itself.
extern CSettings *g_pSettings; // ptr to global settings class.
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CSyncMgrHandler, public
//
// Synopsis: Constructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
CSyncMgrHandler::CSyncMgrHandler() { g_cRefThisDll++;
m_cRef = 1; m_phThread = NULL; m_pSyncMgrSynchronizeCallback = NULL; m_pItemsToSyncList = NULL; m_dwSyncFlags = 0; m_hwndWorker = FALSE; m_hwndHandler = FALSE; m_fSynchronizing = FALSE; m_fPrepareForSync = FALSE; m_fStopped = FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::~CSyncMgrHandler, public
//
// Synopsis: Destructor
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
CSyncMgrHandler::~CSyncMgrHandler() { Assert(NULL == m_pSyncMgrSynchronizeCallback);
Assert(NULL == m_pItemsToSyncList);
if (m_phThread) { HANDLE hThread = m_phThread;
m_phThread = NULL;
PostMessage(m_hwndWorker,WM_WORKERMSG_RELEASE,0,0);
WaitForSingleObject(hThread,INFINITE); // wait for thread to go away
CloseHandle(hThread); }
if (m_hwndHandler) { DestroyWindow(m_hwndHandler); m_hwndHandler = NULL; }
g_cRefThisDll--; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::QueryInteface, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::QueryInterface(REFIID riid, LPVOID FAR *ppv) { *ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown)) { *ppv = (LPUNKNOWN)this; } else if (IsEqualIID(riid, IID_ISyncMgrSynchronize)) { *ppv = (LPSYNCMGRSYNCHRONIZE)this; } if (*ppv) { AddRef();
return NOERROR; }
return E_NOINTERFACE; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::AddRef, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSyncMgrHandler::AddRef() { return ++m_cRef; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::Release, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSyncMgrHandler::Release() { if (--m_cRef) return m_cRef;
delete this;
return 0L; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::Initialize, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::Initialize(DWORD dwReserved,DWORD dwSyncFlags, DWORD cbCookie,const BYTE *lpCooke) { HRESULT hr = NOERROR;
m_dwSyncFlags = dwSyncFlags;
RegisterHandlerWndClasses();
// create hwnd for main class.
m_hwndHandler = CreateWindowEx(0, SZ_SAMPLESYNCMGRHANDLERWNDCLASS, TEXT(""), // must use WS_POPUP so the window does not get
// assigned a hot key by user.
(WS_DISABLED | WS_POPUP), CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hmodThisDll, this);
if (NULL == m_hwndHandler) { hr = E_UNEXPECTED; }
if (NOERROR == hr) { hr = CreateWorkerThread(); }
// if hr is not NOERROR then clean up.
if (NOERROR != hr) { if (m_phThread) { HANDLE hThread = m_phThread;
m_phThread = NULL;
PostMessage(m_hwndWorker,WM_WORKERMSG_RELEASE,0,0);
WaitForSingleObject(hThread,INFINITE); // wait for thread to go away
CloseHandle(hThread); }
if (m_hwndHandler) { DestroyWindow(m_hwndHandler); m_hwndHandler = NULL; }
}
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CreateWorkerThread, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
HRESULT CSyncMgrHandler::CreateWorkerThread() { HRESULT hr = E_FAIL; HANDLE hNewThread = NULL; DWORD dwThreadID; WorkerThreadArgs ThreadArgs;
ThreadArgs.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); ThreadArgs.pThis = this;
if (ThreadArgs.hEvent) { hNewThread = CreateThread(NULL,0,WorkerThread,&ThreadArgs,0,&dwThreadID);
if (hNewThread) { WaitForSingleObject(ThreadArgs.hEvent,INFINITE); if (NOERROR == ThreadArgs.hr) { m_hwndWorker = ThreadArgs.hwnd; m_phThread = hNewThread; hr = NOERROR; } else { CloseHandle(hNewThread); hr = ThreadArgs.hr; }
} else { hr = GetLastError(); }
CloseHandle(ThreadArgs.hEvent); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::GetHandlerInfo, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::GetHandlerInfo(LPSYNCMGRHANDLERINFO *ppSyncMgrHandlerInfo) { LPSYNCMGRHANDLERINFO pSyncInfo;
if (!ppSyncMgrHandlerInfo) { Assert(ppSyncMgrHandlerInfo) return E_INVALIDARG; }
pSyncInfo = (LPSYNCMGRHANDLERINFO) CoTaskMemAlloc(sizeof(SYNCMGRHANDLERINFO));
if (pSyncInfo) { pSyncInfo->cbSize = sizeof(SYNCMGRHANDLERINFO); pSyncInfo->hIcon = LoadIcon(g_hmodThisDll,MAKEINTRESOURCE(IDI_SAMPLEHANDLERICON)); pSyncInfo->SyncMgrHandlerFlags = SYNCMGRHANDLER_HASPROPERTIES; pSyncInfo->SyncMgrHandlerFlags |= SYNCMGRHANDLER_ALWAYSLISTHANDLER; lstrcpyW(pSyncInfo->wszHandlerName,L"Sample Handler"); }
*ppSyncMgrHandlerInfo = pSyncInfo;
return *ppSyncMgrHandlerInfo ? NOERROR : E_OUTOFMEMORY; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::GetItemObject, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::GetItemObject(REFSYNCMGRITEMID ItemID,REFIID riid,void** ppv) {
return E_NOTIMPL; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::EnumSyncMgrItems, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::EnumSyncMgrItems(ISyncMgrEnumItems** ppenumOffineItems) {
Assert(g_pSettings);
if (g_pSettings) { return g_pSettings->EnumSyncMgrItems(ppenumOffineItems); }
return E_UNEXPECTED; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ShowProperties, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::ShowProperties(HWND hWndParent,REFSYNCMGRITEMID ItemID) { METHODARGS *pMethodArgs;
pMethodArgs = (METHODARGS*) ALLOC(sizeof(METHODARGS));
if (NULL == pMethodArgs) { Assert(pMethodArgs); return E_OUTOFMEMORY; }
pMethodArgs->fAsync = TRUE; pMethodArgs->dwWorkerMsg = WM_WORKERMSG_SHOWPROPERTIES; pMethodArgs->ShowPropertiesMsg.hWndParent = hWndParent; pMethodArgs->ShowPropertiesMsg.ItemID = ItemID;
PostMessage(m_hwndWorker,WM_WORKERMSG_SHOWPROPERTIES,0,(LPARAM) pMethodArgs);
return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ShowPropertiesCall, private
//
// Synopsis: Called on WorkerThread
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ShowPropertiesCall(HWND hWndParent,REFSYNCMGRITEMID ItemID) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); HRESULT hr = NOERROR;
Assert(g_pSettings);
if (g_pSettings) { hr = g_pSettings->ShowProperties(hWndParent,ItemID); }
if (pCallback) { pCallback->ShowPropertiesCompleted(hr); pCallback->Release(); }
return; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::SetProgressCallback, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::SetProgressCallback(ISyncMgrSynchronizeCallback *lpCallBack) { LPSYNCMGRSYNCHRONIZECALLBACK pCallbackCurrent; CLock clock(this);
clock.Enter();
pCallbackCurrent = m_pSyncMgrSynchronizeCallback;
m_pSyncMgrSynchronizeCallback = lpCallBack;
if (m_pSyncMgrSynchronizeCallback) m_pSyncMgrSynchronizeCallback->AddRef();
if (pCallbackCurrent) pCallbackCurrent->Release();
clock.Leave();
return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::GetProgressCallback, private
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LPSYNCMGRSYNCHRONIZECALLBACK CSyncMgrHandler::GetProgressCallback() { #ifdef _USECURRENTTHREADFORCALLBACK
LPSYNCMGRSYNCHRONIZECALLBACK pCallback; CLock clock(this);
clock.Enter();
pCallback = m_pSyncMgrSynchronizeCallback;
if (pCallback) { pCallback->AddRef(); }
clock.Leave();
return pCallback; #else
return new CCallbackWrapper(m_hwndHandler); #endif
}
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::PrepareForSync, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::PrepareForSync(ULONG cbNumItems,SYNCMGRITEMID *pItemIDs, HWND hWndParent,DWORD dwReserved)
{ METHODARGS *pMethodArgs; SYNCMGRITEMID *pItemIdCopy; LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); CLock clock(this);
if (!pCallback) { Assert(pCallback); return E_UNEXPECTED; }
pMethodArgs = (METHODARGS*) ALLOC(sizeof(METHODARGS)); pItemIdCopy = (SYNCMGRITEMID *) ALLOC(sizeof(SYNCMGRITEMID) * cbNumItems);
// create items list before kicking off async call so can handle case
// skip and stop come in before PrepareForSyncCall is handled.
clock.Enter();
m_fStopped = FALSE; // always reset stop on a new PrepareForSync, (for example retry came in)
m_fPrepareForSync = TRUE;
Assert(NULL == m_pItemsToSyncList); m_pItemsToSyncList = CreateItemList();
// lookup and request a lock on the items to synchronize
// we then place the ones that we found and have permission into our
// own private sync queue.
if (g_pSettings && m_pItemsToSyncList) { ULONG ulIndex; SYNCMGRITEMID *pCurItemID;
pCurItemID = pItemIDs;
for (ulIndex = 0 ; ulIndex < cbNumItems; ++ulIndex) { BOOL fAdded = FALSE;;
if (g_pSettings->RequestItemLock(this,*pCurItemID)) { LPHANDLERITEM_SYNCSTATUS pNewItem;
pNewItem = (LPHANDLERITEM_SYNCSTATUS) AddNewItemToList(m_pItemsToSyncList,sizeof(HANDLERITEM_SYNCSTATUS));
if (pNewItem) { pNewItem->ItemID = *pCurItemID; fAdded = TRUE; } else { // not enough memory to allocate itemList,
LogError(pCallback,(*pCurItemID),SYNCMGRLOGLEVEL_ERROR, TEXT("Not Enough Memory to Synchronize"));
// update progress for this item
ProgressSetItemStatusType(pCallback,(*pCurItemID),SYNCMGRSTATUS_FAILED); }
}
if (!fAdded) { // if another instance already syncing set progress
// to complete since done but don't update statustext
// so we dont' stomp the running instance.
Progress(pCallback,(*pCurItemID), SYNCMGRPROGRESSITEM_PROGVALUE | SYNCMGRPROGRESSITEM_MAXVALUE, NULL,0,100,100); }
++pCurItemID; } }
if (NULL == pMethodArgs || NULL == pItemIdCopy || NULL == m_pItemsToSyncList) { Assert(pMethodArgs); Assert(pItemIdCopy);
if (pMethodArgs) { FREE(pMethodArgs); }
if (pItemIdCopy) { FREE(pItemIdCopy); }
if (m_pItemsToSyncList) { if (0 == Release_ItemList(m_pItemsToSyncList)) { m_pItemsToSyncList = NULL; } }
clock.Leave();
pCallback->Release(); m_fPrepareForSync = FALSE;
return E_OUTOFMEMORY; }
clock.Leave();
// now make the async call
pMethodArgs->fAsync = TRUE; pMethodArgs->dwWorkerMsg = WM_WORKERMSG_PREPFORSYNC; pMethodArgs->PrepareForSyncMsg.cbNumItems = cbNumItems; pMethodArgs->PrepareForSyncMsg.hWndParent = hWndParent; pMethodArgs->PrepareForSyncMsg.dwReserved = dwReserved;
memcpy(pItemIdCopy,pItemIDs,sizeof(SYNCMGRITEMID) * cbNumItems); pMethodArgs->PrepareForSyncMsg.pItemIDs = pItemIdCopy;
pCallback->Release();
PostMessage(m_hwndWorker,WM_WORKERMSG_PREPFORSYNC,0,(LPARAM) pMethodArgs);
return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::PrepareForSyncCall, private
//
// Synopsis: Called on WorkerThread
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::PrepareForSyncCall(ULONG cbNumItems,SYNCMGRITEMID* pItemIDs,HWND hWndParent, DWORD dwReserved) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); CLock clock(this);
if (!pCallback) { Assert(pCallback); return; }
clock.Enter();
// if a stop came in then release the sync list if any
if (m_fStopped && m_pItemsToSyncList) { if (0 == Release_ItemList(m_pItemsToSyncList)) { m_pItemsToSyncList = NULL; } }
m_fPrepareForSync = FALSE;
clock.Leave();
// currently all PrepareForSync is handled before the async call since we
// just create a list and store it.
pCallback->PrepareForSyncCompleted(NOERROR); pCallback->Release();
return; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::Synchronize, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::Synchronize(HWND hWndParent) { METHODARGS *pMethodArgs; CLock clock(this);
clock.Enter(); m_fSynchronizing = TRUE; clock.Leave();
pMethodArgs = (METHODARGS*) ALLOC(sizeof(METHODARGS));
if (NULL == pMethodArgs) { Assert(pMethodArgs); return E_OUTOFMEMORY; }
pMethodArgs->fAsync = TRUE; pMethodArgs->dwWorkerMsg = WM_WORKERMSG_SYNCHRONIZE; pMethodArgs->SynchronizeMsg.hWndParent = hWndParent;
PostMessage(m_hwndWorker,WM_WORKERMSG_SYNCHRONIZE,0,(LPARAM) pMethodArgs);
return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::SynchronizeCall, private
//
// Synopsis: Called on WorkerThread
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::SynchronizeCall(HWND hWndParent) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); CLock clock(this);
if (!pCallback) { Assert(pCallback); clock.Enter(); m_fSynchronizing = FALSE; clock.Leave(); return; }
clock.Enter();
// should either have a syncList or receive a Stop Item request.
Assert(m_pItemsToSyncList || m_fStopped);
if (m_pItemsToSyncList) { LPHANDLERITEM_SYNCSTATUS pCurItem;
if (g_pSettings) { // get first item in the list, sync, remove, repeat
// until no more items in the list.
while (pCurItem = (LPHANDLERITEM_SYNCSTATUS) m_pItemsToSyncList->pFirstGenericItem) { FILETIME ft; SYSTEMTIME sysTime; HANDLERITEMSETTINGS HANDLERITEMSETTINGS;
// if already cancelled such as setItemstatus came in while not synchronizing
// then just skip over
if (!pCurItem->fSynchronizeComplete) { Assert(sizeof(HANDLERITEM_SYNCSTATUS) == pCurItem->genericItem.cbSize); Assert(FALSE == pCurItem->fSynchronizing);
if (g_pSettings->CopyHandlerSyncInfo(pCurItem->ItemID,&HANDLERITEMSETTINGS)) { pCurItem->fSynchronizing = TRUE; // set synchronizing before releasing lock.
// release lock and call call helper to do the real sync work.
clock.Leave(); SyncDirs(hWndParent,pCurItem,&HANDLERITEMSETTINGS); clock.Enter();
// assert that noboday changed the state on us while
// the sync was in progress.
Assert(TRUE == pCurItem->fSynchronizing); Assert(FALSE == pCurItem->fSynchronizeComplete);
pCurItem->fSynchronizing = FALSE; pCurItem->fSynchronizeComplete = TRUE; }
// only update file time if item wasn't cancelled,
// no failures occured and no
// unresolved conflicts.
if (!pCurItem->fUnresolvedConflicts && !pCurItem->fCancelled && (SYNCMGRSTATUS_SUCCEEDED == pCurItem->dwSyncMgrResultStatus) ) { GetSystemTime(&sysTime); SystemTimeToFileTime(&sysTime,&ft); } else { ft = HANDLERITEMSETTINGS.ft; }
// tell settings class we are done syncing.
g_pSettings->ReleaseItemLock(this,pCurItem->ItemID,&ft); DeleteItemFromList(m_pItemsToSyncList, (LPGENERICITEM) pCurItem); } } }
// release the item list if this is the last ref then null out
// the member var
if (0 == Release_ItemList(m_pItemsToSyncList)) { m_pItemsToSyncList = NULL; }
}
m_fSynchronizing = FALSE; clock.Leave();
if (pCallback) { pCallback->SynchronizeCompleted(NOERROR); pCallback->Release(); }
return; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::SetItemStatus, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::SetItemStatus(REFSYNCMGRITEMID ItemID,DWORD dwSyncMgrStatus) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); CLock clock(this);
if (!pCallback) { Assert(pCallback); return E_UNEXPECTED; }
clock.Enter();
if (m_pItemsToSyncList) { LPHANDLERITEM_SYNCSTATUS pCurItem = (LPHANDLERITEM_SYNCSTATUS) m_pItemsToSyncList->pFirstGenericItem;
while (pCurItem) { LPHANDLERITEM_SYNCSTATUS pCurItemNext;
pCurItemNext = (LPHANDLERITEM_SYNCSTATUS) pCurItem->genericItem.pNextGenericItem;
Assert(sizeof(HANDLERITEM_SYNCSTATUS) == pCurItem->genericItem.cbSize);
if ((SYNCMGRSTATUS_SKIPPED == dwSyncMgrStatus && ItemID == pCurItem->ItemID) || SYNCMGRSTATUS_STOPPED == dwSyncMgrStatus) { pCurItem->fCancelled = TRUE;
if (!pCurItem->fSynchronizeComplete) { pCurItem->dwSyncMgrResultStatus = dwSyncMgrStatus; }
// if not currently synchronizing and synchronization is
// not already done on this item set the progress accordingly
if (!pCurItem->fSynchronizing && !pCurItem->fSynchronizeComplete) { ProgressSetItemStatusType(pCallback,pCurItem->ItemID,dwSyncMgrStatus); ProgressSetItemProgMaxValue(pCallback,pCurItem->ItemID,10); ProgressSetItemProgValue(pCallback,pCurItem->ItemID,10);
pCurItem->fSynchronizeComplete = TRUE;
// if we have a syncList
// then delete the items from the list
// and relesae the lock
// Note: this code relies on PrepareForSync
// not yielding while setting up item table.
g_pSettings->ReleaseItemLock(this,pCurItem->ItemID); DeleteItemFromList(m_pItemsToSyncList, (LPGENERICITEM) pCurItem);
}
if (SYNCMGRSTATUS_SKIPPED == dwSyncMgrStatus) { break; // if skipped done when found a match.
} }
pCurItem = pCurItemNext; } }
// if not in a synchronize or prepareForSync call when stop is
// pressed release the itemList.
if ((SYNCMGRSTATUS_STOPPED == dwSyncMgrStatus) && !m_fSynchronizing && !m_fPrepareForSync) { m_fStopped = TRUE;
if (m_pItemsToSyncList) { if (0 == Release_ItemList(m_pItemsToSyncList)) { m_pItemsToSyncList = NULL; } } }
clock.Leave();
pCallback->Release(); return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ShowError, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
STDMETHODIMP CSyncMgrHandler::ShowError(HWND hWndParent,REFSYNCMGRERRORID ErrorID) { METHODARGS *pMethodArgs;
pMethodArgs = (METHODARGS*) ALLOC(sizeof(METHODARGS));
if (NULL == pMethodArgs) { Assert(pMethodArgs); return E_OUTOFMEMORY; }
pMethodArgs->fAsync = TRUE; pMethodArgs->dwWorkerMsg = WM_WORKERMSG_SHOWERROR; pMethodArgs->ShowErrorMsg.hWndParent = hWndParent; pMethodArgs->ShowErrorMsg.ErrorID = ErrorID;
PostMessage(m_hwndWorker,WM_WORKERMSG_SHOWERROR,0,(LPARAM) pMethodArgs);
return NOERROR; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ShowErrorCall, private
//
// Synopsis: Called on Worker Thread
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ShowErrorCall(HWND hWndParent,REFSYNCMGRERRORID ErrorID) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback();
if (pCallback) { pCallback->ShowErrorCompleted(NOERROR,0,NULL); pCallback->Release(); }
return; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::Progress, private
//
// Synopsis: Helper method for sending progress information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::Progress(ISyncMgrSynchronizeCallback *lpCallBack,REFSYNCMGRITEMID pItemID, UINT mask,TCHAR *pStatusText,DWORD dwStatusType, int iProgValue,int iMaxValue) { SYNCMGRPROGRESSITEM syncProg; Assert(lpCallBack);
syncProg.cbSize = sizeof(SYNCMGRPROGRESSITEM); syncProg.mask = mask;
if (SYNCMGRPROGRESSITEM_STATUSTEXT & mask) { #ifdef _UNICODE
syncProg.lpcStatusText = pStatusText; #else
WCHAR wszStatusText[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, pStatusText, -1, wszStatusText,MAX_PATH);
syncProg.lpcStatusText = wszStatusText; #endif // _UNICODE
}
syncProg.dwStatusType = dwStatusType; syncProg.iProgValue = iProgValue; syncProg.iMaxValue = iMaxValue;
lpCallBack->Progress(pItemID,&syncProg); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ProgressSetItemStatusType, private
//
// Synopsis: Helper method for sending progress information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ProgressSetItemStatusType(ISyncMgrSynchronizeCallback *lpCallBack, REFSYNCMGRITEMID pItemID,DWORD dwSyncMgrStatus) { Progress(lpCallBack,pItemID,SYNCMGRPROGRESSITEM_STATUSTYPE, NULL,dwSyncMgrStatus,0,0); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ProgressSetItemStatusText, private
//
// Synopsis: Helper method for sending progress information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ProgressSetItemStatusText(ISyncMgrSynchronizeCallback *lpCallBack, REFSYNCMGRITEMID pItemID,TCHAR *pStatusText) { Progress(lpCallBack,pItemID,SYNCMGRPROGRESSITEM_STATUSTEXT, pStatusText,0,0,0); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ProgressSetItemProgValue, private
//
// Synopsis: Helper method for sending progress information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ProgressSetItemProgValue(ISyncMgrSynchronizeCallback *lpCallBack, REFSYNCMGRITEMID pItemID,int iProgValue) { Progress(lpCallBack,pItemID,SYNCMGRPROGRESSITEM_PROGVALUE, NULL,0,iProgValue,0); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ProgressSetItemMaxValue, private
//
// Synopsis: Helper method for sending progress information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ProgressSetItemProgMaxValue(ISyncMgrSynchronizeCallback *lpCallBack, REFSYNCMGRITEMID pItemID,int iProgMaxValue) { Progress(lpCallBack,pItemID,SYNCMGRPROGRESSITEM_MAXVALUE, NULL,0,0,iProgMaxValue); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::LogError, private
//
// Synopsis: Helper method for logging Error information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::LogError(ISyncMgrSynchronizeCallback *lpCallBack,REFSYNCMGRITEMID pItemID, DWORD dwErrorLevel,TCHAR *lpErrorText,DWORD mask,DWORD dwSyncMgrErrorFlags, SYNCMGRERRORID ErrorID) { SYNCMGRLOGERRORINFO logError; WCHAR *pwszErrorText;
Assert(lpCallBack);
logError.cbSize = sizeof(SYNCMGRLOGERRORINFO); logError.mask = mask | SYNCMGRLOGERROR_ERRORID | SYNCMGRLOGERROR_ERRORFLAGS; logError.dwSyncMgrErrorFlags = dwSyncMgrErrorFlags | SYNCMGRERRORFLAG_ENABLEJUMPTEXT; logError.ErrorID = ErrorID; logError.ItemID = pItemID;
#ifdef _UNICODE
pwszErrorText = lpErrorText; #else
WCHAR wszErrorText[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, lpErrorText, -1, wszErrorText,MAX_PATH);
pwszErrorText = wszErrorText; #endif // _UNICODE
lpCallBack->LogError(dwErrorLevel,pwszErrorText,&logError); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::LogError, private
//
// Synopsis: Helper method for logging Error information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::LogError(ISyncMgrSynchronizeCallback *lpCallBack,REFSYNCMGRITEMID pItemID, DWORD dwErrorLevel,TCHAR *lpErrorText) { LogError(lpCallBack,pItemID,dwErrorLevel,lpErrorText,SYNCMGRLOGERROR_ITEMID,0,GUID_NULL); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::LogError, private
//
// Synopsis: Helper method for logging Error information.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::LogError(ISyncMgrSynchronizeCallback *lpCallBack, DWORD dwErrorLevel,TCHAR *lpErrorText) { LogError(lpCallBack,GUID_NULL,dwErrorLevel,lpErrorText,0,0,GUID_NULL); }
////******
///
// methods specific to this implementation to sync up file directories
//
///*******
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::GetFilesForDir, private
//
// Synopsis: creates a list of files for the given directory.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LPFILEOBJECTLIST CSyncMgrHandler::GetFilesForDir(TCHAR *pDirName,BOOL fRecursive)
{ LPFILEOBJECTLIST pDirList; HANDLE hFind; BOOL bMore; WIN32_FIND_DATA finddata; TCHAR szSearch[MAX_PATH];
pDirList = CreateItemList();
if (!pDirList) { return NULL; }
wsprintf(szSearch,TEXT("%s\\*.*"),pDirName);
hFind = FindFirstFile(szSearch, &finddata); bMore = (hFind != (HANDLE) -1);
while (bMore) {
if ( (lstrcmp(finddata.cFileName, TEXT(".")) != 0) && ( lstrcmp(finddata.cFileName, TEXT("..")) != 0) ) { LPFILEOBJECT pFileObject = (LPFILEOBJECT) AddNewItemToList(pDirList,sizeof(FILEOBJECT)); BOOL bIsDir;
if (!pFileObject) // if alloc ever fails just bail.
{ break; }
// init the data.
lstrcpy(pFileObject->fName,finddata.cFileName);
bIsDir = (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE; pFileObject->fDirectory = bIsDir;
if (!bIsDir) { HANDLE hFile; FILETIME ftCreate; FILETIME ftLastAccess;
// Review - need to check failure
// and if way to get modified with openning file.
wsprintf(szSearch,TEXT("%s\\%s"),pDirName,pFileObject->fName);
hFile = CreateFile(szSearch, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (GetFileTime(hFile, &ftCreate, &ftLastAccess,&(pFileObject->ftLastUpdate)) ) { pFileObject->fLastUpdateValid = TRUE; }
CloseHandle(hFile);
} else { // if this is a directory and recursive, get children
if (fRecursive) { TCHAR szFullPath[MAX_PATH];
// fullpath is current dir name + \ + this dir name.
wsprintf(szFullPath,TEXT("%s\\%s"),pDirName,pFileObject->fName);
pFileObject->pChildList = GetFilesForDir(szFullPath,fRecursive); } } }
bMore = FindNextFile(hFind, &finddata); }
FindClose(hFind);
return pDirList; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CreateDirFileListFromPath, private
//
// Synopsis: creates a new FileObjectList for the given Directory
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LPFILEOBJECTLIST CSyncMgrHandler::CreateDirFileListFromPath(TCHAR *pDirName,BOOL fRecursive) { LPFILEOBJECTLIST pDirObj; BOOL fValidDir = FALSE;
if (!IsValidDir(pDirName)) { return NULL; }
pDirObj = CreateItemList();
if (pDirObj) { LPFILEOBJECT pFileObject;
// go ahead and add this as the toplevel dir
pFileObject = (LPFILEOBJECT) AddNewItemToList(pDirObj,sizeof(FILEOBJECT));
if (pFileObject) { pFileObject->fDirectory = TRUE; lstrcpy(pFileObject->fName,pDirName);
pFileObject->pChildList = GetFilesForDir(pFileObject->fName,fRecursive);
} }
return pDirObj; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::ReleaseFileObjectList, private
//
// Synopsis: releases the fileobject list.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ReleaseFileObjectList(LPFILEOBJECTLIST pfObjList,BOOL fRecursive) { LPFILEOBJECT pCurItem;
if (!pfObjList) { Assert(pfObjList) return; }
// see if object has any childs and free them if they do.
pCurItem= (LPFILEOBJECT) pfObjList->pFirstGenericItem;
while(pCurItem) { Assert(sizeof(FILEOBJECT ) == pCurItem->genericItem.cbSize);
if (pCurItem->fDirectory) { Assert(pCurItem->pChildList || (!fRecursive));
if (pCurItem->pChildList) { ReleaseFileObjectList(pCurItem->pChildList,fRecursive); } }
pCurItem = (LPFILEOBJECT) pCurItem->genericItem.pNextGenericItem; }
Release_ItemList(pfObjList); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CountNumberofFilesInList, private
//
// Synopsis: returns a total count of the number of items in the list.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
ULONG CSyncMgrHandler::CountNumberOfFilesInList(LPFILEOBJECTLIST pfObjList,BOOL fRecursive) { LPFILEOBJECT pCurItem; ULONG ulTotalCount = 0;
if (!pfObjList) { Assert(pfObjList) return 0; }
// see if object has any childs and free them if they do.
pCurItem= (LPFILEOBJECT) pfObjList->pFirstGenericItem;
while(pCurItem) { Assert(sizeof(FILEOBJECT ) == pCurItem->genericItem.cbSize);
if (pCurItem->fDirectory) { Assert(pCurItem->pChildList || (!fRecursive));
if (pCurItem->pChildList) { ulTotalCount += CountNumberOfFilesInList(pCurItem->pChildList,fRecursive); } } else { ++ulTotalCount; }
pCurItem = (LPFILEOBJECT) pCurItem->genericItem.pNextGenericItem; }
return ulTotalCount; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::FindFileItemWithName, private
//
// Synopsis: trys to find the items with with the specified filename in
// the fileobject list.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LPFILEOBJECT CSyncMgrHandler::FindFileItemWithName(LPFILEOBJECTLIST pDir,TCHAR *pfName) { LPFILEOBJECT pCurItem = NULL;
if (!pDir) { Assert(pDir) return NULL; }
// see if object has any childs and free them if they do.
pCurItem= (LPFILEOBJECT) pDir->pFirstGenericItem;
while(pCurItem) { Assert(sizeof(FILEOBJECT ) == pCurItem->genericItem.cbSize);
if (0 == lstrcmp(pfName,pCurItem->fName)) { break; }
pCurItem = (LPFILEOBJECT) pCurItem->genericItem.pNextGenericItem; }
return pCurItem; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CopyfileFullPath, private
//
// Synopsis: copies file1 to file2 along with attribs.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
BOOL CSyncMgrHandler::CopyFileFullPath(TCHAR *pszFile1,TCHAR *pszFile2) { HANDLE hfile; DWORD dwAttribs; FILETIME ftCreate,ftLastAccess,ftLastWrite; BOOL fOk;
fOk = CopyFile(pszFile1, pszFile2, FALSE);
if (fOk) { BOOL fFileTime = FALSE;
// having copied the file, now copy the times, attributes
// if fail to get go ahead and say copy succeeded.
hfile = CreateFile(pszFile1, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hfile) {
fFileTime = GetFileTime(hfile, &ftCreate, &ftLastAccess, &ftLastWrite); CloseHandle(hfile); }
if (fFileTime) { hfile = CreateFile(pszFile2, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hfile) { SetFileTime(hfile, &ftCreate, &ftLastAccess, &ftLastWrite);
CloseHandle(hfile); } }
// update attributes
dwAttribs = GetFileAttributes(pszFile1); if (-1 != dwAttribs) { SetFileAttributes(pszFile2,dwAttribs); }
}
return fOk; }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::CopyFiles, private
//
// Synopsis: copies all files from dir1 to dir2
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::CopyFiles( LPHANDLERITEM_SYNCSTATUS pHandlerItemID, LPHANDLERITEMSETTINGS pHANDLERITEMSETTINGS, LPSYNCMGRSYNCHRONIZECALLBACK pCallback, DWORD *pdwCurProgValue, TCHAR *pszDir1, LPFILEOBJECTLIST pDir1, TCHAR *pszDir2) { LPFILEOBJECT pCurDir1Item; LPFILEOBJECT pNextDir1Item;
// anything left is list when done is unique and needs to be copied
// walk through each list moving the items.
pNextDir1Item = (LPFILEOBJECT) pDir1->pFirstGenericItem;
while(pNextDir1Item) {
// each time through the loop check for if item is cancelled
// and if so return;
if (pHandlerItemID->fCancelled) return;
Assert(sizeof(FILEOBJECT ) == pNextDir1Item->genericItem.cbSize); pCurDir1Item = pNextDir1Item;
pNextDir1Item = (LPFILEOBJECT) pNextDir1Item->genericItem.pNextGenericItem;
if (pCurDir1Item->fDirectory) { if (pCurDir1Item->pChildList) { TCHAR szDir1[MAX_PATH]; TCHAR szDir2[MAX_PATH];
wsprintf(szDir1,TEXT("%s\\%s"),pszDir1,pCurDir1Item->fName); wsprintf(szDir2,TEXT("%s\\%s"),pszDir2,pCurDir1Item->fName);
// create destination dir if necessary.
CreateDirectory(szDir2,NULL);
CopyFiles(pHandlerItemID,pHANDLERITEMSETTINGS,pCallback,pdwCurProgValue, szDir1,pCurDir1Item->pChildList,szDir2); }
} else { TCHAR szFullPath1[MAX_PATH]; TCHAR szFullPath2[MAX_PATH]; TCHAR szProgress[MAX_PATH];
wsprintf(szProgress,TEXT("Copying %s"),pCurDir1Item->fName); ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,szProgress);
wsprintf(szFullPath1,TEXT("%s\\%s"),pszDir1,pCurDir1Item->fName); wsprintf(szFullPath2,TEXT("%s\\%s"),pszDir2,pCurDir1Item->fName);
// copy the file over
if (FALSE == CopyFileFullPath(szFullPath1,szFullPath2)) { wsprintf(szProgress,TEXT("Error Copying %s"),pCurDir1Item->fName);
LogError(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRLOGLEVEL_ERROR, szProgress); }
// update the progress bar value.
*pdwCurProgValue += 1; ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,*pdwCurProgValue);
// always release, even on
DeleteItemFromList(pDir1,(LPGENERICITEM) pCurDir1Item);
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::reconcileDir, private
//
// Synopsis: does main job of reconciling dir1 and dir2
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::ReconcileDir(HWND hWndParent, LPHANDLERITEM_SYNCSTATUS pHandlerItemID, LPHANDLERITEMSETTINGS pHANDLERITEMSETTINGS, LPSYNCMGRSYNCHRONIZECALLBACK pCallback, DWORD *pdwCurProgValue, TCHAR *pszDir1,LPFILEOBJECTLIST pDir1, TCHAR *pszDir2,LPFILEOBJECTLIST pDir2) { LPFILEOBJECT pCurDir1Item; LPFILEOBJECT pCurDir1NextItem; LPFILEOBJECT pCurDir2Item;
if (!pDir1 || !pDir2 || !pCallback) { Assert(pCallback); Assert(pDir1); Assert(pDir1); return; } // loop through dir finding and comparing matches,
// if find matching dirs call ReconcileDir
pCurDir1NextItem= (LPFILEOBJECT) pDir1->pFirstGenericItem;
while(pCurDir1NextItem) { Assert(sizeof(FILEOBJECT ) == pCurDir1NextItem->genericItem.cbSize);
// each time through the loop check for if item is cancelled
// and if so return;
if (pHandlerItemID->fCancelled) return;
pCurDir1Item = pCurDir1NextItem; pCurDir1NextItem = (LPFILEOBJECT) pCurDir1Item->genericItem.pNextGenericItem;
pCurDir2Item = FindFileItemWithName(pDir2,pCurDir1Item->fName);
// if found match, deal with it, else leave in list and
// catch on the copy pass.
if (pCurDir2Item) { // if both directies
if (pCurDir1Item->fDirectory && pCurDir2Item->fDirectory) { if (pCurDir1Item->pChildList && pCurDir2Item->pChildList) { TCHAR szDir1[MAX_PATH]; TCHAR szDir2[MAX_PATH];
wsprintf(szDir1,TEXT("%s\\%s"),pszDir1,pCurDir1Item->fName); wsprintf(szDir2,TEXT("%s\\%s"),pszDir2,pCurDir2Item->fName);
ReconcileDir(hWndParent,pHandlerItemID,pHANDLERITEMSETTINGS, pCallback, pdwCurProgValue, szDir1,pCurDir1Item->pChildList, szDir2,pCurDir2Item->pChildList);
} else { // one of the directories didn't have a child list and
// one did.
if (pCurDir1Item->pChildList) { *pdwCurProgValue += CountNumberOfFilesInList(pCurDir1Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); ReleaseFileObjectList(pCurDir1Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); pCurDir1Item->pChildList = NULL; }
*pdwCurProgValue += 1; DeleteItemFromList(pDir1,(LPGENERICITEM) pCurDir1Item);
if (pCurDir2Item->pChildList) { *pdwCurProgValue += CountNumberOfFilesInList(pCurDir2Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); ReleaseFileObjectList(pCurDir2Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); pCurDir2Item->pChildList = NULL; }
*pdwCurProgValue += 1; DeleteItemFromList(pDir2,(LPGENERICITEM) pCurDir2Item);
// update the progress value.
ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,*pdwCurProgValue);
} } else if (!pCurDir1Item->fDirectory && !pCurDir2Item->fDirectory) { FILETIME *pftLastUpdate = &(pHANDLERITEMSETTINGS->ft); int iFileCompare; BOOL fCopy = FALSE;
ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,pCurDir1Item->fName);
// if filestimes are the same do nothing
// both filetimes are greater than < last sync time, conflict,
// else copy newer file over.
if (0 != (iFileCompare = CompareFileTime(&(pCurDir1Item->ftLastUpdate),&(pCurDir2Item->ftLastUpdate)) )) { int iFile1UpdateTimeCompare = CompareFileTime(&(pCurDir1Item->ftLastUpdate),pftLastUpdate); int iFile2UpdateTimeCompare = CompareFileTime(&(pCurDir2Item->ftLastUpdate),pftLastUpdate);
if (iFile1UpdateTimeCompare == iFile2UpdateTimeCompare) { RFCDLGPARAM rfcParam; int iResolution; TCHAR szNetModifiedOnBuf[MAX_PATH]; TCHAR szLocalModifiedOnBuf[MAX_PATH];
// !!! Conflict
memset(&rfcParam,0,sizeof(RFCDLGPARAM));
rfcParam.dwFlags = 0; rfcParam.pszFilename = pCurDir1Item->fName; rfcParam.pszLocation = pszDir1; rfcParam.pszNewName = pCurDir2Item->fName; rfcParam.pszNetworkModifiedOn = FormatDateTime(&(pCurDir1Item->ftLastUpdate),szNetModifiedOnBuf,sizeof(szNetModifiedOnBuf)/sizeof(TCHAR)); rfcParam.pszLocalModifiedOn = FormatDateTime(&(pCurDir2Item->ftLastUpdate),szLocalModifiedOnBuf,sizeof(szLocalModifiedOnBuf)/sizeof(TCHAR));
// if can show UI call enable modeless, and show
// conflict dialog, else log and error and treat
// as if use chose to keep both.
if ( (m_dwSyncFlags & SYNCMGRFLAG_MAYBOTHERUSER) && (S_OK == pCallback->EnableModeless(TRUE)) ) { iResolution = SyncMgrResolveConflict(hWndParent,&rfcParam); pCallback->EnableModeless(FALSE); } else { TCHAR szLogText[MAX_PATH];
iResolution = RFC_KEEPBOTH;
wsprintf(szLogText,TEXT("Conflict occured - %s"),pCurDir1Item->fName);
LogError(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRLOGLEVEL_WARNING, szLogText);
}
switch (iResolution) { case RFC_KEEPNETWORK: // treat dir1 as network copy
iFileCompare = 1; fCopy = TRUE; break; case RFC_KEEPLOCAL: // treat dir2 as local copy.
iFileCompare = - 1; fCopy = TRUE; break; case RFC_KEEPBOTH: // if keep both wait until next sync.
default: fCopy = FALSE; pHandlerItemID->fUnresolvedConflicts = TRUE; break; }
} else { fCopy = TRUE; }
if (fCopy) { TCHAR szProgressText[MAX_PATH]; TCHAR szFile1FullPath[MAX_PATH],szFile2FullPath[MAX_PATH]; BOOL fOk;
wsprintf(szProgressText,TEXT("Updating %s"),pCurDir1Item->fName); ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,szProgressText);
wsprintf(szFile1FullPath,TEXT("%s\\%s"),pszDir1,pCurDir1Item->fName); wsprintf(szFile2FullPath,TEXT("%s\\%s"),pszDir2,pCurDir2Item->fName);
// copy newer file.
if (0 < iFileCompare) { // 1 > 2.
fOk = CopyFileFullPath(szFile1FullPath,szFile2FullPath); } else { fOk = CopyFileFullPath(szFile2FullPath,szFile1FullPath);
}
}
}
// when done incmrement the progress value and release the items.
*pdwCurProgValue += 2; // incrent progress by 2 since we handled both files.
ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,*pdwCurProgValue);
// always release, even on error since don't want copy to kick in.
DeleteItemFromList(pDir1,(LPGENERICITEM) pCurDir1Item); DeleteItemFromList(pDir2,(LPGENERICITEM) pCurDir2Item);
} else { TCHAR szLogError[MAX_PATH];
wsprintf(szLogError,TEXT("%s is a Directory in one location and file in another.") ,pCurDir1Item->fName); LogError(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRLOGLEVEL_ERROR,szLogError);
// release both dir and file.
if (pCurDir1Item->fDirectory && pCurDir1Item->pChildList) { *pdwCurProgValue += CountNumberOfFilesInList(pCurDir1Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); ReleaseFileObjectList(pCurDir1Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); pCurDir1Item->pChildList = NULL; }
*pdwCurProgValue += 1; DeleteItemFromList(pDir1,(LPGENERICITEM) pCurDir1Item);
if (pCurDir2Item->fDirectory && pCurDir2Item->pChildList) { *pdwCurProgValue += CountNumberOfFilesInList(pCurDir2Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); ReleaseFileObjectList(pCurDir2Item->pChildList,pHANDLERITEMSETTINGS->fRecursive); pCurDir2Item->pChildList = NULL; }
*pdwCurProgValue += 1; DeleteItemFromList(pDir2, (LPGENERICITEM) pCurDir2Item);
// update the progress value.
ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,*pdwCurProgValue);
}
}
}
// Anything left is a copy
// This sample doesn't properly handle the following cases
// 1) file has been deleted in one folder and not the other - next sync file will be
// copied back to folder it was delted from
// 2) File has been renamed in one folder and not the other - next sync both files will
// appear.
CopyFiles(pHandlerItemID,pHANDLERITEMSETTINGS,pCallback,pdwCurProgValue,pszDir1,pDir1,pszDir2); CopyFiles(pHandlerItemID,pHANDLERITEMSETTINGS,pCallback,pdwCurProgValue,pszDir2,pDir2,pszDir1); }
//+---------------------------------------------------------------------------
//
// Member: CSyncMgrHandler::SyncDirs, private
//
// Synopsis: Called by SynchronizeCall(). Sets up dirlists
// for synchronization and then calls the ReconcileDir function.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
void CSyncMgrHandler::SyncDirs(HWND hWndParent,LPHANDLERITEM_SYNCSTATUS pHandlerItemID, LPHANDLERITEMSETTINGS pHANDLERITEMSETTINGS) { LPSYNCMGRSYNCHRONIZECALLBACK pCallback = GetProgressCallback(); LPFILEOBJECTLIST pfObjDir1 = NULL,pfObjDir2 = NULL; ULONG ulProgressMaxValue = 0; ULONG ulProgressCurValue = 0; TCHAR szStatusText[MAX_PATH];
// if already cancelled go on.
if (pHandlerItemID->fCancelled) goto synccomplete;
// synchronizing flag should be TRUE so SetItemStatus knows this is
Assert(TRUE == pHandlerItemID->fSynchronizing);
pHandlerItemID->dwSyncMgrResultStatus = SYNCMGRSTATUS_SUCCEEDED;
ProgressSetItemStatusType(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRSTATUS_UPDATING);
wsprintf(szStatusText,TEXT("Scanning %s"),pHANDLERITEMSETTINGS->dir1); ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,szStatusText);
pfObjDir1 = CreateDirFileListFromPath(pHANDLERITEMSETTINGS->dir1, pHANDLERITEMSETTINGS->fRecursive);
if (pHandlerItemID->fCancelled) goto synccomplete;
if (!pfObjDir1) { wsprintf(szStatusText,TEXT("Error Scanning %s"),pHANDLERITEMSETTINGS->dir1); LogError(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRLOGLEVEL_ERROR,szStatusText); pHandlerItemID->dwSyncMgrResultStatus = SYNCMGRSTATUS_FAILED; } else { wsprintf(szStatusText,TEXT("Scanning %s"),pHANDLERITEMSETTINGS->dir2); ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,szStatusText);
pfObjDir2 = CreateDirFileListFromPath(pHANDLERITEMSETTINGS->dir2, pHANDLERITEMSETTINGS->fRecursive);
if (!pfObjDir2) { wsprintf(szStatusText,TEXT("Error Scanning %s"),pHANDLERITEMSETTINGS->dir2); LogError(pCallback,pHANDLERITEMSETTINGS->ItemID,SYNCMGRLOGLEVEL_ERROR,szStatusText); pHandlerItemID->dwSyncMgrResultStatus = SYNCMGRSTATUS_FAILED; } }
if (pHandlerItemID->fCancelled) goto synccomplete;
if (pfObjDir1 && pfObjDir2) { // Calc the progress Item MaxValue which is the total
// number of items to sync.
ulProgressMaxValue += CountNumberOfFilesInList(pfObjDir1,pHANDLERITEMSETTINGS->fRecursive); ulProgressMaxValue += CountNumberOfFilesInList(pfObjDir2,pHANDLERITEMSETTINGS->fRecursive);
ProgressSetItemProgMaxValue(pCallback,pHANDLERITEMSETTINGS->ItemID,ulProgressMaxValue); ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,0);
// want to kick Reconcil off pointing to childlist of each toplevel dir
if (pfObjDir1->pFirstGenericItem && pfObjDir2->pFirstGenericItem) { LPFILEOBJECTLIST pfObjStartDir1,pfObjStartDir2; TCHAR *pszDir1Name,*pszDir2Name;
pfObjStartDir1 = ((LPFILEOBJECT) pfObjDir1->pFirstGenericItem)->pChildList; pfObjStartDir2 = ((LPFILEOBJECT) pfObjDir2->pFirstGenericItem)->pChildList;
pszDir1Name = ((LPFILEOBJECT) pfObjDir1->pFirstGenericItem)->fName; pszDir2Name = ((LPFILEOBJECT) pfObjDir2->pFirstGenericItem)->fName;
if (pfObjStartDir1 && pfObjStartDir2) { ReconcileDir(hWndParent,pHandlerItemID,pHANDLERITEMSETTINGS,pCallback,&ulProgressCurValue, pszDir1Name,pfObjStartDir1,pszDir2Name,pfObjStartDir2); } } }
synccomplete:
// set progress to max and clear status
ProgressSetItemProgValue(pCallback,pHANDLERITEMSETTINGS->ItemID,ulProgressMaxValue); ProgressSetItemStatusText(pCallback,pHANDLERITEMSETTINGS->ItemID,TEXT(""));
// update item status based on result.
ProgressSetItemStatusType(pCallback,pHANDLERITEMSETTINGS->ItemID,pHandlerItemID->dwSyncMgrResultStatus);
if (pCallback) { pCallback->Release(); }
if (pfObjDir1) { ReleaseFileObjectList(pfObjDir1,pHANDLERITEMSETTINGS->fRecursive); }
if (pfObjDir2) { ReleaseFileObjectList(pfObjDir2,pHANDLERITEMSETTINGS->fRecursive); } }
//+---------------------------------------------------------------------------
//
// Function: HandlerThreadWndProc, private
//
// Synopsis: WndProc for hwnd on thread handler was created on
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LRESULT CALLBACK HandlerThreadWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { CSyncMgrHandler *pThis = (CSyncMgrHandler *) GetWindowLong(hWnd, DWL_THREADWNDPROCCLASS); METHODARGS *pMethodArgs = (METHODARGS *) lParam; BOOL fMethodCall = FALSE;
switch (msg) { case WM_CREATE : { CREATESTRUCT *pCreateStruct = (CREATESTRUCT *) lParam;
SetWindowLong(hWnd, DWL_THREADWNDPROCCLASS,(LONG) pCreateStruct->lpCreateParams ); pThis = (CSyncMgrHandler *) pCreateStruct->lpCreateParams ; } break; case WM_DESTROY: break; case WM_WORKERMSG_PROGRESS: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { PROGRESSMSG *pMsg = &(pMethodArgs->ProgressMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->Progress( pMsg->ItemID, pMsg->lpSyncProgressItem); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_PREPAREFORSYNCCOMPLETED: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { PREPAREFORSYNCCOMPLETEDMSG *pMsg = &(pMethodArgs->PrepareForSyncCompletedMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->PrepareForSyncCompleted( pMsg->hr); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_SYNCHRONIZECOMPLETED: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { SYNCHRONIZECOMPLETEDMSG *pMsg = &(pMethodArgs->SynchronizeCompletedMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->SynchronizeCompleted( pMsg->hr); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_SHOWPROPERTIESCOMPLETED: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { SHOWPROPERTIESCOMPLETEDMSG *pMsg = &(pMethodArgs->ShowPropertiesCompletedMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->ShowPropertiesCompleted( pMsg->hr); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_SHOWERRORCOMPLETED: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { SHOWERRORCOMPLETEDMSG *pMsg = &(pMethodArgs->ShowErrorCompletedMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->ShowErrorCompleted( pMsg->hr, pMsg->cbNumItems, pMsg->pItemIDs ); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_ENABLEMODELESS: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { ENABLEMODELESSMSG *pMsg = &(pMethodArgs->EnableModelessMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->EnableModeless( pMsg->fEnable); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_LOGERROR: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { LOGERRORMSG *pMsg = &(pMethodArgs->LogErrorMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->LogError( pMsg->dwErrorLevel, pMsg->lpcErrorText, pMsg->lpSyncLogError); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_DELETELOGERROR: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { DELETELOGERRORMSG *pMsg = &(pMethodArgs->DeleteLogErrorMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->DeleteLogError( pMsg->ErrorID, pMsg->dwReserved); }
Assert(!pMethodArgs->fAsync); } break; case WM_WORKERMSG_ESTABLISHCONNECTION: Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { pMethodArgs->hr = E_UNEXPECTED;
if (pThis->m_pSyncMgrSynchronizeCallback) { ESTABLISHCONNECTIONMSG *pMsg = &(pMethodArgs->EstablishConnectionMsg);
Assert(msg == pMethodArgs->dwWorkerMsg);
pMethodArgs->hr = pThis->m_pSyncMgrSynchronizeCallback->EstablishConnection( pMsg->lpwszConnection, pMsg->dwReserved ); }
Assert(!pMethodArgs->fAsync); } break; default: break; }
// if this was a method call and async then free methodArgs,
// on synchronous calls up to the caller to free.
if (fMethodCall && pMethodArgs && pMethodArgs->fAsync) { FREE(pMethodArgs); }
return DefWindowProc(hWnd, msg, wParam, lParam); }
//+---------------------------------------------------------------------------
//
// Function: WorkerThreadWndProc, private
//
// Synopsis: WndProc for hwnd on the worker thread.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
LRESULT CALLBACK WorkerThreadWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { CSyncMgrHandler *pThis = (CSyncMgrHandler *) GetWindowLong(hWnd, DWL_THREADWNDPROCCLASS); METHODARGS *pMethodArgs = (METHODARGS *) lParam; BOOL fMethodCall = FALSE;
switch (msg) { case WM_CREATE : { CREATESTRUCT *pCreateStruct = (CREATESTRUCT *) lParam;
SetWindowLong(hWnd, DWL_THREADWNDPROCCLASS,(LONG) pCreateStruct->lpCreateParams ); pThis = (CSyncMgrHandler *) pCreateStruct->lpCreateParams ; } break; case WM_DESTROY: PostQuitMessage(0); // shut down this thread.
break; case WM_WORKERMSG_SHOWPROPERTIES: Assert(pMethodArgs); fMethodCall = TRUE; if (pMethodArgs) { SHOWPROPERTIESMSG *pShowPropertiesMsg = &(pMethodArgs->ShowPropertiesMsg);
Assert(WM_WORKERMSG_SHOWPROPERTIES == pMethodArgs->dwWorkerMsg);
pThis->ShowPropertiesCall(pShowPropertiesMsg->hWndParent, pShowPropertiesMsg->ItemID);
Assert(pMethodArgs->fAsync); }
break; case WM_WORKERMSG_PREPFORSYNC:
Assert(pMethodArgs); fMethodCall = TRUE;
if (pMethodArgs) { PREPAREFORSYNCMSG *pPrepareForSyncMsg = &(pMethodArgs->PrepareForSyncMsg);
Assert(WM_WORKERMSG_PREPFORSYNC == pMethodArgs->dwWorkerMsg);
pThis->PrepareForSyncCall(pPrepareForSyncMsg->cbNumItems, pPrepareForSyncMsg->pItemIDs, pPrepareForSyncMsg->hWndParent, pPrepareForSyncMsg->dwReserved);
if (pPrepareForSyncMsg->pItemIDs) { FREE(pPrepareForSyncMsg->pItemIDs); }
Assert(pMethodArgs->fAsync); } break; case WM_WORKERMSG_SYNCHRONIZE: Assert(pMethodArgs); fMethodCall = TRUE; if (pMethodArgs) { SYNCHRONIZEMSG *pSynchronizeMsg = &(pMethodArgs->SynchronizeMsg);
Assert(WM_WORKERMSG_SYNCHRONIZE == pMethodArgs->dwWorkerMsg); Assert(pMethodArgs->fAsync); pThis->SynchronizeCall(pSynchronizeMsg->hWndParent);
}
break; case WM_WORKERMSG_SHOWERROR: Assert(pMethodArgs);
fMethodCall = TRUE; if (pMethodArgs) { SHOWERRORMSG *pShowErrorMsg = &(pMethodArgs->ShowErrorMsg);
Assert(pMethodArgs->fAsync); Assert(WM_WORKERMSG_SHOWERROR == pMethodArgs->dwWorkerMsg);
pThis->ShowErrorCall(pShowErrorMsg->hWndParent, pShowErrorMsg->ErrorID);
}
break; case WM_WORKERMSG_RELEASE: DestroyWindow(hWnd); break; default: break; }
// if this was a method call and async then free methodArgs,
// on synchronous calls up to the caller to free.
if (fMethodCall && pMethodArgs && pMethodArgs->fAsync) { FREE(pMethodArgs); }
return DefWindowProc(hWnd, msg, wParam, lParam); }
//+---------------------------------------------------------------------------
//
// Function: WorkerThread, private
//
// Synopsis: ThreadProc for WorkerThread.
//
// Arguments:
//
// Returns:
//
// Modifies:
//
//----------------------------------------------------------------------------
DWORD WINAPI WorkerThread( LPVOID lpArg ) { MSG msg; HRESULT hr; HRESULT hrCoInitialize; WorkerThreadArgs *pThreadArgs = (WorkerThreadArgs *) lpArg; HWND hwndWorker;
pThreadArgs->hr = NOERROR;
hrCoInitialize = CoInitialize(NULL);
// need to do a PeekMessage and then set an event to make sure
// a message loop is created before the first PostMessage is sent.
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// initialize the dialog box before returning to main thread.
if (FAILED(hrCoInitialize) ) { pThreadArgs->hr = E_OUTOFMEMORY; } else {
hwndWorker = CreateWindowEx(0, SZ_SAMPLESYNCMGRWORKERWNDCLASS, TEXT(""), // must use WS_POPUP so the window does not get
// assigned a hot key by user.
(WS_DISABLED | WS_POPUP), CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hmodThisDll, pThreadArgs->pThis);
pThreadArgs->hwnd = hwndWorker; pThreadArgs->hr = hwndWorker ? NOERROR : E_UNEXPECTED; }
hr = pThreadArgs->hr;
// let the caller know the thread is done initializing.
if (pThreadArgs->hEvent) SetEvent(pThreadArgs->hEvent);
if (NOERROR == hr) { // sit in loop receiving messages.
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
if (SUCCEEDED(hrCoInitialize)) CoUninitialize();
return 0; }
BOOL g_fWndRegistered = FALSE;
BOOL RegisterHandlerWndClasses(void) {
if (!g_fWndRegistered) { ATOM aWndClass; WNDCLASS xClass;
// register class for window created on handler thread.
xClass.style = 0; xClass.lpfnWndProc = HandlerThreadWndProc; xClass.cbClsExtra = 0;
xClass.cbWndExtra = sizeof(DWORD); // room for class this ptr
xClass.hInstance = g_hmodThisDll; xClass.hIcon = NULL; xClass.hCursor = NULL; xClass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); xClass.lpszMenuName = NULL; xClass.lpszClassName = SZ_SAMPLESYNCMGRHANDLERWNDCLASS;
aWndClass = RegisterClass( &xClass );
// Register windows class.we need for handling thread communication
xClass.style = 0; xClass.lpfnWndProc = WorkerThreadWndProc; xClass.cbClsExtra = 0;
xClass.cbWndExtra = sizeof(DWORD); // room for class this ptr
xClass.hInstance = g_hmodThisDll; xClass.hIcon = NULL; xClass.hCursor = NULL; xClass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); xClass.lpszMenuName = NULL; xClass.lpszClassName = SZ_SAMPLESYNCMGRWORKERWNDCLASS;
aWndClass = RegisterClass( &xClass );
g_fWndRegistered = TRUE; }
return g_fWndRegistered;
}
// implementation of callback wrappers so all callback calls are sent to
// syncmgr on the thread we were created on. We only implement the
// methods we call.
CCallbackWrapper::CCallbackWrapper(HWND hwndCallback) {
Assert(hwndCallback);
m_hwndCallback = hwndCallback; m_cRef = 1;
}
CCallbackWrapper::~CCallbackWrapper() { m_hwndCallback = NULL;
Assert(0 == m_cRef); }
//IUnknown methods
STDMETHODIMP CCallbackWrapper::QueryInterface(REFIID, LPVOID FAR *) { return E_NOTIMPL; }
STDMETHODIMP_(ULONG) CCallbackWrapper::AddRef() { ++m_cRef;
return m_cRef; }
STDMETHODIMP_(ULONG) CCallbackWrapper::Release() { DWORD cRefs;
--m_cRef;
cRefs = m_cRef;
if (0 == m_cRef) { delete this; }
return cRefs; }
// Callback methods.
STDMETHODIMP CCallbackWrapper::Progress(REFSYNCMGRITEMID ItemID,LPSYNCMGRPROGRESSITEM lpSyncProgressItem) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_PROGRESS; MethodArgs.ProgressMsg.ItemID = ItemID; MethodArgs.ProgressMsg.lpSyncProgressItem = lpSyncProgressItem;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::PrepareForSyncCompleted(HRESULT hr) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_PREPAREFORSYNCCOMPLETED; MethodArgs.PrepareForSyncCompletedMsg.hr = hr;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::SynchronizeCompleted(HRESULT hr) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_SYNCHRONIZECOMPLETED; MethodArgs.SynchronizeCompletedMsg.hr = hr;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::ShowPropertiesCompleted(HRESULT hr) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_SHOWPROPERTIESCOMPLETED; MethodArgs.ShowPropertiesCompletedMsg.hr = hr;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr;
}
STDMETHODIMP CCallbackWrapper::ShowErrorCompleted(HRESULT hr,ULONG cbNumItems,SYNCMGRITEMID *pItemIDs) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_SHOWERRORCOMPLETED; MethodArgs.ShowErrorCompletedMsg.hr = hr; MethodArgs.ShowErrorCompletedMsg.cbNumItems = cbNumItems; MethodArgs.ShowErrorCompletedMsg.pItemIDs = pItemIDs;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::EnableModeless(BOOL fEnable) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_ENABLEMODELESS; MethodArgs.EnableModelessMsg.fEnable = fEnable;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::LogError(DWORD dwErrorLevel,const WCHAR *lpcErrorText,LPSYNCMGRLOGERRORINFO lpSyncLogError) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_LOGERROR; MethodArgs.LogErrorMsg.dwErrorLevel = dwErrorLevel; MethodArgs.LogErrorMsg.lpcErrorText = lpcErrorText; MethodArgs.LogErrorMsg.lpSyncLogError = lpSyncLogError;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::DeleteLogError(REFSYNCMGRERRORID ErrorID,DWORD dwReserved) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_DELETELOGERROR; MethodArgs.DeleteLogErrorMsg.ErrorID = ErrorID; MethodArgs.DeleteLogErrorMsg.dwReserved = dwReserved;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
STDMETHODIMP CCallbackWrapper::EstablishConnection( WCHAR const * lpwszConnection, DWORD dwReserved) { METHODARGS MethodArgs;
MethodArgs.fAsync = FALSE; MethodArgs.hr = E_UNEXPECTED;
MethodArgs.dwWorkerMsg = WM_WORKERMSG_ESTABLISHCONNECTION; MethodArgs.EstablishConnectionMsg.lpwszConnection = lpwszConnection; MethodArgs.EstablishConnectionMsg.dwReserved = dwReserved;
if (m_hwndCallback) { SendMessage(m_hwndCallback,MethodArgs.dwWorkerMsg,0,(LPARAM) &MethodArgs); }
return MethodArgs.hr; }
|