Лучший способ всегда обнаружить съемное устройство

В моем предыдущем вопросе, "Как найти уникальный порядковый номер устройства флэш-памяти?" Я закончил тем, что просил способ получить букву диска. Та проблема решена.

Однако на мой начальный вопрос не ответили. Я хотел смочь сказать съемные устройства (Карты памяти, SD-карты, (внешние жесткие диски?), и т.д.) независимо и всегда мочь распознать их снова, когда они повторно подключены. Это должно также быть возможно на любом другом компьютере. К счастью я не забочусь об отформатированных дисках (если/когда они, их рассматривают как новые диски в моей программе), таким образом, я могу использовать раздел и идентификаторы объема как часть моего распознавания? Я спрашиваю это, поскольку PNPDeviceID не уникален. Я нашел, что это зависит от аппаратных средств, читая его, посмотрите ниже изображений:

alt text

alt text

Так, что я ищу, способ обнаружить и распознать любое съемное устройство на любом использующем компьютеры следующее: 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.

Заключительное редактирование
Я считал, что разработчики могут безопасно использовать идентификатор раздела/объема для распознавания. Я могу рассчитывать на это?

Решение:
Так, начиная с чтения "уникального" идентификатора не эффективное решение, существует два способа обойти это:

  1. Сохраните скрытый файл на диске с уникальным идентификатором, который программа может распознать (сравните с локальной базой данных).
  2. Сохраните все связанное с диском на диске в форме скрытого файла настроек. Я проявил этот подход, так как сама программа не имеет никаких настроек. Все настройки на раздел. Это также делает настройки/программу портативными.

6
задан Glorfindel 23 May 2019 в 04:07
поделиться

2 ответа

У вас должна быть возможность использовать идентификатор тома в паре с общим размером диска и именем тома, чтобы определить, такой же диск или нет, хотя самого идентификатора тома должно быть достаточно.

Единственная проблема может быть в СМИ. В некоторых случаях идентификатор тома, размер диска и имя тома будут совпадать для всех копий.

РЕДАКТИРОВАТЬ Я не уверен, что вы можете полностью обойти это для всех устройств в целом. Оборудование от каждого производителя разное, и спецификации могут быть интерпретированы, поэтому серийный номер для некоторых устройств имеет значение null, а для некоторых - нет. Ваша единственная надежда - либо поставить оборудование самостоятельно, либо потребовать определенного оборудования, которое ведет себя предсказуемым образом.

Если вы можете писать на устройство, и это будет приемлемо для пользователя, вы можете создать скрытый системный файл только для чтения, содержащий уникальный идентификатор (например, guid), и использовать этот файл для сравнения. Это остановит только обычных пользователей, которые запускают окна со значениями по умолчанию (скрывают системные файлы и не проверяют отображение скрытых файлов) от копирования файла, а включение идентификатора тома, размера диска и имени тома также в вашу проверку будет настаивать на том, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить.

размер диска и имя тома также в вашей проверке будут указывать на то, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить.

размер диска и имя тома также в вашей проверке будут указывать на то, что это разрешено только для зеркального устройства. Он может не получить все экземпляры, но этого может хватить.

2
ответ дан 17 December 2019 в 07:05
поделиться

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
2
ответ дан 17 December 2019 в 07:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: