Welcome to MSDN Blogs Sign in | Join | Help

Change ‘Unidentified network’ from Public to Work in Windows 7

There isn’t an easy way to set the category of an Unidentified network in Windows 7 RC+ builds. By default, an Unidentified network will be set to Public for security. Often, the Unidentified network is setup intentionally (e.g. two machines connected via a hub; a network TV tuner, etc.). In these cases, Home/Work is a better category to allow common network tasks to succeed.

Below is a Powershell script to change the category from Public to Work (identical to Home, except Homegroup won’t be started up). You need to be already connected to the ‘Unidentified network’ prior to running this script.

 

  1. Save the script locally as ChangeCategory.ps1 (say under c:\)
  2. Launch an elevated Powershell command window
  3. Change your execution policy to allow the script to run (if not already changed)
    PS> set-executionpolicy remotesigned
  4. Run the script
    PS> c:\ChangeCategory.ps1

At the end of this, the category for the Unidentified network will show as Work in Network and Sharing Center. This setting is not persisted across re-connects and you will require to run the script again to change the category. Be sure to run the script only for networks that you trust since this affects the firewall profile that will be used.

Posted by dimeby8 | 1 Comments

Where is wpdmtpextensions.h?

The header file - Wpdmtpextensions.h - has been referenced in several of my posts and is needed to talk MTP to the device through WPD. The header file is not available in the Vista SDK/WDK or the WMP 11 SDK, but is planned for inclusion in the Windows Server code name "Longhorn" SDK.

I've just received a heads-up from the WPD team that the Server SDK has been published as a Beta (link). Once you install the Server SDK, you can copy over wpdmtpextensions.h file to your desired SDK (e.g. Vista SDK/Visual Studio SDK) include folder if needed. 

Posted by dimeby8 | 0 Comments
Filed under: ,

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.

Posted by dimeby8 | 3 Comments
Filed under: ,

Creating WPD PROPVARIANTs in C# without using interop

Previous posts have covered how to create, manage and marshal PROPVARIANTs using interop. Here's a way on how to create a PROPVARIANT without interop.

The IPortableDeviceValues interface exposes a SetStringValue method that allows a regular C# string to be added into the collection. IPortableDeviceValues also exposes a GetValue method which lets us retrieve any added property value as a PROPVARIANT. Armed with these two facts, it's pretty obvious how we can manufacture a string PROPVARIANT.

static void StringToPropVariant(string value,
        out PortableDeviceApiLib.tag_inner_PROPVARIANT propvarValue)
{
    // We'll use an IPortableDeviceValues object to transform the
    // string into a PROPVARIANT
    PortableDeviceApiLib.IPortableDeviceValues pValues =
        (PortableDeviceApiLib.IPortableDeviceValues)
            new PortableDeviceTypesLib.PortableDeviceValuesClass();

    // We insert the string value into the IPortableDeviceValues object
    // using the SetStringValue method
    pValues.SetStringValue(ref PortableDevicePKeys.WPD_OBJECT_ID, value);

    // We then extract the string into a PROPVARIANT by using the 
    // GetValue method
    pValues.GetValue(ref PortableDevicePKeys.WPD_OBJECT_ID, 
                                out propvarValue);
}

We create an instance of an IPortableDeviceValues object named pValues. We then call SetStringValue with a dummy property key and the string to be converted. pValues now contains exactly one item - a string value which is internally held as a PROPVARIANT. To extract the internally held PROPVARIANT, we call GetValue which returns us a PROPVARIANT value.

This example function can be extended for other PROPVARIANT types. Use Object Browser and take a look at the Set* methods exposed by IPortableDeviceValues. Follow the same paradigm - use Set*Value for your source target type and then use GetValue to extract it as a PROPVARIANT.

Posted by dimeby8 | 3 Comments
Filed under: ,

Connecting to a WPD device in C#

This is the C# equivalent of an earlier C++ post on connecting to a WPD device. We'll concentrate on the implementation here - you may refer back to that earlier post for further explanation.

