6

アプリケーションが別のコンピューターに移動したかどうかを判断するために、一意の識別子を使用したいと思います。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 //

私のマシンには1つのネットワークポートがありますが、このコードは18のネットワーク関連のポート/モノ/その他を検出します。それらの中には4つのMACアドレスがあります。ネットワークポートをIP対応にして、2つ残しておく必要があると思います(画像ではMACとラベル付けされています)。このようにフィルタリングされたポートのうち、インデックスが最も低いポートがハードウェアポートであると想定するのは正しいですか?

ここに画像の説明を入力してください

上記のスナップショットで編集するRealtekアダプターは、マシン内の唯一の物理アダプターです。もう1つのアダプターは、VirtualBox仮想アダプターです。TLamaの答えは、これら2つのアダプターを識別しますが、唯一の物理(Realtek)アダプターのアドレスを見つける方法はありますか?

アップデート1EJPは、MACアドレスを変更できると指摘しました。これは私の目的をいくらか損なうものですが、ほとんどの状況に適合する解決策を探しているので、私はそれと一緒に暮らすことにしました。

TLamaとTOndrejは、いくつかの解決策を指摘しました。どちらも、間違いなく物理アダプターが見つからないという状況になります。

Update 2 TLamaの優れた読書リストは、物理アダプターを判別する特定の方法がおそらくないことを示しています。最初の箇条書きで言及された記事は、いくつかの単純な仮定に基づいてアダプターの量を減らす方法を示しています。3番目の箇条書きの記事は、PCIバスに接続されているアダプターを選択する方法を示しています。これは、実際、私が知りたかったことです。記事で言及されているいくつかの奇妙な例外がありますが、これはほとんどの場合に答えを提供すると思います。

貢献してくれてありがとう!

4

2 に答える 2

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

アップデート:

実際には、仮想マシンに属するアダプターをフィルターで除外しようとしていますが、物理的なアダプターのようにシミュレートされているため(Device Managerで物理アダプターとして表示することもできます)、それほど簡単ではありません。そのため、それらを区別することはできません。例えば:

  • 仮想マシンでさえDHCPサーバーからIPアドレスを取得するように構成されている可能性があるためDHCPEnabled、クラスのメンバーによってWin32_NetworkAdapter
  • 仮想アダプタには特別なタイプがないためAdapterTypeId、クラスのメンバーによってWin32_NetworkAdapter
  • PhysicalAdapterクラスのメンバーによって、Win32_NetworkAdapter物理的であるようにシミュレートされているため

追加の読み物:

于 2012-05-15T08:53:14.953 に答える
4

IPヘルパーライブラリGetAdaptersAddressesのAPIを使用することもできます。Delphiの翻訳の場合、MagentaSystemsIPヘルパーコンポーネントは一見見栄えがします。

于 2012-05-15T08:56:35.593 に答える