summaryrefslogtreecommitdiff
path: root/wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp')
-rw-r--r--wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp b/wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp
new file mode 100644
index 00000000..d67e6c5d
--- /dev/null
+++ b/wpd/WpdWudfSampleDriver/WpdObjectEnum.cpp
@@ -0,0 +1,386 @@
+#include "stdafx.h"
+#include "WpdObjectEnum.tmh"
+
+WpdObjectEnumerator::WpdObjectEnumerator()
+{
+
+}
+
+WpdObjectEnumerator::~WpdObjectEnumerator()
+{
+
+}
+
+HRESULT WpdObjectEnumerator::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 WpdObjectEnumerator::DispatchWpdMessage(_In_ REFPROPERTYKEY Command,
+ _In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+
+ if (hr == S_OK)
+ {
+ if (Command.fmtid != WPD_CATEGORY_OBJECT_ENUMERATION)
+ {
+ 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_ENUMERATION_START_FIND.pid)
+ {
+ hr = OnStartFind(pParams, pResults);
+ CHECK_HR(hr, "Failed to begin enumeration");
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_ENUMERATION_FIND_NEXT.pid)
+ {
+ hr = OnFindNext(pParams, pResults);
+ if(FAILED(hr))
+ {
+ CHECK_HR(hr, "Failed to find next object");
+ }
+ }
+ else if (Command.pid == WPD_COMMAND_OBJECT_ENUMERATION_END_FIND.pid)
+ {
+ hr = OnEndFind(pParams, pResults);
+ CHECK_HR(hr, "Failed to end enumeration");
+ }
+ 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_ENUMERATION_START_FIND
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID: the parent where we should start
+ * the enumeration.
+ * - WPD_PROPERTY_OBJECT_ENUMERATION_FILTER: the filter to use when doing
+ * enumeration. Since this parameter is optional, it may not exist.
+ * This driver currently ignores the filter parameter.
+ *
+ * The driver should:
+ * - Create a new context for this enumeration.
+ * - Return an identifier for the context in WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT.
+ *
+ */
+HRESULT WpdObjectEnumerator::OnStartFind(_In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszParentID = NULL;
+ LPWSTR pszEnumContext = NULL;
+ IUnknown* pContextMap = NULL;
+
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID, &pszParentID);
+ if (FAILED(hr))
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID");
+ }
+
+ 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))
+ {
+ hr = CreateEnumContext((ContextMap*)pContextMap, pszParentID, &pszEnumContext);
+ CHECK_HR(hr, "Failed to create enumeration context");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, pszEnumContext);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT");
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszParentID);
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszEnumContext);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+HRESULT WpdObjectEnumerator::OnFindNext(_In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszEnumContext = NULL;
+ DWORD dwNumObjects = 0;
+ ContextMap* pContextMap = NULL;
+ CComPtr<IPortableDevicePropVariantCollection> pObjectIDCollection;
+
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, &pszEnumContext);
+ if (FAILED(hr))
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_ENUMERATION_NUM_OBJECTS_REQUESTED, &dwNumObjects);
+ if (FAILED(hr))
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_NUM_OBJECTS_REQUESTED");
+ }
+ }
+
+ // Get the context map which the driver stored in pParams for convenience
+ 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))
+ {
+ // Find the next objects in the enumeration
+ hr = GetObjectIDs(pContextMap, dwNumObjects, pszEnumContext, &pObjectIDCollection);
+ CHECK_HR(hr, "Failed to get the objectIDs");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pResults->SetIPortableDevicePropVariantCollectionValue(WPD_PROPERTY_OBJECT_ENUMERATION_OBJECT_IDS, pObjectIDCollection);
+ CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_ENUMERATION_OBJECT_IDS");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if(pObjectIDCollection != NULL)
+ {
+ ULONG ulCount = 0;
+
+ pObjectIDCollection->GetCount(&ulCount);
+ if(ulCount < dwNumObjects)
+ {
+ hr = S_FALSE;
+ }
+ }
+ }
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszEnumContext);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+/**
+ * This method is called when we receive a WPD_COMMAND_OBJECT_ENUMERATION_END_FIND
+ * command.
+ *
+ * The parameters sent to us are:
+ * - WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT: the context the driver returned to
+ * the client in OnStartFind.
+ *
+ * The driver should:
+ * - Destroy any resources associated with this context.
+ */
+HRESULT WpdObjectEnumerator::OnEndFind(_In_ IPortableDeviceValues* pParams,
+ _In_ IPortableDeviceValues* pResults)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszEnumContext = NULL;
+ IUnknown* pContextMap = NULL;
+
+ UNREFERENCED_PARAMETER(pResults);
+
+ hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, &pszEnumContext);
+ if (FAILED(hr))
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT");
+ }
+
+ 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))
+ {
+ hr = DestroyEnumContext((ContextMap*) pContextMap, pszEnumContext);
+ CHECK_HR(hr, "Failed to destroy enumeration context");
+ }
+
+ // Free the memory. CoTaskMemFree ignores NULLs so no need to check.
+ CoTaskMemFree(pszEnumContext);
+
+ SAFE_RELEASE(pContextMap);
+
+ return hr;
+}
+
+HRESULT WpdObjectEnumerator::CreateEnumContext(
+ _In_ ContextMap* pContextMap,
+ _In_ LPCWSTR pszParentID,
+ _Outptr_result_nullonfailure_ LPWSTR* ppszEnumContext)
+{
+ HRESULT hr = S_OK;
+ GUID guidContext = GUID_NULL;
+ CComBSTR bstrContext;
+ EnumContext* pContext = NULL;
+
+ if((pContextMap == NULL) ||
+ (pszParentID == NULL) ||
+ (ppszEnumContext == NULL))
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "Cannot have NULL parameter");
+ return hr;
+ }
+
+ *ppszEnumContext = 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 EnumContext();
+ if(pContext != NULL)
+ {
+ CAtlStringW strKey = bstrContext;
+ pContext->ParentID = pszParentID;
+
+ hr = pContextMap->Add(strKey, pContext);
+ CHECK_HR(hr, "Failed to add enumeration context to client context map");
+
+ pContext->Release();
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ CHECK_HR(hr, "Failed to allocate enumeration context");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *ppszEnumContext = AtlAllocTaskWideString(bstrContext);
+ }
+
+ return hr;
+}
+
+HRESULT WpdObjectEnumerator::DestroyEnumContext(
+ _In_ ContextMap* pContextMap,
+ _In_ LPCWSTR pszEnumContext)
+{
+ HRESULT hr = S_OK;
+
+ CAtlStringW strKey = pszEnumContext;
+ pContextMap->Remove(strKey);
+
+ return hr;
+}
+
+#pragma warning(suppress: 6388) // PREFast bug means here there is a false positive for the call to CComPtr<>::QueryInterface().
+HRESULT WpdObjectEnumerator::GetObjectIDs(
+ _In_ ContextMap* pContextMap,
+ _In_ const DWORD dwNumObjects,
+ _In_ LPCWSTR pszEnumContext,
+ _COM_Outptr_ IPortableDevicePropVariantCollection** ppCollection)
+{
+ HRESULT hr = S_OK;
+ EnumContext* pContext = NULL;
+ CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
+
+ if(ppCollection == NULL)
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "Cannot have NULL collection parameter");
+ return hr;
+ }
+
+ *ppCollection = NULL;
+
+ hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&pObjectIDs));
+ CHECK_HR(hr, "Failed to CoCreate CLSID_PortableDevicePropVariantCollection");
+
+ if (SUCCEEDED(hr))
+ {
+ CAtlStringW strKey = pszEnumContext;
+ pContext = (EnumContext*) pContextMap->GetContext(strKey);
+ if(pContext != NULL)
+ {
+ for(DWORD dwCount = 0; dwCount < dwNumObjects; dwCount++)
+ {
+ CAtlStringW strObjectID;
+
+ DWORD dwNextStartIndex = 0;
+ if(m_pFakeDevice->FindNext(pContext->SearchIndex,
+ pContext->ParentID,
+ strObjectID,
+ &dwNextStartIndex))
+ {
+ PropVariantWrapper pvObjectID(strObjectID);
+
+ hr = pObjectIDs->Add(&pvObjectID);
+ CHECK_HR(hr, "Failed to add object [%ws]", pvObjectID.pwszVal);
+ pContext->SearchIndex = dwNextStartIndex;
+ }
+ }
+
+ pContext->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ CHECK_HR(hr, "Cannot find enum context [%ws]", pszEnumContext);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pObjectIDs->QueryInterface(IID_PPV_ARGS(ppCollection));
+ CHECK_HR(hr, "Failed to QI for IID_IPortableDevicePropVariantCollection on IPortableDevicePropVariantCollection");
+ }
+ return hr;
+}
+