Share via


Get Storage Information from a Portable Device using WPD

I've been doing some WPD development recently and I wanted to share some information about getting storage information from a portable device, but first I wanted to thank dimeby8 (https://blogs.msdn.com/dimeby8) for the great posts on WPD development. 

One issue with WPD development that I didn't find any reference to was getting storage information so I jumped into it by trying to use GetDiskFreeSpaceEx().  I thought that this was a safe place to start, but my assumptions got the best of me.  It turns out that WPD devices dont hook into the System Volume APIs, and you need to get storage information through the WPD Storage Properties. 

I've included a short sample below.  I hope it saves someone from making the same assumption I did.

HRESULT hr = S_OK;

DWORD cPnPDeviceIDs = 0;

LPWSTR DeviceId = NULL;

TCHAR szDebugMsg[256] = TEXT("");

     

try

{

CComPtr<IPortableDeviceManager> spDevMgr;

hr = CoCreateInstance(CLSID_PortableDeviceManager, NULL, CLSCTX_INPROC_SERVER,

IID_IPortableDeviceManager, (VOID**) &spDevMgr);

           

      // Get the device (I use a helper function here. Not shown)

DeviceId = CCommonFunctions::GetDevice(spDevMgr, deviceFriendlyName);

// Create an instance of a Values collection to hold the client information

      CComPtr<IPortableDeviceValues> spClientInfo;

hr = CoCreateInstance(CLSID_PortableDeviceValues, NULL, CLSCTX_INPROC_SERVER, IID_IPortableDeviceValues, (VOID**)&spClientInfo);

           

      // Add client information to the Values collection

      hr = spClientInfo->SetStringValue(WPD_CLIENT_NAME, L"Enumerator");

      hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, 1);

      hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, 0);

      hr = spClientInfo->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, 0);

      // Create an instance of the first WPD device

      CComPtr<IPortableDevice> spDevice;

hr = CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER, IID_IPortableDevice, (VOID**) &spDevice);

           

      // Connect to the device

      BOOL bDeviceOpened = TRUE;

hr = spDevice->Open(_bstr_t(DeviceId), spClientInfo);

CComPtr<IPortableDeviceContent> spContent;

      hr = spDevice->Content(&spContent);

           

      CComPtr<IPortableDeviceProperties> spProperties;

      hr = spContent->Properties(&spProperties);

      // Enumerate children (if any) of provided object

      CComPtr<IEnumPortableDeviceObjectIDs> spEnum;

      hr = spContent->EnumObjects(0, WPD_DEVICE_OBJECT_ID, NULL, &spEnum);

           

      // Get the first object. This should be the primary storage object

      LPWSTR pwszStorageObjectId = NULL;

      ULONG celtFetched = 0;

      hr = spEnum->Next(1, &pwszStorageObjectId, &celtFetched);

      // We'll need an IPortableDeviceKeyCollection instance

      CComPtr<IPortableDeviceKeyCollection> spKeys;

hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL, CLSCTX_INPROC_SERVER, IID_IPortableDeviceKeyCollection, (VOID**) &spKeys);

           

      //Specify the properties that we need to retrieve

      hr = spKeys->Add(WPD_STORAGE_CAPACITY);

           

      CComPtr<IPortableDeviceValues> spValues;

      hr = spProperties->GetValues(pwszStorageObjectId, spKeys, &spValues);

           

      ULONGLONG ullDiskTotalBytes = 0;

hr = spValues->GetUnsignedLargeIntegerValue(WPD_STORAGE_CAPACITY, &ullDiskTotalBytes);

      *ReturnVal = ullDiskTotalBytes;

           

      // Cleanup

      CoTaskMemFree(pwszStorageObjectId);

      ullDiskTotalBytes = NULL;

      // Close connection to the device

      if (bDeviceOpened)

      {

      hr = spDevice->Close();

      }

      // Free memory allocated by the GetDevices call

      if (DeviceId != NULL)

      {

      CoTaskMemFree(DeviceId);

      }

}

catch (_com_error &e)

{

      HRESULT _hr = e.Error();

      wsprintf(szDebugMsg, TEXT("Caught an error %08x - %s"), _hr, e.Description());

      OutputDebugString(szDebugMsg);

      AtlThrow(_hr);

}

return S_OK;