// Create our client information collection
PortableDeviceApiLib.IPortableDeviceValues pValues = 
        (PortableDeviceApiLib.IPortableDeviceValues)
            new PortableDeviceTypesLib.PortableDeviceValuesClass();

// We have to provide at the least our name, version, revision
pValues.SetStringValue(
        ref PortableDevicePKeys.WPD_CLIENT_NAME, "Sample Client");
pValues.SetUnsignedIntegerValue(
        ref PortableDevicePKeys.WPD_CLIENT_MAJOR_VERSION, 1);
pValues.SetUnsignedIntegerValue(
        ref PortableDevicePKeys.WPD_CLIENT_MINOR_VERSION, 0);
pValues.SetUnsignedIntegerValue(
        ref PortableDevicePKeys.WPD_CLIENT_REVISION, 2);

// Create a new IPortableDevice instance
PortableDeviceApiLib.PortableDeviceClass pPortableDevice = 
        new PortableDeviceApiLib.PortableDeviceClass();

// We are now ready to open a connection to the device
// We'll assume deviceID contains a valid WPD device path and connect to it
pPortableDevice.Open(deviceID, pValues);

As you can see, it's pretty straight-forward to open a connection to a WPD device. We will set up our client information in a PortableDeviceValues collection and then send in the collection to the Open API call. If the device ID was valid, then a device connection will be opened and we can begin to use pPortableDevice to communicate with the device.

Posted by dimeby8 | 1 Comments

Marshalling variant properties in C#

This post is a continuation of the one covering WPD property retrieval in C#. That post explained how to marshal strings and the basic int properties. Handling other types such as VT_DATE and VT_BOOL is trickier so I'll try to cover them here.

VT_DATE

VT_DATE variants hold the date time value in a field of type double. So we'll need to update our C# PropVariant definition to include a double field.

[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
    [FieldOffset(0)]
    public short variantType;
    [FieldOffset(8)]
    public IntPtr pointerValue;
    [FieldOffset(8)]
    public byte byteValue;
    [FieldOffset(8)]
    public long longValue;
    [FieldOffset(8)]
    public double dateValue;
} 

Once we have a field that can hold the value, we need to convert it to something C# can understand. PROPVARIANTs are really OLE automation structures, so we can use the DateTime.FromOADate method to coerce our double into a DateTime object.

DateTime date = DateTime.FromOADate(pvValue.dateValue);

To convert from DateTime to the double value in the PropVariant, use DateTime.ToOADate.

VT_BOOL

VT_BOOL variants hold the bool value in a field of type short. So we'll need to update the C# PropVariant definition to include the short field.

[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
    [FieldOffset(0)]
    public short variantType;
    [FieldOffset(8)]
    public IntPtr pointerValue;
    [FieldOffset(8)]
    public byte byteValue;
    [FieldOffset(8)]
    public long longValue;
    [FieldOffset(8)]
    public double dateValue;
    [FieldOffset(8)]
    public short boolValue;
} 

Once we have the short field, we can convert it to a bool using Convert.ToBoolean.

bool b = Convert.ToBoolean(pvValue.boolValue);

VT_CLSID

VT_CLSID variants hold the GUID value in a field of type CLSID*. The value itself is a pointer to a blob of memory allocated using CoTaskMemAlloc. Since we are dealing with a pointer, we can use the pointerValue field to access this.

We then use PtrToStructure (similar to how we handled LPWSTR) to marshal this pointer into a Guid we can use ourselves.

Guid guid = (Guid)Marshal.PtrToStructure(pvValue.pointerValue, typeof(Guid));

StructureToPtr can be used to marshal a Guid back into the PropVariant.

 

I'll update this post if I encounter other types that require special handling. Feel free to leave a comment on any that you come across as well.

Posted by dimeby8 | 3 Comments
Filed under: ,

WPD Content Enumeration in C#

WPD content enumeration in C# is pretty close to the C++ style. Here's a basic example that enumerates the object IDs of the objects present on the device.

