Перечисление переносных устройств Windows в С#
Я пытаюсь перечислить подключенные переносные устройства в Windows с помощью API Windows Portable Devices и PortableDeviceManager, предоставляемых этим API.
Я реализовал перечисление идентификаторов устройств после документации MSDN ссылка и различных блогов , но все они приводят к одной и той же проблеме - я могу получить ее, чтобы дать мне идентификатор одного устройства, если есть несколько подключенных.
Вот фрагмент кода С#, который я использую:
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-накопитель и одна цифровая камера. Когда оба они активны, будет возвращен только идентификатор устройства моей камеры. Когда я деактивирую камеру, возвращается идентификатор устройства съемного USB-накопителя.
Есть ли у кого-нибудь опыт работы с этим API, который может указать мне в сторону того, что я делаю неправильно?
Ответы
Ответ 1
Яран,
Взгляните на следующую публикацию команды WPD, в которой упоминается, как вы можете исправить сборку interop.
http://blogs.msdn.com/b/dimeby8/archive/2006/12/05/enumerating-wpd-devices-in-c.aspx
Чтобы быть полным, я также скажу вам ответ:
Это связано с ограничением сортировки. В этом примере кода будет обнаружено только одно устройство. Вам нужно вручную исправить сборку interop.
-
Разберите сборку 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,
-
Сохраните ИЛ и заново скомпонуйте взаимодействие с помощью команды:
ilasm pdapi.il /dll /output=Interop.PortableDeviceApiLib.dll
Восстановите свой проект. Вы можете сначала вызвать GetDevices
с параметром NULL
, чтобы получить количество устройств, а затем снова вызвать его с помощью массива, чтобы получить идентификаторы устройств.
Надеюсь, что это поможет.
Ответ 2
Одна строка Power-shell script ниже удаляет USB-кабель, прикрепленный Windows Portable Device (WPD) из операционной системы Windows Система (XP через W8/2012)
И на всякий случай, когда вы еще не начали играть с Powershell, вот эквивалентный VBScript (возможно, может быть порт на С#):
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"
Некачественный документ googleing, не найдено больше 2 ссылок.
Может быть порт на С#, используя:
var oScope = new ManagementScope(@"\\" + MachineName + @"\root\cimv2");
Ссылка:
http://squadratechnologies.wordpress.com/2013/07/24/windows-powershellvbscript-to-un-mount-a-smart-phone-or-tablet/
Ответ 3
Возможно, я ошибаюсь, но строка deviceManager.GetDevices(ref deviceIds[0], ref numberOfDevices);
для меня не имеет смысла. Если вы хотите заполнить массив строк, вы должны передать целый массив, а не только одну строку.
Я нашел сообщение на blgs.msdn.com, где передается весь массив.
string[] deviceIDs = new string[cDevices];
devMgr.GetDevices(deviceIDs, ref cDevices);
Однако это только догадывается. Надеюсь, это поможет вам.
EDIT:
Я нашел несколько примеров кода, где передается полный массив вместо первого элемента:
Например: http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/22288487-caf3-4da5-855f-6447ad9fa48d
И я обнаружил, что Импорт PortableDeviceApiLib генерирует неправильную версию Interop in VB.NET - похоже, что сборка по умолчанию по умолчанию неверна. Может быть, успешный способ - получить правильную сборку взаимодействия от кого-то и использовать ее. Или используйте другой мост между управляемым кодом (С#/VB.NET/...) и собственным кодом. С++\CLI может быть хорошим способом, если вы достаточно хороши в С++.
Я нашел Portable Device Lib проект на CodePlex - возможно, это правильный мост.
Ответ 4
WPD-.NET-Wrapper на github. Можно перечислить устройства и скопировать файлы. так что вам не нужно тратить время на кодирование. вы можете просто открыть, подключиться и скопировать...
https://github.com/kumushoq/WPD-.NET-Wrapper/blob/2d502d883b981b8bc57d32389e8280877632f6de/WindowsPortableDeviceNet/Utility.cs
Ответ 5
Просто обновление принятого ответа.
Правильная замена заключается в следующем.
GetDevices([in][out] string& marshal( lpwstr) pPnPDeviceIDs,
к
GetDevices([in][out] string[] marshal( lpwstr[]) pPnPDeviceIDs,
По Эндрю Треварроу.
Ответ 6
Я опаздываю на вечеринку, но это то, что сработало для меня:
-
Загрузите этот пакет NuGet: PortableDevices
-
Добавьте ссылки на эти 4 библиотеки COM:
- PortableDeviceClassExtension
- PortableDeviceConnectApi
- PortableDeviceTypes
- PortableDeviceApi
-
Возьмите 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();