В моем предыдущем вопросе, "Как найти уникальный порядковый номер устройства флэш-памяти?" Я закончил тем, что просил способ получить букву диска. Та проблема решена.
Однако на мой начальный вопрос не ответили. Я хотел смочь сказать съемные устройства (Карты памяти, SD-карты, (внешние жесткие диски?), и т.д.) независимо и всегда мочь распознать их снова, когда они повторно подключены. Это должно также быть возможно на любом другом компьютере. К счастью я не забочусь об отформатированных дисках (если/когда они, их рассматривают как новые диски в моей программе), таким образом, я могу использовать раздел и идентификаторы объема как часть моего распознавания? Я спрашиваю это, поскольку PNPDeviceID не уникален. Я нашел, что это зависит от аппаратных средств, читая его, посмотрите ниже изображений:
Так, что я ищу, способ обнаружить и распознать любое съемное устройство на любом использующем компьютеры следующее: Win32_DiskDrive, Win32_DiskPartition, Win32_LogicalDisk. Я благодарю RRUZ за исходный код:
program GetWMI_USBConnectedInfo;
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
ActiveX,
Variants,
SysUtils,
WbemScripting_TLB in '..\..\Documents\RAD Studio\5.0\Imports\WbemScripting_TLB.pas';
procedure GetUSBDiskDriveInfo;
var
WMIServices : ISWbemServices;
Root,a,b : ISWbemObjectSet;
Item,Item2 : Variant;
i,ii,iii,iiii: Integer;
start,stop,freq:Int64;
begin
QueryPerformanceFrequency(freq);
QueryPerformanceCounter(start);
WMIServices := CoSWbemLocator.Create.ConnectServer('.', 'root\cimv2','', '', '', '', 0, nil);
Root := WMIServices.ExecQuery('Select * From Win32_DiskDrive','WQL', 0, nil);
for i := 0 to Root.Count - 1 do
begin
Item := Root.ItemIndex(i);
for ii := VarArrayLowBound(Item.Capabilities, 1) to VarArrayHighBound(Item.Capabilities, 1) do if (Item.Capabilities[ii] = 7) then begin
Writeln('Caption '+VarToStr(Item.Caption));
Writeln('Name '+VarToStr(Item.Name));
Writeln('DeviceID '+VarToStr(Item.DeviceID));
Writeln('Partitions '+VarToStr(Item.Partitions));
Writeln('PNPDeviceID '+VarToStr(Item.PNPDeviceID));
Writeln('SerialNumber '+VarToStr(Item.SerialNumber));
Writeln('Signature '+VarToStr(Item.Signature));
a := WMIServices.ExecQuery('ASSOCIATORS OF {Win32_DiskDrive.DeviceID=''' + VarToStr(Item.DeviceID) + '''} WHERE AssocClass = Win32_DiskDriveToDiskPartition','WQL', 0, nil);
for iiii := 0 to a.Count - 1 do begin
b := WMIServices.ExecQuery('ASSOCIATORS OF {Win32_DiskPartition.DeviceID=''' + VarToStr(Variant(a.ItemIndex(iiii)).DeviceID) + '''} WHERE AssocClass = Win32_LogicalDiskToPartition','WQL', 0, nil);
for iii := 0 to b.Count - 1 do begin
Item2 := b.ItemIndex(iii);
Writeln('Drive = ' + Item2.Caption);
end;
end;
Writeln;
Writeln;
end;
end;
QueryPerformanceCounter(stop);
if (freq > 0) then
Writeln('Time took: ' + FloatToStr((stop-start) / freq))
else
Writeln('Unable to measure time!');
end;
begin
try
CoInitialize(nil);
GetUSBDiskDriveInfo;
Readln;
CoUninitialize;
except
on E:Exception do
Begin
CoUninitialize;
Writeln(E.Classname, ': ', E.Message);
Readln;
End;
end;
end.
Править
Я должен добавить, что код, обнаруживающий диски, когда они вставляются, уже работает, хотя он только дает мне букву диска. Я использую ту букву диска для получения всех других информация от WMI.
Заключительное редактирование
Я считал, что разработчики могут безопасно использовать идентификатор раздела/объема для распознавания. Я могу рассчитывать на это?
Решение:
Так, начиная с чтения "уникального" идентификатора не эффективное решение, существует два способа обойти это:
У вас должна быть возможность использовать идентификатор тома в паре с общим размером диска и именем тома, чтобы определить, такой же диск или нет, хотя самого идентификатора тома должно быть достаточно.
Единственная проблема может быть в СМИ. В некоторых случаях идентификатор тома, размер диска и имя тома будут совпадать для всех копий.
РЕДАКТИРОВАТЬ Я не уверен, что вы можете полностью обойти это для всех устройств в целом. Оборудование от каждого производителя разное, и спецификации могут быть интерпретированы, поэтому серийный номер для некоторых устройств имеет значение null, а для некоторых - нет. Ваша единственная надежда - либо поставить оборудование самостоятельно, либо потребовать определенного оборудования, которое ведет себя предсказуемым образом.
Если вы можете писать на устройство, и это будет приемлемо для пользователя, вы можете создать скрытый системный файл только для чтения, содержащий уникальный идентификатор (например, guid), и использовать этот файл для сравнения. Это остановит только обычных пользователей, которые запускают окна со значениями по умолчанию (скрывают системные файлы и не проверяют отображение скрытых файлов) от копирования файла, а включение идентификатора тома, размера диска и имени тома также в вашу проверку будет настаивать на том, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить.
размер диска и имя тома также в вашей проверке будут указывать на то, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить. размер диска и имя тома также в вашей проверке будут указывать на то, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить.USB-устройства должны иметь уникальный идентификатор. Я успешно использовал это в прошлом из приложения .NET, и это должно работать одинаково хорошо в приложении Delphi.
Вы должны иметь возможность импортировать COM-объекты WMI в Delphi с помощью редактора библиотеки типов, таким образом вы можете используйте раннее связывание вместо вариантов.
Если вам нужен реальный образец, мне нужно будет найти код C #. Напишите мне личное сообщение или электронное письмо, если оно вам нужно.
Я только что бегло посмотрел, как это делается в .NET: вы используете Генератор строго типизированных классов управления (Mgmtclassgen.exe) , который недоступен в родном мире.
Я не уверен насчет устройств, отличных от USB. Вы ожидаете, что идентификаторы PNP будут одинаковыми для устройств, но вы заявляете, что это не так, однако я не вижу одинаковых идентификаторов PNP с разными устройствами в вашем примере (конечно, я могу упустить из виду кое-что очевидное).
- jeroen
USB-устройства имеют уникальный идентификатор.
Нашел несколько частей кода C #, в котором перечислены все USB-устройства:
public static List<DiskDrive> GetUsbDiskDrives()
{
DiskDrive.DiskDriveCollection diskDrives = DiskDrive.GetInstances("InterfaceType = 'USB'");
return DiskDriveList(diskDrives);
}
public static List<DiskDrive> DiskDriveList(DiskDrive.DiskDriveCollection diskDrives)
{
List<DiskDrive> result = new List<DiskDrive>();
foreach (DiskDrive diskDrive in diskDrives)
{
result.Add(diskDrive);
}
return result;
}
public static string Serial(DiskDrive diskDrive)
{
// pick the last portion of diskDrive.PNPDeviceID:
string[] splitted = diskDrive.PNPDeviceID.Split('\\'); // note this becomes one backslash
string result = splitted[splitted.Length - 1];
return result;
}
Вышеупомянутые части используют пространство имен .NET System.Collections.Generic, поэтому вы можете иметь общий список.
DiskDrive находится в пространстве имен Win32.WMI в файле C #, созданном с помощью этой команды:
MgmtClassGen.exe Win32_DiskDrive /oWin32.WMI