static void Enumerate(
    ref PortableDeviceApiLib.IPortableDeviceContent pContent,
    string parentID,
    string indent)
{
    //
    // Output object ID
    //
    Console.WriteLine(indent + parentID);

    indent += "    ";

    //
    // Enumerate children (if any)
    //
    PortableDeviceApiLib.IEnumPortableDeviceObjectIDs pEnum;
    pContent.EnumObjects(0, parentID, null, out pEnum);

    uint cFetched = 0;
    do
    {
        string objectID;
        pEnum.Next(1, out objectID, ref cFetched);

        if (cFetched > 0)
        {
            //
            // Recurse into children
            //
            Enumerate(ref pContent, objectID, indent);
        }
    } while (cFetched > 0);
}

static void StartEnumerate(
    ref PortableDeviceApiLib.PortableDeviceClass pPortableDevice)
{
    //
    // Get content interface required to enumerate
    //
    PortableDeviceApiLib.IPortableDeviceContent pContent;
    pPortableDevice.Content(out pContent);

    Enumerate(ref pContent, "DEVICE", "");
}

StartEnumerate is the entry point into the enumeration. This needs to be called with a valid opened device connection. StartEnumerate then defers to the recursive Enumerate function which requires the parent object ID to enumerate. Using the EnumObjects API, we get back the IEnumPortableDeviceObjectIDs enumerator. For each object in the enumeration, we call Enumerate again.

Caveats:

  • IEnumPortableDeviceObjectIDs::Next allows more than one object IDs to be returned. We don't take advantage of this optimization since the default interop doesn't handle the array very well. If you need to use this, you will have to edit the interop by hand and fix up the assembly to handle the array correctly.
Posted by dimeby8 | 0 Comments
Filed under: ,

Setting WPD properties in C#

Since setting a WPD property requires manipulating a PROPVARIANT structure through interop, we must make use of the marshalling rules we set in our last post.

We'll take a look at a function that allows string properties to be set.

static void SetStringValue(
    PortableDeviceApiLib.PortableDeviceClass pPortableDevice,
    string objectID,
    ref PortableDeviceApiLib._tagpropertykey propKey,
    string newValue)
{
    //
    // Retrieve IPortableDeviceContent interface required to
    // obtain the IPortableDeviceProperties interface
    //
    PortableDeviceApiLib.IPortableDeviceContent pContent;
    pPortableDevice.Content(out pContent);

    //
    // Retrieve IPortableDeviceProperties interface required
    // to get all the properties
    //
    PortableDeviceApiLib.IPortableDeviceProperties pProperties;
    pContent.Properties(out pProperties);

    //
    // Create the Values collection to hold the value to be set
    //
    PortableDeviceApiLib.IPortableDeviceValues pSetValues = 
        (PortableDeviceApiLib.IPortableDeviceValues)
            new PortableDeviceTypesLib.PortableDeviceValuesClass();

    //
    // Use the C# PropVariant definition to set the string value
    //
    PropVariant pvSet = new PropVariant();
    pvSet.variantType = 31; // VT_LPWSTR
    pvSet.pointerValue = Marshal.StringToCoTaskMemUni(newValue);

    //
    // Marshal our definition into a pointer
    //
    IntPtr ptrValue = Marshal.AllocHGlobal(Marshal.SizeOf(pvSet));
    Marshal.StructureToPtr(pvSet, ptrValue, false);

    //
    // Marshal pointer into the interop PROPVARIANT 
    //
    PortableDeviceApiLib.tag_inner_PROPVARIANT ipSet =
      (PortableDeviceApiLib.tag_inner_PROPVARIANT)
        Marshal.PtrToStructure(ptrValue, typeof(PortableDeviceApiLib.tag_inner_PROPVARIANT));

    //
    // Call the SetValues API to set the specified property
    //
    pSetValues.SetValue(ref propKey, ref ipSet);

    PortableDeviceApiLib.IPortableDeviceValues pResults;
    pProperties.SetValues(objectID, pSetValues, out pResults);
}

