// 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" // #define CLIENT_NAME L"WPD Sample Application" #define CLIENT_MAJOR_VER 1 #define CLIENT_MINOR_VER 0 #define CLIENT_REVISION 2 // // Reads and displays the device friendly name for the specified PnPDeviceID string void DisplayFriendlyName( _In_ IPortableDeviceManager* deviceManager, _In_ PCWSTR pnpDeviceID) { DWORD friendlyNameLength = 0; // 1) Pass nullptr as the PWSTR return string parameter to get the total number // of characters to allocate for the string value. HRESULT hr = deviceManager->GetDeviceFriendlyName(pnpDeviceID, nullptr, &friendlyNameLength); if (FAILED(hr)) { wprintf(L"! Failed to get number of characters for device friendly name, hr = 0x%lx\n", hr); } else if (friendlyNameLength > 0) { // 2) Allocate the number of characters needed and retrieve the string value. PWSTR friendlyName = new (std::nothrow) WCHAR[friendlyNameLength]; if (friendlyName != nullptr) { ZeroMemory(friendlyName, friendlyNameLength * sizeof(WCHAR)); hr = deviceManager->GetDeviceFriendlyName(pnpDeviceID, friendlyName, &friendlyNameLength); if (SUCCEEDED(hr)) { wprintf(L"Friendly Name: %ws\n", friendlyName); } else { wprintf(L"! Failed to get device friendly name, hr = 0x%lx\n", hr); } // Delete the allocated friendly name string delete [] friendlyName; friendlyName = nullptr; } else { wprintf(L"! Failed to allocate memory for the device friendly name string\n"); } } else { wprintf(L"The device did not provide a friendly name.\n"); } } // Reads and displays the device manufacturer for the specified PnPDeviceID string void DisplayManufacturer( _In_ IPortableDeviceManager* deviceManager, _In_ PCWSTR pnpDeviceID) { DWORD manufacturerLength = 0; // 1) Pass nullptr as the PWSTR return string parameter to get the total number // of characters to allocate for the string value. HRESULT hr = deviceManager->GetDeviceManufacturer(pnpDeviceID, nullptr, &manufacturerLength); if (FAILED(hr)) { wprintf(L"! Failed to get number of characters for device manufacturer, hr = 0x%lx\n", hr); } else if (manufacturerLength > 0) { // 2) Allocate the number of characters needed and retrieve the string value. PWSTR manufacturer = new (std::nothrow) WCHAR[manufacturerLength]; if (manufacturer != nullptr) { ZeroMemory(manufacturer, manufacturerLength * sizeof(WCHAR)); hr = deviceManager->GetDeviceManufacturer(pnpDeviceID, manufacturer, &manufacturerLength); if (SUCCEEDED(hr)) { wprintf(L"Manufacturer: %ws\n", manufacturer); } else { wprintf(L"! Failed to get device manufacturer, hr = 0x%lx\n", hr); } // Delete the allocated manufacturer string delete [] manufacturer; manufacturer = nullptr; } else { wprintf(L"! Failed to allocate memory for the device manufacturer string\n"); } } else { wprintf(L"The device did not provide a manufacturer.\n"); } } // Reads and displays the device discription for the specified PnPDeviceID string void DisplayDescription( _In_ IPortableDeviceManager* deviceManager, _In_ PCWSTR pnpDeviceID) { DWORD descriptionLength = 0; // 1) Pass nullptr as the PWSTR return string parameter to get the total number // of characters to allocate for the string value. HRESULT hr = deviceManager->GetDeviceDescription(pnpDeviceID, nullptr, &descriptionLength); if (FAILED(hr)) { wprintf(L"! Failed to get number of characters for device description, hr = 0x%lx\n", hr); } else if (descriptionLength > 0) { // 2) Allocate the number of characters needed and retrieve the string value. PWSTR description = new (std::nothrow) WCHAR[descriptionLength]; if (description != nullptr) { ZeroMemory(description, descriptionLength * sizeof(WCHAR)); hr = deviceManager->GetDeviceDescription(pnpDeviceID, description, &descriptionLength); if (SUCCEEDED(hr)) { wprintf(L"Description: %ws\n", description); } else { wprintf(L"! Failed to get device description, hr = 0x%lx\n", hr); } // Delete the allocated description string delete [] description; description = nullptr; } else { wprintf(L"! Failed to allocate memory for the device description string\n"); } } else { wprintf(L"The device did not provide a description.\n"); } } // Enumerates all Windows Portable Devices, displays the friendly name, // manufacturer, and description of each device. This function also // returns the total number of devices found. DWORD EnumerateAllDevices() { DWORD pnpDeviceIDCount = 0; ComPtr deviceManager; // CoCreate the IPortableDeviceManager interface to enumerate // portable devices and to get information about them. // HRESULT hr = CoCreateInstance(CLSID_PortableDeviceManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceManager)); if (FAILED(hr)) { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = 0x%lx\n", hr); } // // 1) Pass nullptr as the PWSTR array pointer to get the total number // of devices found on the system. // if (SUCCEEDED(hr)) { hr = deviceManager->GetDevices(nullptr, &pnpDeviceIDCount); if (FAILED(hr)) { wprintf(L"! Failed to get number of devices on the system, hr = 0x%lx\n", hr); } } // Report the number of devices found. NOTE: we will report 0, if an error // occured. wprintf(L"\n%u Windows Portable Device(s) found on the system\n\n", pnpDeviceIDCount); // // 2) Allocate an array to hold the PnPDeviceID strings returned from // the IPortableDeviceManager::GetDevices method // if (SUCCEEDED(hr) && (pnpDeviceIDCount > 0)) { PWSTR* pnpDeviceIDs = new (std::nothrow) PWSTR[pnpDeviceIDCount]; if (pnpDeviceIDs != nullptr) { ZeroMemory(pnpDeviceIDs, pnpDeviceIDCount * sizeof(PWSTR)); DWORD retrievedDeviceIDCount = pnpDeviceIDCount; hr = deviceManager->GetDevices(pnpDeviceIDs, &retrievedDeviceIDCount); if (SUCCEEDED(hr)) { _Analysis_assume_(retrievedDeviceIDCount <= pnpDeviceIDCount); // For each device found, display the devices friendly name, // manufacturer, and description strings. for (DWORD index = 0; index < retrievedDeviceIDCount; index++) { wprintf(L"[%u] ", index); DisplayFriendlyName(deviceManager.Get(), pnpDeviceIDs[index]); wprintf(L" "); DisplayManufacturer(deviceManager.Get(), pnpDeviceIDs[index]); wprintf(L" "); DisplayDescription(deviceManager.Get(), pnpDeviceIDs[index]); } } else { wprintf(L"! Failed to get the device list from the system, hr = 0x%lx\n", hr); } // // Free all returned PnPDeviceID strings by using CoTaskMemFree. // NOTE: CoTaskMemFree can handle nullptr pointers, so no nullptr // check is needed. for (DWORD index = 0; index < pnpDeviceIDCount; index ++) { CoTaskMemFree(pnpDeviceIDs[index]); pnpDeviceIDs[index] = nullptr; } // Delete the array of PWSTR pointers delete [] pnpDeviceIDs; pnpDeviceIDs = nullptr; } else { wprintf(L"! Failed to allocate memory for PWSTR array\n"); } } return pnpDeviceIDCount; } // Creates and populates an IPortableDeviceValues with information about // this application. The IPortableDeviceValues is used as a parameter // when calling the IPortableDevice::Open() method. void GetClientInformation( _Outptr_result_maybenull_ IPortableDeviceValues** clientInformation) { // Client information is optional. The client can choose to identify itself, or // to remain unknown to the driver. It is beneficial to identify yourself because // drivers may be able to optimize their behavior for known clients. (e.g. An // IHV may want their bundled driver to perform differently when connected to their // bundled software.) // CoCreate an IPortableDeviceValues interface to hold the client information. // HRESULT hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(clientInformation)); // // if (SUCCEEDED(hr)) { // Attempt to set all bits of client information hr = (*clientInformation)->SetStringValue(WPD_CLIENT_NAME, CLIENT_NAME); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CLIENT_NAME, hr = 0x%lx\n", hr); } hr = (*clientInformation)->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, CLIENT_MAJOR_VER); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CLIENT_MAJOR_VERSION, hr = 0x%lx\n", hr); } hr = (*clientInformation)->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, CLIENT_MINOR_VER); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CLIENT_MINOR_VERSION, hr = 0x%lx\n", hr); } hr = (*clientInformation)->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, CLIENT_REVISION); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CLIENT_REVISION, hr = 0x%lx\n", hr); } // Some device drivers need to impersonate the caller in order to function correctly. Since our application does not // need to restrict its identity, specify SECURITY_IMPERSONATION so that we work with all devices. hr = (*clientInformation)->SetUnsignedIntegerValue(WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDeviceValues, hr = 0x%lx\n", hr); } // } // Calls EnumerateDevices() function to display devices on the system // and to obtain the total number of devices found. If 1 or more devices // are found, this function prompts the user to choose a device using // a zero-based index. void ChooseDevice( _Outptr_result_maybenull_ IPortableDevice** device) { *device = nullptr; HRESULT hr = S_OK; UINT currentDeviceIndex = 0; DWORD pnpDeviceIDCount = 0; PWSTR* pnpDeviceIDs = nullptr; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr deviceManager; ComPtr clientInformation; // Fill out information about your application, so the device knows // who they are speaking to. GetClientInformation(&clientInformation); // Enumerate and display all devices. pnpDeviceIDCount = EnumerateAllDevices(); if (pnpDeviceIDCount > 0) { // Prompt user to enter an index for the device they want to choose. wprintf(L"Enter the index of the device you wish to use.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (SUCCEEDED(hr)) { currentDeviceIndex = static_cast(_wtoi(selection)); if (currentDeviceIndex >= pnpDeviceIDCount) { wprintf(L"An invalid device index was specified, defaulting to the first device in the list.\n"); currentDeviceIndex = 0; } } else { wprintf(L"An invalid device index was specified, defaulting to the first device in the list.\n"); currentDeviceIndex = 0; } // CoCreate the IPortableDeviceManager interface to enumerate // portable devices and to get information about them. hr = CoCreateInstance(CLSID_PortableDeviceManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceManager)); if (FAILED(hr)) { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = 0x%lx\n", hr); } // Allocate an array to hold the PnPDeviceID strings returned from // the IPortableDeviceManager::GetDevices method if (SUCCEEDED(hr) && (pnpDeviceIDCount > 0)) { pnpDeviceIDs = new (std::nothrow)PWSTR[pnpDeviceIDCount]; if (pnpDeviceIDs != nullptr) { ZeroMemory(pnpDeviceIDs, pnpDeviceIDCount * sizeof(PWSTR)); DWORD retrievedDeviceIDCount = pnpDeviceIDCount; hr = deviceManager->GetDevices(pnpDeviceIDs, &retrievedDeviceIDCount); if (SUCCEEDED(hr)) { _Analysis_assume_(retrievedDeviceIDCount <= pnpDeviceIDCount); // // CoCreate the IPortableDevice interface and call Open() with // the chosen PnPDeviceID string. hr = CoCreateInstance(CLSID_PortableDeviceFTM, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(device)); if (SUCCEEDED(hr)) { hr = (*device)->Open(pnpDeviceIDs[currentDeviceIndex], clientInformation.Get()); if (hr == E_ACCESSDENIED) { wprintf(L"Failed to Open the device for Read Write access, will open it for Read-only access instead\n"); clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ); hr = (*device)->Open(pnpDeviceIDs[currentDeviceIndex], clientInformation.Get()); } if (FAILED(hr)) { wprintf(L"! Failed to Open the device, hr = 0x%lx\n", hr); // Release the IPortableDevice interface, because we cannot proceed // with an unopen device. (*device)->Release(); *device = nullptr; } } else { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDeviceFTM, hr = 0x%lx\n", hr); } // } else { wprintf(L"! Failed to get the device list from the system, hr = 0x%lx\n", hr); } // Free all returned PnPDeviceID strings by using CoTaskMemFree. // NOTE: CoTaskMemFree can handle nullptr pointers, so no nullptr // check is needed. // for (DWORD index = 0; index < pnpDeviceIDCount; index ++) { CoTaskMemFree(pnpDeviceIDs[index]); pnpDeviceIDs[index] = nullptr; } // Delete the array of PWSTR pointers delete [] pnpDeviceIDs; pnpDeviceIDs = nullptr; // } else { wprintf(L"! Failed to allocate memory for PWSTR array\n"); } } } // If no devices were found on the system, just exit this function. }