2025-11-28 00:35:46 +09:00

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