14

我正在尝试使用 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。当我停用相机时,会返回可移动 U 盘的设备 ID。

有没有人有这个 API 的经验,可以指出我做错的方向?

4

6 回答 6

19

贾兰,

看看 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 并使用以下命令重新组装互操作:

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

重建你的项目。您现在可以先使用参数调用GetDevicesNULL获取设备计数,然后使用数组再次调用以获取设备 ID。

希望这可以帮助。

于 2011-05-29T07:34:49.210 回答
3

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

正确的替换如下。

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

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

根据安德鲁·特雷瓦罗

于 2015-11-12T01:31:55.123 回答
1

下面的一行 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/

于 2014-08-26T08:46:34.727 回答
0

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

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

于 2015-07-03T09:39:42.167 回答
0

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

  1. 下载此 NuGet 包:PortableDevices

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

    • 便携式设备类扩展
    • PortableDeviceConnectApi
    • 便携式设备类型
    • 便携设备接口
  3. 将dll放在下面obj\Debug并将它们放入bin\Debug

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

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

    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;
    }

下一步是从设备中获取内容,操作如下:

var contents = device.GetContents();
于 2016-10-02T15:11:38.837 回答
-1

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

在 blgs.msdn.com 上找到了一个帖子,其中传递了整个数组。

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

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

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

于 2011-05-28T14:04:48.873 回答