在C#中枚举Windows便携设备

我试图使用Windows Portable Devices API和此API提供的PortableDeviceManager在Windows上枚举连接的便携式设备。

我已经在MSDN文档链接和各种博客链接之后实现了设备ID的枚举,但它们都导致了同样的问题 – 我只能在有多个连接时给我一个设备的ID。

这是我正在使用的C#代码片段:

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; 

我有两台设备连接到我的电脑,一台可拆卸USB记忆棒和一台数码相机。 当两者都处于活动状态时,将仅返回我的相机的设备ID。 当我取消激活相机时,将返回可移动USB记忆棒的设备ID。

是否有任何有这种API经验的人可以指出我做错的方向?

巴丹吉林,

看看WPD团队的以下文章,它提到了如何修复互操作程序集。

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

为了完整,我在这里也会提到答案:

这是由于编组限制。 此示例代码仅检测一个设备。 您需要手动修复互操作程序集。

  • 使用以下命令反汇编PortableDeviceApi Interop程序集:

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

  • 在记事本中打开IL并搜索以下字符串:

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

  • 用以下字符串替换上面的字符串的所有实例:

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

  • 保存IL并使用以下命令重新组装interop:

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

重建您的项目。 您现在可以首先使用NULL参数调用GetDevices来获取设备数,然后使用数组再次调用它以获取设备ID。

希望这可以帮助。

下面的一行Power-shell脚本从Windows操作系统(XP到W8 / 2012)卸载连接Windows便携设备(WPD)的USB电缆

如果你还没有开始玩Powershell,这里是等效的VBScript(也许可以移植到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 

注意将“SAMSUNG-SGH-I747”更改为您在Windows资源管理器中看到的手机/平板电脑名称

关于Win32ext_WPD

“从Win32ext_WPD中选择*其中strFriendlyName =’SAMSUNG-SGH-I747’”

不好的文件谷歌,没有找到更多2参考。

也许通过以下方式移植到C#:

 var oScope = new ManagementScope(@"\\" + MachineName + @"\root\cimv2"); 

参考:

http://squadratechnologies.wordpress.com/2013/07/24/windows-powershellvbscript-to-un-mount-a-smart-phone-or-tablet/

也许我错了,但行deviceManager.GetDevices(ref deviceIds[0], ref numberOfDevices); 对我来说没有意义。 如果要填充字符串数组,则应传递整个数组,而不是只传递一个字符串。

我在blgs.msdn.com上发现了一个post,其中传递了整个数组。

 string[] deviceIDs = new string[cDevices]; devMgr.GetDevices(deviceIDs, ref cDevices); 

然而,这只是猜测。 我希望,它会对你有所帮助。

编辑:我发现了几个代码示例,其中传递整个数组而不是第一项:例如: http : //social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/22288487-caf3-4da5-855f -6447ad9fa48d

我发现导入PortableDeviceApiLib在VB.NET问题中生成错误的Interop – 它看起来像默认的互操作程序集是不正确的。 也许成功的方法是从某人那里获得正确的互操作程序集并使用它。 或者在托管代码(C#/ VB.NET / …)和本机代码之间使用另一个桥梁。 如果你在C ++中足够好,那么C ++ \ CLI可能是个好方法。

我在CodePlex上找到了Portable Device Lib项目 – 也许它是正确的桥梁。

github上的WPD-.NET-Wrapper – 可以成功枚举设备和复制文件。 这样你就不必浪费时间编码了。 你可以打开,连接和复制……

https://github.com/kumushoq/WPD-.NET-Wrapper/blob/2d502d883b981b8bc57d32389e8280877632f6de/WindowsPortableDeviceNet/Utility.cs

只是对已接受答案的更新。

正确的替换如下。

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

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

按照Andrew Trevarrow的说法 。

我迟到了,但这对我有用:

  1. 下载此NuGet包: PortableDevices

  2. 添加对这4个COM库的引用:

    • PortableDeviceClassExtension
    • PortableDeviceConnectApi
    • PortableDeviceTypes
    • PortableDeviceApi
  3. obj\Debug下获取dll并将它们放入bin\Debug

    • Interop.PortableDeviceClassExtension.dll
    • Interop.PortableDeviceConnectApiLib.dll
    • Interop.PortableDeviceTypesLib.dll
    • Interop.PortableDeviceApiLib.dll

现在您可以使用以下函数列出所有设备,尽管FriendlyName似乎不起作用(它返回一个空字符串):

  private IDictionary GetDeviceIds() { var deviceIds = new Dictionary(); 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; } 

下一步是从设备获取内容,如下所示:

 var contents = device.GetContents();