// 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_hMethodCompleteEvent = NULL; void DisplayParameterUsage( DWORD dwUsage) { switch(static_cast(dwUsage)) { case WPD_PARAMETER_USAGE_RETURN: printf("Return Value"); break; case WPD_PARAMETER_USAGE_IN: printf("Input Parameter"); break; case WPD_PARAMETER_USAGE_OUT: printf("Output Parameter"); break; case WPD_PARAMETER_USAGE_INOUT: printf("Input/Output Parameter"); break; default: printf("Unknown Parameter Usage"); break; } } void DisplayMethodAccess( DWORD dwAccess) { switch(static_cast(dwAccess)) { case WPD_COMMAND_ACCESS_READ: printf("Read"); break; case WPD_COMMAND_ACCESS_READWRITE: printf("Read/Write"); break; default: printf("Unknown Access"); break; } } // Display the method parameters. void DisplayMethodParameters( IPortableDeviceServiceCapabilities* pCapabilities, REFGUID Method, IPortableDeviceKeyCollection* pParameters) { DWORD dwNumParameters = 0; // Get the number of parameters for this event. HRESULT hr = pParameters->GetCount(&dwNumParameters); if (FAILED(hr)) { printf("! Failed to get number of parameters, hr = 0x%lx\n",hr); } printf("\n\t%d Method Parameters:\n", dwNumParameters); // Loop through each parameter and display it if (SUCCEEDED(hr)) { for (DWORD dwIndex = 0; dwIndex < dwNumParameters; dwIndex++) { PROPERTYKEY parameter; hr = pParameters->GetAt(dwIndex, ¶meter); if (SUCCEEDED(hr)) { CComPtr pAttributes; // Display the parameter's Name, Usage, Vartype, and Form hr = pCapabilities->GetMethodParameterAttributes(Method, parameter, &pAttributes); if (FAILED(hr)) { printf("! Failed to get the method parameter attributes, hr = 0x%lx\n",hr); } if (SUCCEEDED(hr)) { PWSTR pszParameterName = NULL; DWORD dwAttributeVarType = 0; DWORD dwAttributeForm = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED; DWORD dwAttributeUsage = (DWORD)-1; hr = pAttributes->GetStringValue(WPD_PARAMETER_ATTRIBUTE_NAME, &pszParameterName); if (SUCCEEDED(hr)) { printf("\t\tName: %ws\n", pszParameterName); } else { printf("! Failed to get the method parameter name, hr = 0x%lx\n",hr); } // Read the WPD_PARAMETER_ATTRIBUTE_USAGE value, if specified. hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_USAGE, &dwAttributeUsage); if (SUCCEEDED(hr)) { printf("\t\tUsage: "); DisplayParameterUsage(dwAttributeUsage); printf("\n"); } else { printf("! Failed to get the method parameter usage, hr = 0x%lx\n",hr); } hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_VARTYPE, &dwAttributeVarType); if (SUCCEEDED(hr)) { printf("\t\tVARTYPE: "); DisplayVarType(static_cast(dwAttributeVarType)); printf("\n"); } else { printf("! Failed to get the method parameter VARTYPE, hr = 0x%lx\n",hr); } // Read the WPD_PARAMETER_ATTRIBUTE_FORM value. hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_FORM, &dwAttributeForm); if (FAILED(hr)) { // If the read fails, assume WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED dwAttributeForm = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED; hr = S_OK; } printf("\t\tForm: "); DisplayParameterForm(dwAttributeForm); printf("\n"); CoTaskMemFree(pszParameterName); pszParameterName = NULL; } printf("\n"); } } } } // Display basic information about a method void DisplayMethod( IPortableDeviceServiceCapabilities* pCapabilities, REFGUID Method) { CComPtr pAttributes; // Get the method attributes which describe the method HRESULT hr = pCapabilities->GetMethodAttributes(Method, &pAttributes); if (FAILED(hr)) { printf("! Failed to get the method attributes, hr = 0x%lx\n",hr); } if (SUCCEEDED(hr)) { PWSTR pszMethodName = NULL; DWORD dwMethodAccess = WPD_COMMAND_ACCESS_READ; GUID guidFormat = GUID_NULL; CComPtr pOptions; CComPtr pParameters; // Display the name of the method if available. Otherwise, fall back to displaying the GUID. hr = pAttributes->GetStringValue(WPD_METHOD_ATTRIBUTE_NAME, &pszMethodName); if (SUCCEEDED(hr)) { printf("%ws", pszMethodName); } else { printf("%ws", (PWSTR)CGuidToString(Method)); } // Display the method access if available, otherwise default to WPD_COMMAND_ACCESS_READ access hr = pAttributes->GetUnsignedIntegerValue(WPD_METHOD_ATTRIBUTE_ACCESS, &dwMethodAccess); if (FAILED(hr)) { dwMethodAccess = WPD_COMMAND_ACCESS_READ; hr = S_OK; } printf("\n\tAccess: "); DisplayMethodAccess(dwMethodAccess); // 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 = pAttributes->GetGuidValue(WPD_METHOD_ATTRIBUTE_ASSOCIATED_FORMAT, &guidFormat); if (SUCCEEDED(hr)) { printf("\n\tAssociated Format: "); DisplayFormat(pCapabilities, guidFormat); } // Display the method parameters, if available hr = pAttributes->GetIPortableDeviceKeyCollectionValue(WPD_METHOD_ATTRIBUTE_PARAMETERS, &pParameters); if (SUCCEEDED(hr)) { DisplayMethodParameters(pCapabilities, Method, pParameters); } CoTaskMemFree(pszMethodName); pszMethodName = NULL; } } // List all supported methods on the service void ListSupportedMethods(IPortableDeviceService* pService) { HRESULT hr = S_OK; DWORD dwNumMethods = 0; CComPtr pCapabilities; CComPtr pMethods; if (pService == NULL) { printf("! A NULL IPortableDeviceService interface pointer was received\n"); return; } // Get an IPortableDeviceServiceCapabilities interface from the IPortableDeviceService interface to // access the service capabilities-specific methods. hr = pService->Capabilities(&pCapabilities); if (FAILED(hr)) { printf("! Failed to get IPortableDeviceServiceCapabilities from IPortableDeviceService, hr = 0x%lx\n",hr); } // Get all methods supported by the service. if (SUCCEEDED(hr)) { hr = pCapabilities->GetSupportedMethods(&pMethods); if (FAILED(hr)) { printf("! 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 = pMethods->GetCount(&dwNumMethods); if (FAILED(hr)) { printf("! Failed to get number of supported methods, hr = 0x%lx\n",hr); } } printf("\n%d Supported Methods Found on the service\n\n", dwNumMethods); // Loop through each method and display it if (SUCCEEDED(hr)) { for (DWORD dwIndex = 0; dwIndex < dwNumMethods; dwIndex++) { PROPVARIANT pv = {0}; PropVariantInit(&pv); hr = pMethods->GetAt(dwIndex, &pv); if (SUCCEEDED(hr)) { // We have a method. It is assumed that // methods are returned as VT_CLSID VarTypes. if (pv.puuid != NULL) { DisplayMethod(pCapabilities, *pv.puuid); printf("\n"); } } PropVariantClear(&pv); } } } class CMethodCallback : public IPortableDeviceServiceMethodCallback { public: CMethodCallback () : m_cRef(1) { } ~CMethodCallback () { } public: // IPortableDeviceServiceMethodCallback::QueryInterface virtual HRESULT STDMETHODCALLTYPE OnComplete( HRESULT hrStatus, IPortableDeviceValues* /*pResults*/) // We are ignoring results as our methods will not return any results { printf("** Method completed, status HRESULT = 0x%lx **\n", hrStatus); if (g_hMethodCompleteEvent != NULL) { SetEvent(g_hMethodCompleteEvent); } return S_OK; } // IUnknown::AddRef virtual ULONG STDMETHODCALLTYPE AddRef(void) { InterlockedIncrement((long*) &m_cRef); return m_cRef; } // IUnknown::QueryInterface virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID* ppvObj) { HRESULT hr = S_OK; if (ppvObj == NULL) { hr = E_INVALIDARG; return hr; } if ((riid == IID_IUnknown) || (riid == IID_IPortableDeviceServiceMethodCallback)) { AddRef(); *ppvObj = this; } else { *ppvObj = NULL; hr = E_NOINTERFACE; } return hr; } // IUnknown::Release virtual ULONG STDMETHODCALLTYPE Release(void) { ULONG ulRefCount = m_cRef - 1; if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } return ulRefCount; } private: DWORD m_cRef; }; // Invoke methods on the Contacts Service. // BeginSync and EndSync are methods defined by the FullEnumerationSync Device Service. void InvokeMethods(IPortableDeviceService* pService) { HRESULT hr = S_OK; CComPtr pMethods; if (pService == NULL) { printf("! A NULL IPortableDeviceService interface pointer was received\n"); return; } // Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to // invoke methods. hr = pService->Methods(&pMethods); if (FAILED(hr)) { printf("! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n",hr); } // Invoke() the BeginSync method if (SUCCEEDED(hr)) { // This method does not take any parameters or results, so we pass in NULL hr = pMethods->Invoke(METHOD_FullEnumSyncSvc_BeginSync, NULL, NULL); if (SUCCEEDED(hr)) { printf("%ws called, hr = 0x%lx\n",NAME_FullEnumSyncSvc_BeginSync, hr); } else { printf("! Failed to invoke %ws, hr = 0x%lx\n",NAME_FullEnumSyncSvc_BeginSync, hr); } } // Invoke the EndSync method asynchronously if (SUCCEEDED(hr)) { // This method does not take any parameters or results, so we pass in NULL hr = pMethods->Invoke(METHOD_FullEnumSyncSvc_EndSync, NULL, NULL); if (SUCCEEDED(hr)) { printf("%ws called, hr = 0x%lx\n",NAME_FullEnumSyncSvc_EndSync, hr); } else { printf("! Failed to invoke %ws, hr = 0x%lx\n",NAME_FullEnumSyncSvc_EndSync, hr); } } } HRESULT InvokeMethodAsync( IPortableDeviceServiceMethods* pMethods, REFGUID Method, IPortableDeviceValues* pParameters) { HRESULT hr = S_OK; // Cleanup any previously created global event handles. if (g_hMethodCompleteEvent != NULL) { CloseHandle(g_hMethodCompleteEvent); g_hMethodCompleteEvent = NULL; } // 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_hMethodCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (g_hMethodCompleteEvent != NULL) { CMethodCallback* pCallback = new (std::nothrow) CMethodCallback(); if (pCallback == NULL) { hr = E_OUTOFMEMORY; printf("! 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 = pMethods->InvokeAsync(Method, pParameters, pCallback); if(FAILED(hr)) { printf("! 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_hMethodCompleteEvent != NULL) { WaitForSingleObject(g_hMethodCompleteEvent, INFINITE); } } } // Cleanup previously created callback interface if (pCallback) { pCallback->Release(); pCallback = NULL; } // Cleanup any previously created global event handles. if (g_hMethodCompleteEvent != NULL) { CloseHandle(g_hMethodCompleteEvent); g_hMethodCompleteEvent = NULL; } } else { printf("! 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(IPortableDeviceService* pService) { HRESULT hr = S_OK; CComPtr pMethods; if (pService == NULL) { printf("! A NULL IPortableDeviceService interface pointer was received\n"); return; } // Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to // invoke methods. hr = pService->Methods(&pMethods); if (FAILED(hr)) { printf("! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n",hr); } // Invoke the BeginSync method asynchronously if (SUCCEEDED(hr)) { printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_BeginSync); // This method does not take any parameters, so we pass in NULL hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_BeginSync, NULL); if (FAILED(hr)) { printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_BeginSync, hr); } } // Invoke the EndSync method asynchronously if (SUCCEEDED(hr)) { printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_EndSync); hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_EndSync, NULL); if (FAILED(hr)) { printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_EndSync, hr); } } }