寻找物理适配器的MAC地址 [英] looking for a MAC address of a physical adapter

查看:412
本文介绍了寻找物理适配器的MAC地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用唯一标识符来确定我的应用程序是否移动到另一台计算机。 MAC地址似乎适合于这个目的。我使用的代码是这样的:

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

函数GetWMIObject(const objectName:String):IDispatch;
var
chEaten:Integer;
BindCtx:IBindCtx; //访问绑定上下文
Moniker:IMoniker; //使您可以使用昵称对象
begin
OleCheck(CreateBindCtx(0,bindCtx) );
OleCheck(MkParseDisplayName(BindCtx,StringToOleStr(objectName),chEaten,Moniker)); //将字符串转换为标识由字符串命名的对象的标记
OleCheck(Moniker.BindToObject(BindCtx,nil ,IDispatch,Result)); //绑定到指定的对象
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');
如果colItem.IPEnabled
then Item.SubItems.Add('yes')
else Item.SubItems.Add('no');
Item.SubItems.Add(VarToStrNil(colItem.SettingID));
Item.SubItems.Add(IntToStr(colItem.InterfaceIndex));
结束// if
end; // GetMacAddress //

我的机器有一个网络端口,但是这个代码找到18个网络相关端口/事物/事物其中有四个MAC地址。我认为一个网络端口应该是IP启用,以便留下两个左边(在图像中标记的MAC)。假设这样筛选的端口是正确的,索引最低的那个端口是硬件端口?





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



更新1 EJP指出可以更改MAC地址。这有点破坏了我的目的,但是正如我正在寻找一种适合大多数情况的解决方案,我决定与之一起生活。



TLama和TOndrej指出了几个解决方案。两者都有可能无法找到物理适配器的情况。



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



感谢大家的贡献!

解决方案

使用 Win32_NetworkAdapter 类。它具有 PhysicalAdapter 成员。以下示例应列出物理适配器的MAC地址:

 程序Program1; 

{$ APPTYPE CONSOLE}

使用
SysUtils,ActiveX,ComObj,Variants;

程序GetWin32_NetworkAdapterInfo;
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $ 00000020;
var
ElementCount:LongWord;
FWMIService:OleVariant;
FWbemObject:OleVariant;
EnumVariant:IEnumVARIANT;
FSWbemLocator:OleVariant;
FWbemObjectSet:OleVariant;
开始;
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;
而EnumVariant.Next(1,FWbemObject,ElementCount)= 0 do
begin
Writeln(Format('MACAddress%s',[VarToStr(FWbemObject.MACAddress)]));
FWbemObject:=未分配;
结束
结束

begin
try
CoInitialize(nil);
try
GetWin32_NetworkAdapterInfo;
finally
CoUninitialize;
结束
除了
在E:EOleException do
Writeln(Format('EOleException%s%x',[E.Message,E.ErrorCode]));
在E:异常do
Writeln(E.Classname,':',E.Message);
结束
Writeln('按Enter键退出);
Readln;
结束。

根据 WMI Delphi代码创建者



更新:



您实际上正在尝试过滤掉属于虚拟机的适配器,这不是那么容易,因为它们被仿真成为物理的(您甚至可以在设备管理器中看到它们作为物理适配器),因此您无法区分它们,例如:




  • by DHCPEnabled Win32_NetworkAdapter 类,因为甚至可以配置虚拟机,来自DHCP服务器的IP地址

  • AdapterTypeId 成员 Win32_NetworkAdapter 类,因为没有特殊类型的虚拟适配器

  • 通过 PhysicalAdapter 成员。 85%29.aspxrel =nofollow> Win32_NetworkAdapter 类,因为它们被模拟为物理的



    • 附加阅读:




      I would like to use a unique identifier to determine whether my application moved to a different computer. The MAC address seems to be suitable for this purpose. The code I use is this:

      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 //
      

      My machine has one network port, but this code finds 18 network related ports/things/whatever. Among them there are four MAC adresses. I presume that a network port should be IP enabled so that leaves two left (labeled MAC in the image). Is it correct to assume that of the ports thus filtered, the one with the lowest index is the hardware port?

      Edit in the snapshot above the Realtek adapter is the only physical adapter in the machine. The other adapter is the VirtualBox virtual adapter. The answer of TLama identifies these two adapters, but is there a way to find the address of the only Physical (Realtek) adapter?

      Update 1 EJP pointed out that the MAC address can be changed. This somewhat undermines my purpose, but as I am looking for a solution that fits most situations I decided to live with it.

      TLama and TOndrej pointed to several solutions. Both end up with a situation that a physical adapter could not be found without any doubt.

      Update 2 TLama's excellent reading list shows that there is probably not a certain way to determine the physical adapter. The article mentioned in the first bullet shows how to shrink the amount of adapters based on some simple assumptions. The article in the third bullet shows how to select the adapter connected to the PCI bus, which is in fact exactly what I wanted to know. There are some weird exceptions mentioned in the article but I think this will provide an answer in most cases.

      Thank you all for your contributions!

      解决方案

      Use the Win32_NetworkAdapter class instead. It has the PhysicalAdapter member. The following example should list you the MAC addresses of physical adapters:

      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.
      

      Based on the code generated by the WMI Delphi Code Creator.

      Update:

      You are actually trying to filter out the adapters which belongs to virtual machines, what is not that easy since they are simulated like to be as physical ones (you can even see them in Device Manager as the physical adapters), so you cannot distinguish them e.g.:

      • by the DHCPEnabled member of the Win32_NetworkAdapter class, because even virtual machines might be configured so they get IP address from a DHCP server
      • by the AdapterTypeId member of the Win32_NetworkAdapter class, since there is no special type for virtual adapters
      • by the PhysicalAdapter member of the Win32_NetworkAdapter class, because they are being simulated to be physical

      Additional reading:

      这篇关于寻找物理适配器的MAC地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