519 lines
18 KiB
C++
519 lines
18 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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:
|
|
// MyDeviceHandlerCollection.cpp
|
|
//
|
|
// Abstract:
|
|
// Implementation of the Sync Center handler collection for a device.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Pch.h"
|
|
#include "MyDeviceHandlerCollection.h"
|
|
#include "MyDeviceSyncHandler.h"
|
|
#include "Guids.h" // Declare the GUIDs used by this component.
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// class CMyDeviceHandlerCollection
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Create an instance of the handler collection class.
|
|
//
|
|
// Parameters:
|
|
// punkOuter - Outer IUnknown for aggregation.
|
|
// ppunk - IUnknown 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 CMyDeviceHandlerCollection_CreateInstance(
|
|
__in_opt IUnknown *punkOuter,
|
|
__deref_out IUnknown **ppunk
|
|
)
|
|
{
|
|
*ppunk = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(punkOuter);
|
|
|
|
CMyDeviceHandlerCollection *phc = new CMyDeviceHandlerCollection();
|
|
HRESULT hr = (phc != NULL) ? S_OK : E_OUTOFMEMORY;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = phc->QueryInterface(IID_PPV_ARGS(ppunk));
|
|
phc->Release();
|
|
}
|
|
|
|
return hr;
|
|
|
|
} //*** CMyDeviceHandlerCollection_CreateInstance
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Default constructor.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMyDeviceHandlerCollection::CMyDeviceHandlerCollection()
|
|
:
|
|
_cRef(1),
|
|
_cDevices(0),
|
|
_pDevices(NULL)
|
|
{
|
|
DllAddRef();
|
|
|
|
} //*** default constructor CMyDeviceHandlerCollection::CMyDeviceHandlerCollection
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Destructor.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMyDeviceHandlerCollection::~CMyDeviceHandlerCollection()
|
|
{
|
|
if (_pDevices != NULL)
|
|
{
|
|
delete [] _pDevices;
|
|
}
|
|
DllRelease();
|
|
|
|
} //*** destructor CMyDeviceHandlerCollection::~CMyDeviceHandlerCollection
|
|
|
|
//----------------------------------------------------------------------------
|
|
// IUnknown (CMyDeviceHandlerCollection)
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CMyDeviceHandlerCollection::QueryInterface(__in REFIID riid, __deref_out void **ppv)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(CMyDeviceHandlerCollection, ISyncMgrHandlerCollection),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppv);
|
|
|
|
} //*** CMyDeviceHandlerCollection::QueryInterface
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CMyDeviceHandlerCollection::Release()
|
|
{
|
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
|
|
} //*** CMyDeviceHandlerCollection::Release
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ISyncMgrHandlerCollection (CMyDeviceHandlerCollection)
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Called by Sync Center to get an enumerator of sync handlers.
|
|
//
|
|
// Implements: ISyncMgrHandlerCollection
|
|
//
|
|
// Parameters:
|
|
// ppenum - IEnumString interface pointer returned by handler.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// Other HRESULTs.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CMyDeviceHandlerCollection::GetHandlerEnumerator(__deref_out IEnumString **ppenum)
|
|
{
|
|
return CEnumDeviceHandlerIDs_CreateInstance(this, IID_PPV_ARGS(ppenum));
|
|
|
|
} //*** CMyDeviceHandlerCollection::GetHandlerEnumerator
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Called by Sync Center to bind to (load) a particular handler.
|
|
// Note that there are times when this method will be called before the
|
|
// EnumHandlers() method is called.
|
|
//
|
|
// Implements: ISyncMgrHandlerCollection
|
|
//
|
|
// Parameters:
|
|
// pszHandlerID - ID representing the handler to bind to.
|
|
// riid - ID for the interface pointer to return.
|
|
// ppv - Interface pointer.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// CLASS_E_CLASSNOTAVAILABLE - Unrecognized handler ID.
|
|
// Other HRESULTs - Error loading handlers or creating the handler instance.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CMyDeviceHandlerCollection::BindToHandler(
|
|
__in LPCWSTR pszHandlerID,
|
|
__in REFIID riid,
|
|
__deref_out void **ppv)
|
|
{
|
|
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
HRESULT hrLoadHandlersIDs = S_OK;
|
|
|
|
*ppv = NULL;
|
|
|
|
// The BindToHandler() method can be called even if EnumHandlers() hasn't
|
|
// been called. Therefore it is possible that the handler ID array hasn't
|
|
// been loaded yet. If it hasn't, load it here so that we can bind to the
|
|
// specified handler.
|
|
if (_pDevices == NULL)
|
|
{
|
|
hrLoadHandlersIDs = _LoadHandlerIDs();
|
|
}
|
|
|
|
// Find the device (represented by pszHandlerID) in the table collected by
|
|
// _LoadHandlerIDs().
|
|
if (SUCCEEDED(hrLoadHandlersIDs))
|
|
{
|
|
for (DWORD iDevice = 0; iDevice < _cDevices; iDevice++)
|
|
{
|
|
if (CompareSyncMgrID(pszHandlerID, _pDevices[iDevice].szHandlerID) == 0)
|
|
{
|
|
hr = CMyDeviceSyncHandler_CreateInstance(NULL, riid, &_pDevices[iDevice], ppv);
|
|
break;
|
|
}
|
|
} // for: each device in the table
|
|
} // if: handlers loaded successfully
|
|
|
|
return hr;
|
|
|
|
} //*** CMyDeviceHandlerCollection::BindToHandler
|
|
|
|
//----------------------------------------------------------------------------
|
|
// CMyDeviceHandlerCollection Private Methods
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Load handler IDs (i.e. devices) to sync from the registry.
|
|
// This works by enumerating partners in the registry for a sample device
|
|
// and loading the partner ID, Sync Center ID, and device name so that
|
|
// it can be used when handlers are enumerated.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// E_OUTOFMEMORY - Error allocating memory for the device info array.
|
|
// Other HRESULTs - Operation failed.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CMyDeviceHandlerCollection::_LoadHandlerIDs()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hkeyPartners = NULL;
|
|
DWORD cPartners = 0;
|
|
|
|
// Open the root of the sample device key to find partnerships.
|
|
DWORD nStatus = RegOpenKeyExW(
|
|
HKEY_CURRENT_USER,
|
|
L"Software\\Microsoft\\Sample Device\\Partnerships",
|
|
0,
|
|
KEY_READ,
|
|
&hkeyPartners);
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
|
|
// Get the number of subkeys to determine the number of partnerships to sync.
|
|
// Then allocate the item array.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
nStatus = RegQueryInfoKey(hkeyPartners, NULL, NULL, NULL, &cPartners,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
if (nStatus == ERROR_SUCCESS)
|
|
{
|
|
delete [] _pDevices;
|
|
_pDevices = new SYNCDEVICEINFO[cPartners];
|
|
if (_pDevices == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_cDevices = 0;
|
|
}
|
|
else
|
|
{
|
|
_cDevices = cPartners;
|
|
}
|
|
} // if: regkey queried successfully
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
} // if: regkey opened successfully
|
|
|
|
// Enumerate each subkey and initialize its corresponding device entry in the array.
|
|
if (SUCCEEDED(hr) && (cPartners > 0))
|
|
{
|
|
HKEY hkeyPartnership = NULL;
|
|
WCHAR szRegString[MAX_PATH];
|
|
for (DWORD iPartner = 0; iPartner < cPartners; iPartner++)
|
|
{
|
|
// If we fail trying to retrieve information for a single handler,
|
|
// we should continue to retrieve the rest of our handlers that
|
|
// belong to this collection.
|
|
HRESULT hrLocal = S_OK;
|
|
// Get the next partner key name.
|
|
nStatus = RegEnumKeyW(hkeyPartners, iPartner, szRegString, ARRAYSIZE(szRegString));
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hrLocal = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
if (SUCCEEDED(hrLocal))
|
|
{
|
|
// Save the partner ID.
|
|
_pDevices[iPartner].nPartnerID = wcstoul(szRegString, NULL, 10);
|
|
|
|
// Open the partner key.
|
|
nStatus = RegOpenKeyExW(hkeyPartners, szRegString, 0, (KEY_READ | KEY_WRITE), &hkeyPartnership);
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hrLocal = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
|
|
if (SUCCEEDED(hrLocal))
|
|
{
|
|
// Read the sync Center handler ID.
|
|
DWORD cbData = sizeof(_pDevices[iPartner].szHandlerID);
|
|
nStatus = RegQueryValueExW(hkeyPartnership, L"SyncCenterGUID", 0, NULL, (PBYTE) _pDevices[iPartner].szHandlerID, &cbData);
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hrLocal = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
if (FAILED(hrLocal))
|
|
{
|
|
// TODO For Developers: Remove demo code
|
|
// Generate a GUID and write it back to the registry.
|
|
// This causes every device partnership to show up as a sync partnership.
|
|
GUID guidHandlerID;
|
|
hrLocal = CoCreateGuid(&guidHandlerID);
|
|
if (SUCCEEDED(hrLocal))
|
|
{
|
|
StringFromGUID2(guidHandlerID, _pDevices[iPartner].szHandlerID, ARRAYSIZE(_pDevices[iPartner].szHandlerID));
|
|
nStatus = RegSetValueExW(
|
|
hkeyPartnership,
|
|
L"SyncCenterGUID",
|
|
0,
|
|
REG_SZ,
|
|
(const BYTE *) _pDevices[iPartner].szHandlerID,
|
|
(lstrlenW(_pDevices[iPartner].szHandlerID) + 1) * sizeof(_pDevices[iPartner].szHandlerID[0]));
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hrLocal = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
} // if: successfully created GUID
|
|
if (FAILED(hrLocal))
|
|
{
|
|
ZeroMemory(_pDevices[iPartner].szHandlerID, sizeof(_pDevices[iPartner].szHandlerID));
|
|
hrLocal = S_OK;
|
|
}
|
|
} // if: failed to read or convert handler ID
|
|
|
|
// Read the partnership name.
|
|
cbData = sizeof(_pDevices[iPartner].szName);
|
|
nStatus = RegQueryValueExW(hkeyPartnership, L"DisplayName", 0, NULL, (PBYTE) _pDevices[iPartner].szName, &cbData);
|
|
if (nStatus != ERROR_SUCCESS)
|
|
{
|
|
hrLocal = HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
|
|
RegCloseKey(hkeyPartnership);
|
|
hkeyPartnership = NULL;
|
|
} // if: successfully open the partner key
|
|
} // if: successfully retrieve next partner key name
|
|
|
|
} // for: each partner subkey
|
|
} // if: regkey queried successfully
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (_pDevices != NULL)
|
|
{
|
|
delete [] _pDevices;
|
|
}
|
|
_pDevices = NULL;
|
|
}
|
|
|
|
if (hkeyPartners)
|
|
{
|
|
RegCloseKey(hkeyPartners);
|
|
}
|
|
return hr;
|
|
|
|
} //*** CMyDeviceHandlerCollection::_LoadHandlerIDs
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// class CEnumDeviceHandlerIDs
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Create an instance of the enumerator class.
|
|
//
|
|
// Parameters:
|
|
// pHandlerCollection - Handler collection 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 CEnumDeviceHandlerIDs_CreateInstance(
|
|
__inout CMyDeviceHandlerCollection *pHandlerCollection,
|
|
__in REFIID riid,
|
|
__deref_out void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
// Create an enumerator for the handler IDs.
|
|
CEnumDeviceHandlerIDs *penum = new CEnumDeviceHandlerIDs(pHandlerCollection);
|
|
HRESULT hr = (penum != NULL) ? S_OK : E_OUTOFMEMORY;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = penum->QueryInterface(riid, ppv);
|
|
penum->Release();
|
|
}
|
|
|
|
return hr;
|
|
|
|
} //*** CEnumDeviceHandlerIDs_CreateInstance
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IUnknown (CEnumDeviceHandlerIDs)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CEnumDeviceHandlerIDs::QueryInterface(__in REFIID riid, __deref_out void **ppv)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(CEnumDeviceHandlerIDs, IEnumString),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppv);
|
|
|
|
} //*** CEnumDeviceHandlerIDs::QueryInterface
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CEnumDeviceHandlerIDs::Release()
|
|
{
|
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
|
|
} //*** CEnumDeviceHandlerIDs::Release
|
|
|
|
//----------------------------------------------------------------------------
|
|
// IEnumString (CEnumDeviceHandlerIDs)
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Description:
|
|
// Get the next entry from the enumeration.
|
|
//
|
|
// Implements: IEnumString
|
|
//
|
|
// Parameters:
|
|
// celt
|
|
// Number of items requested.
|
|
//
|
|
// rgelt
|
|
// Array of items returned. Each item must be deallocated using
|
|
// CoTaskMemFree().
|
|
//
|
|
// pceltFetched
|
|
// Number of items returned.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Number of items requested was returned.
|
|
// S_FALSE - Fewer items than requested was returned.
|
|
// Other HRESULTs
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumDeviceHandlerIDs::Next(
|
|
__in ULONG celt,
|
|
__deref_out_ecount(celt) LPWSTR *rgelt,
|
|
__out_opt ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cFetched = 0;
|
|
|
|
// Load handler IDs if they haven't been loaded already.
|
|
if (_pHandlerCollection->_pDevices == NULL)
|
|
{
|
|
hr = _pHandlerCollection->_LoadHandlerIDs();
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SYNCDEVICEINFO *pDevices = _pHandlerCollection->_pDevices;
|
|
while ((cFetched < celt) && (_iCur < _pHandlerCollection->_cDevices) && SUCCEEDED(hr))
|
|
{
|
|
// Skip devices without a handler ID.
|
|
// These devices haven't been set up for sync yet.
|
|
if (pDevices[_iCur].szHandlerID[0] != L'\0')
|
|
{
|
|
hr = SHStrDupW(pDevices[_iCur].szHandlerID, &rgelt[cFetched]);
|
|
cFetched++;
|
|
}
|
|
_iCur++;
|
|
} // while: more handlers
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Deallocate memory if we encountered an error while building
|
|
// the return values..
|
|
while (cFetched > 0)
|
|
{
|
|
--cFetched;
|
|
CoTaskMemFree(rgelt[cFetched]);
|
|
rgelt[cFetched] = NULL;
|
|
}
|
|
} // if: error allocating memory for the handler ID
|
|
else
|
|
{
|
|
hr = (cFetched == celt) ? S_OK : S_FALSE;
|
|
}
|
|
} // if: handler IDs loaded successfully
|
|
|
|
if (pceltFetched != NULL)
|
|
{
|
|
*pceltFetched = cFetched;
|
|
}
|
|
|
|
return hr;
|
|
|
|
} //*** CEnumDeviceHandlerIDs::Next
|
|
|