From 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 17 Mar 2015 19:50:07 -0700 Subject: Initial publish --- wpd/WpdServiceSampleDriver/FakeDevice.cpp | 1122 +++++++++++++++++++++++++++++ 1 file changed, 1122 insertions(+) create mode 100644 wpd/WpdServiceSampleDriver/FakeDevice.cpp (limited to 'wpd/WpdServiceSampleDriver/FakeDevice.cpp') diff --git a/wpd/WpdServiceSampleDriver/FakeDevice.cpp b/wpd/WpdServiceSampleDriver/FakeDevice.cpp new file mode 100644 index 00000000..d5f8d4d4 --- /dev/null +++ b/wpd/WpdServiceSampleDriver/FakeDevice.cpp @@ -0,0 +1,1122 @@ +#include "stdafx.h" + +#include "FakeDevice.tmh" + +const PROPERTYKEY* g_SupportedCommands[] = +{ + // WPD_CATEGORY_OBJECT_ENUMERATION + &WPD_COMMAND_OBJECT_ENUMERATION_START_FIND, + &WPD_COMMAND_OBJECT_ENUMERATION_FIND_NEXT, + &WPD_COMMAND_OBJECT_ENUMERATION_END_FIND, + + // WPD_CATEGORY_OBJECT_PROPERTIES + &WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED, + &WPD_COMMAND_OBJECT_PROPERTIES_GET, + &WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL, + &WPD_COMMAND_OBJECT_PROPERTIES_SET, + &WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES, + &WPD_COMMAND_OBJECT_PROPERTIES_DELETE, + + // WPD_CATEGORY_OBJECT_RESOURCES + &WPD_COMMAND_OBJECT_RESOURCES_GET_SUPPORTED, + &WPD_COMMAND_OBJECT_RESOURCES_OPEN, + &WPD_COMMAND_OBJECT_RESOURCES_READ, + &WPD_COMMAND_OBJECT_RESOURCES_CLOSE, + &WPD_COMMAND_OBJECT_RESOURCES_GET_ATTRIBUTES, + + // WPD_CATEGORY_CAPABILITIES + &WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_COMMANDS, + &WPD_COMMAND_CAPABILITIES_GET_COMMAND_OPTIONS, + &WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FUNCTIONAL_CATEGORIES, + &WPD_COMMAND_CAPABILITIES_GET_FUNCTIONAL_OBJECTS, + &WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_CONTENT_TYPES, + &WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FORMATS, + &WPD_COMMAND_CAPABILITIES_GET_SUPPORTED_FORMAT_PROPERTIES, + &WPD_COMMAND_CAPABILITIES_GET_FIXED_PROPERTY_ATTRIBUTES, + + // WPD_CATEGORY_OBJECT_MANAGEMENT + &WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT_WITH_PROPERTIES_ONLY, + &WPD_COMMAND_OBJECT_MANAGEMENT_DELETE_OBJECTS, + + // WPD_CATEGORY_OBJECT_PROPERTIES_BULK + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_LIST_START, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_LIST_NEXT, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_LIST_END, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_FORMAT_START, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_FORMAT_NEXT, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_GET_VALUES_BY_OBJECT_FORMAT_END, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_SET_VALUES_BY_OBJECT_LIST_START, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_SET_VALUES_BY_OBJECT_LIST_NEXT, + &WPD_COMMAND_OBJECT_PROPERTIES_BULK_SET_VALUES_BY_OBJECT_LIST_END, + + // WPD_CATEGORY_COMMON + &WPD_COMMAND_COMMON_GET_OBJECT_IDS_FROM_PERSISTENT_UNIQUE_IDS, +}; + + +const GUID* g_SupportedFunctionalCategories[] = +{ + &WPD_FUNCTIONAL_CATEGORY_DEVICE, + &WPD_FUNCTIONAL_CATEGORY_STORAGE, + &SERVICE_Contacts, +}; + +const PROPERTYKEY* g_SupportedCommonProperties[] = +{ + &WPD_OBJECT_ID, + &WPD_OBJECT_PERSISTENT_UNIQUE_ID, + &WPD_OBJECT_PARENT_ID, + &WPD_OBJECT_NAME, + &WPD_OBJECT_FORMAT, + &WPD_OBJECT_CONTENT_TYPE, + &WPD_OBJECT_CAN_DELETE, + &WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, +}; + + +HRESULT FakeDevice::InitializeContent() +{ + HRESULT hr = m_DeviceContent.InitializeContent(&m_dwLastObjectID); + CHECK_HR(hr, "Failed to initialize device content"); + return hr; +} + +FakeContactsService* FakeDevice::GetContactsService() +{ + return &m_ContactsService; +} + +ACCESS_SCOPE FakeDevice::GetAccessScope( + _In_ IPortableDeviceValues* pParams) +{ + ACCESS_SCOPE Scope = FULL_DEVICE_ACCESS; + LPWSTR pszFileName = NULL; + + // For simplicity, our request filename is the same as the the service object ID + if (pParams && (pParams->GetStringValue(PRIVATE_SAMPLE_DRIVER_REQUEST_FILENAME, &pszFileName) == S_OK)) + { + CAtlStringW strRequestFilename = pszFileName; + // For simplicity, our request filename is the same as the the service object ID + // Case-insensitive comparison is required + if (strRequestFilename.CompareNoCase(m_ContactsService.GetRequestFilename()) == 0) + { + Scope = CONTACTS_SERVICE_ACCESS; + } + } + + CoTaskMemFree(pszFileName); + return Scope; +} + +HRESULT FakeDevice::GetSupportedCommands( + _In_ IPortableDeviceKeyCollection* pCommands) +{ + HRESULT hr = S_OK; + + if(pCommands == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedCommands); dwIndex++) + { + PROPERTYKEY key = *(g_SupportedCommands[dwIndex]); + hr = pCommands->Add(key); + CHECK_HR(hr, "Failed to add supported command at index %d", dwIndex); + if (FAILED(hr)) + { + break; + } + } + return hr; +} + +HRESULT FakeDevice::GetCommandOptions( + _In_ REFPROPERTYKEY Command, + _In_ IPortableDeviceValues* pOptions) +{ + HRESULT hr = S_OK; + + if(pOptions == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + // Check for command options + if (IsEqualPropertyKey(WPD_COMMAND_OBJECT_MANAGEMENT_DELETE_OBJECTS, Command)) + { + // This driver does not support recursive deletion + hr = pOptions->SetBoolValue(WPD_OPTION_OBJECT_MANAGEMENT_RECURSIVE_DELETE_SUPPORTED, TRUE); + CHECK_HR(hr, "Failed to set WPD_OPTION_OBJECT_MANAGEMENT_RECURSIVE_DELETE_SUPPORTED"); + } + if (IsEqualPropertyKey(WPD_COMMAND_OBJECT_RESOURCES_READ, Command)) + { + // For better read performance, tell the API not to provide the input buffer parameter + // when issuing a WPD_COMMAND_OBJECT_RESOURCES_READ command. + hr = pOptions->SetBoolValue(WPD_OPTION_OBJECT_RESOURCES_NO_INPUT_BUFFER_ON_READ, TRUE); + CHECK_HR(hr, "Failed to set WPD_OPTION_OBJECT_RESOURCES_NO_INPUT_BUFFER_ON_READ"); + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedFunctionalCategories( + _In_ IPortableDevicePropVariantCollection* pFunctionalCategories) +{ + HRESULT hr = S_OK; + + if(pFunctionalCategories == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + // Device-wide command + for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedFunctionalCategories); dwIndex++) + { + PROPVARIANT pv = {0}; + PropVariantInit(&pv); + // Don't call PropVariantClear, since we did not allocate the memory for these GUIDs + + pv.vt = VT_CLSID; + pv.puuid = (CLSID*)g_SupportedFunctionalCategories[dwIndex]; + + hr = pFunctionalCategories->Add(&pv); + CHECK_HR(hr, "Failed to add supported functional category at index %d", dwIndex); + if (FAILED(hr)) + { + break; + } + } + + return hr; +} + +HRESULT FakeDevice::GetFunctionalObjects( + _In_ REFGUID guidFunctionalCategory, + _In_ IPortableDevicePropVariantCollection* pFunctionalObjects) +{ + HRESULT hr = S_OK; + PROPVARIANT pv = {0}; + + if(pFunctionalObjects == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + PropVariantInit(&pv); + // Don't call PropVariantClear, since we did not allocate the memory for these object identifiers + + // Add WPD_DEVICE_OBJECT_ID to the functional object identifiers collection + if ((guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_DEVICE) || + (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_ALL)) + { + pv.vt = VT_LPWSTR; + pv.pwszVal = WPD_DEVICE_OBJECT_ID; + hr = pFunctionalObjects->Add(&pv); + CHECK_HR(hr, "Failed to add device object ID"); + } + + // Add CONTACTS_SERVICE_OBJECT_ID to the functional object identifiers collection + if (hr == S_OK) + { + if ((guidFunctionalCategory == SERVICE_Contacts) || + (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_ALL)) + { + pv.vt = VT_LPWSTR; + pv.pwszVal = CONTACTS_SERVICE_OBJECT_ID; + hr = pFunctionalObjects->Add(&pv); + CHECK_HR(hr, "Failed to add contacts service object ID"); + } + } + + // Add STORAGE_OBJECT_ID to the functional object identifiers collection + // if request is not scoped by the contacts service + if ((guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_STORAGE) || + (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_ALL)) + { + pv.vt = VT_LPWSTR; + pv.pwszVal = STORAGE_OBJECT_ID; + hr = pFunctionalObjects->Add(&pv); + CHECK_HR(hr, "Failed to add storage object ID"); + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedContentTypes( + _In_ REFGUID guidFunctionalCategory, + _In_ IPortableDevicePropVariantCollection* pContentTypes) +{ + HRESULT hr = S_OK; + + if(pContentTypes == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + PROPVARIANT pv = {0}; + PropVariantInit(&pv); + // Don't call PropVariantClear, since we did not allocate the memory for these GUIDs + + // Add supported content types for known functional categories + if (guidFunctionalCategory == WPD_FUNCTIONAL_CATEGORY_STORAGE) + { + // Add WPD_CONTENT_TYPE_DOCUMENT to the supported content type collection + pv.vt = VT_CLSID; + pv.puuid = (CLSID*)&WPD_CONTENT_TYPE_DOCUMENT; + hr = pContentTypes->Add(&pv); + CHECK_HR(hr, "Failed to add WPD_CONTENT_TYPE_DOCUMENT"); + + if (hr == S_OK) + { + // Add WPD_CONTENT_TYPE_FOLDER to the supported content type collection + pv.vt = VT_CLSID; + pv.puuid = (CLSID*)&WPD_CONTENT_TYPE_FOLDER; + hr = pContentTypes->Add(&pv); + CHECK_HR(hr, "Failed to add WPD_CONTENT_TYPE_FOLDER"); + } + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedFormats( + _In_ REFGUID guidContentType, + _In_ IPortableDevicePropVariantCollection* pFormats) +{ + HRESULT hr = S_OK; + + if(pFormats == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + PROPVARIANT pv = {0}; + PropVariantInit(&pv); + pv.vt = VT_CLSID; + + // Don't call PropVariantClear, since we did not allocate the memory for these GUIDs + + if ((guidContentType == WPD_CONTENT_TYPE_CONTACT) || + (guidContentType == WPD_CONTENT_TYPE_ALL)) + { + pv.puuid = (CLSID*)&FORMAT_AbstractContact; + hr = pFormats->Add(&pv); + CHECK_HR(hr, "Failed to add FORMAT_AbstractContact"); + + pv.puuid = (CLSID*)&FORMAT_VCard2Contact; + hr = pFormats->Add(&pv); + CHECK_HR(hr, "Failed to add FORMAT_VCard2Contact"); + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedFormatProperties( + _In_ REFGUID guidObjectFormat, + _In_ IPortableDeviceKeyCollection* pKeys) +{ + HRESULT hr = S_OK; + + if(pKeys == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + if (guidObjectFormat == WPD_OBJECT_FORMAT_ALL) + { + for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(g_SupportedCommonProperties); dwIndex++) + { + PROPERTYKEY key = *g_SupportedCommonProperties[dwIndex]; + hr = pKeys->Add(key); + CHECK_HR(hr, "Failed to add common property"); + } + } + + return hr; +} + +HRESULT FakeDevice::GetFixedPropertyAttributes( + _In_ REFGUID guidObjectFormat, + _In_ REFPROPERTYKEY Key, + _In_ IPortableDeviceValues* pAttributes) +{ + UNREFERENCED_PARAMETER(guidObjectFormat); + UNREFERENCED_PARAMETER(Key); + + HRESULT hr = S_OK; + + if(pAttributes == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + // + // Since ALL of our properties have the same attributes, we are ignoring the + // passed in guidObjectFormat and Key parameters. These parameters allow you to + // customize fixed property attributes for properties for specific formats. + // + + if (hr == S_OK) + { + hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_DELETE, FALSE); + CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_DELETE"); + } + + if (hr == S_OK) + { + hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_READ, TRUE); + CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_READ"); + } + + if (hr == S_OK) + { + hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_CAN_WRITE, FALSE); + CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_CAN_WRITE"); + } + + if (hr == S_OK) + { + hr = pAttributes->SetBoolValue(WPD_PROPERTY_ATTRIBUTE_FAST_PROPERTY, TRUE); + CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_FAST_PROPERTY"); + } + + if (hr == S_OK) + { + hr = pAttributes->SetUnsignedIntegerValue(WPD_PROPERTY_ATTRIBUTE_FORM, WPD_PROPERTY_ATTRIBUTE_FORM_UNSPECIFIED); + CHECK_HR(hr, "Failed to set WPD_PROPERTY_ATTRIBUTE_FORM"); + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedEvents( + _In_ IPortableDevicePropVariantCollection* pEvents) +{ + UNREFERENCED_PARAMETER(pEvents); + + HRESULT hr = S_OK; + + if(pEvents == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + return hr; +} + +HRESULT FakeDevice::GetEventOptions( + _In_ IPortableDeviceValues* pOptions) +{ + UNREFERENCED_PARAMETER(pOptions); + + HRESULT hr = S_OK; + + if(pOptions == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + return hr; +} + +void FakeDevice::InitializeEnumerationContext( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszParentID, + _In_ WpdObjectEnumeratorContext* pEnumContext) +{ + if (pEnumContext == NULL) + { + return; + } + + pEnumContext->m_Scope = Scope; + pEnumContext->m_strParentObjectID = wszParentID; + + if (pEnumContext->m_strParentObjectID.GetLength() == 0) + { + // Clients passing an 'empty' string for the parent are asking for the + // 'DEVICE' object. We should return 1 child in this case. + pEnumContext->m_TotalChildren = 1; + } + else + { + FakeContent* pContent = NULL; + HRESULT hr = GetContent(Scope, wszParentID, &pContent); + if (hr == S_OK) + { + hr = pContent->InitializeEnumerationContext(Scope, pEnumContext); + CHECK_HR(hr, "Failed to initialize enuemration context for '%ws'", wszParentID); + } + + if (hr != S_OK) + { + // Invalid, or non-existing objects contain no children. + pEnumContext->m_TotalChildren = 0; + } + } +} + +HRESULT FakeDevice::FindNext( + const DWORD dwNumObjectsRequested, + _In_ WpdObjectEnumeratorContext* pEnumContext, + _In_ IPortableDevicePropVariantCollection* pObjectIDCollection, + _Out_opt_ DWORD* pdwNumObjectsEnumerated) +{ + HRESULT hr = S_OK; + DWORD NumObjectsEnumerated = 0; + + if ((pEnumContext == NULL) || + (pObjectIDCollection == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + if (pdwNumObjectsEnumerated) + { + *pdwNumObjectsEnumerated = 0; + } + + // If the enumeration context reports that their are more objects to return, then continue, if not, + // return an empty results set. + if (pEnumContext->HasMoreChildrenToEnumerate()) + { + if (pEnumContext->m_strParentObjectID.CompareNoCase(L"") == 0) + { + // We are being asked for the device + hr = AddStringValueToPropVariantCollection(pObjectIDCollection, m_DeviceContent.ObjectID); + CHECK_HR(hr, "Failed to add 'DEVICE' object ID to enumeration collection"); + + // Update the the number of children we are returning for this enumeration call + NumObjectsEnumerated++; + } + else + { + FakeContent* pContent = NULL; + HRESULT hrGet = GetContent(pEnumContext->m_Scope, pEnumContext->m_strParentObjectID, &pContent); + CHECK_HR(hrGet, "Failed to get content '%ws'", pEnumContext->m_strParentObjectID); + + if (hrGet == S_OK) + { + DWORD dwStartIndex = pEnumContext->m_ChildrenEnumerated; + for (DWORD i=0; iFindNext(pEnumContext->m_Scope, dwStartIndex, &pChild)) + { + hr = AddStringValueToPropVariantCollection(pObjectIDCollection, pChild->ObjectID); + CHECK_HR(hr, "Failed to add object [%ws]", pChild->ObjectID); + + if (hr == S_OK) + { + // Update the the number of children we are returning for this enumeration call + dwStartIndex++; + NumObjectsEnumerated++; + } + } + else + { + // no more children + break; + } + } + } + } + } + + if (hr == S_OK && pdwNumObjectsEnumerated) + { + *pdwNumObjectsEnumerated = NumObjectsEnumerated; + } + + return hr; +} + +HRESULT FakeDevice::GetObjectIDsByFormat( + ACCESS_SCOPE Scope, + _In_ REFGUID guidObjectFormat, + _In_ LPCWSTR wszParentObjectID, + const DWORD dwDepth, + _In_ IPortableDevicePropVariantCollection* pObjectIDs) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if(pObjectIDs == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, ("Cannot have NULL parameter")); + return hr; + } + + hr = GetContent(Scope, wszParentObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszParentObjectID); + + if (hr == S_OK) + { + hr = pContent->GetObjectIDsByFormat(Scope, guidObjectFormat, dwDepth, pObjectIDs); + CHECK_HR(hr, "Failed to get object IDs by format"); + } + + return hr; +} + +HRESULT FakeDevice::GetObjectIDsFromPersistentUniqueIDs( + ACCESS_SCOPE Scope, + _In_ IPortableDevicePropVariantCollection* pPersistentIDs, + _In_ IPortableDevicePropVariantCollection* pObjectIDs) +{ + HRESULT hr = S_OK; + DWORD dwCount = 0; + + if ((pPersistentIDs == NULL) || + (pObjectIDs == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, ("Cannot have NULL parameter")); + return hr; + } + + // Iterate through the persistent ID list and add the equivalent object ID for each element. + hr = pPersistentIDs->GetCount(&dwCount); + CHECK_HR(hr, "Failed to get count from persistent ID collection"); + + if (hr == S_OK) + { + PROPVARIANT pvPersistentID = {0}; + + for(DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++) + { + PropVariantInit(&pvPersistentID); + + hr = pPersistentIDs->GetAt(dwIndex, &pvPersistentID); + CHECK_HR(hr, "Failed to get persistent ID at index %d", dwIndex); + + if (hr == S_OK) + { + hr = m_DeviceContent.GetObjectIDByPersistentID(Scope, pvPersistentID.pwszVal, pObjectIDs); + CHECK_HR(hr, "Failed to get object ID from persistent unique ID '%ws'", pvPersistentID.pwszVal); + } + + if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + PROPVARIANT pvEmptyObjectID = {0}; + pvEmptyObjectID.vt = VT_LPWSTR; + pvEmptyObjectID.pwszVal = L""; + + // Insert empty string when object cannot be found + hr = pObjectIDs->Add(&pvEmptyObjectID); + CHECK_HR(hr, "Failed to set empty string for persistent unique ID '%ws' when object cannot be found", pvPersistentID.pwszVal); + } + + PropVariantClear(&pvPersistentID); + + if(FAILED(hr)) + { + break; + } + } + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedProperties( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceKeyCollection* pKeys) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pKeys == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->GetSupportedProperties(pKeys); + CHECK_HR(hr, "Failed to get supported properties for '%ws'", wszObjectID); + } + + return hr; +} + +HRESULT FakeDevice::GetAllPropertyValues( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceValues* pValues) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pValues == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->GetAllValues(pValues); + CHECK_HR(hr, "Failed to get all property values for '%ws'", wszObjectID); + } + return hr; +} + + +HRESULT FakeDevice::GetPropertyValues( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceKeyCollection* pKeys, + _In_ IPortableDeviceValues* pValues) +{ + HRESULT hrReturn = S_OK; + HRESULT hr = S_OK; + DWORD cKeys = 0; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pKeys == NULL) || + (pValues == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pKeys->GetCount(&cKeys); + CHECK_HR(hr, "Failed to number of PROPERTYKEYs in collection"); + } + + if (hr == S_OK) + { + for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++) + { + PROPERTYKEY Key = WPD_PROPERTY_NULL; + hr = pKeys->GetAt(dwIndex, &Key); + CHECK_HR(hr, "Failed to get PROPERTYKEY at index %d in collection", dwIndex); + + if (hr == S_OK) + { + hr = pContent->GetValue(Key, pValues); + CHECK_HR(hr, "Failed to get property at index %d", dwIndex); + if (FAILED(hr)) + { + // Mark the property as failed by setting the error value + // hrReturn is marked as S_FALSE indicating that at least one property has failed. + hr = pValues->SetErrorValue(Key, hr); + hrReturn = S_FALSE; + } + } + } + } + + if (FAILED(hr)) + { + // A general error has occurred (rather than failure to set one or more properties) + hrReturn = hr; + } + + return hrReturn; +} + +HRESULT FakeDevice::SetPropertyValues( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceValues* pValues, + _In_ IPortableDeviceValues* pResults, + _In_ IPortableDeviceValues* pEventParams, + _Out_ bool* pbObjectChanged) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pValues == NULL) || + (pResults == NULL) || + (pEventParams == NULL) || + (pbObjectChanged == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + *pbObjectChanged = false; + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->WriteValues(pValues, pResults, pbObjectChanged); + CHECK_HR(hr, "Failed to write value for '%ws'", wszObjectID); + + if (SUCCEEDED(hr) && (*pbObjectChanged)) // hr can be S_OK or S_FALSE (if one or more property writes failed) + { + HRESULT hrEvent = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_UPDATED); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID"); + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, pContent->PersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID, pContent->ParentPersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + // Adding this event parameter will allow WPD to scope this event to the container functional object + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, pContent->ContainerFunctionalObjectID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID"); + } + } + + } + + return hr; +} + +HRESULT FakeDevice::GetPropertyAtributes( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ REFPROPERTYKEY Key, + _In_ IPortableDeviceValues* pAttributes) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pAttributes == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->GetPropertyAttributes(Key, pAttributes); + CHECK_HR(hr, "Failed to get property attributes for '%ws'", wszObjectID); + } + + return hr; +} + +HRESULT FakeDevice::CreatePropertiesOnlyObject( + ACCESS_SCOPE Scope, + _In_ IPortableDeviceValues* pObjectProperties, + _In_ IPortableDeviceValues* pEventParams, + _Outptr_result_nullonfailure_ LPWSTR* ppszNewObjectID) +{ + HRESULT hr; + LPWSTR pszParentID = NULL; + FakeContent* pParent = NULL; + FakeContent* pNewObject = NULL; + + if ((pObjectProperties == NULL) || + (pEventParams == NULL) || + (ppszNewObjectID == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + *ppszNewObjectID = NULL; + + // Get WPD_OBJECT_PARENT_ID + hr = pObjectProperties->GetStringValue(WPD_OBJECT_PARENT_ID, &pszParentID); + CHECK_HR(hr, "Failed to get WPD_OBJECT_PARENT_ID"); + + // Check if it is within our current access scope + if (SUCCEEDED(hr)) + { + hr = GetContent(Scope, pszParentID, &pParent); + CHECK_HR(hr, "Failed to get content '%ws'", pszParentID); + } + + if (SUCCEEDED(hr)) + { + hr = pParent->CreatePropertiesOnlyObject(pObjectProperties, &m_dwLastObjectID, &pNewObject); + CHECK_HR(hr, "Failed to create properties only object with parent '%ws'", pszParentID); + } + + if (SUCCEEDED(hr)) + { + *ppszNewObjectID = AtlAllocTaskWideString(pNewObject->ObjectID); + if (*ppszNewObjectID == NULL) + { + hr = E_OUTOFMEMORY; + CHECK_HR(hr, "Failed to allocate memory for created object ID"); + } + + HRESULT hrEvent = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_ADDED); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID"); + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, pNewObject->PersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID, pNewObject->ParentPersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + // Adding this event parameter will allow WPD to scope this event to the container functional object + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, pNewObject->ContainerFunctionalObjectID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID"); + } + } + + CoTaskMemFree(pszParentID); + return hr; +} + +HRESULT FakeDevice::DeleteObject( + ACCESS_SCOPE Scope, + const DWORD dwDeleteOptions, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceValues* pEventParams) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pEventParams == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->MarkForDelete(dwDeleteOptions); + CHECK_HR(hr, "Failed to mark '%ws' for delete with option %d", wszObjectID, dwDeleteOptions); + } + + if (hr == S_OK) + { + HRESULT hrEvent = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_REMOVED); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID"); + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, pContent->PersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + hrEvent = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID, pContent->ParentPersistentUniqueID); + CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID"); + } + + if (hrEvent == S_OK) + { + // Adding this event parameter will allow WPD to scope this event to the container functional object + hrEvent = pEventParams->SetStringValue(WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, pContent->ContainerFunctionalObjectID); + CHECK_HR(hrEvent, "Failed to add WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID"); + } + + hr = m_DeviceContent.RemoveObjectsMarkedForDeletion(Scope); + CHECK_HR(hr, "Failed to remove all objects marked for deletion"); + } + + return hr; +} + +HRESULT FakeDevice::GetSupportedResources( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ IPortableDeviceKeyCollection* pResources) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pResources == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->GetSupportedResources(pResources); + CHECK_HR(hr, "Failed to get the supported resources for '%ws'", wszObjectID); + } + + return hr; +} + +HRESULT FakeDevice::GetResourceAttributes( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ REFPROPERTYKEY Resource, + _In_ IPortableDeviceValues* pAttributes) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pAttributes == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + hr = pContent->GetResourceAttributes(Resource, pAttributes); + CHECK_HR(hr, "Failed to get the supported resources for '%ws'", wszObjectID); + } + + return hr; +} + +HRESULT FakeDevice::OpenResource( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _In_ REFPROPERTYKEY Resource, + const DWORD dwMode, + _In_ WpdObjectResourceContext* pResourceContext) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((wszObjectID == NULL) || + (pResourceContext == NULL)) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + return hr; + } + + hr = GetContent(Scope, wszObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + if (hr == S_OK) + { + pResourceContext->m_Scope = Scope; + hr = pContent->OpenResource(Resource, dwMode, pResourceContext); + CHECK_HR(hr, "Failed to open resource for '%ws'", wszObjectID); + } + + return hr; +} + +HRESULT FakeDevice::ReadResourceData( + _In_ WpdObjectResourceContext* pResourceContext, + _Out_writes_to_(dwNumBytesToRead, *pdwNumBytesRead) BYTE* pBuffer, + const DWORD dwNumBytesToRead, + _Out_ DWORD* pdwNumBytesRead) +{ + HRESULT hr = S_OK; + FakeContent* pContent = NULL; + + if ((pResourceContext == NULL) || + (pBuffer == NULL) || + (pdwNumBytesRead == NULL)) + { + hr = E_INVALIDARG; + return hr; + } + + *pdwNumBytesRead = 0; + + hr = GetContent(pResourceContext->m_Scope, pResourceContext->m_strObjectID, &pContent); + CHECK_HR(hr, "Failed to get content '%ws'", pResourceContext->m_strObjectID); + + if (hr == S_OK) + { + hr = pContent->ReadResourceData(pResourceContext, pBuffer, dwNumBytesToRead, pdwNumBytesRead); + CHECK_HR(hr, "Failed to read resource data for '%ws'", pResourceContext->m_strObjectID); + } + + return hr; +} + +HRESULT FakeDevice::GetContent( + ACCESS_SCOPE Scope, + _In_ LPCWSTR wszObjectID, + _Outptr_result_nullonfailure_ FakeContent** ppContent) +{ + HRESULT hr = S_OK; + + if (ppContent == NULL) + { + hr = E_POINTER; + CHECK_HR(hr, "Cannot have NULL parameter"); + } + + *ppContent = NULL; + + hr = m_DeviceContent.GetContent(Scope, wszObjectID, ppContent); + CHECK_HR(hr, "Failed to get content '%ws'", wszObjectID); + + return hr; +} -- cgit v1.3.1