Creating a WPD playlist object in C#


This is a C# follow-up post on the earlier C++ playlist creation post. Be sure to read the earlier post for background information on playlists and how it stores references. We will also re-use the StringToPropVariant helper function that we defined in our previous post.

To create a playlist object, the objects to be referenced should already have been transferred previously to the device. We’ll write a function that will create a brand new playlist and set the references at creation-time. Setting the references is as easy as setting a property value, specifically the WPD_OBJECT_REFERENCES property.

static void CreatePlaylistObject(
        PortableDeviceApiLib.PortableDeviceClass pPortableDevice,
        string parentID,
        string filename,
        ref string[] refObjectIDs,
        ref string newObjectID)
{
    // Get content interface required to create object
    PortableDeviceApiLib.IPortableDeviceContent pContent;
    pPortableDevice.Content(out pContent);

    // Create properties collection to send while creating object
    PortableDeviceApiLib.IPortableDeviceValues pValues =
        (PortableDeviceApiLib.IPortableDeviceValues)
            new PortableDeviceTypesLib.PortableDeviceValuesClass();

    pValues.SetStringValue(ref PortableDevicePKeys.WPD_OBJECT_PARENT_ID,
                            parentID);
    pValues.SetStringValue(ref PortableDevicePKeys.WPD_OBJECT_ORIGINAL_FILE_NAME,
                            filename);
    pValues.SetStringValue(ref PortableDevicePKeys.WPD_OBJECT_NAME,
                            filename);
    pValues.SetGuidValue(ref PortableDevicePKeys.WPD_OBJECT_FORMAT,
                            ref PortableDeviceGuids.WPD_OBJECT_FORMAT_WPLPLAYLIST);

    // References are stored in a PropVariantCollection object
    PortableDeviceApiLib.IPortableDevicePropVariantCollection pRefIDs =
        (PortableDeviceApiLib.IPortableDevicePropVariantCollection)
            new PortableDeviceTypesLib.PortableDevicePropVariantCollection();

    // Add the string object IDs to the references property
    for (int i = 0; i < refObjectIDs.Length; i++)
    {
        PortableDeviceApiLib.tag_inner_PROPVARIANT propvarValue;
        StringToPropVariant(refObjectIDs[i], out propvarValue);

        pRefIDs.Add(ref propvarValue);
    }

    // Add the references property to the property collection
    pValues.SetIPortableDevicePropVariantCollectionValue(
        ref PortableDevicePKeys.WPD_OBJECT_REFERENCES, pRefIDs);

    // Create the playlist object using the CreateObjectWithPropertiesOnly API
    // The properties to be set have already been defined in pValues
    pContent.CreateObjectWithPropertiesOnly(pValues, ref newObjectID);
}

Since the playlist object does not require any data to be transferred, we will be using the CreateObjectWithPropertiesOnly API to create it. The function takes in the parent object i.e. the location at which the playlist object should be created and the name to use for the object. The object IDs that the playlist object will reference are passed in as a string array. The function will return the object ID of the new playlist object on success.

We create an IPortableDeviceValues instance – pValues – that will hold the properties of the playlist object to be applied. We set the required parent object ID, name and format properties. To add the references, we convert each string into a PROPVARIANT using our StringToPropVariant converter. We then add the PROPVARIANT into an IPortableDevicePropVariantCollection object.

Once we are done converting the input string array of object IDs into a PropVariant collection, we add the WPD_OBJECT_REFERENCES property to the pValues values collection with the PropVariant collection as the value (which is the list of object IDs to add as a reference).

Once the properties have been prepared, we call the CreateObjectWithPropertiesOnly API and create the object. Once the API completes successfully, a new object ID is returned which is the object ID of the newly created playlist object.

Invoking this function would look something like this:

string newObjectID = "";

// Set the playlist to reference objects o1 and o2
string[] refObjectIDs = new string[2];
refObjectIDs[0] = "o1";
refObjectIDs[1] = "o2";

CreatePlaylistObject(pPortableDevice, "s10001", "hits2006.pls",
                            ref refObjectIDs, ref newObjectID);

Creating properties-only objects of other formats follows the same style. An example of another properties-only object is a Contact object – name, email, phone, etc. are just properties of the object itself. The object doesn’t have any data. You can modify the function we have just presented to use the appropriate WPD_OBJECT_FORMAT code and create a contact object.

Comments (5)

  1. hipswich says:

    Thank you very much for all the posts that I have just gone over them – reading some carefully and skimming through others.  They have given me a very good sense about what WPD is and its current status.  I am a believer of the direction that WPD is heading and I will jump on it as soon as the wrapper class library is available so WPD API can be accessed with C# seamlessly. Most of my applications have been written

    For one of my current projects that involves a Webcam and has led me to read your blog, I will stay with WIA looking forward to port the code to WPD in the future.  I have written more than a dozen applications in C++, but the overwhelming advantages offered by C#  in combination with .Net makes me shun C++ even though it is supported by WPD development tools better.  

  2. Tree says:

    I have to agree, that WPD does have poor support in .NET. The number of edits I’ve had to make to the interop assemblies to handle pointer types is now nearly a dozen, the low-level nature of the API while useful does mean wrappers for PropVariant are essential. If .NET is the future, then MS C++ developers should be designing COM interfaces with .NET in mind.

    On top of this, there are a number of formats (which appear to be standard across manufacturers) with no defined Guid in PortableDevices.h, which appear for several content types, notably the playlist type with guid {BA050000-AE6C-4804-98BA-C57B46965FE7} is the only format on a number of devices I test with. It’s easy to handle (exactly as a WPL), but it does show a little immaturity of the API these standard types are missing.

  3. Tree says:

    I would like to say many thanks to dimeby8 for this WPD blog, it has saved me a great deal of time integrating MTP device support into our app.

    I almost went back to writing a dll in C++, before I found your posts!

  4. itzmcgin says:

    Hello, I was wondering if i could just return the value of the combined o1 and o2 object IDs? I require the path for these in my application, would appreciate if you can let me know how to go along with this. Thanks.

  5. WPD C# no longer work in Windows 8.1? says:

    Thanks for the great post series about WPD. I was able to build a C# application using WPD to read images from my camera. However, the application no longer works on Windows 8.1, it always fails when getting list of devices. Any ideas? Thanks in advance