////////////////////////////////////////////////////////////////////////////// // // 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 (c) Microsoft Corporation. All rights reserved. // // Module Name: // MyDeviceSyncHandler.cpp // // Abstract: // Implementation of the Sync Center device handler for a device. // ////////////////////////////////////////////////////////////////////////////// #include "Pch.h" #include "MyDeviceSyncHandler.h" #include "SetupUI.h" #include "Guids.h" // Declare the GUIDs used by this component. #include "Resources.h" #include // Used for generating random errors #include ////////////////////////////////////////////////////////////////////////////// // class CMyDeviceSyncHandler ////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------- // // Description: // Create an instance of the device handler class. // // Parameters: // punkOuter - Outer IUnknown for aggregation. // riid - ID of interface to return pointer to. // pDeviceInfo - Info about the device to create the handler for. // ppv - Interface pointer. // // Return Values: // S_OK - Operation completed successfully. // E_OUTOFMEMORY - Error allocating the object. // Other HRESULTs - Error querying for requested interface. // //---------------------------------------------------------------------------- HRESULT CMyDeviceSyncHandler_CreateInstance( __in_opt IUnknown *punkOuter, __in REFIID riid, __in SYNCDEVICEINFO *pDeviceInfo, __deref_out void **ppv) { *ppv = NULL; UNREFERENCED_PARAMETER(punkOuter); CMyDeviceSyncHandler *psh = new CMyDeviceSyncHandler(pDeviceInfo); HRESULT hr = (psh != NULL) ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = psh->QueryInterface(riid, ppv); psh->Release(); } return hr; } //*** CMyDeviceSyncHandler_CreateInstance //---------------------------------------------------------------------------- // // Description: // Constructor. // // Parameters: // pDeviceInfo // Structure containing information about the device this handler is for. // //---------------------------------------------------------------------------- CMyDeviceSyncHandler::CMyDeviceSyncHandler(__in const SYNCDEVICEINFO *pDeviceInfo) : _cRef(1), _cItems(0), _ppItems(NULL), _pszPartnershipName(NULL) { DllAddRef(); _nPartnerID = pDeviceInfo->nPartnerID; // Truncate if source string is too long. // Space for displaying the name is limited. StringCchCopyNW(_szHandlerID, ARRAYSIZE(_szHandlerID), pDeviceInfo->szHandlerID, ARRAYSIZE(pDeviceInfo->szHandlerID)); StringCchCopyNW(_szDeviceName, ARRAYSIZE(_szDeviceName), pDeviceInfo->szName, ARRAYSIZE(pDeviceInfo->szName)); } //*** CMyDeviceSyncHandler::CMyDeviceSyncHandler //---------------------------------------------------------------------------- // // Description: // Destructor. // //---------------------------------------------------------------------------- CMyDeviceSyncHandler::~CMyDeviceSyncHandler() { if (_pszPartnershipName) { LocalFree(_pszPartnershipName); } if (_ppItems != NULL) { for (ULONG iItem = 0; iItem < _cItems; iItem++) { if (_ppItems[iItem] != NULL) { _ppItems[iItem]->Release(); } } delete [] _ppItems; } DllRelease(); } //*** destructor CMyDeviceSyncHandler::~CMyDeviceSyncHandler //---------------------------------------------------------------------------- // IUnknown (CMyDeviceSyncHandler) //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::QueryInterface(__in REFIID riid, __deref_out void **ppv) { static const QITAB qit[] = { QITABENT(CMyDeviceSyncHandler, ISyncMgrHandler), QITABENT(CMyDeviceSyncHandler, ISyncMgrSyncItemContainer), QITABENT(CMyDeviceSyncHandler, ISyncMgrHandlerInfo), { 0 }, }; return QISearch(this, qit, riid, ppv); } //*** CMyDeviceSyncHandler::QueryInterface //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CMyDeviceSyncHandler::Release() { ULONG cRef = InterlockedDecrement(&_cRef); if (cRef == 0) { delete this; } return cRef; } //*** CMyDeviceSyncHandler::Release //---------------------------------------------------------------------------- // ISyncMgrHandler (CMyDeviceSyncHandler) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the name of the handler. This name will // be displayed in the main Sync Center folder. // // Implements: ISyncMgrHandler // // Parameters: // ppszName // Name of the handler being returned. Caller will free using // CoTaskMemFree(). // // // Return Values: // S_OK - Operation completed successfully. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetName(__deref_out LPWSTR *ppszName) { HRESULT hr = S_OK; *ppszName = NULL; // Construct the name of the partnership from the name of the device and // save it for future uses. if (_pszPartnershipName == NULL) { hr = FormatString(g_hmodThisDll, IDS_DEVICE_FORMAT, &_pszPartnershipName, _szDeviceName); } // if: partnership name not constructed yet if (SUCCEEDED(hr)) { hr = SHStrDupW(_pszPartnershipName, ppszName); } // if: partnership name loaded successfully return hr; } //*** CMyDeviceSyncHandler::GetName //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get information about the handler. // // Parameters: // ppHandlerInfo - Interface for getting handler info to return to Sync Center. // // Return Values: // S_OK - Operation completed successfully. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetHandlerInfo(__deref_out ISyncMgrHandlerInfo **ppHandlerInfo) { return QueryInterface(IID_PPV_ARGS(ppHandlerInfo)); } //*** CMyDeviceSyncHandler::GetHandlerInfo //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get an interface pointer for a specific // type of object. // // Implements: ISyncMgrHandler // // Parameters: // rguidObjectID - GUID for the item to get the object for. // riid - Interface to get. // ppv - Interface returned to Sync Center // // Return Values: // S_OK - Operation completed successfully. // E_NOTIMPL - Object not supported by the handler. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetObject( __in REFGUID rguidObjectID, __in REFIID riid, __deref_out void **ppv) { HRESULT hr = E_NOTIMPL; *ppv = NULL; if (rguidObjectID == SYNCMGR_OBJECTID_QueryBeforeActivate) { hr = CMyDeviceSetupUI_CreateInstance(this, riid, ppv); } else if (rguidObjectID == SYNCMGR_OBJECTID_BrowseContent) { hr = CBrowseUI_CreateInstance(FOLDERID_Profile, riid, ppv); } else if (rguidObjectID == SYNCMGR_OBJECTID_ShowSchedule) { // Create the Schedule Wizard UI operation and initialize it. ISyncMgrScheduleWizardUIOperation *pUIOperation = NULL; hr = CoCreateInstance(CLSID_SyncMgrScheduleWizard, NULL, CLSCTX_SERVER, IID_PPV_ARGS(&pUIOperation)); if (SUCCEEDED(hr)) { hr = pUIOperation->InitWizard(_szHandlerID); if (SUCCEEDED(hr)) { hr = pUIOperation->QueryInterface(riid, ppv); } pUIOperation->Release(); } } return hr; } //*** CMyDeviceSyncHandler::GetObject //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the mask of capabilities of the handler. // The following capabilities are defined: // // SYNCMGR_HCM_NONE // No capabilities are specified. // // SYNCMGR_HCM_PROVIDES_ICON // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_Icon is specified. // // SYNCMGR_HCM_EVENT_STORE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_EventStore is specified. // // SYNCMGR_HCM_CONFLICT_STORE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_ConflictStore is // specified. // // SYNCMGR_HCM_CAN_ENABLE // Indicates whether the handler wants to allow the user to enable // the handler. Typically a handler is enabled if at least one of // its items is enabled and it is disabled if all of its items are // disabled. Setting this value allows a handler to implement // handler-wide enable functionality. If this value is set the // Enable task will be shown in the main Sync Center folder when // this handler is selected. // // SYNCMGR_HCM_CAN_DISABLE // Indicate whether the handler wants to allow the user to disable // the handler. Typically a handler is enabled if at least on of its // items Is enabled and it is disabled if all of its items are // disabled. Setting this value allows a handler to implement // handler-wide disable functionality. It can also be used by a // handler to implement support for group policy that forces a // handler to always be able to sync. If this value is set the // Disable task will be shown in the main Sync Center folder when // this handler is selected. // // SYNCMGR_HCM_CAN_BROWSE_CONTENT // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_BrowseContent is // specified. If this value is set, the Browse Content task will be // added to the context menu for the handler. // // SYNCMGR_HCM_CAN_SHOW_SCHEDULE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_ShowSchedule is // specified. If this value is set, the Show Schedule task will be // added to the context menu for the handler. // // SYNCMGR_HCM_QUERY_BEFORE_ACTIVATE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_QueryBeforeActivate is // specified. // // SYNCMGR_HCM_QUERY_BEFORE_DEACTIVATE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_QueryBeforeDeactivate is // specified. // // SYNCMGR_HCM_QUERY_BEFORE_ENABLE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_QueryBeforeEnable is // specified. // // SYNCMGR_HCM_QUERY_BEFORE_DISABLE // Indicates that the handler will return a valid object from the // GetObject() method when SYNCMGR_OBJECTID_QueryBeforeDisable is // specified. // // // Implements: ISyncMgrHandler // // Parameters: // pmCapabilities - Capabilities mask being returned. // // Return Values: // S_OK - Operation completed successfully. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetCapabilities(__out SYNCMGR_HANDLER_CAPABILITIES *pmCapabilities) { *pmCapabilities = (SYNCMGR_HANDLER_CAPABILITIES) (SYNCMGR_HCM_QUERY_BEFORE_ACTIVATE | SYNCMGR_HCM_CAN_SHOW_SCHEDULE | SYNCMGR_HCM_CAN_BROWSE_CONTENT); return S_OK; } //*** CMyDeviceSyncHandler::GetCapabilities //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the mask of policies of the handler. // The following policies are defined: // // SYNCMGR_HPM_NONE // No policies are specified. // // SYNCMGR_HPM_PREVENT_ACTIVATE // Indicates that activation of the handler is not supported. This // can be used by a handler to implement support for group policy // that prevents a handler from being setup. If this value is set, // the Setup task will be not shown in the Setup Sync folder when // this handler is selected. Most handlers should not set this // value. // // SYNCMGR_HPM_PREVENT_DEACTIVATE // Indicates that deactivation of the handler is not supported. This // can be used by a handler to implement support for group policy // that prevents a handler from being removed from the main Sync // Center folder. If this value is set, the Delete task will be not // shown in the main Sync Center folder when this handler is // selected. Most handlers should not set this value. // // SYNCMGR_HPM_PREVENT_ENABLE // Indicates that enabling the handler is not supported. This can be // used by a handler to implement support for group policy that // prevents the handler from being enabled. If this value is set the // Enable task will not be shown in the main Sync Center folder when // this handler is selected. The handler should provide a comment // (returned from its implement of the GetComment() method on // ISyncMgrHandlerInfo) to let the user know why the Enable task is // not available. Most handlers should never set this value. // // SYNCMGR_HPM_PREVENT_DISABLE // Indicates that disabling the handler is not supported. This can // be used by a handler to implement support for group policy that // forces the handler to always be able to sync. If this value is // set the Disable task will not be shown in the main Sync Center // folder when this handler is selected. The handler should provide // a comment (returned from its implementation of the GetComment() // method on ISyncMgrHandlerInfo) to let the user know why the // Disable task is not available. Most handlers should never set // this value. // // SYNCMGR_HPM_PREVENT_START_SYNC // Indicates that starting a sync through the user interface or // through the APIs is not supported. Sync can only be started by // an external application that creates a session creator to report // progress. If this value is set, the Start Sync task will not be // shown in the main Sync Center folder when the handler is selected. // Most handlers should not set this value. // // SYNCMGR_HPM_PREVENT_STOP_SYNC // Indicates that stopping a sync through the user interface or // through the APIs is not supported. If this value is set, the Stop // Sync task will not be shown in the main Sync Center folder when // the handler is selected. Most handlers should not set this value. // // SYNCMGR_HPM_DISABLE_ENABLE // Indicates that the enable task should be disabled when it is // shown for this handler. With this policy set, the Enable option // will appear in the context menu (if SYNCMGR_HPM_PREVENT_ENABLE is // not set) but will be disabled. // // SYNCMGR_HPM_DISABLE_DISABLE // Indicates that the disable task should be disabled when it is // shown for this handler. With this policy set, the Disable option // will appear in the context menu (if SYNCMGR_HPM_PREVENT_DISABLE is // not set) but will be disabled. // // SYNCMGR_HPM_DISABLE_START_SYNC // Indicates that the Start Sync task should be disabled when it is // shown for this handler. With this policy set, the Start Sync // option will appear in the context menu (if // SYNCMGR_HPM_PREVENT_START_SYNC not set) but will be disabled. // // SYNCMGR_HPM_DISABLE_STOP_SYNC // Indicates that the Stop Sync task should be disabled when it is // shown for this handler. With this policy set, the Stop Sync // option will appear in the context menu (if // SYNCMGR_HPM_PREVENT_STOP_SYNC not set) but will be disabled. // // SYNCMGR_HPM_DISABLE_BROWSE // Indicates that the Browse task should be disabled when it is shown // for this handler. The Browse task will only be shown if the // SYNCMGR_HCM_CAN_BROWSE_CONTENT value is returned from the // GetCapabilities() method. // // SYNCMGR_HPM_DISABLE_SCHEDULE // Indicates that the Schedule task should be disabled when it is // shown for this handler. The Schedule task will only be shown if // the SYNCMGR_HCM_CAN_SHOW_SCHEDULE value is returned from the // GetCapabilities() method. // // SYNCMGR_HPM_HIDDEN_BY_DEFAULT // Indicates that the handler should be hidden from the user unless // the Show Hidden Files option has been enabled. This policy only // applies the first time the handler is loaded. After that, the // hidden state is maintained by Sync Center and can be changed by // the user through the property sheet. // // SYNCMGR_HPM_BACKGROUND_SYNC_ONLY // Equivalent to setting the SYNCMGR_HPM_DISABLE_START_SYNC and // SYNCMGR_HPM_DISABLE_STOP_SYNC values. // // Implements: ISyncMgrHandler // // Parameters: // pmPolicies - Policy mask being returned. // // Return Values: // S_OK - Operation completed successfully. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetPolicies(__out SYNCMGR_HANDLER_POLICIES *pmPolicies) { *pmPolicies = SYNCMGR_HPM_NONE; return S_OK; } //*** CMyDeviceSyncHandler::GetPolicies //---------------------------------------------------------------------------- // // Description: // Called by Sync Center when the user chooses to setup or delete // the handler from the Sync Setup folder. // // Implements: ISyncMgrHandler // // Return Values: // S_OK - Handler changed activation state successfully. // Failure HRESULTs - Handler failed to change the activation state. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::Activate(BOOL fActivate) { // Note that your handler will still be called on IsActive() to // to determine its activation state. UNREFERENCED_PARAMETER(fActivate); return S_OK; } //*** CMyDeviceSyncHandler::Activate //---------------------------------------------------------------------------- // // Description: // Called by Sync Center when the user chooses to enable or disable the // handler from the main Sync Center folder. // // Implements: ISyncMgrHandler // // Return Values: // S_OK - Handler changed enabled state successfully. // Failure HRESULTs - Handler failed to change the enabled state. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::Enable(BOOL fEnable) { // Note that your handler will still be called on IsEnabled() to // determine its enabled state. UNREFERENCED_PARAMETER(fEnable); return S_OK; } //*** CMyDeviceSyncHandler::Enable //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to perform a synchronization of the specified // items. // // Implements: ISyncMgrHandler // // Parameters: // cItems // Number of items to sync. // // ppszItemIDs // Array of items to sync. // // hwndOwner // Owner window handle. // // pCreator // Sync session creator interface. // // punk // IUnknown passed to the StartHandlerSync() or StartItemSync() // methods on the ISyncMgrControl interface. // // Return Values: // S_OK - Operation completed. // Other HRESULT. // //---------------------------------------------------------------------------- HRESULT CMyDeviceSyncHandler::Synchronize( __in_ecount(cItems) LPCWSTR *ppszItemIDs, __in ULONG cItems, __in HWND hwndOwner, __in ISyncMgrSessionCreator *pCreator, __in_opt IUnknown *punk) { // TODO: Replace this sample code with real sync code. // Note: If an external application performs the sync, simply signal that // application and return. The external application then CoCreates // CLSID_SyncMgrClient specifying ISyncMgrSessionCreator and creates a // session to report sync progress and state. UNREFERENCED_PARAMETER(hwndOwner); UNREFERENCED_PARAMETER(punk); // Seed the random number generator - we will use this to generate some errors. // This line should be removed when implementing a real handler. srand((unsigned)time(0)); // Create a sync session. If sync occurs in an external process, we would // instead signal that process and have it create the sync session. ISyncMgrSyncCallback *pCallback = NULL; HRESULT hr = pCreator->CreateSession(_szHandlerID, ppszItemIDs, cItems, &pCallback); if (SUCCEEDED(hr)) { // Loop through each item until we finish or we receive a // cancel request. SYNCMGR_CANCEL_REQUEST nCancelRequest = SYNCMGR_CR_NONE; HRESULT hrSync = S_OK; // Send the initial progress on the handler ULONG uCurrentHandlerStep = 1; ULONG cMaxHandlerSteps = cItems * 50; _SetHandlerProgressText(pCallback, IDS_FILE_SYNC_STEP, &nCancelRequest, 0, cMaxHandlerSteps); for (ULONG iItem = 0; iItem < cItems; iItem++) { // Find the item. PCWSTR pszItemID = ppszItemIDs[iItem]; CMyDeviceSyncItem *pItem = _FindItem(pszItemID); if (pItem == NULL) { _ReportItemProgress(pCallback, pszItemID, IDS_ITEM_NOT_FOUND, SYNCMGR_PS_FAILED, 0, 0, &nCancelRequest); continue; } // if: couldn't find requested item // If the handler was canceled, acknowledge the cancel request. if (nCancelRequest == SYNCMGR_CR_CANCEL_ALL) { // Report that this item has been canceled and proceed to // the next item. If no progress is reported for an item, // Sync Center will mark it as failed. _ReportItemProgress(pCallback, pszItemID, 0, SYNCMGR_PS_CANCELED, 0, 0, &nCancelRequest); continue; } // Send the initial progress report to set the max value. ULONG uCurrentStep = 1; ULONG cMaxSteps = 50; _ReportItemProgress(pCallback, pszItemID, pItem->GetSyncTextID(), SYNCMGR_PS_UPDATING, 0, cMaxSteps, &nCancelRequest); if (nCancelRequest == SYNCMGR_CR_NONE) { int nDocsCompareResult = CompareStringOrdinal(pszItemID, -1, L"Documents", -1, TRUE); for (; (uCurrentStep <= cMaxSteps) && (SUCCEEDED(hrSync)); uCurrentStep++, uCurrentHandlerStep++) { // Simulate warning for sample purposes only. // This will generate a warning on the 40th Documents item. if ((nDocsCompareResult == CSTR_EQUAL) && (uCurrentStep == 40)) { GUID guidEventID; _ReportEvent( pCallback, pszItemID, IDS_SYNC_WARNING_1, IDS_SYNC_WARNING_DESC_1, SYNCMGR_EL_WARNING, SYNCMGR_EF_NONE, NULL, NULL, NULL, &guidEventID); } // Simulate errors for example purposes only. // This will generate an error on an item // synchronization with 10% probability. int nRandError = (rand() % (50 * 10)) + 1; if (nRandError == 1) { GUID guidEventID; _ReportEvent( pCallback, pszItemID, IDS_SYNC_ERROR_1, IDS_SYNC_ERROR_DESC_1, SYNCMGR_EL_ERROR, SYNCMGR_EF_NONE, NULL /*pszLinkText*/, NULL /*pszLinkReference*/, NULL /*pszContext*/, &guidEventID); hrSync = E_FAIL; } // Report progress. _ReportItemProgress( pCallback, pszItemID, pItem->GetSyncTextID(), SYNCMGR_PS_UPDATING, uCurrentStep, cMaxSteps, &nCancelRequest, uCurrentStep, cMaxSteps); if (nCancelRequest != SYNCMGR_CR_NONE) { // The handler or item has been canceled. break; } // Update the info text shown for the handler. _SetHandlerProgressText( pCallback, IDS_FILE_SYNC_STEP, &nCancelRequest, uCurrentHandlerStep, cMaxHandlerSteps); if (nCancelRequest != SYNCMGR_CR_NONE) { // The handler has been canceled. break; } // TODO: Implement synchronization here instead of a call to Sleep(). Sleep(100); } // for: each sync pass } // if: not canceled // We're done synchronizing, but regardless of our current state, // we need to send a final progress update to Sync Center so the // UI properly reflects the current state of the item. if (nCancelRequest == SYNCMGR_CR_NONE) { // Send the final progress report for this item. if (SUCCEEDED(hrSync)) { _ReportItemProgress(pCallback, pszItemID, IDS_ITEM_SYNC_DONE, SYNCMGR_PS_SUCCEEDED, uCurrentStep - 1, cMaxSteps, &nCancelRequest); } else { _ReportItemProgress(pCallback, pszItemID, IDS_ITEM_FAILED, SYNCMGR_PS_FAILED, uCurrentStep - 1, cMaxSteps, &nCancelRequest, uCurrentStep - 1, cMaxSteps); } } else { // Report that the current item has canceled. _ReportItemProgress(pCallback, pszItemID, 0, SYNCMGR_PS_CANCELED, uCurrentStep, cMaxSteps, &nCancelRequest); } hrSync = S_OK; } // for: each item to sync pCallback->Release(); } // if: sync session created successfully return hr; } //*** CMyDeviceSyncHandler::Synchronize //---------------------------------------------------------------------------- // ISyncMgrHandlerInfo (CMyDeviceSyncHandler) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the handler type value for the handler. // The following types are defined: // // SYNCMGR_HT_UNSPECIFIED // All handlers that do not specify or do not fit // in the rest of the options should use this value. // // SYNCMGR_HT_APPLICATION // Handler is an application. // // SYNCMGR_HT_DEVICE // Handler syncs with a device. // // SYNCMGR_HT_FOLDER // Handler syncs with local or remote folders. // // SYNCMGR_HT_SERVICE // Handler syncs with a web service. // // SYNCMGR_HT_COMPUTER // Handler syncs with a computer. // // Implements: ISyncMgrHandlerInfo // // Parameters: // pnType - Type to return to Sync Center. // // Return Values: // S_OK - Operation completed successfully // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetType(__out SYNCMGR_HANDLER_TYPE *pnType) { *pnType = SYNCMGR_HT_DEVICE; return S_OK; } //*** CMyDeviceSyncHandler::GetType //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get a label for the handler type. This is // usually used to display the model of the device or some other handler- // specific identifying string. // // Implements: ISyncMgrHandlerInfo // // Parameters: // ppszLabel // Pointer to fill with a pointer to a string. Must be allocated // with CoTaskMemAlloc(). Sync Center will free this using // CoTaskMemFree(). // // Return Values: // S_OK - Operation completed successfully. // E_OUTOFMEMORY - Error allocating memory for the string buffer. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetTypeLabel(__deref_out LPWSTR *ppszLabel) { *ppszLabel = NULL; WCHAR wszLabel[MAX_SYNCMGR_NAME]; HRESULT hr = E_FAIL; // LoadString returns 0 if the string could not be found. if (LoadStringW(g_hmodThisDll, IDS_HANDLER_TYPE_LABEL, wszLabel, ARRAYSIZE(wszLabel)) != 0) { hr = SHStrDupW(wszLabel, ppszLabel); } // if: label string loaded successfully return hr; } //*** CMyDeviceSyncHandler::GetTypeLabel //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get a string to display in the folder in // the far right column when a synchronization is not being performed. // If no string is provided, a blank string will be displayed. // // Implements: ISyncMgrHandlerInfo // // Parameters: // ppszComment // Pointer to fill with a pointer to a string. Must be allocated // with CoTaskMemAlloc(). Sync Center will free this using // CoTaskMemFree(). // // Return Values: // S_OK - Operation completed successfully. // E_OUTOFMEMORY - Error allocating memory for the string buffer. // E_NOTIMPL - No comment is provided by the handler. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetComment(__deref_out LPWSTR *ppszComment) { UNREFERENCED_PARAMETER(ppszComment); return E_NOTIMPL; } //*** CMyDeviceSyncHandler::GetComment //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the date and time the handler was last // synchronized. If a failure is returned, the value calculated from the // last synchronization will be used. // // Implements: ISyncMgrHandlerInfo // // Parameters: // pftLastSync - Last sync time. // // Return Values: // S_OK - Operation completed successfully. // E_NOTIMPL - No last sync time is provided by the handler. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetLastSyncTime(__out FILETIME *pftLastSync) { // If your handler does not return the last sync time, // Sync Center will manage this state for you. UNREFERENCED_PARAMETER(pftLastSync); return E_NOTIMPL; } //*** CMyDeviceSyncHandler::GetLastSyncTime //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to determine whether the handler is active or // not. // // If a handler is not active it appears in the Sync Setup folder. // Handlers in that folder cannot be synced. To move a handler to the // main Sync Center folder, the user selects the Setup task on the // context menu or on the command module. // // If a handler is active it appears in the main Sync Center folder. // A handler that is active can be synced by the user or through the // ISyncMgrControl interface. To move a handler to the Sync Setup // folder, the user selects the Delete task on the context menu or on the // command module. // // If a handler doesn't want to maintain its active state, it can return // E_NOTIMPL and Sync Center will maintain it for the handler. // // Return Values: // S_OK - Handler is active. // S_FALSE - Handler is not active. // E_NOTIMPL - Let Sync Center maintain the enabled state. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::IsActive() { return E_NOTIMPL; } //*** CMyDeviceSyncHandler::IsActive //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to determine whether the handler is enabled or // not. // // If a handler is disabled, neither it nor any of its items will be // synchronized by Sync Center and many of the actions will be removed // or disabled in the UI. // // If a handler doesn't want to maintain its enabled state, it can return // E_NOTIMPL and Sync Center will maintain it for the handler. // // Implements: ISyncMgrHandlerInfo // // Return Values: // S_OK - Handler is enabled. // S_FALSE - Handler is not enabled. // E_NOTIMPL - Let Sync Center maintain the enabled state. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::IsEnabled() { return E_NOTIMPL; } //*** CMyDeviceSyncHandler::IsEnabled //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to determine whether the handler is in a // connected state or not. // // If a handler is in a disconnected state, neither it nor any of its // items will be synchronized by Sync Center and many of the actions // will be removed or disabled in the UI. // // Return Values: // S_OK - Handler is connected. // S_FALSE - Handler is disconnected. // E_NOTIMPL - Handler doesn't support this state. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::IsConnected() { return E_NOTIMPL; } //*** CMyDeviceSyncHandler::IsConnected //---------------------------------------------------------------------------- // ISyncMgrItemContainer (CMyDeviceSyncHandler) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Description: // Return the specified sync item to Sync Center. // // Implements: ISyncMgrHandlerInfo // // Parameters: // pszItemID - The ID of the item to return. // ppItem - The item being returned. // // Return Values: // S_OK - Operation completed successfully. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetSyncItem(__in LPCWSTR pszItemID, __deref_out ISyncMgrSyncItem **ppItem) { *ppItem = NULL; // Make sure the items have been loaded first. HRESULT hr = _LoadItems(); if (SUCCEEDED(hr)) { for (DWORD iItem = 0; iItem < _cItems; iItem++) { if ((_ppItems[iItem] != NULL) && (CompareSyncMgrID(_ppItems[iItem]->GetItemIDPointer(), pszItemID) == 0)) { hr = _ppItems[iItem]->QueryInterface(IID_ISyncMgrSyncItem, (void **) ppItem); break; } } // for: each item } return hr; } //*** CMyDeviceSyncHandler::GetSyncItem //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to return an enumeration of items managed by // this handler. // // Implements: ISyncMgrHandlerInfo // // Return Values: // S_OK - Operation completed successfully. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetSyncItemEnumerator(__deref_out IEnumSyncMgrSyncItems **ppenum) { *ppenum = NULL; // Make sure the items have been loaded first. HRESULT hr = _LoadItems(); if (SUCCEEDED(hr)) { hr = CEnumSyncMgrItems_CreateInstance(this, IID_PPV_ARGS(ppenum)); } return hr; } //*** CMyDeviceSyncHandler::GetSyncItemEnumerator //---------------------------------------------------------------------------- // // Description: // Called by Sync Center to get the count of items managed by this handler. // // Implements: ISyncMgrHandlerInfo // // Return Values: // S_OK - Operation completed successfully. // Other HRESULTs. // //---------------------------------------------------------------------------- STDMETHODIMP CMyDeviceSyncHandler::GetSyncItemCount(__out ULONG *pcItems) { // Make sure the items have been loaded. HRESULT hr = _LoadItems(); if (SUCCEEDED(hr)) { *pcItems = _cItems; } return hr; } //*** CMyDeviceSyncHandler::GetSyncItemCount //---------------------------------------------------------------------------- // CMyDeviceSyncHandler Private Methods //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Description: // Load items for the device handler. // Model 1 - Single item representing all content. // Model 2 - Multiple items representing each type of content. // // Return Values: // S_OK - Operation completed successfully. // E_OUTOFMEMORY - Error allocating memory for the items. // //---------------------------------------------------------------------------- HRESULT CMyDeviceSyncHandler::_LoadItems() { HRESULT hr = S_OK; if (_ppItems == NULL) { // In this case, we're providing a static array of items that each // handler will have. You could also store this information in the // registry similar to how handler properties are stored in this sample. // Alternatively, if the user has control over which items appear with // each handler, this data could be generated dynamically. struct DEVICE_ITEM_INFO { PCWSTR pszItemID; UINT nItemNameStringID; UINT nItemLabelStringID; KNOWNFOLDERID folderID; // Folder which should open when the user browses on the item UINT uSyncTextID; // Text to be displayed on the item during syncing ("Document x of X") }; static const DEVICE_ITEM_INFO s_rgItemInfo[] = { { L"Documents", IDS_ITEMNAME_DOCUMENTS, IDS_ITEMLABEL_DOCUMENTS, FOLDERID_Documents, IDS_DOC_SYNC_STEP }, { L"Music", IDS_ITEMNAME_MUSIC, IDS_ITEMLABEL_MUSIC, FOLDERID_Music, IDS_SONG_SYNC_STEP }, { L"Pictures", IDS_ITEMNAME_PICTURES, IDS_ITEMLABEL_PICTURES, FOLDERID_Pictures, IDS_PIC_SYNC_STEP } }; // Allocate the array of sync item pointers. _ppItems = new CMyDeviceSyncItem*[ARRAYSIZE(s_rgItemInfo)](); hr = (_ppItems != NULL) ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { // Create each of the sync items. _cItems = 0; hr = S_OK; for (int iItemInfo = 0; (iItemInfo < ARRAYSIZE(s_rgItemInfo)) && SUCCEEDED(hr); iItemInfo++) { // Retrieve the localized name of the item out of our resource PWSTR pszItemName = NULL; hr = FormatString(g_hmodThisDll, s_rgItemInfo[iItemInfo].nItemNameStringID, &pszItemName); if (SUCCEEDED(hr)) { // Retrieve the localized label of the item out of our resource PWSTR pszItemLabel = NULL; hr = FormatString(g_hmodThisDll, s_rgItemInfo[iItemInfo].nItemLabelStringID, &pszItemLabel); if (SUCCEEDED(hr)) { // Create our item with our ID, name, known folder, and label details. hr = CMyDeviceSyncItem_CreateInstance( s_rgItemInfo[iItemInfo].pszItemID, pszItemName, pszItemLabel, _szHandlerID, s_rgItemInfo[iItemInfo].folderID, s_rgItemInfo[iItemInfo].uSyncTextID, &_ppItems[_cItems]); if (SUCCEEDED(hr)) { // Increment our total item count. _cItems++; } LocalFree(pszItemLabel); } LocalFree(pszItemName); } } // for: each item to create } // if: array allocated successfully } // if: items not loaded yet return hr; } //*** CMyDeviceSyncHandler::_LoadItems //---------------------------------------------------------------------------- // // Description: // Find the item structure for an item ID. // // Parameters: // pszItemID - Item to find. // // Return Values: // The item that was found. // //---------------------------------------------------------------------------- CMyDeviceSyncItem *CMyDeviceSyncHandler::_FindItem(__in LPCWSTR pszItemID) { if (_cItems == 0) { _LoadItems(); } CMyDeviceSyncItem *pItem = NULL; for (ULONG iItem = 0; iItem < _cItems; iItem++) { if (CompareSyncMgrID(_ppItems[iItem]->GetItemIDPointer(), pszItemID) == 0) { pItem = _ppItems[iItem]; break; } } // for: each item return pItem; } //*** CMyDeviceSyncHandler::_FindItem //---------------------------------------------------------------------------- // // Description: // Report progress of synchronization. // // Parameters: // pCallback - Callback interface to update progress on. // pszItemID - ID of item to report progress on. Can be NULL. // nProgressTextID - String resource ID of progress text. // nStatus - Status being reported. // uCurrentStep - Current step in the progress report. // uMaxStep - Total number of steps. // pfCanceled - Returns whether user canceled sync for this item. // ... - Optional parameters to format into the string. // // Return Values: // Any values from ISyncMgrSyncCallback::ReportProgress(). // //---------------------------------------------------------------------------- void CMyDeviceSyncHandler::_ReportItemProgress( __in ISyncMgrSyncCallback *pCallback, __in LPCWSTR pszItemID, __in UINT nProgressTextID, __in SYNCMGR_PROGRESS_STATUS nStatus, __in ULONG uCurrentStep, __in ULONG uMaxStep, __out SYNCMGR_CANCEL_REQUEST *pnCancelRequest, ...) { HRESULT hr = S_OK; *pnCancelRequest = SYNCMGR_CR_NONE; if (pCallback != NULL) { // Default to clearing the progress if we've stopped unless we have // something important to convey to the user. Otherwise, only change // the item progress text if we have a new string. PWSTR pszProgressText = (nStatus == SYNCMGR_PS_CANCELED) ? L"" : NULL; if (nProgressTextID != 0) { va_list vaParamList; va_start(vaParamList, pnCancelRequest); hr = FormatStringVA(g_hmodThisDll, nProgressTextID, &pszProgressText, vaParamList); va_end(vaParamList); assert(SUCCEEDED(hr)); } if (SUCCEEDED(hr)) { hr = pCallback->ReportProgress(pszItemID, pszProgressText, nStatus, uCurrentStep, uMaxStep, pnCancelRequest); assert(SUCCEEDED(hr)); LocalFree(pszProgressText); } } // if: callback interface was specified } //*** CMyDeviceSyncHandler::_ReportItemProgress //---------------------------------------------------------------------------- // // Description: // Report progress of synchronization for the handler. // // Parameters: // pCallback - Callback interface to update progress on. // nProgressTextID - String resource ID of progress text. // pnCancelRequest - Returns whether user canceled sync for this item. // ... - Optional parameters to format into the string. // // Return Values: // Any values from ISyncMgrSyncCallback::SetHandlerProgressText(). // //---------------------------------------------------------------------------- void CMyDeviceSyncHandler::_SetHandlerProgressText( __in ISyncMgrSyncCallback *pCallback, __in UINT nProgressTextID, __out SYNCMGR_CANCEL_REQUEST *pnCancelRequest, ...) { HRESULT hr = S_OK; if (pCallback != NULL) { PWSTR pszProgressText = NULL; if (nProgressTextID != 0) { va_list vaParamList; va_start(vaParamList, pnCancelRequest); hr = FormatStringVA(g_hmodThisDll, nProgressTextID, &pszProgressText, vaParamList); va_end(vaParamList); assert(SUCCEEDED(hr)); } if (SUCCEEDED(hr)) { hr = pCallback->SetHandlerProgressText(pszProgressText, pnCancelRequest); assert(SUCCEEDED(hr)); LocalFree(pszProgressText); } } // if: callback interface was specified } //*** CMyDeviceSyncHandler::_SetHandlerProgressText //---------------------------------------------------------------------------- // // Description: // Report a synchronization event // // Parameters: // pCallback - Callback interface to update progress on. // pszItemID - ID of item to report progress on. Can be NULL. // nEventNameID - String resource ID of the Event Name. // nDescriptionTextID - String resource ID of description text. // nLevel - Level of the event being reported. // nFlags - Additional flags for the event. // pszLinkText - Link text for the event. Can be NULL // pszLinkReference - Action to shellexecute when the link is activated. Can be NULL. // pszContext - Additional data to associate with the event. Can be NULL. // ... - Optional parameters to format into the string. // // Return Values: // Any values from ISyncMgrSyncCallback::ReportEvent(). // //---------------------------------------------------------------------------- void CMyDeviceSyncHandler::_ReportEvent( __in ISyncMgrSyncCallback *pCallback, __in LPCWSTR pszItemID, __in UINT nEventNameID, __in UINT nDescriptionTextID, __in SYNCMGR_EVENT_LEVEL nLevel, __in SYNCMGR_EVENT_FLAGS nFlags, __in_opt LPCWSTR pszLinkText, __in_opt LPCWSTR pszLinkReference, __in_opt LPCWSTR pszContext, __out GUID *pguidEventID, ...) { // We must have a valid name and description for all events. assert((nEventNameID != 0) && (nDescriptionTextID != 0)); HRESULT hr = E_INVALIDARG; if (pCallback != NULL) { // Load the localized error name out of our resource. WCHAR wszName[MAX_SYNCMGR_NAME]; PWSTR pszDescription = NULL; if (LoadStringW(g_hmodThisDll, nEventNameID, wszName, ARRAYSIZE(wszName)) != 0) { // Load and format the description string with the optional parameters. va_list vaParamList; va_start(vaParamList, pguidEventID); hr = FormatStringVA(g_hmodThisDll, nDescriptionTextID, &pszDescription, vaParamList); va_end(vaParamList); assert(SUCCEEDED(hr)); } if (SUCCEEDED(hr)) { // Report the event to Sync Center. hr = pCallback->ReportEvent(pszItemID, nLevel, nFlags, wszName, pszDescription, pszLinkText, pszLinkReference, pszContext, pguidEventID); assert(SUCCEEDED(hr)); LocalFree(pszDescription); } } // if: callback interface was specified } //*** CMyDeviceSyncHandler::_ReportEvent ////////////////////////////////////////////////////////////////////////////// // class CEnumSyncMgrItems ////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------- // // Description: // Create an instance of the enumerator class. // // Parameters: // pDeviceHandler - Device handler to associate this enumerator with. // riid - Interface ID to get. // ppv - Interface pointer returned to caller. // // Return Values: // S_OK - Operation completed successfully. // E_OUTOFMEMORY - Error allocating the object. // Other HRESULTs - Error querying for requested interface. // //---------------------------------------------------------------------------- HRESULT CEnumSyncMgrItems_CreateInstance( __inout CMyDeviceSyncHandler *pDeviceHandler, __in REFIID riid, __deref_out void **ppv) { *ppv = NULL; // Create an enumerator for the handler GUIDs. CEnumSyncMgrItems *penum = new CEnumSyncMgrItems(pDeviceHandler); HRESULT hr = (penum != NULL) ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = penum->QueryInterface(riid, ppv); penum->Release(); } return hr; } //*** CEnumSyncMgrItems_CreateInstance //---------------------------------------------------------------------------- // IUnknown (CEnumSyncMgrItems) //---------------------------------------------------------------------------- STDMETHODIMP CEnumSyncMgrItems::QueryInterface(__in REFIID riid, __deref_out void **ppv) { static const QITAB qit[] = { QITABENT(CEnumSyncMgrItems, IEnumSyncMgrSyncItems), { 0 }, }; return QISearch(this, qit, riid, ppv); } //*** CEnumSyncMgrItems::QueryInterface //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CEnumSyncMgrItems::Release() { ULONG cRef = InterlockedDecrement(&_cRef); if (cRef == 0) { delete this; } return cRef; } //*** CEnumSyncMgrItems::Release //---------------------------------------------------------------------------- // ISyncMgrEnumItems (CEnumSyncMgrItems) //---------------------------------------------------------------------------- STDMETHODIMP CEnumSyncMgrItems::Next(__in ULONG celt, __deref_out_ecount(celt) ISyncMgrSyncItem *rgelt[], __out_opt ULONG *pceltFetched) { HRESULT hr = S_OK; ULONG cFetched = 0; while ((cFetched < celt) && (_iCur < _pDeviceHandler->_cItems)) { hr = _pDeviceHandler->_ppItems[_iCur]->QueryInterface(IID_ISyncMgrSyncItem, (void **) &rgelt[cFetched]); if (FAILED(hr)) { break; } cFetched++; _iCur++; } // while: more items // If we failed to QI one item, return the others we already queried. hr = (cFetched == celt) ? S_OK : S_FALSE; if (pceltFetched != NULL) { *pceltFetched = cFetched; } return hr; } //*** CEnumSyncMgrItems::Next