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.)
//
// Name: genCSinc.js
// Copyright: Microsoft 2006
// Revision: 1.0
//
// This script can be used to generate a C# .cs file that contains
// the equivalent WPD property-keys and GUIDs as defined in
// portabledevice.h
// This script is provided as-is and Microsoft does not assume any
// liability. This script may be redistributed as long as the file
// contains these terms of use unmodified.
//
// Usage:
// Switch to the folder where portabledevice.h is present and then run
// cscript //nologo genCSinc.js
// This will generate portabledeviceconstants.cs. This .cs file can
// then be included in a C# project.
// To use the propertykeys and the GUIDs, add "using PortableDeviceConstants;"
// to the target file.
// Propertykeys can then be referenced as PortableDevicePKeys.desired_prop_name
// e.g. PortableDevicePKeys.WPD_PROPERTY_COMMON_HRESULT
// GUIDs can be referenced as PortableDeviceGuids.desired_GUID_name
// e.g. PortableDeviceGuids.WPD_OBJECT_FORMAT_ALL
//
//
// Use FSO to read/write input/output
//
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = null;
var fOut = null;
var sIn = "portabledevice.h";
var sOut = "portabledeviceconstants.cs";
//
// Check for input file
//
try
{
f = fso.OpenTextFile(sIn);
}
catch(e)
{
WScript.Echo("Expected portabledevice.h to be in the current folder!");
}
//
// Check for output file
//
try
{
fOut = fso.OpenTextFile(sOut, 2, true);
}
catch(e)
{
WScript.Echo("Cannot open " + sOut + " for writing!");
}
//
// Write out header
//
fOut.Write("\
using System;\r\n\
\r\n\
namespace PortableDeviceConstants\r\n\
{\r\n\
class PortableDevicePKeys\r\n\
{\r\n\
static PortableDevicePKeys()\r\n\
{\r\n\
");
//
// RegEx declarations for PKEYs and GUIDs
//
//e.g. DEFINE_PROPERTYKEY( WPD_CLIENT_MINOR_VERSION , 0x204D9F0C, 0x2292, 0x4080, 0x9F, 0x42, 0x40, 0x66, 0x4E, 0x70, 0xF8, 0x59 , 4 );
var rePKEY = /\s*DEFINE_PROPERTYKEY\(\s*(\w+)\s*,\s*(.+)\s*,\s*(\d+)\s*\);/;
var arrPKEY = new Array();
//e.g. DEFINE_GUID(WPD_EVENT_DEVICE_RESET, 0x7755CF53, 0xC1ED, 0x44F3, 0xB5, 0xA2, 0x45, 0x1E, 0x2C, 0x37, 0x6B, 0x27 );
var reGUID = /\s*DEFINE_GUID\((\w+),\s(.+)\s\);/;
var arrGUID = new Array();
//
// Parse the file
//
while (!f.AtEndOfStream)
{
var l = f.ReadLine();
//
// Check for PKEYs
//
if (l.match(rePKEY))
{
//
// Write out initializations for the PKEYs
//
var sName = l.replace(rePKEY, "$1");
var sGUID = l.replace(rePKEY, "$2");
var sPID = l.replace(rePKEY, "$3");
//WPD_CLIENT_NAME.fmtid = new Guid(0x204D9F0C, 0x2292, 0x4080, 0x9F, 0x42, 0x40, 0x66, 0x4E, 0x70, 0xF8, 0x59);
//WPD_CLIENT_NAME.pid = 2;
fOut.Write(" " + sName + ".fmtid = new Guid( " + sGUID + ");\r\n");
fOut.Write(" " + sName + ".pid = " + sPID + ";\r\n");
fOut.Write("\r\n");
//
// Save the PKEY name for declaration at class level
//
arrPKEY.push(sName);
}
else if (l.match(reGUID))
{
//
// Save the GUIDs since they go into a second class
//
var sName = l.replace(reGUID, "$1");
var sGUID = l.replace(reGUID, "$2");
arrGUID.push("public static Guid " + sName + " = new Guid( " + sGUID + " );");
}
}
//
// Write out declarations for PKEYs
//
fOut.Write(" }\r\n\r\n");
for (var i = 0; i < arrPKEY.length; i++)
{
fOut.Write(" " + "public static PortableDeviceApiLib._tagpropertykey " + arrPKEY[i] + ";\r\n");
}
fOut.Write("\
} // class PortableDevicePKeys\r\n\
");
//
// Write out GUIDs
//
fOut.Write("\r\n\r\n");
fOut.Write("\
class PortableDeviceGuids\r\n\
{\r\n\
");
for (var i = 0; i < arrGUID.length; i++)
{
fOut.Write(" " + arrGUID[i] + "\r\n");
}
//
// Write out footer
//
fOut.Write("\
} // class PortableDeviceGuids\r\n\
} // namespace PortableDeviceConstants\r\n\
");
WScript.Echo("Done: " + sOut + " now contains C# WPD constants");
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).
Comments
Anonymous
December 11, 2006
Since setting a WPD property requires manipulating a PROPVARIANT structure through interop, we must makeAnonymous
November 26, 2007
This article was written for application developers who are interested in displaying portable deviceAnonymous
November 26, 2007
This article was written for application developers who are interested in displaying portable deviceAnonymous
February 15, 2011
thanx tons for your special blog' but howdo i get the PortableDevice.h ?????????????