mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2884 lines
78 KiB
2884 lines
78 KiB
//==========================================================================
|
|
//
|
|
// 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;
|
|
}
|