Delphi 如何判斷當前網卡是物理網卡(有線網卡,無線網卡)還是虛擬網卡


MAC地址作為硬件唯一標識,在很多時候會被使用,如在軟件授權方面,很多軟件在產生機器碼時會采用CPUID或MAC地址,或使用MAC地址來做一對一綁定。

相信很多人會碰到以下問題:

1)獲取的是VMWare的網卡MAC地址

2)獲取的是VPN的網卡MAC地址

VMWare或VPN軟件的安裝卸載都會導致獲取的MAC地址變化,所以我們需要正確獲取當前物理網卡的MAC地址。

 

下面是根據網卡實例ID判斷是否為物理網卡的Delphi代碼(RAD Studio 10.1版本的):

const
  NCF_VIRTUAL  =$01; //  說明組件是個虛擬適配器
  NCF_SOFTWARE_ENUMERATED = $02;//  說明組件是一個軟件模擬的適配器
  NCF_PHYSICAL = $04; //  說明組件是一個物理適配器
  NCF_HIDDEN = $08;  //說明組件不顯示用戶接口
  NCF_NO_SERVICE = $10; //  說明組件沒有相關的服務(設備驅動程序)
  NCF_NOT_USER_REMOVABLE = $20;  // 說明不能被用戶刪除(例如,通過控制面板或設備管理器)
  NCF_MULTIPORT_INSTANCED_ADAPTER  = $40; //  說明組件有多個端口,每個端 口作為單獨的設備安裝。
                                          //  每個 端口有自己的hw_id(組件ID) 並可被單獨安裝,
                                          //  這只適合於 EISA適配器
  NCF_HAS_UI = $80; // 說明組件支持用戶接口(例如,Advanced Page或Customer  Properties Sheet)
  NCF_FILTER = $400; //  說明組件是一個過濾器

  function IsPhysicalAdapter(sAdapterGUID: string; bOnlyPCI: Boolean=False):Boolean;
  const
    NET_CARD_KEY_PATH =
    'SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}';
  var
    Reg: TRegistry;
    sList: TStrings;
    vCharacteristics: DWORD;
    I: Integer;
  begin
    Result := False;
    sList:=TStringList.Create;
    Reg:=TRegistry.Create;
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if not Reg.OpenKey(NET_CARD_KEY_PATH, False) then
        Exit;
      Reg.GetKeyNames(sList);
      Reg.CloseKey;
      if sList.Count>0 then
      for I := 0 to Pred(sList.Count) do
      if Reg.OpenKey(NET_CARD_KEY_PATH+'\'+sList.Strings[I], False) then
      begin
        try
          if sAdapterGUID.ToUpper.Trim.Equals(Reg.ReadString('NetCfgInstanceId').ToUpper.Trim) then
          begin
            vCharacteristics := DWORD(Reg.ReadInteger('Characteristics'));
            Result := (NCF_PHYSICAL and vCharacteristics) = NCF_PHYSICAL;
            Break;
          end;
        finally
          Reg.CloseKey;
        end;
      end;
    finally
      Reg.Free;
      sList.Free;
    end;
  end;

 

上面IsPhysicalAdapter的參數網卡實例ID通過GetAdaptersInfo即可得到,綜合起來的具體代碼如下:

注意:

調用 GetAdaptersInfo 可以直接引用下面2個單元

Winapi.IpTypes,
Winapi.IpHlpApi

 

function GetMacAddress(): string;
var
  dwRet: DWORD;
  AI,Work : PIpAdapterInfo;
  sGUID, sTmp, sLastMAC, sFirstMAC: string;
  I: Integer;
  uSize: ULONG;
begin
  Result := '';
  sLastMAC := '';
  sFirstMAC := '';
  uSize := SizeOf(TIpAdapterInfo);
  GetMem(AI,uSize);
  dwRet := GetAdaptersInfo(AI,uSize);
  if (dwRet = ERROR_BUFFER_OVERFLOW)then
  begin
    FreeMem(AI);
    GetMem(AI,uSize);
    dwRet := GetAdaptersInfo(AI,uSize);
  end;
  try
    if (dwRet <> ERROR_SUCCESS)then
      Exit;
    Work := AI;
    while Work<>nil do
    begin
      try
        sGUID := string(AnsiString(Work.AdapterName));
        sTmp := string(AnsiString(Work.Description));
        // 名稱描述出現VMWare,直接忽略
        if Pos('VMWare', sTmp)>0 then
          Continue;
        // 配置的ID地址不正常,忽略
        if Work.AddressLength=0 then
          Continue;

        // 將網卡MAC地址轉成字符串
        sLastMAC := '';
        for I:=0 to Work.AddressLength-1 do
        begin
          sLastMAC := sLastMAC + Format('%.2x', [Work.Address[I]]);
        end;

        if sFirstMAC='' then
          sFirstMAC := sLastMAC;

        // 不是物理網卡,忽略
        if not IsPhysicalAdapter(sGUID) then
          Continue;

        Result := sLastMAC;

        //找到第一個物理網卡后退出
        Break;
      finally
        Work := Work.Next;
      end;
    end;
    // 找不到物理網卡MAC,返回第一個即可
    if Result='' then
      Result := sFirstMAC;
  finally
    FreeMem(AI);
  end;
end;

 

理論上從軟件層面是無法直接判斷一個網絡適配器硬件到底是有線還是無線的,因為不管是miniPCIE還是普通PCI接口的網卡,都可以是有線也可以是無線,

但是也有以下的方法判斷:

1)網卡可以通過名稱描述上判斷:一般有線網卡名稱上帶PCI,無線帶WLAN 或Wireless,此方法不依賴於網絡是否連接,但對那些自定義驅動名稱的高人當然無效

2)獲取網絡配置信息,也就是獲取網絡連接里的整個列表,包含物理網卡和寬帶連接,VPN等各種連接設備信息,再查看連接類型,根據MSDN的說明,類型包含ETHERNET/PPP/IEEE80211等等,甚至包含移動手機卡的類型。
3)獲取網絡速率,和2)一樣也是獲取網絡連接的配置信息,100/10Mbps一般是有線,54Mbps或其他一般為WLAN連接,雖說WLAN並不包含一個最高的速度標准,但是普通2.4G或5G的WIFI速度也快不到哪去。

注:

方法 2)和3)中的網絡類型和網絡速率均是通過 API GetIfEntry配合GetAdaptersInfo 獲取(或直接通過 GetIfTable獲取)網絡配置信息得到的,代碼MSDN也有

具體查看MSDN中對此函數返回的結構體MIB_IFROW字段dwType和dwSpeed的說明,除了類型速率,也包含其他非常多的信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM