summaryrefslogtreecommitdiff
path: root/wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp')
-rw-r--r--wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp1160
1 files changed, 1160 insertions, 0 deletions
diff --git a/wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp b/wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp
new file mode 100644
index 00000000..9c3d22b2
--- /dev/null
+++ b/wpd/WpdWudfSampleDriver/WpdObjectManagement.cpp
@@ -0,0 +1,1160 @@
+#include "stdafx.h"
+#include "WpdObjectManagement.tmh"
+
+WpdObjectManagement::WpdObjectManagement()
+{
+
+}
+
+WpdObjectManagement::~WpdObjectManagement()
+{
+
+}
+
+HRESULT WpdObjectManagement::Initialize(_In_ FakeDevice *pFakeDevice)
+{
+ HRESULT hr = S_OK;
+
+ if(pFakeDevice == NULL)
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "Cannot have NULL parameter");
+ return hr;
+ }
+
+ m_pFakeDevice = pFakeDevice;
+
+ return hr;
+}
+
+HRESULT WpdObjectManagement::DispatchWpdMessage(
+ _In_ REFPROPERTYKEY Command,
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+
+ if (hr == S_OK)
+ {
+ if (Command.fmtid != WPD_CATEGORY_OBJECT_MANAGEMENT)
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "This object does not support this command category %ws",CComBSTR(Command.fmtid));
+ }
+ }
+
+ if (hr == S_OK)
+ {
+ if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_DELETE_OBJECTS.pid)
+ {
+ hr = OnDelete(pParams, pResults);
+ CHECK_HR(hr, "Failed to delete object");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT_WITH_PROPERTIES_ONLY.pid)
+ {
+ hr = OnCreateObjectWithPropertiesOnly(pParams, pResults);
+ CHECK_HR(hr, "Failed to create object");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT_WITH_PROPERTIES_AND_DATA.pid)
+ {
+ hr = OnCreateObjectWithPropertiesAndData(pParams, pResults);
+ CHECK_HR(hr, "Failed to create object");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_WRITE_OBJECT_DATA.pid)
+ {
+ hr = OnWriteObjectData(pParams, pResults);
+ CHECK_HR(hr, "Failed to write object data");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_COMMIT_OBJECT.pid)
+ {
+ hr = OnCommit(pParams, pResults);
+ CHECK_HR(hr, "Failed to commit object");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_REVERT_OBJECT.pid)
+ {
+ hr = OnRevert(pParams, pResults);
+ CHECK_HR(hr, "Failed to revert object");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_MOVE_OBJECTS.pid)
+ {
+ hr = OnMove(pParams, pResults);
+ CHECK_HR(hr, "Failed to Move objects");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_COPY_OBJECTS.pid)
+ {
+ hr = OnCopy(pParams, pResults);
+ CHECK_HR(hr, "Failed to Copy objects");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_MANAGEMENT_UPDATE_OBJECT_WITH_PROPERTIES_AND_DATA.pid)
+ {
+ hr = OnUpdateObjectWithPropertiesAndData(pParams, pResults);
+ CHECK_HR(hr, "Failed to update object");
+ }
+ else
+ {
+ hr = E_NOTIMPL;
+ CHECK_HR(hr, "This object does not support this command id %d", Command.pid);
+ }
+ }
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_DELETE_OBJECTS
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS: the ObjectIDs, indicating which objects to delete. These may
+ * contain children.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_OPTIONS: Flag parameter indicating delete options. Must be one
+ * of the following:
+ * - PORTABLE_DEVICE_DELETE_NO_RECURSION - Deletes the
+ * object only. This should fail if children exist.
+ * - PORTABLE_DEVICE_DELETE_WITH_RECURSION - Deletes this
+ * object and all children.
+ *
+ * The driver should:
+ * - If the flag is PORTABLE_DEVICE_DELETE_NO_RECURSION the driver should delete the
+ * specified object only. If the object still has children the driver should not delete
+ * the object and instead return HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION).
+ * - If the flag is PORTABLE_DEVICE_DELETE_WITH_RECURSION the driver should delete the
+ * specified object and all of its children.
+ * - Fill out the operation results in WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_RESULTS. It contains an IPortableDevicePropVariantCollection of
+ * VT_ERROR values indicating the success or failure of the operation for that element.
+ * Order is implicit, i.e. the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_RESULTS corresponds to the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS and so on.
+ * - The driver should return:
+ * - S_OK if all objects were deleted successfully.
+ * - S_FALSE if any object delete failed.
+ * - An error return indicates that the driver did not delete any objects, and
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_RESULTS is ignored.
+ */
+HRESULT WpdObjectManagement::OnDelete(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ DWORD dwOptions = PORTABLE_DEVICE_DELETE_NO_RECURSION;
+ BOOL bDeleteFailed = FALSE;
+ CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
+ CComPtr<IPortableDevicePropVariantCollection> pDeleteResults;
+ CComPtr<IPortableDeviceValues> pEventParams;
+ VARTYPE vt = VT_EMPTY;
+
+ if (hr == S_OK)
+ {
+ hr = pParams->GetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS, &pObjectIDs);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+ }
+
+ // Ensure that this is a collection of VT_LPWSTR
+ if (hr == S_OK)
+ {
+ hr = pObjectIDs->GetType(&vt);
+ CHECK_HR(hr, "Failed to get the VARTYP of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+ if (hr == S_OK)
+ {
+ if (vt != VT_LPWSTR)
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS is not a collection of VT_LPWSTR");
+ }
+ }
+ }
+
+ if (hr == S_OK)
+ {
+ hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_OPTIONS, &dwOptions);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_OPTIONS");
+ }
+
+ if (hr == S_OK)
+ {
+ hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IPortableDevicePropVariantCollection,
+ (VOID**) &pDeleteResults);
+ CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDevicePropVariantCollection");
+ }
+
+
+ if (hr == S_OK)
+ {
+ DWORD cObjects = 0;
+ // Loop through the object list and attempt to delete
+ hr = pObjectIDs->GetCount(&cObjects);
+ CHECK_HR(hr, "Failed to get number of objects to delete");
+
+ if (hr == S_OK)
+ {
+ for(DWORD dwIndex = 0; dwIndex < cObjects; dwIndex++)
+ {
+ HRESULT hrTemp = S_OK;
+ PROPVARIANT pv = {0};
+
+ PropVariantInit(&pv);
+ // Get the next Object to delete
+ hr = pObjectIDs->GetAt(dwIndex, &pv);
+ CHECK_HR(hr, "Failed to get next object id at index %d", dwIndex);
+ if (hr == S_OK)
+ {
+ pEventParams = NULL;
+ // Get the object properties used for sending the event. Ignore errors (these are expected in some cases
+ // e.g. app is sending object ID that doesn't exist), since this relates to the event, not the delete operation,
+ // and we return results for the delete (an error posting the event is non-fatal).
+ hrTemp = m_pFakeDevice->GetObjectPropertiesForEvent(pv.pwszVal, &pEventParams);
+ CHECK_HR(hrTemp, "Failed to get properties for event on object %ws", pv.pwszVal);
+
+ HRESULT hrDelete = S_OK;
+ PROPVARIANT pvResult = {0};
+
+ PropVariantInit(&pvResult);
+
+ hrDelete = m_pFakeDevice->DeleteObject(dwOptions, pv.pwszVal);
+ CHECK_HR(hrDelete, "Failed to delete object [%ws]", pv.pwszVal);
+
+ if(FAILED(hrDelete))
+ {
+ bDeleteFailed = TRUE;
+ }
+
+ // Save this result
+ pvResult.vt = VT_ERROR;
+ pvResult.scode = hrDelete;
+ hrTemp = pDeleteResults->Add(&pvResult);
+ PropVariantClear(&pvResult);
+ CHECK_HR(hrTemp, "Failed to add result for [%ws] to list of results", pv.pwszVal);
+
+ if ((hrDelete == S_OK) && (hrTemp == S_OK))
+ {
+ HRESULT hrEvent = S_OK;
+ // Set the event-specific parameters
+ hrEvent = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_REMOVED);
+ CHECK_HR(hrEvent, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
+
+ // Send the Event
+ if (hrEvent == S_OK)
+ {
+ PostWpdEvent(pParams, pEventParams);
+ }
+ }
+ PropVariantClear(&pv);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // Set the results
+ if (hr == S_OK)
+ {
+ hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_RESULTS, pDeleteResults);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_DELETE_RESULTS");
+ }
+
+ // If an object failed to delete, make sure we return S_FALSE
+ if ((hr == S_OK) && (bDeleteFailed))
+ {
+ hr = S_FALSE;
+ }
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_MOVE_OBJECTS
+ * command.
+ *
+ * This command will move the specified objects to the destination folder.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS : the ObjectIDs, indicating which objects to move. These may
+ * be folder objects.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID: Indicates the destination folder for the move operation.
+ *
+ * The driver should:
+ * - Attempt to Move the object specified in WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS to the folder specified in
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID.
+ * - Fill out the operation results in WPD_PROPERTY_OBJECT_MANAGEMENT_MOVE_RESULTS. It contains an IportableDevicePropVariantCollection of
+ * VT_ERROR values indicating the success or failure of the operation for that element.
+ * Order is implicit, i.e. the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_MOVE_RESULTS corresponds to the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS and so on.
+ * - The driver should return:
+ * - S_OK if all objects were moved successfully.
+ * - S_FALSE if any object move failed.
+ * - An error return indicates that the driver did not move any objects, and
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_MOVE_RESULTS is ignored.
+ */
+HRESULT WpdObjectManagement::OnMove(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszDestFolderObjectID = NULL;
+ CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
+ CComPtr<IPortableDevicePropVariantCollection> pMoveResults;
+ BOOL bMoveFailed = FALSE;
+ VARTYPE vt = VT_EMPTY;
+
+ if (hr == S_OK)
+ {
+ hr = pParams->GetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS, &pObjectIDs);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+ }
+
+ // Ensure that this is a collection of VT_LPWSTR
+ if (hr == S_OK)
+ {
+ hr = pObjectIDs->GetType(&vt);
+ CHECK_HR(hr, "Failed to get the VARTYP of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+ if (hr == S_OK)
+ {
+ if (vt != VT_LPWSTR)
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS is not a collection of VT_LPWSTR");
+ }
+ }
+ }
+
+ if (hr == S_OK)
+ {
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID, &pszDestFolderObjectID);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID");
+ }
+
+ if (hr == S_OK)
+ {
+ hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IPortableDevicePropVariantCollection,
+ (VOID**) &pMoveResults);
+ CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDevicePropVariantCollection");
+ }
+
+
+ if (hr == S_OK)
+ {
+ DWORD cObjects = 0;
+ // Loop through the object list and attempt to move
+ hr = pObjectIDs->GetCount(&cObjects);
+ CHECK_HR(hr, "Failed to get number of objects to move");
+
+ if (hr == S_OK)
+ {
+ for(DWORD dwIndex = 0; dwIndex < cObjects; dwIndex++)
+ {
+ HRESULT hrTemp = S_OK;
+ PROPVARIANT pv = {0};
+
+ PropVariantInit(&pv);
+ // Get the next Object to move
+ hrTemp = pObjectIDs->GetAt(dwIndex, &pv);
+ CHECK_HR(hr, "Failed to get next object id at index %d", dwIndex);
+ if (hrTemp == S_OK)
+ {
+ // Move this object
+ hrTemp = m_pFakeDevice->MoveObject(pv.pwszVal, pszDestFolderObjectID);
+ CHECK_HR(hrTemp, "Failed to move object [%ws] to folder [%ws]", pv.pwszVal, pszDestFolderObjectID);
+
+ if(FAILED(hrTemp))
+ {
+ bMoveFailed = TRUE;
+ }
+
+ PROPVARIANT pvResult = {0};
+
+ PropVariantInit(&pvResult);
+
+ // Save this result
+ pvResult.vt = VT_ERROR;
+ pvResult.scode = hrTemp;
+ hrTemp = pMoveResults->Add(&pvResult);
+ CHECK_HR(hrTemp, "Failed to add result for [%ws] to list of results", pv.pwszVal);
+
+ PropVariantClear(&pvResult);
+ }
+ PropVariantClear(&pv);
+ }
+ }
+ }
+
+ // Set the results
+ if (hr == S_OK)
+ {
+ hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_MOVE_RESULTS, pMoveResults);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_MOVE_RESULTS");
+ }
+
+ CoTaskMemFree(pszDestFolderObjectID);
+
+ // If an object failed to move, make sure we return S_FALSE
+ if ((hr == S_OK) && (bMoveFailed))
+ {
+ hr = S_FALSE;
+ }
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_COPY_OBJECTS
+ * command.
+ *
+ * This command will copy the specified objects to the destination folder.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS : the ObjectIDs, indicating which objects to copy. These may
+ * be folder objects.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID: Indicates the destination folder for the copy operation.
+ *
+ * The driver should:
+ * - Attempt to copy the object specified in WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS to the folder specified in
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID.
+ * - Fill out the operation results in WPD_PROPERTY_OBJECT_MANAGEMENT_COPY_RESULTS. It contains an IPortableDevicePropVariantCollection of
+ * VT_ERROR values indicating the success or failure of the operation for that element.
+ * Order is implicit, i.e. the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_COPY_RESULTS corresponds to the first element of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS and so on.
+ * - The driver should return:
+ * - S_OK if all objects were copied successfully.
+ * - S_FALSE if any object copy failed.
+ * - An error return indicates that the driver did not copy any objects, and
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_COPY_RESULTS is ignored.
+ */
+HRESULT WpdObjectManagement::OnCopy(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszDestFolderObjectID = NULL;
+ CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
+ CComPtr<IPortableDevicePropVariantCollection> pCopyResults;
+ BOOL bCopyFailed = FALSE;
+ VARTYPE vt = VT_EMPTY;
+
+ hr = pParams->GetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS, &pObjectIDs);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+
+ // Ensure that this is a collection of VT_LPWSTR
+ if (SUCCEEDED(hr))
+ {
+ hr = pObjectIDs->GetType(&vt);
+ CHECK_HR(hr, "Failed to get the VARTYP of WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS");
+ if (hr == S_OK)
+ {
+ if (vt != VT_LPWSTR)
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_IDS is not a collection of VT_LPWSTR");
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID, &pszDestFolderObjectID);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_DESTINATION_FOLDER_OBJECT_ID");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IPortableDevicePropVariantCollection,
+ (VOID**) &pCopyResults);
+ CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDevicePropVariantCollection");
+ }
+
+
+ if (SUCCEEDED(hr))
+ {
+ DWORD cObjects = 0;
+ // Loop through the object list and attempt to copy
+ hr = pObjectIDs->GetCount(&cObjects);
+ CHECK_HR(hr, "Failed to get number of objects to copy");
+
+ if (SUCCEEDED(hr))
+ {
+ for(DWORD dwIndex = 0; dwIndex < cObjects; dwIndex++)
+ {
+ CComPtr<IPortableDeviceValues> pEventParams;
+ LPWSTR pszNewObjectID = NULL;
+ HRESULT hrTemp = S_OK;
+ PROPVARIANT pv = {0};
+
+ PropVariantInit(&pv);
+ // Get the next Object to copy
+ hrTemp = pObjectIDs->GetAt(dwIndex, &pv);
+ CHECK_HR(hr, "Failed to get next object id at index %d", dwIndex);
+ if (SUCCEEDED(hrTemp))
+ {
+ // Copy this object
+ hrTemp = m_pFakeDevice->CopyObject(pv.pwszVal, pszDestFolderObjectID, &pszNewObjectID);
+ CHECK_HR(hrTemp, "Failed to copy object [%ws] to folder [%ws]", pv.pwszVal, pszDestFolderObjectID);
+
+ if(FAILED(hrTemp))
+ {
+ bCopyFailed = TRUE;
+ }
+
+ PROPVARIANT pvResult = {0};
+
+ PropVariantInit(&pvResult);
+
+ // Save this result
+ pvResult.vt = VT_ERROR;
+ pvResult.scode = hrTemp;
+ hrTemp = pCopyResults->Add(&pvResult);
+ CHECK_HR(hrTemp, "Failed to add result for [%ws] to list of results", pv.pwszVal);
+
+ PropVariantClear(&pvResult);
+
+ if (SUCCEEDED(hrTemp))
+ {
+ // Send the event
+ // Get the object properties used for sending the event
+ hrTemp = m_pFakeDevice->GetObjectPropertiesForEvent(pszNewObjectID, &pEventParams);
+ CHECK_HR(hrTemp, "Failed to get properties for event on object %ws", pszNewObjectID);
+ if (SUCCEEDED(hrTemp))
+ {
+ // Set the event-specific parameters
+ hrTemp = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_ADDED);
+ CHECK_HR(hrTemp, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
+
+ // Send the Event
+ if (SUCCEEDED(hrTemp))
+ {
+ PostWpdEvent(pParams, pEventParams);
+ }
+ }
+ }
+ }
+
+ if (pszNewObjectID != NULL)
+ {
+ CoTaskMemFree(pszNewObjectID);
+ pszNewObjectID = NULL;
+ }
+
+ PropVariantClear(&pv);
+ }
+ }
+ }
+
+ // Set the results
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_MANAGEMENT_COPY_RESULTS, pCopyResults);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_COPY_RESULTS");
+ }
+
+ CoTaskMemFree(pszDestFolderObjectID);
+
+ // If an object failed to copy, make sure we return S_FALSE
+ if (SUCCEEDED(hr) && bCopyFailed)
+ {
+ hr = S_FALSE;
+ }
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT_WITH_PROPERTIES_ONLY
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES: Contains an IPortableDeviceValues, describing
+ * properties of the new object. At the very least, it will contain:
+ * - WPD_OBJECT_NAME: The object name.
+ * - WPD_PARENT_ID: Identifies the parent object. The object should be inserted as a child of
+ * this parent (e.g. this would be the target directory in a file system based device).
+ *
+ * The driver should:
+ * - Create the object, and return its ID in WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID.
+ */
+HRESULT WpdObjectManagement::OnCreateObjectWithPropertiesOnly(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ CComPtr<IPortableDeviceValues> pValues;
+ CComPtr<IPortableDeviceValues> pEventParams;
+
+ // Get the Object Properties
+ hr = pParams->GetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES, &pValues);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES");
+
+ // Save the object to the device here.
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pFakeDevice->SaveNewObject(pValues, &pszContext);
+ CHECK_HR(hr, "Failed to save new (properties only) object to device");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID, pszContext);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Send the event
+ HRESULT hrTemp = S_OK;
+ // Get the object properties used for sending the event
+ hrTemp = m_pFakeDevice->GetObjectPropertiesForEvent(pszContext, &pEventParams);
+ CHECK_HR(hrTemp, "Failed to get properties for event on object %ws", pszContext);
+ if (SUCCEEDED(hrTemp))
+ {
+ // Set the event-specific parameters
+ hrTemp = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_ADDED);
+ CHECK_HR(hrTemp, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
+
+ // Send the Event
+ if (SUCCEEDED(hrTemp))
+ {
+ PostWpdEvent(pParams, pEventParams);
+ }
+ }
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszContext);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT_WITH_PROPERTIES_AND_DATA
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES: Contains an IPortableDeviceValues, describing
+ * properties of the new object. At the very least, it will contain:
+ * - WPD_OBJECT_NAME: The object name.
+ * - WPD_PARENT_ID: Identifies the parent object. The object should be inserted as a child of
+ * this parent (e.g. this would be the target directory in a file system based device).
+ * - WPD_OBJECT_SIZE: The total size of the object data stream.
+ * - WPD_OBJECT_FORMAT: The format the object data stream.
+ *
+ * The driver should:
+ * - Create a context for this operation and return it in WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT.
+ * - Return the optimal transfer buffer size in WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE.
+ */
+HRESULT WpdObjectManagement::OnCreateObjectWithPropertiesAndData(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ LPWSTR pszObjectName = NULL;
+ IUnknown* pContextMap = NULL;
+ CComPtr<IPortableDeviceValues> pValues;
+
+ // Get the Object Properties
+ hr = pParams->GetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES, &pValues);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES");
+
+ // Get Object Name from pValues
+ if (SUCCEEDED(hr))
+ {
+ hr = pValues->GetStringValue(WPD_OBJECT_NAME, &pszObjectName);
+ CHECK_HR(hr, "Failed to get WPD_OBJECT_NAME");
+ }
+
+ // Get the context map
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, &pContextMap);
+ CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Object data will be provided by the caller. So Create a context identifying this
+ // creation request, since the actual data will come later, and the object can only be saved
+ // when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_COMMIT_OBJECT call.
+ hr = CreateObjectManagementContext((ContextMap*) pContextMap, pszObjectName, pValues, false /*bUpdateRequest*/, &pszContext);
+ CHECK_HR(hr, "Failed to create object management context");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT, pszContext);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT");
+ }
+
+ // Set the optimal buffer size
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE, OPTIMAL_BUFFER_SIZE);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE value");
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszContext);
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszObjectName);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_REVERT_OBJECT
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT: identifies the object creation request (driver returned this in
+ * WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT).
+ *
+ * The driver should:
+ * - Free any resources associated with this context/operation. The object should not be saved to the
+ * device. If a placeholder was created on the device for this operation, it should be removed.
+ */
+HRESULT WpdObjectManagement::OnRevert(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ ContextMap* pContextMap = NULL;
+
+ // There are no return parameters for this operation.
+ UNREFERENCED_PARAMETER(pResults);
+
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT, &pszContext);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap);
+ CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = DestroyObjectManagementContext(pContextMap, pszContext);
+ CHECK_HR(hr, "Failed to revert object identified by context [%ws]", pszContext);
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszContext);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_COMMIT_OBJECT
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT: identifies the object creation request (driver returned this in
+ * WPD_COMMAND_OBJECT_MANAGEMENT_CREATE_OBJECT).
+ *
+ * The driver should:
+ * - Commit the object to the device.
+ * - Return the new/updated ObjectID in WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID.
+ */
+HRESULT WpdObjectManagement::OnCommit(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ ObjectManagementContext* pContext = NULL;
+ ContextMap* pContextMap = NULL;
+ CComPtr<IPortableDeviceValues> pEventParams;
+
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT, &pszContext);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+
+ // Get the object management context for this request
+ if (SUCCEEDED(hr))
+ {
+ hr = GetClientContext(pParams, pszContext, (IUnknown**)&pContext);
+ CHECK_HR(hr, "Failed to get Object Management Context");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap);
+ CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (pContext->UpdateRequest)
+ {
+ // Update the object
+ hr = UpdateObject(pContext, pParams, pResults);
+ }
+ else
+ {
+ // Save the new object
+ hr = CommitNewObject(pContext, pszContext, pParams, pResults);
+ }
+ }
+
+ // We're done with the context
+ SAFE_RELEASE(pContext);
+
+ // Destroy the context associated with this request, since it is no longer needed
+ if (SUCCEEDED(hr))
+ {
+ hr = DestroyObjectManagementContext(pContextMap, pszContext);
+ CHECK_HR(hr, "Failed to destroy object identified by context [%ws]", pszContext);
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszContext);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_WRITE_OBJECT_DATA
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT: identifies the object creation request previsouly started with
+ * WPD_PROPERTY_OBJECT_MANAGEMENT_CREATE_OBJECT.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_TO_WRITE: specifies the next number of bytes to write.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_DATA: specifies byte array where the data should be copied from.
+ *
+ * The driver should:
+ * - Write the next WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_TO_WRITE to the resource.
+ * - Return the number of bytes actually written in WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_WRITTEN.
+ * It is normally considered an error if this value does not match WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_TO_WRITE.
+ */
+HRESULT WpdObjectManagement::OnWriteObjectData(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ DWORD dwNumBytesToWrite = 0;
+ DWORD dwNumBytesWritten = 0;
+ BYTE* pBuffer = NULL;
+ DWORD cbBuffer = 0;
+ ObjectManagementContext* pContext = NULL;
+
+ // Get the Context string
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT, &pszContext);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT");
+
+ // Get the number of bytes to write
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_TO_WRITE, &dwNumBytesToWrite);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_TO_WRITE");
+ }
+
+ // Get the source buffer
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetBufferValue(WPD_PROPERTY_OBJECT_MANAGEMENT_DATA, &pBuffer, &cbBuffer);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_DATA");
+ }
+
+ // Get the resource context for this object creation request
+ if (SUCCEEDED(hr))
+ {
+ hr = GetClientContext(pParams, pszContext, (IUnknown**)&pContext);
+ CHECK_HR(hr, "Failed to get Object Management Context");
+ }
+
+ // Write the next band of data for this new object request
+ if (SUCCEEDED(hr))
+ {
+ // TBD: Write bytes to object. This sample driver ignores the data content.
+ dwNumBytesWritten = dwNumBytesToWrite;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_WRITTEN, dwNumBytesWritten);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_NUM_BYTES_WRITTEN");
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszContext);
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pBuffer);
+
+ SAFE_RELEASE(pContext);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_UPDATE_OBJECT_WITH_PROPERTIES_AND_DATA
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID: Identifies the object to update.
+ * - WPD_PROPERTY_OBJECT_MANAGEMENT_UPDATE_PROPERTIES: Contains an IPortableDeviceValues, describing
+ * the updated properties of the object. At the very least, it will contain:
+ * - WPD_OBJECT_SIZE: The total size of the object data stream.
+ *
+ * The driver should:
+ * - Create a context for this operation and return it in WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT.
+ * - Return the optimal transfer buffer size in WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE.
+ */
+HRESULT WpdObjectManagement::OnUpdateObjectWithPropertiesAndData(
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszContext = NULL;
+ LPWSTR pszObjectId = NULL;
+ IUnknown* pContextMap = NULL;
+ BOOL bUpdatable = NULL;
+ CComPtr<IPortableDeviceValues> pValues;
+
+ // Get the Object Identifier.
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID, &pszObjectId);
+ CHECK_HR(hr, "Failed to get WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+
+ // Get the Object Properties
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetIPortableDeviceValuesValue(WPD_PROPERTY_OBJECT_MANAGEMENT_UPDATE_PROPERTIES, &pValues);
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_MANAGEMENT_CREATION_PROPERTIES");
+ }
+
+ // Get the context map
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, &pContextMap);
+ CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP");
+ }
+
+ // Validate whether this object supports the default resource
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pFakeDevice->SupportsResource(pszObjectId, WPD_RESOURCE_DEFAULT, &bUpdatable);
+ CHECK_HR(hr, "Failed to check whether object supports WPD_RESOURCE_DEFAULT");
+
+ if (SUCCEEDED(hr) && !bUpdatable)
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Object does not support WPD_RESOURCE_DEFAULT");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Object data will be provided by the caller. So Create a context identifying this
+ // creation request, since the actual data will come later, and the object can only be saved
+ // when we receive a WPD_COMMAND_OBJECT_MANAGEMENT_COMMIT_OBJECT call.
+ hr = CreateObjectManagementContext((ContextMap*) pContextMap, pszObjectId, pValues, true /*bUpdateRequest*/, &pszContext);
+ CHECK_HR(hr, "Failed to create object management context");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT, pszContext);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_CONTEXT");
+ }
+
+ // Set the optimal buffer size
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE, OPTIMAL_BUFFER_SIZE);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_OPTIMAL_TRANSFER_BUFFER_SIZE value");
+ }
+
+ CoTaskMemFree(pszContext);
+ CoTaskMemFree(pszObjectId);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+HRESULT WpdObjectManagement::CreateObjectManagementContext(
+ _In_ ContextMap* pContextMap,
+ _In_ LPCWSTR pszObjectName,
+ _In_ IPortableDeviceValues* pObjectProperties,
+ _In_ BOOL bUpdateRequest,
+ _Outptr_result_nullonfailure_ LPWSTR* ppszObjectManagementContext)
+{
+ HRESULT hr = S_OK;
+ GUID guidContext = GUID_NULL;
+ ObjectManagementContext* pContext = NULL;
+ CComBSTR bstrContext;
+
+ if((pContextMap == NULL) ||
+ (pObjectProperties == NULL) ||
+ (pszObjectName == NULL) ||
+ (ppszObjectManagementContext == NULL))
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "Cannot have NULL parameter");
+ return hr;
+ }
+
+ *ppszObjectManagementContext = NULL;
+
+ hr = CoCreateGuid(&guidContext);
+ if (SUCCEEDED(hr))
+ {
+ bstrContext = guidContext;
+ if(bstrContext.Length() == 0)
+ {
+ hr = E_OUTOFMEMORY;
+ CHECK_HR(hr, "Failed to create BSTR from GUID");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ pContext = new ObjectManagementContext();
+ if(pContext != NULL)
+ {
+ CAtlStringW strKey = bstrContext;
+ pContext->Name = pszObjectName;
+ pContext->ObjectProperties = pObjectProperties;
+ pContext->UpdateRequest = bUpdateRequest;
+
+ hr = pContextMap->Add(strKey, pContext);
+ CHECK_HR(hr, "Failed to add object creation context to client context map");
+
+ pContext->Release();
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ CHECK_HR(hr, "Failed to allocate object creation context");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *ppszObjectManagementContext = AtlAllocTaskWideString(bstrContext);
+ }
+
+ return hr;
+}
+
+HRESULT WpdObjectManagement::DestroyObjectManagementContext(
+ _In_ ContextMap* pContextMap,
+ _In_ LPCWSTR pszObjectManagementContext)
+{
+ HRESULT hr = S_OK;
+
+ CAtlStringW strKey = pszObjectManagementContext;
+ pContextMap->Remove(strKey);
+
+ return hr;
+}
+
+HRESULT WpdObjectManagement::CommitNewObject(
+ _In_ ObjectManagementContext* pContext,
+ _In_ LPCWSTR pszContext,
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ LPWSTR pszObjectID = NULL;
+
+ // Save the new object
+ HRESULT hr = m_pFakeDevice->SaveNewObject(pContext->ObjectProperties, &pszObjectID);
+ CHECK_HR(hr, "Failed to save new object [%ws] to device", pContext->Name);
+
+ // Let the caller know the new object's ID.
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID, pszObjectID);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Send the event
+ HRESULT hrTemp = S_OK;
+ CComPtr<IPortableDeviceValues> pEventParams;
+
+ // Get the object properties used for sending the event
+ hrTemp = m_pFakeDevice->GetObjectPropertiesForEvent(pszObjectID, &pEventParams);
+ CHECK_HR(hrTemp, "Failed to get properties for event on object %ws", pszObjectID);
+
+ if (SUCCEEDED(hrTemp))
+ {
+ // Set the event-specific parameters
+ hrTemp = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_ADDED);
+ CHECK_HR(hrTemp, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
+
+ hrTemp = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_CREATION_COOKIE, pszContext);
+ CHECK_HR(hrTemp, "Failed to add WPD_EVENT_PARAMETER_OBJECT_CREATION_COOKIE");
+
+ // Send the Event
+ if (SUCCEEDED(hr))
+ {
+ PostWpdEvent(pParams, pEventParams);
+ }
+ }
+ }
+
+ CoTaskMemFree(pszObjectID);
+
+ return hr;
+}
+
+HRESULT WpdObjectManagement::UpdateObject(
+ _In_ ObjectManagementContext* pContext,
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ // For convenience, the ObjectID was stored in Name for object updates
+ LPCWSTR pszObjectId = pContext->Name;
+
+ // Update the object
+ HRESULT hr = m_pFakeDevice->UpdateContentObject(pszObjectId, pContext->ObjectProperties);
+ CHECK_HR(hr, "Failed to update object [%ws] to device", pszObjectId);
+
+ // Set the object ID.
+ if (hr == S_OK)
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID, pszObjectId);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_MANAGEMENT_OBJECT_ID");
+ }
+
+ if (hr == S_OK)
+ {
+ // Send the event
+ HRESULT hrTemp = S_OK;
+ CComPtr<IPortableDeviceValues> pEventParams;
+
+ // Get the object properties used for sending the event
+ hrTemp = m_pFakeDevice->GetObjectPropertiesForEvent(pContext->Name, &pEventParams);
+ CHECK_HR(hrTemp, "Failed to get properties for event on object %ws", pszObjectId);
+
+ if (hrTemp == S_OK)
+ {
+ // Set the event-specific parameters
+ hrTemp = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, WPD_EVENT_OBJECT_UPDATED);
+ CHECK_HR(hrTemp, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
+
+ // Send the Event
+ if (hrTemp == S_OK)
+ {
+ PostWpdEvent(pParams, pEventParams);
+ }
+ }
+ }
+
+ return hr;
+}