The example assumes that a device connection has already been opened. For this function to build, the PropVariant definition needs to be present and PortableDeviceConstants.cs needs to be part of the project.

We first acquire the IPortableDeviceProperties interface since that exposes the SetValues API method. Next we prepare the PROPVARIANT of vartype VT_LPWSTR that needs to be sent in. We first create an instance of the C# definition and set the pointer value to a marshalled instance of the value to be set using Marshal.StringToCoTaskMemUni. We next marshal our definition into a pointer and then re-marshal the pointer into the tag_inner_PROPVARIANT type expected by the API. This final value is then added to the values collection and this collection is sent down to the driver via the SetValues API.

This style of preparing the PROPVARIANT is common across different APIs. e.g. The Delete API expects a PropVariantCollection. All that needs to be done is prepare the PROPVARIANT using the style above and then add the prepared PROPVARIANT into a PropVariantCollection. This collection can then be sent down with the Delete API.

Posted by dimeby8 | 0 Comments
Filed under: ,

WPD property retrieval in C#

WPD property values are retrieved as PROPVARIANTs through the WPD API. Unfortunately there is no native support for PROPVARIANTs in C#. To correctly retrieve the property values (or anything that is in a PROPVARIANT) through the WPD API in C#, we must use marshalling.

PortableDeviceApiLib.tag_inner_PROPVARIANT is the data-type exposed through the WPD Interop layer. This data-type exposes the .vt member, but it does not expose the anonymous union which is the raison d'être for the PROPVARIANT structure.

To get to the union, we need to re-define the PROPVARIANT data-type in C#. We can get by with the following definition:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
    [FieldOffset(0)]
    public short variantType;
    [FieldOffset(8)]
    public IntPtr pointerValue;
    [FieldOffset(8)]
    public byte byteValue;
    [FieldOffset(8)]
    public long longValue;
} 

This follows exactly the struct layout of a PROPVARIANT. We haven't included all the PROPVARIANT fields, feel free to add them as and when you need them. For our example, we'll manage with the ones above.

Now that we have a C# specific PROPVARIANT definition, we should be able to convert back and forth to the interop version. This isn't as easy as a simple cast - we'll have to use marshalling to do this.

To convert from the interop tag_inner_PROPVARIANT to our C# PropVariant:

PortableDeviceApiLib.tag_inner_PROPVARIANT ipValue = 
                     new PortableDeviceApiLib.tag_inner_PROPVARIANT();

IntPtr ptrValue = Marshal.AllocHGlobal(Marshal.SizeOf(ipValue));
Marshal.StructureToPtr(ipValue, ptrValue, false);

PropVariant pv = (PropVariant)Marshal.PtrToStructure(p, typeof(PropVariant));

To convert from our C# PropVariant to the interop tag_inner_PROPVARIANT:

PropVariant pvValue = new PropVariant();

IntPtr ptrValue = Marshal.AllocHGlobal(Marshal.SizeOf(pvValue));
Marshal.StructureToPtr(pvValue, ptrValue, false);

PortableDeviceApiLib.tag_inner_PROPVARIANT ipValue =
    (PortableDeviceApiLib.tag_inner_PROPVARIANT)
    Marshal.PtrToStructure(ptrValue, typeof(PortableDeviceApiLib.tag_inner_PROPVARIANT));

Essentially what we are doing for both cases is getting a pointer to the original structure and then casting it back (via marshalling) to the second structure.

Now let's see this in action - we'll attempt to retrieve all the properties for the DEVICE object and display the value for all string properties.

