我想使用唯一标识符来确定我的应用程序是否移至另一台计算机。 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的答案可以识别这两个适配器,但是有没有办法找到唯一的物理(Realtek)适配器的地址?

更新1 EJP指出可以更改MAC地址。这在某种程度上破坏了我的目标,但是当我在寻找适合大多数情况的解决方案时,我决定接受它。

TLama和TOndrej指出了几种解决方案。两者最终都会导致毫无疑问地找不到物理适配器的情况。

更新2 TLama的优秀阅读 list 显示,可能没有确定物理适配器的某种方法。第一个项目符号中提到的文章展示了如何基于一些简单的假设来减少适配器的数量。第三个项目符号中的文章显示了如何选择连接到PCI总线的适配器,实际上这正是我想知道的。文章中提到了一些奇怪的异常(exception),但是我认为这将在大多数情况下提供一个答案。

谢谢大家的贡献!

最佳答案

请改用 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\\的开头时,我个人会坚持使用考虑我何时比较数据)
  • 关于windows - 寻找物理适配器的MAC地址,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10596613/

    10-14 04:47