Вопрос по networking, windows, delphi, wmi, delphi-xe – ищет MAC-адрес физического адаптера

6

Я хотел бы использовать уникальный идентификатор, чтобы определить, было ли мое приложение перенесено на другой компьютер. MAC-адрес, кажется, подходит для этой цели. Код, который я использую, таков:

Procedure TForm4.GetMacAddress;
var item: TListItem;
    objWMIService : OLEVariant;
    colItems      : OLEVariant;
    colItem       : OLEVariant;
    oEnum         : IEnumvariant;
    iValue        : LongWord;
    wmiHost, root, wmiClass: string;
    i: Int32;

  function GetWMIObject(const objectName: String): IDispatch;
  var
    chEaten: Integer;
    BindCtx: IBindCtx;//for access to a bind context
    Moniker: IMoniker;//Enables you to use a moniker object
  begin
    OleCheck(CreateBindCtx(0, bindCtx));
    OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object
  end;

begin
   wmiHost       := '.';
   root          := 'root\CIMV2';
   wmiClass      := 'Win32_NetworkAdapterConfiguration';
   objWMIService := GetWMIObject(Format('winmgmts:\\%s\%s',[wmiHost,root]));
   colItems      := objWMIService.ExecQuery(Format('SELECT * FROM %s',[wmiClass]),'WQL',0);
   oEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;
   i := 0;
   while oEnum.Next(1, colItem, iValue) = 0 do
   begin
      Item := View.Items.Add;
      item.Caption := Copy (colItem.Caption, 2, 8);

      Item.SubItems.Add (colItem.Description);
      Item.SubItems.Add (colItem.ServiceName);
      Item.SubItems.Add (VarToStrNil (colItem.MACAddress));
      if (VarToStrNil(colItem.MACAddress) <> '')
         then Item.SubItems.Add ('yes')
         else Item.SubItems.Add ('no');
      if colItem.IPEnabled
         then Item.SubItems.Add ('yes')
         else Item.SubItems.Add ('no');
     Item.SubItems.Add (VarToStrNil (colItem.SettingID));
     Item.SubItems.Add (IntToStr (colItem.InterfaceIndex));
   end; // if
end; // GetMacAddress //

Моя машина имеет один сетевой порт, но этот код находит 18 сетевых портов / вещей / чего угодно. Среди них четыре MAC-адреса. Я предполагаю, что в сетевом порту должна быть включена поддержка IP, чтобы оставалось два (помечено MAC на изображении). Правильно ли предположить, что из отфильтрованных портов порт с наименьшим индексом является аппаратным портом?

Редактироват на снимке выше адаптера Realtek - единственный физический адаптер в машине. Другой адаптер - это VirtualBox Virtual Ada, Pter. Ответ TLama идентифицирует эти два адаптера, но есть ли способ найти адрес единственного физического (Realtek) адаптера?

Обновление 1 EJP указал, что MAC-адрес можно изменить. Это несколько подрывает мою цель, но, поскольку я ищу решение, подходящее для большинства ситуаций, я решил с этим смириться.

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

Обновление 2ревосходный список чтения @ TLama показывает, что, вероятно, нет определенного способа определить физический адаптер. В статье, упомянутой в первом пункте, показано, как уменьшить количество адаптеров на основе простых предположений. В статье в третьем пункте показано, как выбрать адаптер, подключенный к шине PCI, и это именно то, что я хотел знать. Есть некоторые странные исключения, упомянутые в статье, но я думаю, что это даст ответ в большинстве случаев.

Спасибо всем за ваш вклад!

Панель управления Windows для начала. user207421
Хорошо, я принял ваше предложение. Благодарность Arnold
MAC-адрес не подходит для этой цели. Это может быть изменено пользователем. user207421
Извините, не могу найти. Arnold
@ EJP, есть указатели на это? Arnold

Ваш Ответ

2   ответа
7

ИспользоватьWin32_NetworkAdapter класс вместо. Это имеетPhysicalAdapter участник. В следующем примере должны быть перечислены MAC-адреса физических адаптеров:

program Program1;

{$APPTYPE CONSOLE}

uses
  SysUtils, ActiveX, ComObj, Variants;

procedure GetWin32_NetworkAdapterInfo;
const
  WbemUser = '';
  WbemPassword = '';
  WbemComputer = 'localhost';
  wbemFlagForwardOnly = $00000020;
