Enumerating Windows Portable Devices in C#

Jaran picture Jaran · May 28, 2011 · Viewed 18.3k times · Source

I am attempting to enumerate connected portable devices on Windows using the Windows Portable Devices API and the PortableDeviceManager provided by this API.

I have implemented enumeration of device IDs following the MSDN documentation link and various blogs link, but they all result in the same issue - I can only get it to give me the ID of one device when there are several connected.

Here's the snippet of C# code I am using:

PortableDeviceManagerClass deviceManager = new PortableDeviceManagerClass();
deviceManager.RefreshDeviceList();  

uint numberOfDevices = 1;            
deviceManager.GetDevices(null, ref numberOfDevices);

if (numberOfDevices == 0)
{
    return new string[0];
}

string [] deviceIds = new string[numberOfDevices];
deviceManager.GetDevices(ref deviceIds[0], ref numberOfDevices);

return deviceIds;

I have two devices connected to my computer, one Removable USB memory stick and one digital camera. When both are active, only the device ID of my camera will be returned. When I deactivate the camera, the device ID of the removable USB stick is returned.

Is there anyone with experience with this API which can point me in the direction of what I am doing wrong?

Answer

Christophe Geers picture Christophe Geers · May 29, 2011

Jaran,

Take a look at the following post by the WPD team, it mentions how you can fix the interop assembly.

http://blogs.msdn.com/b/dimeby8/archive/2006/12/05/enumerating-wpd-devices-in-c.aspx

Just to be complete, I'll mention the answer here as well:

This is due to a marshalling restriction. This sample code will only detect one device. You need to manually fix the interop assembly.

  • Disassemble the PortableDeviceApi Interop assembly using the command:

    ildasm Interop.PortableDeviceApiLib.dll /out:pdapi.il

  • Open the IL in Notepad and search for the following string:

    instance void GetDevices([in][out] string& marshal( lpwstr) pPnPDeviceIDs,

  • Replace all instances of the string above with the following string:

    instance void GetDevices([in][out] string[] marshal([]) pPnPDeviceIDs,

  • Save the IL and reassemble the interop using the command:

    ilasm pdapi.il /dll /output=Interop.PortableDeviceApiLib.dll

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.

Hope this helps.