寻找物理适配器的MAC地址

我想使用一个唯一的标识符来确定我的应用程序是否移动到不同的计算机。 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 // 

我的机器有一个networking端口,但是这个代码find了18个与networking相关的端口/东西/任何东西。 其中有四个MAC地址。 我假设一个networking端口应该是IP启用,留下两个左侧(图像中标记的MAC)。 假设过滤的端口是否正确,索引最小的端口是硬件端口?

在这里输入图像说明

在上面的快照中编辑 Realtek适配器是机器中唯一的物理适配器。 另一个适配器是VirtualBox虚拟适配器。 TLama的答案确定了这两个适配器,但有没有办法find唯一的物理(Realtek)适配器的地址?

更新1 EJP指出可以更改MAC地址。 这有点破坏了我的目的,但是当我正在寻找适合大多数情况的解决scheme时,我决定和它一起生活。

TLama和TOndrej指出了几个解决scheme。 这两种情况最终都会导致无法find物理适配器的情况。

更新2 TLama的优秀阅读列表显示,可能没有确定物理适配器的确定方法。 第一个项目中提到的文章展示了如何根据一些简单的假设来缩小适配器的数量。 第三篇文章中的文章展示了如何select连接到PCI总线的适配器,这正是我想知道的。 文章中提到了一些奇怪的例外,但是我认为这将在大多数情况下提供答案。

谢谢大家的贡献!

改用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生成的WMI Delphi Code Creator

更新:

实际上,你正试图过滤掉属于虚拟机的适配器,因为它们被模拟成与物理适配器一样(你甚至可以在设备管理器中看到它们作为物理适配器),所以不容易,所以你不能区分它们例如:

  • Win32_NetworkAdapter类的DHCPEnabled成员,因为即使是虚拟机可能配置,以便他们从DHCP服务器获得IP地址
  • Win32_NetworkAdapter类的AdapterTypeId成员,因为虚拟适配器没有特殊的类型
  • Win32_NetworkAdapter类的PhysicalAdapter成员,因为他们被模拟为物理

补充阅读:

  • 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\\不同的东西(实际上是我比较数据时我正在考虑的相同)

您也可以使用IP助手库中的GetAdaptersAddresses API。 对于Delphi翻译, Magenta Systems IP Helper组件乍一看看起来不错。