var
  ElementCount: LongWord;
  FWMIService: OleVariant;
  FWbemObject: OleVariant;
  EnumVariant: IEnumVARIANT;
  FSWbemLocator: OleVariant;
  FWbemObjectSet: OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
  FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Win32_NetworkAdapter WHERE PhysicalAdapter = 1', 'WQL', wbemFlagForwardOnly);
  EnumVariant := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while EnumVariant.Next(1, FWbemObject, ElementCount) = 0 do
  begin
    Writeln(Format('MACAddress %s', [VarToStr(FWbemObject.MACAddress)]));
    FWbemObject := Unassigned;
  end;
end;

begin
  try
    CoInitialize(nil);
    try
      GetWin32_NetworkAdapterInfo;
    finally
      CoUninitialize;
    end;
  except
    on E:EOleException do
      Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
      Writeln(E.Classname, ':', E.Message);
  end;
  Writeln('Press Enter to exit');
  Readln;
end.

На основе кода, сгенерированногоWMI Delphi Code Creator.

Обновить

Вы на самом деле пытаетесь отфильтровать адаптеры, принадлежащие виртуальным машинам, что не так просто, поскольку они имитируются как физические (вы даже можете видеть их в диспетчере устройств как физические адаптеры), поэтому вы не можете различить их например:

посредствомDHCPEnabled членWin32_NetworkAdapter class, потому что даже виртуальные машины могут быть настроены так, чтобы они получали IP-адрес от DHCP-серверапосредствомAdapterTypeId членWin32_NetworkAdapter class, так как не существует специального типа для виртуальных адаптеровпосредствомPhysicalAdapter членWin32_NetworkAdapter класс, потому что они моделируются как физические

Дополнительное чтение:

Find only physical network adapters with WMI Win32_NetworkAdapter class - эта статья имеет хороший анализ и может удовлетворить ваши потребности (хотя я не проверял ее)

How to determine physical network adapter type using WMI - этот вопрос открыт сейчас, и это именно то, что вам нужно

How to determine MAC Address of the physical network card - есть одна идея, которая мне нравится, и я лично буду придерживаться ее, когда буду на 100% уверен, что кореньPNPDeviceID member
изWin32_NetworkAdapter класс для аппаратных адаптеров не может начинаться с чего-то отличного отPCI\\ (фактически то же самое, о чем я думал, когда сравнивал данные)

Кажется, я думал, чтоsimilar way. Боюсь, что эти адаптеры в Windows обрабатываются как настоящие физические сетевые адаптеры, поэтому без этого хитрого способа невозможно отличить их от аппаратных. TLama
Я экспериментировал с библиотекой IP Helper, на которую указывал TOndrej. Структура AdapterInfo также содержит слишком мало информации. Хотя это интересный код, если вы не хотите зависеть от WMI. Arnold
Я надеялся больше наPNPDeviceID где корень будетPCI\... например, но я не знаю, подойдет ли это для USB-адаптеров (если таковые имеются), но это все же не такое гладкое решение. Виртуальные адаптеры похожи на настоящие аппаратные, поэтому их довольно сложно отличить. Я искал похожие темы по этому поводу, но, похоже, никто не решил это чисто. TLama
TheManufacturer находится вWin32_NetworkAdapter класс, а неWin32_NetworkAdapterConfiguration, так и должно бытьSELECT * FROM Win32_NetworkAdapter WHERE Manufacturer != "Microsoft". В любом случае, лучшее, что вы можете сделать, это загрузить последнюю версию RRUWMI Delphi Code Creator, он также включает в себя редактор запросов, где вы можете создавать запросы, а также создавать полный код Delphi. TLama
Спасибо за разъяснения и за указатель на RRUZ. Я использую PNPDeviceID сейчас, если это ничего не дает, вероятно, это виртуальная машина, и я беру первую доступную. Чтобы проверить, работает ли он при любых обстоятельствах, мне нужно протестировать сотни машин. Во всяком случае, это отвечает на мой вопрос, большое спасибо за вашу помощь и объяснение! Arnold
4

GetAdaptersAddresses API отIP Helper библиотека. Для перевода Delphi,Magenta Systems IP Helper Component выглядит хорошо с первого взгляда.

Спасибо за указатель. Интересный код, но, насколько я вижу, результат примерно такой же, как и для WMI-класса «Win32_NetworkAdapterConfiguration», в результате получается один и тот же вывод: два порта, которые действуют как физический адаптер. Arnold

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