static void DisplayProperties(
    PortableDeviceApiLib.PortableDeviceClass pPortableDevice, 
    string objectID)
{
    //
    // Retrieve IPortableDeviceContent interface required to
    // obtain the IPortableDeviceProperties interface
    //
    PortableDeviceApiLib.IPortableDeviceContent pContent;
    pPortableDevice.Content(out pContent);

    //
    // Retrieve IPortableDeviceProperties interface required
    // to get all the properties
    //
    PortableDeviceApiLib.IPortableDeviceProperties pProperties;
    pContent.Properties(out pProperties);

    //
    // Call the GetValues API, we specify null to indicate we
    // want to retrieve all properties
    //
    PortableDeviceApiLib.IPortableDeviceValues pPropValues;
    pProperties.GetValues(objectID, null, out pPropValues);

    //
    // Get count of properties
    //
    uint cPropValues = 0;
    pPropValues.GetCount(ref cPropValues);
    Console.WriteLine("Received " + cPropValues.ToString() + " properties");

    for (uint i = 0; i < cPropValues; i++)
    {
        //
        // Retrieve the property at index 'i'
        //
        PortableDeviceApiLib._tagpropertykey propKey = 
                        new PortableDeviceApiLib._tagpropertykey();
        PortableDeviceApiLib.tag_inner_PROPVARIANT ipValue = 
                        new PortableDeviceApiLib.tag_inner_PROPVARIANT();
        pPropValues.GetAt(i, ref propKey, ref ipValue);

        //
        // Allocate memory for the intermediate marshalled object
        // and marshal it as a pointer
        //
        IntPtr ptrValue = Marshal.AllocHGlobal(Marshal.SizeOf(ipValue));
        Marshal.StructureToPtr(ipValue, ptrValue, false);

        //
        // Marshal the pointer into our C# object
        //
        PropVariant pvValue = 
            (PropVariant)Marshal.PtrToStructure(ptrValue, typeof(PropVariant));

        //
        // Display the property if it a string (VT_LPWSTR is decimal 31)
        //
        if (pvValue.variantType == 31 /*VT_LPWSTR*/)
        {
            Console.WriteLine("{0}: Value is \"{1}\"", 
                (i + 1).ToString(), Marshal.PtrToStringUni(pvValue.pointerValue));
        }
        else
        {
            Console.WriteLine("{0}: Vartype is {1}", 
                (i + 1).ToString(), pvValue.variantType.ToString());
        }
        //PropVariant pv = new PropVariant(ip);
    }
}

The example assumes that a device connection has already been opened. It also assumes that the PropVariant definition (from above) is present somewhere in the class definition.

We need to start with obtaining the IPortableDeviceProperties interface. Once we have the interface, we call the GetValues API to retrieve the properties. This is in a ValuesCollection object, so we use GetAt to retrieve each property. The retrieved property is of type tag_inner_PROPVARIANT which we convert to our C# PropVariant definition using marshalling. Once we have the data in our PropVariant structure, we can reference the string by marshalling the pointer value in the PropVariant to a string object.

As an exercise, try extending this example to display the value for properties of different vartypes.  In our next post, we'll see how we can set property values.

Posted by dimeby8 | 4 Comments
Filed under: ,

Where are the WPD property keys in C#?

If you followed the exercise from our first C# post, you must have noticed that the PortableDeviceApi and PortableDeviceTypes typelibs don't expose the WPD property keys such as WPD_OBJECT_ID, WPD_OBJECT_FORMAT, etc. This can be a major blocker since for starters, we need to specify a basic set of client information properties to open a connection to the device.

If you used C++, the WPD property keys definitions could be brought in by linking against PortableDeviceGuids.lib. Linking against a C lib is not an option for a C# application. It's not even possible to generate a typelib for a C lib. The only option is to manually define each of the property keys all over again in your C# application.

The C++ PROPERTYKEY data type maps to the PortableDeviceApiLib._tagpropertykey interop data type. We can look up the PROPERTYKEY declaration in PortableDevice.h and use that to generate an equivalent C# property key object.

Let's take a look at WPD_OBJECT_ID - the C++ definition (from PortableDevice.h) is:

// 
// WPD_OBJECT_ID 
//   [ VT_LPWSTR ] Uniquely identifies object on the Portable Device. 
DEFINE_PROPERTYKEY( WPD_OBJECT_ID , 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C , 2 ); 

