How to get MTP device Available Storage & Storage Capacity using C#?

940 views Asked by At

I am using PortableDevice API to get the MTP Device detection and Device properties. I want to get the MTP Device Storage like capacity of storage and available storage.Here is my sample code for getting the friendly name of the device is,

public string FriendlyName
    {
        get
        {
            if (!this._isConnected)
            {
                throw new InvalidOperationException("Not connected to device.");
            }

            // Retrieve the properties of the device
            IPortableDeviceContent content;
            IPortableDeviceProperties properties;
            this._device.Content(out content);
            content.Properties(out properties);

            // Retrieve the values for the properties
            IPortableDeviceValues propertyValues;
            properties.GetValues("DEVICE", null, out propertyValues);

            // Identify the property to retrieve
            var property = new _tagpropertykey();
            property.fmtid = new Guid(0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B,
                                      0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC);
            property.pid = 12;

            // Retrieve the friendly name
            string propertyValue;
            propertyValues.GetStringValue(ref property, out propertyValue);

            return propertyValue;
        }
    }

Same way I want to read the Device storage and free space from the MTP device.

I tried like this, but I am missing some thing,

IPortableDeviceKeyCollection keys;
        properties.GetSupportedProperties(objectId, out keys);

        IPortableDeviceValues values;
        properties.GetValues(objectId, keys, out values);

        // Get the name of the object
        string name;
        var property = new _tagpropertykey();            
        property.fmtid = new Guid(0x01A3057A, 0x74D6, 0x4E80, 0xBE, 0xA7, 0xDC, 0x4C, 0x21, 0x2C, 0xE5, 0x0A);
        property.pid = 7;
        values.GetStringValue(property, out name);

        // Get the type of the object
        Guid contentType;
        property = new _tagpropertykey();

        property.fmtid = new Guid(0x01A3057A, 0x74D6, 0x4E80, 0xBE, 0xA7, 0xDC, 0x4C, 0x21, 0x2C, 0xE5, 0x0A);

        property.pid = 5;
        values.GetGuidValue(property, out contentType);

        var storageType = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);

        var functionalType = new Guid(0x8F052D93, 0xABCA, 0x4FC5, 0xA5, 0xAC, 0xB0, 0x1D, 0xF4, 0xDB, 0xE5, 0x98);

...................................... ...................................

Thanks in advance.

1

There are 1 answers

1
Malte N. On
//Collecting the supported keys
IPortableDeviceKeyCollection keys;
properties.GetSupportedProperties(objectId, out keys);

//Init
_tagpropertykey key = new _tagpropertykey();
uint count = 0;
keys.GetCount(ref count);

//temporarily store each key and display
for (uint i = 0; i < count; i++)
{
    keys.GetAt(i, ref key);
    Console.WriteLine("fmtid " + key.fmtid + " pid " + key.pid);
}

Just FYI this is some code to display supported propertykeys. If you pass the objectID not of the root folder, but of the first folder (in Explorer for example Internal Storage), you'll see

WPD_STORAGE_CAPACITY _tagpropertykey

I highly recommend to make a class to store all PropertyKeys¹, it will do it much better looking.

I think you probably should take a glance at cgeers tutorials, so I will take that as a base.

  1. Add a Root folder to your PortableDevice class for easy access:

    private readonly PortableDeviceFolder root = new PortableDeviceFolder("DEVICE", "DEVICE");
    public PortableDeviceFolder Root
    {
        get
        {
            return root;
        }
    }
    
  2. Use that code for your folder objectId (as mentioned before for example Internal Storage)

    IPortableDeviceProperties properties;
    content.Properties(out properties);
    
    IPortableDeviceValues values;
    properties.GetValues(objectId, keys, out values);
    
    //capacity stored as UI8 in PropVariant as stated in ² -> ulong
    ulong capacity = 0;
    values.GetUnsignedLargeIntegerValue(WPD_STORAGE_CAPACITY_IN_OBJECTS, out capacity); 
    

This code is very similar to parts of the Refresh method (and submethods) from cgeers, so your folder object has already to be created.

The fact that you can retrieve this information from this folder is either pure knowledge/common sense (Win Explorer also shows the information on that folder) or can be learned by executing the first code lines at the top.

I - for myself - changed the PortableDeviceFolder structure, which now contains a Collection of PortableDeviceObjects which are in the folder and each one also saves its parent.
Like that the access on folders is very easy, for example to get your desired folderId I'd just use this code:

PortableDeviceCollection c = new PortableDeviceCollection();
c.Refresh();
PortableDevice device = c.First();
device.Root.RefreshFiles();
PortableDeviceFolder internalstorageFolder = (PortableDeviceFolder)device.Root.Files.First();

You can try to implement a structure like this yourself or go a completely other way, I think there is no perfect structure for access, so one needs to figure out what fits best.

¹: https://github.com/gtaglang/WpdLib/blob/master/src/WpdLib/WpdProperties.cs

²: https://msdn.microsoft.com/de-de/library/ff597918(v=vs.85).aspx