/** * This method is called when we receive a WPD_COMMAND_OBJECT_RESOURCES_OPEN * command. * * The parameters sent to us are: * - WPD_PROPERTY_OBJECT_RESOURCES_OBJECT_ID: the object identifier of the * object which contains the specified resource * * - WPD_PROPERTY_OBJECT_RESOURCES_RESOURCE_KEYS: the specified resource * to open * * - WPD_PROPERTY_OBJECT_RESOURCES_ACCESS_MODE: the access mode to which to * open the specified resource * * The driver should: * - Create a new context for this resource operation. * - Return an identifier for the context in WPD_PROPERTY_OBJECT_RESOURCES_CONTEXT. * - Set the optimal transfer size in WPD_PROPERTY_OBJECT_RESOURCES_OPTIMAL_TRANSFER_BUFFER_SIZE * */ HRESULT WpdObjectResources::OnOpenResource( _In_ IPortableDeviceValues* pParams, _In_ IPortableDeviceValues* pResults) { HRESULT hr = S_OK; LPWSTR wszObjectID = NULL; PROPERTYKEY Key = WPD_PROPERTY_NULL; DWORD dwMode = STGM_READ; CAtlStringW strStrObjectID; CAtlStringW strResourceContext; ContextMap* pContextMap = NULL; // Get the Object identifier of the object which contains the specified resource hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_RESOURCES_OBJECT_ID, &wszObjectID); if (hr != S_OK) { hr = E_INVALIDARG; CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_RESOURCES_OBJECT_ID"); } // Get the resource key if (hr == S_OK) { hr = pParams->GetKeyValue(WPD_PROPERTY_OBJECT_RESOURCES_RESOURCE_KEYS, &Key); CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_RESOURCES_RESOURCE_KEYS"); } // Get the access mode if (hr == S_OK) { hr = pParams->GetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_RESOURCES_ACCESS_MODE, &dwMode); CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_RESOURCES_ACCESS_MODE"); } // Validate whether the params given to us are correct. In this case, we need to check that the object // supports the resource requested, and can be opened in the requested access mode. if (hr == S_OK) { // In this sample, we only have one object (README_FILE_OBJECT_ID) which supports a // resource (WPD_RESOURCE_DEFAULT) for reading only. // So if any other Object ID or any other resource is specified, it must be invalid. strStrObjectID = wszObjectID; if(strStrObjectID.CompareNoCase(README_FILE_OBJECT_ID) != 0) { hr = E_INVALIDARG; CHECK_HR(hr, "Object [%ws] does not support resources", wszObjectID); } if (hr == S_OK) { if (!IsEqualPropertyKey(Key, WPD_RESOURCE_DEFAULT)) { hr = E_INVALIDARG; CHECK_HR(hr, "Only WPD_RESOURCE_DEFAULT is supported in this sample driver"); } } if (hr == S_OK) { if ((dwMode & STGM_WRITE) != 0) { hr = E_ACCESSDENIED; CHECK_HR(hr, "This resource is not available for write access"); } } } // Get the context map which the driver stored in pParams for convenience if (hr == S_OK) { hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap); CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); } // Create a new resource operation context, initialize it, and add it to the client context map. if (hr == S_OK) { WpdObjectResourceContext* pResourceContext = new WpdObjectResourceContext(); if (pResourceContext != NULL) { // Initialize the resource context with ... pResourceContext->m_strObjectID = wszObjectID; pResourceContext->m_Resource = Key; pResourceContext->m_BytesTransferred = 0; pResourceContext->m_BytesTotal = GetObjectSize(wszObjectID); // Add the resource context to the context map pContextMap->Add(pResourceContext, strResourceContext); // Release the resource context because it has been AddRef'ed during Add() SAFE_RELEASE(pResourceContext); } else { hr = E_OUTOFMEMORY; CHECK_HR(hr, "Failed to allocate resource context"); } } if (hr == S_OK) { hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_RESOURCES_CONTEXT, strResourceContext); CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_RESOURCES_CONTEXT"); } // Set the optimal buffer size if (hr == S_OK) { hr = pResults->SetUnsignedIntegerValue(WPD_PROPERTY_OBJECT_RESOURCES_OPTIMAL_TRANSFER_BUFFER_SIZE, FILE_OPTIMAL_READ_BUFFER_SIZE_VALUE); CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_RESOURCES_OPTIMAL_TRANSFER_BUFFER_SIZE value"); } // Free the memory. CoTaskMemFree ignores NULLs so no need to check. CoTaskMemFree(wszObjectID); SAFE_RELEASE(pContextMap); 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. * - Set the string identifier in WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT for the newly created enumeration context. * This value will be passed back during OnFindNext and OnEndFind. */ HRESULT WpdObjectEnumerator::OnStartFind( _In_ IPortableDeviceValues* pParams, _Inout_ IPortableDeviceValues* pResults) { HRESULT hr = S_OK; LPWSTR wszParentID = NULL; ContextMap* pContextMap = NULL; CAtlStringW strEnumContext; // First get ALL parameters for this command. If we cannot get ALL parameters // then E_INVALIDARG should be returned and no further processing should occur. // Get the object identifier of the parent where the enumeration is starting from. hr = pParams->GetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID, &wszParentID); if (hr != S_OK) { hr = E_INVALIDARG; CHECK_HR(hr, "Missing value for WPD_PROPERTY_OBJECT_ENUMERATION_PARENT_ID"); } // Get the client context map so we can store an enumeration context for this enumeration // operation. if (hr == S_OK) { hr = GetClientContextMap(pParams, &pContextMap); CHECK_HR(hr, "Failed to get client context map"); } // Create and initialize a new enumeration context. // Add the new enumertion context to the client context map. This context is used to // keep track of this particular enumeration operation. if (hr == S_OK) { WpdObjectEnumeratorContext* pEnumeratorContext = new WpdObjectEnumeratorContext(); if (pEnumeratorContext != NULL) { ACCESS_SCOPE Scope = m_pDevice->GetAccessScope(pParams); m_pDevice->InitializeEnumerationContext(Scope, wszParentID, pEnumeratorContext); // Add the enumeration context to the client context map. This calls AddRef() on pEnumeratorContext hr = pContextMap->Add(pEnumeratorContext, strEnumContext); CHECK_HR(hr, "Failed to add the enumeration context"); } else { hr = E_OUTOFMEMORY; CHECK_HR(hr, "Failed to allocate enumeration context"); } SAFE_RELEASE(pEnumeratorContext); } // Set the WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT value in the results. // This context identifier will be passed back during OnFindNext and OnEndFind to allow the driver to access it. if (hr == S_OK) { hr = pResults->SetStringValue(WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT, strEnumContext); CHECK_HR(hr, "Failed to set WPD_PROPERTY_OBJECT_ENUMERATION_CONTEXT"); } // Free the memory. CoTaskMemFree ignores NULLs so no need to check. CoTaskMemFree(wszParentID); SAFE_RELEASE(pContextMap); return hr; }
HRESULT WpdServiceMethods::StartMethod( _In_ IPortableDeviceValues* pParams, _Outptr_result_nullonfailure_ LPWSTR* ppwszMethodContext) { HRESULT hr = S_OK; ContextMap* pContextMap = NULL; ServiceMethodContext* pContext = NULL; GUID Method = GUID_NULL; CAtlStringW strKey; CComPtr<IPortableDeviceValues> pMethodParams; if((pParams == NULL) || (ppwszMethodContext == NULL)) { hr = E_POINTER; CHECK_HR(hr, "Cannot have NULL parameter"); return hr; } *ppwszMethodContext = NULL; // Check if the method is supported hr = pParams->GetGuidValue(WPD_PROPERTY_SERVICE_METHOD, &Method); CHECK_HR(hr, "Failed to get WPD_PROPERTY_SERVICE_METHOD"); if (SUCCEEDED(hr) && !m_pContactsService->IsMethodSupported(Method)) { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); CHECK_HR(hr, "Unknown method %ws received",CComBSTR(Method)); } if (SUCCEEDED(hr)) { // Get the context map which the driver stored in pParams for convenience 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)) { pContext = new ServiceMethodContext(); if(pContext == NULL) { hr = E_OUTOFMEMORY; CHECK_HR(hr, "Failed to allocate new method context"); } } if (SUCCEEDED(hr)) { hr = pContextMap->Add(pContext, strKey); CHECK_HR(hr, "Failed to insert method context into our context Map"); } if (SUCCEEDED(hr)) { hr = pContext->Initialize(this, pParams, strKey); CHECK_HR(hr, "Failed to initialize the method context"); } if (SUCCEEDED(hr)) { *ppwszMethodContext = AtlAllocTaskWideString(strKey); if (*ppwszMethodContext == NULL) { hr = E_OUTOFMEMORY; CHECK_HR(hr, "Failed to allocate method context string"); } } SAFE_RELEASE(pContextMap); SAFE_RELEASE(pContext); return hr; }
/** * Save the client information */ HRESULT WpdBaseDriver::OnSaveClientInfo( _In_ IPortableDeviceValues* pParams, _In_ IPortableDeviceValues* pResults) { HRESULT hr = S_OK; GUID guidContext = GUID_NULL; CComBSTR bstrContext; ClientContext* pContext = NULL; ContextMap* pContextMap = NULL; CComPtr<IPortableDeviceValues> pClientInfo; if((pParams == NULL) || (pResults == NULL)) { hr = E_POINTER; CHECK_HR(hr, "Cannot have NULL parameter"); return hr; } hr = CoCreateGuid(&guidContext); if (hr == S_OK) { bstrContext = guidContext; if(bstrContext.Length() == 0) { hr = E_OUTOFMEMORY; CHECK_HR(hr, "Failed to create BSTR from GUID"); } } // Get the client info if (hr == S_OK) { hr = pParams->GetIPortableDeviceValuesValue(WPD_PROPERTY_COMMON_CLIENT_INFORMATION, &pClientInfo); CHECK_HR(hr, "Failed to get WPD_PROPERTY_COMMON_CLIENT_INFORMATION"); } // Get the context map which the driver stored in pParams for convenience if (hr == S_OK) { hr = pParams->GetIUnknownValue(PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP, (IUnknown**)&pContextMap); CHECK_HR(hr, "Failed to get PRIVATE_SAMPLE_DRIVER_CLIENT_CONTEXT_MAP"); } // Create the new client info context we will save in the context map if (hr == S_OK) { pContext = new ClientContext(); if(pContext == NULL) { hr = E_OUTOFMEMORY; CHECK_HR(hr, ("Could not allocate memory for client info context")); } } // Save the client info. Since these are optional, none of this is fatal if // they don't exist. if (hr == S_OK) { LPWSTR pszClientName = NULL; LPWSTR pszEventCookie = NULL; pClientInfo->GetStringValue(WPD_CLIENT_NAME, &pszClientName); if(pszClientName != NULL) { pContext->ClientName = pszClientName; } pClientInfo->GetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, &(pContext->MajorVersion)); pClientInfo->GetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, &(pContext->MinorVersion)); pClientInfo->GetUnsignedIntegerValue(WPD_CLIENT_REVISION, &(pContext->Revision)); pClientInfo->GetStringValue(WPD_CLIENT_EVENT_COOKIE, &pszEventCookie); if (pszEventCookie != NULL) { pContext->EventCookie = pszEventCookie; } CoTaskMemFree(pszClientName); CoTaskMemFree(pszEventCookie); } if ((hr == S_OK) && (pContext->ClientName.GetLength() > 0) && (pContextMap != NULL)) { CAtlStringW strKey = bstrContext; hr = pContextMap->Add(strKey, pContext); CHECK_HR(hr, "Failed to add client info context to context map"); if (hr == S_OK) { hr = pResults->SetStringValue(WPD_PROPERTY_COMMON_CLIENT_INFORMATION_CONTEXT, bstrContext); CHECK_HR(hr, "Failed to set WPD_PROPERTY_COMMON_CLIENT_INFORMATION_CONTEXT"); } } SAFE_RELEASE(pContext); // Always release the context, pContextMap::Add would have AddRef'ed it SAFE_RELEASE(pContextMap); return hr; }