寻找物理适配器的MAC地址(looking for a MAC address of a physi

2019-06-24 11:25发布

我想用一个唯一的标识符,以确定我的应用程序是否移动到不同的计算机。 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的虚拟适配器。 TLama的答案识别这两个适配器,但有没有办法找到的唯一的物理(瑞昱)适配器的地址?

更新1 EJP指出的MAC地址可以被改变。 这一定程度上破坏了我的目的,但我正在寻找一个适合我决定住它大多数情况下的解决方案。

TLama和TOndrej指出了几种解决方案。 无论最终与物理适配器不能毫无疑问地发现的情况。

更新2 TLama出色的阅读清单显示,有可能是没有一定的方法来确定物理适配器。 在第一颗子弹文章提到了如何收缩适配器基于一些简单的假设量。 在第三颗子弹的文章展示了如何选择连接到PCI总线,这实际上正是我想知道的适配器。 有文章中提到一些奇怪的例外情况,但我认为这将提供在大多数情况下的答案。

感谢大家的贡献!

Answer 1:

使用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类,因为即使虚拟机可能配置,使他们从DHCP服务器获取IP地址
  • AdapterTypeId所述的构件Win32_NetworkAdapter类,因为没有特殊类型的虚拟适配器
  • 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成员
    在的Win32_NetworkAdapter硬件适配器类不能用的东西从不同的启动PCI\\ (实际上是一样的,我想,当我比较数据)



Answer 2:

你也可以使用GetAdaptersAddresses API从IP帮助库。 对于德尔福翻译, 品红系统IP助手组件看起来不错乍一看。



文章来源: looking for a MAC address of a physical adapter