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
I am late to the party, but this is what worked for me:
Download this NuGet package: PortableDevices
Add references to these 4 COM libraries:
Take the dll's under obj\Debug
and put them into bin\Debug
:
Now you can use the following function to list all devices, although FriendlyName
does not seem to be working (it returns an empty string):
private IDictionary<string, string> GetDeviceIds()
{
var deviceIds = new Dictionary<string, string>();
var devices = new PortableDeviceCollection();
devices.Refresh();
foreach (var device in devices)
{
device.Connect();
deviceIds.Add(device.FriendlyName, device.DeviceId);
Console.WriteLine(@"DeviceId: {0}, FriendlyName: {1}", device.DeviceId, device.FriendlyName);
device.Disconnect();
}
return deviceIds;
}
The next step is getting the contents from the device, which is done like so:
var contents = device.GetContents();
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.
The one line of Power-shell script below un-mounts a USB cable attached Windows Portable Device (WPD) from the Windows Operating System (XP thru W8/2012)
And just in case you have not yet started playing with Powershell, here is the equivalent VBScript (maybe be can port to C#):
Set objWMIService = GetObject ("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery ("Select * from Win32ext_WPD Where strFriendlyName = 'SAMSUNG-SGH-I747'")
For Each objItem in colItems
Set objWMIWPDStatic = objWMIService.Get("Win32ext_WPD")
Set objInParam = objWMIWPDStatic.Methods_("EjectDevice").inParameters.SpawnInstance_()
objInParam.Properties_.Item("strObjectDeviceId") = objItem.strId
Set objOutParams = objWMIService.ExecMethod("Win32ext_WPD", "EjectDevice", objInParam)
Exit For
Next
Note change ‘SAMSUNG-SGH-I747′ to the phone/tablet name you see in Windows Explorer
About Win32ext_WPD
"Select * from Win32ext_WPD Where strFriendlyName = 'SAMSUNG-SGH-I747'"
Not well document googleing, not found more 2 references.
Maybe port to C# using:
var oScope = new ManagementScope(@"\\" + MachineName + @"\root\cimv2");
Reference:
http://squadratechnologies.wordpress.com/2013/07/24/windows-powershellvbscript-to-un-mount-a-smart-phone-or-tablet/
WPD-.NET-Wrapper on github - Can enumerate devices and copy files successfully. so that you don't have to waste time coding. you can just open, connect and copy...
https://github.com/kumushoq/WPD-.NET-Wrapper/blob/2d502d883b981b8bc57d32389e8280877632f6de/WindowsPortableDeviceNet/Utility.cs
Maybe I'm wrong, but the line deviceManager.GetDevices(ref deviceIds[0], ref numberOfDevices);
does not makes sense to me. If you want fill the array of string, you should pass whole array, not only one string.
I found a post on blgs.msdn.com where is passed the whole array.
string[] deviceIDs = new string[cDevices];
devMgr.GetDevices(deviceIDs, ref cDevices);
However it's only guess. I hope, it will help you.
EDIT: I found several code samples, where is passed whole array instead of first item: For example: http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/22288487-caf3-4da5-855f-6447ad9fa48d
And I found the Importing PortableDeviceApiLib generates incorrect Interop in VB.NET issue - it looks like the default interop assembly is not correct. Maybe the successfull way is getting correct interop assembly from someone and use it. Or use some another bridge between managed code (C#/VB.NET/...) and native code. The C++\CLI could be good way if you are good enough in C++.
I found Portable Device Lib project on CodePlex - maybe it is the correct bridge.
Just an update on the accepted answer.
The correct replacement is as follows.
GetDevices([in][out] string& marshal( lpwstr) pPnPDeviceIDs,
to
GetDevices([in][out] string[] marshal( lpwstr[]) pPnPDeviceIDs,
As per Andrew Trevarrow.