Delphi 如何判断当前网卡是物理网卡


本文整理自网络,侵删。

 

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的说明,除了类型速率,也包含其他非常多的信息。

 

来源:https://www.cnblogs.com/caibirdy1985/p/5816362.html

相关阅读 >>

Delphi中如何用image控件显示网络图片

Delphi colorbox不需要系统那么多颜色,只想自定义显示其中几个,怎么做?

Delphi函数assignfile使用

Delphi 中 inputquery 实现密码输入

Delphi 常见的各种形式的组件的安装方法介绍

Delphi fmx用timage显示不同格式的图片

Delphi 的tstringbuilder防止服务器内存碎片化

Delphi用代码实现注册ocx和dll

Delphi禁止在android上重复按下按钮

Delphi生成的webservice appdebug的程序,编译时出错

更多相关阅读请进入《Delphi》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...