【问题标题】:Enumerating Windows Portable Devices in C#在 C# 中枚举 Windows 便携式设备
【发布时间】:2011-09-03 23:00:42
【问题描述】:

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

我已经按照 MSDN 文档 link 和各种博客 link 实现了设备 ID 的枚举,但它们都导致了同样的问题 - 我只能得到它来给我 one 的 ID em> 设备当有多个连接时。

这是我正在使用的 C# 代码的 sn-p:

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 有经验,可以指出我做错的方向?

【问题讨论】:

  • 对我来说,我尝试使用 PortableDeviceApiLib (COM) 但没有编译,我也没有找到任何完整的源示例工作。我也尝试使用 Win32ext_WPD 进行 WMI,但这对我来说很难。

标签: c# .net wpd


【解决方案1】:

贾兰,

查看 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

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

希望这会有所帮助。

【讨论】:

【解决方案2】:

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

正确的替换如下。

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

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

根据Andrew Trevarrow

【讨论】:

  • 仅仅因为@bash.d 对已接受答案的评论被我埋没了,请务必查看Marshalling Changes 以获取其他类似的替代品。
【解决方案3】:

下面的一行 Power-shell 脚本从 Windows 操作系统(XP 到 W8/2012)卸载连接 Windows Portable Device (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

"Select * from Win32ext_WPD where strFriendlyName = '三星-SGH-I747'"

没有很好的文档 googleing,没有找到更多的 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/

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 对我来说,不是编译,PortableDeviceApiLib; 是 COM 吗?我需要在我的 Windows 7 x64 中安装什么?
    【解决方案5】:

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

    1. 下载此 NuGet 包:PortableDevices

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

      • PortableDeviceClassExtension
      • PortableDeviceConnectApi
      • 便携式设备类型
      • PortableDeviceApi
    3. obj\Debug下的dll放入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();
    

    【讨论】:

      【解决方案6】:

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

      我找到了一个post on 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 generates incorrect Interop in VB.NET 问题 - 看起来默认互操作程序集不正确。也许成功的方法是从某人那里获得正确的互操作程序集并使用它。或者在托管代码(C#/VB.NET/...)和本机代码之间使用另一个桥梁。如果你的 C++ 足够好,C++\CLI 可能是个好方法。

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

      【讨论】:

      • 通常我会同意你的看法,但 API 不提供这样的方法。它要求您传递一个字符串指针。我的理解是,您将指针传递给数组的头部,GetDevices 方法将从该地址开始使用 cDevices 数量的设备 ID 填充数组。
      • @Jaran:问题是,“字符串”是 .NET 中的引用类型,所以如果您从数组中传递对第一个字符串的引用,则与数组中的第二个字符串没有关系。图像 - 一个字符串(一个引用)可以在 0-N 个字符串数组中。那么,哪个字符串(参考)应该是“第一个”的下一个?
      • 他们为什么要传递指针?他们只能返回结果。我只是好奇。
      • 一般情况下,字符串值可以很大。因此,仅通过参考要便宜得多。在这种情况下,您必须询问设备管理器 API 的作者。
      猜你喜欢
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 2013-05-19
      • 2014-02-22
      • 1970-01-01
      • 2013-11-24
      • 2015-12-09
      • 1970-01-01
      相关资源
      最近更新 更多