// 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. #include "stdafx.h" HANDLE g_methodCompleteEvent = nullptr; void DisplayParameterUsage( DWORD usage) { switch(static_cast(usage)) { case WPD_PARAMETER_USAGE_RETURN: wprintf(L"Return Value"); break; case WPD_PARAMETER_USAGE_IN: wprintf(L"Input Parameter"); break; case WPD_PARAMETER_USAGE_OUT: wprintf(L"Output Parameter"); break; case WPD_PARAMETER_USAGE_INOUT: wprintf(L"Input/Output Parameter"); break; default: wprintf(L"Unknown Parameter Usage"); break; } } // void DisplayMethodAccess( DWORD access) { switch(static_cast(access)) { case WPD_COMMAND_ACCESS_READ: wprintf(L"Read"); break; case WPD_COMMAND_ACCESS_READWRITE: wprintf(L"Read/Write"); break; default: wprintf(L"Unknown Access"); break; } } // // // Display the method parameters. void DisplayMethodParameters( _In_ IPortableDeviceServiceCapabilities* capabilities, _In_ REFGUID method, _In_ IPortableDeviceKeyCollection* parameters) { DWORD numParameters = 0; // Get the number of parameters for this event. HRESULT hr = parameters->GetCount(&numParameters); if (FAILED(hr)) { wprintf(L"! Failed to get number of parameters, hr = 0x%lx\n", hr); } else { wprintf(L"\n\t%u Method Parameters:\n", numParameters); // Loop through each parameter and display it for (DWORD index = 0; index < numParameters; index++) { PROPERTYKEY parameter; hr = parameters->GetAt(index, ¶meter); if (SUCCEEDED(hr)) { ComPtr attributes; // Display the parameter's Name, Usage, Vartype, and Form hr = capabilities->GetMethodParameterAttributes(method, parameter, &attributes); if (FAILED(hr)) { wprintf(L"! Failed to get the method parameter attributes, hr = 0x%lx\n", hr); } else { PWSTR parameterName = nullptr; DWORD attributeVarType = 0; DWORD attributeForm = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED; DWORD attributeUsage = (DWORD)-1; hr = attributes->GetStringValue(WPD_PARAMETER_ATTRIBUTE_NAME, ¶meterName); if (SUCCEEDED(hr)) { wprintf(L"\t\tName: %ws\n", parameterName); } else { wprintf(L"! Failed to get the method parameter name, hr = 0x%lx\n", hr); } // Read the WPD_PARAMETER_ATTRIBUTE_USAGE value, if specified. hr = attributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_USAGE, &attributeUsage); if (SUCCEEDED(hr)) { wprintf(L"\t\tUsage: "); DisplayParameterUsage(attributeUsage); wprintf(L"\n"); } else { wprintf(L"! Failed to get the method parameter usage, hr = 0x%lx\n", hr); } hr = attributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_VARTYPE, &attributeVarType); if (SUCCEEDED(hr)) { wprintf(L"\t\tVARTYPE: "); DisplayVarType(static_cast(attributeVarType)); wprintf(L"\n"); } else { wprintf(L"! Failed to get the method parameter VARTYPE, hr = 0x%lx\n", hr); } // Read the WPD_PARAMETER_ATTRIBUTE_FORM value. hr = attributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_FORM, &attributeForm); if (FAILED(hr)) { // If the read fails, assume WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED attributeForm = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED; hr = S_OK; } wprintf(L"\t\tForm: "); DisplayParameterForm(attributeForm); wprintf(L"\n"); CoTaskMemFree(parameterName); parameterName = nullptr; } wprintf(L"\n"); } } } } // // // Display basic information about a method void DisplayMethod( _In_ IPortableDeviceServiceCapabilities* capabilities, _In_ REFGUID method) { ComPtr attributes; // Get the method attributes which describe the method HRESULT hr = capabilities->GetMethodAttributes(method, &attributes); if (FAILED(hr)) { wprintf(L"! Failed to get the method attributes, hr = 0x%lx\n", hr); } if (SUCCEEDED(hr)) { PWSTR methodName = nullptr; DWORD methodAccess = WPD_COMMAND_ACCESS_READ; GUID associatedFormat = GUID_NULL; ComPtr parameters; // Display the name of the method if available. Otherwise, fall back to displaying the GUID. hr = attributes->GetStringValue(WPD_METHOD_ATTRIBUTE_NAME, &methodName); if (SUCCEEDED(hr)) { wprintf(L"%ws", methodName); } else { wprintf(L"%ws", (PCWSTR)CGuidToString(method)); } // Display the method access if available, otherwise default to WPD_COMMAND_ACCESS_READ access hr = attributes->GetUnsignedIntegerValue(WPD_METHOD_ATTRIBUTE_ACCESS, &methodAccess); if (FAILED(hr)) { methodAccess = WPD_COMMAND_ACCESS_READ; hr = S_OK; } wprintf(L"\n\tAccess: "); DisplayMethodAccess(methodAccess); // Display the associated format if specified. // Methods that have an associated format may only be supported for that format. // Methods that don't have associated formats generally apply to the entire service. hr = attributes->GetGuidValue(WPD_METHOD_ATTRIBUTE_ASSOCIATED_FORMAT, &associatedFormat); if (SUCCEEDED(hr)) { wprintf(L"\n\tAssociated Format: "); DisplayFormat(capabilities, associatedFormat); } // Display the method parameters, if available hr = attributes->GetIPortableDeviceKeyCollectionValue(WPD_METHOD_ATTRIBUTE_PARAMETERS, ¶meters); if (SUCCEEDED(hr)) { DisplayMethodParameters(capabilities, method, parameters.Get()); } CoTaskMemFree(methodName); methodName = nullptr; } } // // // List all supported methods on the service void ListSupportedMethods( _In_ IPortableDeviceService* service) { DWORD dwNumMethods = 0; ComPtr capabilities; ComPtr methods; // Get an IPortableDeviceServiceCapabilities interface from the IPortableDeviceService interface to // access the service capabilities-specific methods. HRESULT hr = service->Capabilities(&capabilities); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceServiceCapabilities from IPortableDeviceService, hr = 0x%lx\n", hr); } // Get all methods supported by the service. if (SUCCEEDED(hr)) { hr = capabilities->GetSupportedMethods(&methods); if (FAILED(hr)) { wprintf(L"! Failed to get supported methods from the service, hr = 0x%lx\n", hr); } } // Get the number of supported methods found on the service. if (SUCCEEDED(hr)) { hr = methods->GetCount(&dwNumMethods); if (FAILED(hr)) { wprintf(L"! Failed to get number of supported methods, hr = 0x%lx\n", hr); } } // Loop through each method and display it if (SUCCEEDED(hr)) { wprintf(L"\n%u Supported Methods Found on the service\n\n", dwNumMethods); for (DWORD index = 0; index < dwNumMethods; index++) { PROPVARIANT pv = {0}; hr = methods->GetAt(index, &pv); if (SUCCEEDED(hr)) { // We have a method. It is assumed that // methods are returned as VT_CLSID VarTypes. if (pv.puuid != nullptr) { DisplayMethod(capabilities.Get(), *pv.puuid); wprintf(L"\n"); } } PropVariantClear(&pv); } } } // // class CMethodCallback : public IPortableDeviceServiceMethodCallback { public: CMethodCallback () : m_ref(0) { } ~CMethodCallback () { } public: // IPortableDeviceServiceMethodCallback::QueryInterface IFACEMETHODIMP OnComplete( HRESULT hrStatus, _In_ IPortableDeviceValues* /*pResults*/) // We are ignoring results as our methods will not return any results { wprintf(L"** Method completed, status HRESULT = 0x%lx **\n", hrStatus); if (g_methodCompleteEvent != nullptr) { SetEvent(g_methodCompleteEvent); } return S_OK; } IFACEMETHODIMP QueryInterface( _In_ REFIID riid, _COM_Outptr_ void** ppv) { static const QITAB qitab[] = { QITABENT(CMethodCallback, IPortableDeviceServiceMethodCallback), { }, }; return QISearch(this, qitab, riid, ppv); } IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_ref); } IFACEMETHODIMP_(ULONG) Release() { long ref = InterlockedDecrement(&m_ref); if (ref == 0) { delete this; } return ref; } private: long m_ref; }; // // // Invoke methods on the Contacts Service. // BeginSync and EndSync are methods defined by the FullEnumerationSync Device Service. void InvokeMethods( _In_ IPortableDeviceService* service) { ComPtr methods; // Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to // invoke methods. HRESULT hr = service->Methods(&methods); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n", hr); } else { // Invoke() the BeginSync method synchronously // This method does not take any parameters or results, so we pass in nullptr hr = methods->Invoke(METHOD_FullEnumSyncSvc_BeginSync, nullptr, nullptr); if (SUCCEEDED(hr)) { wprintf(L"%ws called, hr = 0x%lx\n", NAME_FullEnumSyncSvc_BeginSync, hr); } else { wprintf(L"! Failed to invoke %ws, hr = 0x%lx\n", NAME_FullEnumSyncSvc_BeginSync, hr); } } // Invoke the EndSync method synchronously if (SUCCEEDED(hr)) { // This method does not take any parameters or results, so we pass in nullptr hr = methods->Invoke(METHOD_FullEnumSyncSvc_EndSync, nullptr, nullptr); if (SUCCEEDED(hr)) { wprintf(L"%ws called, hr = 0x%lx\n", NAME_FullEnumSyncSvc_EndSync, hr); } else { wprintf(L"! Failed to invoke %ws, hr = 0x%lx\n", NAME_FullEnumSyncSvc_EndSync, hr); } } } // HRESULT InvokeMethodAsync( _In_ IPortableDeviceServiceMethods* methods, _In_ REFGUID method, _In_opt_ IPortableDeviceValues* parameters) { HRESULT hr = S_OK; // Cleanup any previously created global event handles. if (g_methodCompleteEvent != nullptr) { CloseHandle(g_methodCompleteEvent); g_methodCompleteEvent = nullptr; } // In order to create a simpler to follow example we create and wait infinitely // for the method to complete and ignore any errors. // Production code should be written in a more robust manner. // Create the global event handle to wait on for the method to complete. g_methodCompleteEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (g_methodCompleteEvent != nullptr) { // Assign the callback pointer to a ComPtr so that it will automatically release // when out of scope ComPtr callback = new (std::nothrow) CMethodCallback(); if (callback == nullptr) { hr = E_OUTOFMEMORY; wprintf(L"! Failed to get allocate CMethodCallback, hr = 0x%lx\n", hr); } else { // Call InvokeAsync() to begin the Asynchronous method operation. // Each pCallback parameter is used as the method context, and therefore must be unique. hr = methods->InvokeAsync(method, parameters, callback.Get()); if(FAILED(hr)) { wprintf(L"! Failed to invoke method asynchronously, hr = 0x%lx\n", hr); } else { // In order to create a simpler to follow example we will wait infinitly for the operation // to complete and ignore any errors. Production code should be written in a more // robust manner. if (g_methodCompleteEvent != nullptr) { WaitForSingleObject(g_methodCompleteEvent, INFINITE); } } } // Cleanup any previously created global event handles. if (g_methodCompleteEvent != nullptr) { CloseHandle(g_methodCompleteEvent); g_methodCompleteEvent = nullptr; } } else { wprintf(L"! Failed to create the global event handle to wait on for the method operation. Aborting operation.\n"); } return hr; } // // Invoke methods on the Contacts Service asynchornously. // BeginSync and EndSync are methods defined by the FullEnumerationSync Device Service. void InvokeMethodsAsync( _In_ IPortableDeviceService* service) { ComPtr methods; // Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to // invoke methods. HRESULT hr = service->Methods(&methods); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n", hr); } else { // Invoke the BeginSync method asynchronously wprintf(L"Invoking %ws asynchronously...\n", NAME_FullEnumSyncSvc_BeginSync); // This method does not take any parameters, so we pass in nullptr hr = InvokeMethodAsync(methods.Get(), METHOD_FullEnumSyncSvc_BeginSync, nullptr); if (FAILED(hr)) { wprintf(L"! Failed to invoke %ws asynchronously, hr = 0x%lx\n", NAME_FullEnumSyncSvc_BeginSync, hr); } } // Invoke the EndSync method asynchronously if (SUCCEEDED(hr)) { wprintf(L"Invoking %ws asynchronously...\n", NAME_FullEnumSyncSvc_EndSync); hr = InvokeMethodAsync(methods.Get(), METHOD_FullEnumSyncSvc_EndSync, nullptr); if (FAILED(hr)) { wprintf(L"! Failed to invoke %ws asynchronously, hr = 0x%lx\n", NAME_FullEnumSyncSvc_EndSync, hr); } } } //