Mapping this to C# would result in something like:
class PortableDevicePKeys
{
    static PortableDevicePKeys()
    {
        WPD_OBJECT_ID.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
        WPD_OBJECT_ID.pid = 2;
    }

    public static PortableDeviceApiLib._tagpropertykey WPD_OBJECT_ID;
}

We can then reference the property as PortableDevicePKeys.WPD_OBJECT_ID whenever required.

Making life easier

Since defining each of these property keys by hand may cause severe RSI, here's a little script that will generate the definitions for you given PortableDevice.h. In addition to generating the property keys, it will also generate the GUID definitions (such as for WPD_FUNCTIONAL_CATEGORY_STORAGE, WPD_OBJECT_FORMAT_WMA, etc.)

Copy the script from the text-box above, paste it into Notepad and save it as gencsinc.js. Copy PortableDevice.h to the same folder as gencsinc.js and then run gencsinc.js using "cscript gencsinc.js". This will generate a PortableDeviceConstants.cs file which you may add to your C# project.

Once the generated file is added to your project, add "using PortableDeviceConstants;" to your target C# source. To reference property keys, you can simply use PortableDevicePKeys.propertyname (e.g. PortableDevicePKeys.WPD_OBJECT_ID) and to reference GUIDs, you can simply use PortableDeviceGuids.guidname (e.g. PortableDeviceGuids.WPD_OBJECT_FORMAT_WMA).

Posted by dimeby8 | 3 Comments
Filed under: ,

Flying Wiimotes

I just bought a Wii and it has totally changed my gamer attitude, and I wasn't even a gamer to start with. No more button mashing anymore - arm-swinging and flailing with some actual hand-eye coordination is what it's all about.

Of course with all the arm-thrashing, the controllers are bound to gain critical velocity and boldly go where no controller has gone before.

I guess I now need to bullet-proof my entertainment center, shatter-proof my windows and put padding on my walls.... Or maybe not - here's how a short fishing line can go a long way towards protecting you from yourself :).

Posted by dimeby8 | 1 Comments
Filed under:

Enumerating WPD devices in C#

Let's take a look at how we can enumerate WPD devices in C#. This post assumes that you already have a project set up using these instructions. (Update: You will also need to follow the disassembly/reassembly instructions below for this to work correctly.)

static void Main(string[] args)
{
    //
    // Get an instance of the device manager
    //
    PortableDeviceApiLib.PortableDeviceManagerClass devMgr 
        = new PortableDeviceApiLib.PortableDeviceManagerClass();

    //
    // Probe for number of devices
    //
    uint cDevices = 1;
    devMgr.GetDevices(null, ref cDevices);

    //
    // Re-allocate if needed
    //
    if (cDevices > 0)
    {
        string[] deviceIDs = new string[cDevices];
        devMgr.GetDevices(deviceIDs, ref cDevices);

        for (int ndxDevices = 0; ndxDevices < cDevices; ndxDevices++)
        {
            Console.WriteLine("Device[{0}]: {1}", 
                    ndxDevices + 1, deviceIDs[ndxDevices]);
        }
    }
    else
    {
        Console.WriteLine("No WPD devices are present!");
    }
}

This code maps almost line-by-line to the C++ enumeration example. We manufacture an instance of the device manager using PortableDeviceApiLib.PortableDeviceManagerClass. We then use the instance to probe how many devices are there. If you remember, the GetDevices API will return back in cDevices the number of devices (actually the size of the string array that should be specified to retrieve all the device IDs).

Once we know the number of devices, we allocate an appropriately sized array and then call GetDevices again. This time, the array will contain all the device IDs. To display them, we simply iterate over the array and print them out.

Gotchas:

  • We could use the string[]  notation since the GetDevices API returned an array of CoTaskMemAlloc'd LPWSTR strings
  • We can't use the string datatype for API calls that require a buffer allocated by the caller. GetDeviceFriendlyName is an example of this - such API calls require prior allocation of ushort[] and then on success, character-by-character conversion to a C# string.

Update

