Almost all WPD devices allow content to be stored on them and this suggests that a way of organizing the content would exist. In this post we'll try understanding a typical WPD hierarchy.
When a device does allow content to be stored on it, it is through some kind of storage media. In the case of a camera, it would be a removable CF/SD card, while in the case of a media player, it could be a hard-disk. So we can generalize this into the statement - all devices that allow content to be stored have storages.
Device | |--- Storage
The above (rough-hewn) diagram shows a Storage object as being a child of the main Device object. Of course, a device may have multiple storages, so the diagram should really look like this.
Device | |--- Storage 1 | |--- Storage 2
You'll mostly see multiple storages with Pocket PC devices; although some earlier media players had a concept of fixed storage and a removable storage (for expansion) as well.
The storage can have a regular filesystem allowing files and folders to be stored on them. Files and folders are also referred to as plain objects in WPD. The format and content-type of the object decides its type. As an example, if an object had the format WPD_OBJECT_FORMAT_PROPERTIES_ONLY and the content-type WPD_CONTENT_TYPE_FOLDER, then that object would be a folder. As a second example, if an object had the format WPD_OBJECT_FORMAT_MP3 and content-type WPD_CONTENT_TYPE_AUDIO, then that object would be an MP3 file. We'll cover the subtleties of formats and content-types in a later post. A diagram showing objects would now look like this (I've dropped Storage 2 for brevity but the idea remains the same).
Device | |--- Storage 1 | |--- Object 1 | | | |--- Object 1_1 | | |--- Object 2
In WPD, when you enumerate a storage, you get back objects. You need to then interrogate the properties for the objects to figure out if they are files or folders. Each object is also uniquely identified by its WPD_OBJECT_ID property i.e. each object has a unique ID (across the device for the duration of the connection).
Some devices may support additional features (beyond just storing content) while connected to the PC. These could vary from sending SMSs to taking pictures. These are exposed through additional objects called functional objects. Functional objects are children of the main Device object. Below are some of the functional objects you may encounter for MTP devices.
StillCapture functional object
Some cameras support taking pictures while connected to the PC. For such devices, the MTP driver will report an additional StillCapture functional object under the Device object. The StillCapture functional object belongs to the WPD_FUNCTIONAL_CATEGORY_STILL_IMAGE_CAPTURE category. This StillCapture object exposes configuration properties for the camera such as Burst Number, Flash Mode, Image Format, etc. Also since this functional object exists, the WPD_COMMAND_STILL_IMAGE_CAPTURE_INITIATE command will also be supported. This command can be sent to the driver to initiate image capture.
RenderingInformation functional object
Media players can describe the formats that they support and any inter-dependent properties for each format. These are exposed through the RenderingInformation functional object and belongs to the WPD_FUNCTIONAL_CATEGORY_RENDERING_INFORMATION category. As an example, a device may report that it supports the WMA format but only in the cases when the bitrate is 192kbps and the sample-rate is 44.1khz; or the bitrate is 128kbps and the sample-rate is 48khz.
NetworkConfig functional object
Wireless cameras using the MTP/IP protocol are on the horizon (I believe this has been demo'd at WinHec 2006). The MTP driver will expose wireless configuration information for the device through the NetworkConfig functional object. This belongs to the WPD_FUNCTIONAL_CATEGORY_NETWORK_CONFIGURATION.
Storage functional object
The storage that we discussed at the start of this post is also considered a functional object belonging to the WPD_FUNCTIONAL_CATEGORY_STORAGE category.
Object Hierarchy APIs
IPortableDeviceContent::EnumObjects allows the traditional hierarchial walk-through of the WPD hierarchy. You can start with specifying the Device object ID (L"DEVICE") as the parent - this will return any functional objects. Each functional object can then be specified as the parent and the children for that functional object will be returned (this will, of course, be meaningful only for Storage objects).
IPortableDeviceCapabilities::GetFunctionalCategories is another way to discover the various functional categories supported by the device. IPortableDeviceCapabilities::GetFunctionalObjects can then be used to enumerate the actual functional objects for each category.