我想使用唯一标识符来确定我的应用程序是否已移至另一台计算机。 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优秀的阅读列表显示可能没有某种方法来确定物理适配器。第一篇文章中提到的文章展示了如何根据一些简单的假设来缩减适配器的数量。第三个项目中的文章显示了如何选择连接到PCI总线的适配器,这实际上正是我想知道的。文章中提到了一些奇怪的例外,但我认为这在大多数情况下会提供答案。
谢谢大家的贡献!
答案 0 :(得分: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
生成的代码。
<强> 更新 强>
您实际上是在尝试过滤掉属于虚拟机的适配器,这不是那么容易,因为它们被模拟为物理适配器(您甚至可以在设备管理器中将它们视为物理适配器),所以你无法区分它们,例如:
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
成员的根时,我会亲自坚持{3}}硬件适配器的类不能以与PCI\\
不同的东西开始(实际上我在比较数据时的想法是相同的)
答案 1 :(得分:4)
您还可以使用GetAdaptersAddresses
库中的IP Helper API。对于Delphi翻译,Magenta Systems IP Helper Component乍一看看起来不错。