Mike R. brought to my notice that the above sample only enumerates one device even if more than one are connected. This is a marshalling restriction - we can work around it by manually fixing up the generated Interop assembly. Follow the steps below to edit the assembly:

  1. Disassemble the PortableDeviceApi interop using the command -
    ildasm Interop.PortableDeviceApiLib.dll /out:pdapi.il
  2. Open the IL in Notepad and search for the following string
    instance void  GetDevices([in][out] string&  marshal( lpwstr) pPnPDeviceIDs,
  3. Replace all instances of the string above with the following string
    instance void  GetDevices([in][out] string[]  marshal([]) pPnPDeviceIDs,
  4. Save the IL and reassemble the interop using the command -
    ilasm pdapi.il /dll /output=Interop.PortableDeviceApiLib.dll

You can now rebuild your project. You can now first call GetDevices with a NULL parameter to get the count of devices and then call it again with an array to get the device IDs.

Posted by dimeby8 | 14 Comments

C# and the WPD API

There currently is no managed/C# flavor of the WPD API. This, of course, doesn't mean that you are locked out from using the WPD API if you want to use C#. Since the API is a set of COM interfaces, we simply have to interop across from C#. Granted it isn't as easy as a native C# implementation, but it gets the job done.

This and future posts assume that you are using Visual Studio. I used 2005, but other versions should work fine.

To start, create a new C# Console Application project. Next select the "Project>Add Reference ..." menu option. Click the "COM" tab in the "Add Reference" dialog and make sure the following items are selected and then click OK:
PortableDeviceApi 1.0 Type Library
PortableDeviceTypes 1.0 Type Library

Once the references have been added, you can use the Object Browser (Ctrl+Alt+J) to check out the interesting stuff the interop brought in. You'll see two new nodes - Interop.PortableDeviceApiLib and Interop.PortableDeviceTypesLib. Under these nodes, you will find PortableDeviceApiLib and PortableDeviceTypesLib. We will need to use the latter names to reference other objects. As an exercise, spend some time comparing the objects and methods exposed through interop versus those available in WPD API through C++.

In our next post, we'll re-visit the C++ device enumeration example but with a C# twist.

Posted by dimeby8 | 2 Comments
Filed under: ,

Help! WPD API calls randomly fail with 0x800700AA (ERROR_BUSY)

If you notice your API calls are randomly failing with HRESULT_FROM_WIN32(ERROR_BUSY) / 0x800700AA / -2147024726, then it's likely that the device driver is indeed busy doing something else. It could be that WMP is syncing content to the device, or maybe Explorer needs to refresh its view and is enumerating content on the device.

So what do you do? Simply deal with it.

The fact is that the driver has a choice when an operation is requested while it is busy doing something else. It can either block the contending request or it can return right away with a special error code (in this case ERROR_BUSY).

The current driver model does not advocate a particular choice; so to play it safe, you (as a WPD client app developer) should check if the error was HRESULT_FROM_WIN32(ERROR_BUSY). In that special case, you can randomly try the operation again in a while. Alternatively, you can put up a dialog telling the user that the device is busy doing something else and the user should try again later. Or maybe you can write an asynchronous wrapper around the API which frees you from worrying about all this. Whichever choice you make, just don't treat it as a hard error and present the user with an error dialog since the user won't understand why it broke.

While special-handling ERROR_BUSY may seem to be a hack and inelegant, unfortunately the behavior is here to stay. Later iterations of the driver model may enforce/advocate an alternative behavior, but the backward-compatibility cross will still have to be carried.

Posted by dimeby8 | 2 Comments
Filed under:

Transferring playlists through WPD

A playlist (.WPL, .M3U, etc.) is a text file which contains a list of filenames. This list is the "playlist". So transferring the playlist should be easy right? Well, yes it is - if you just want to transfer it as a text file...

However if you want the playlist semantics to be sent to the device as well, you need to go an extra step (well, several extra steps :). Let's take a look.

A .WPL playlist in WPD is an object of format WPD_OBJECT_FORMAT_WPLPLAYLIST. Similar WPD formats exist for .M3U, .MPL, .ASX, etc. To associate tracks with the playlist, you must make use of the WPD_OBJECT_REFERENCES parameter. The WPD_OBJECT_REFERENCES parameter is available for most container-style formats. It is of type IPortableDevicePropVariantCollection.

Now even though WPD_OBJECT_REFERENCES is of type IPortableDevicePropVariantCollection, it can only legally hold PROPVARIANTs of a specific vartype i.e. VT_LPWSTR. Each string must correspond to a valid WPD object ID - these will be the object IDs that you want to associate with the playlist.

Assume we have the following objects already on the device.
Store
 |
 |-- o1 (Happy.wma) [WPD_OBJECT_FORMAT_WMA]
 |-- o2 (Sad.wma)   [WPD_OBJECT_FORMAT_WMA]

 

Next we want to add a playlist to the device. So we send the playlist first as a regular object of format WPLPLAYLIST.
Store
 |
 |-- o1 (Happy.wma) 
 |-- o2 (Sad.wma)
 |-- o3 (Emotions.wpl) [WPD_OBJECT_FORMAT_WPLPLAYLIST]

 

Now that we have a WPLPLAYLIST object (given by handle o3), we can set the WPD_OBJECT_REFERENCES property on it. Let's say we want to include o1 and o2 in the playlist.
LPWSTR pwszPlaylistObject = NULL;
if (hr == S_OK)
{
    // IMP: Add your code to transfer an object to the device and get back
    // a WPD object handle. We are assigning o3 just for this example
    pwszPlaylistObject = L"o3";
}

CComPtr<IPortableDeviceProperties> spProperties;
if (hr == S_OK)
{
    // IMP: Add your code to obtain the Properties interface from the
    // Device interface
}

CComPtr<IPortableDeviceValues> spValues;
CComPtr<IPortableDevicePropVariantCollection> spReferences;

if (hr == S_OK)
{
    // IMP: Add your code to CoCreate spValues and spReferences here
}

// Add o1 and o2 for the references 0 - your code will probably have
// a list of object IDs that you obtained prior by enumeration
PROPVARIANT pv = {0};
if (hr == S_OK)    
{
    pv.vt = VT_LPWSTR;
    pv.pwszVal = L"o1";
    
    hr = spReferences->Add(&pv);
}

if (hr == S_OK)    
{
    pv.vt = VT_LPWSTR;
    pv.pwszVal = L"o2";
    
    hr = spReferences->Add(&pv);
}

// Add the references to the values collection to send to the device
if (hr == S_OK)
{
    hr = spValues->SetIPortableDevicePropVariantCollectionValue(
                        WPD_OBJECT_REFERENCES, spReferences);
}

// Set the references property on the Playlist object
CComPtr<IPortableDeviceValues> spResults;
if (hr == S_OK)
{
    hr = spProperties->SetValues(pwszPlaylistObject, spValues, &spResults);
}

Briefly - you need to create an instance of a PropVariantCollection and add the object IDs that need to be part of the playlist to that collection. Next add that PropVariantCollection to the Values bag that we need to send down to the device. Be sure to specify the REFERENCES propertykey. Finally, use the SetValues API call to send the new value to the device.

Note that:

  • Your objects need to already exist on the device before they can be added to the playlist. So if you are syncing a playlist, sync the referenced content first, get the content object IDs and then sync the playlist object and set the REFERENCES property.
  • Modifying the REFERENCES property will clobber any previous value. If you need to add a new object ID, read the property first, add to the collection and then set the property back.
  • You can also set the references at the same time as playlist object creation. The CreateObject* APIs allow property values to be specified in the same call.

As a curiosity, when you transfer the playlist object to the device, you can transfer just a 0-sized object using CreateObjectWithPropertiesOnly and skip the data since it isn't going to be processed by the device anyway.

Posted by dimeby8 | 2 Comments
Filed under:
More Posts Next page »
 
Page view tracker