查找网卡 并自动设置IP地址---不重启Windows更改IP地址的多种实现

 

有很多网友都遇到过更改IP地址但是要重启机器的问题,在这里,为大家介绍几种不重启Windows直接更改IP地址的方法。首先是调用DhcpNotifyConfigChange的方法,后面还有修改注册表跟使用iphlpapi的方法。

  一、未公开函数:DhcpNotifyConfigChange

  运行效果图如下:


 
  设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API:DhcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:

首先需要包括如下文件及代码:

#include "Iptypes.h"
#include "Iphlpapi.h"
#include "Winsock2.h"
#pragma comment(lib, "Iphlpapi.lib")
typedef int (CALLBACK* DHCPNOTIFYPROC)(LPWSTR, LPWSTR, BOOL, DWORD, DWORD, DWORD, int);


  这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet
Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
  1.1 调用IP helper API取得适配器名称

 

ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);

IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new
char[ulAdapterInfoSize];

if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW
) // 缓冲区不够大

{

delete pAdapterInfo;

pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];

pAdapterInfoBkp = pAdapterInfo;

}

if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS
)

{

do{ // 遍历所有适配器

if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口

{

// pAdapterInfo->Description 是适配器描述

// pAdapterInfo->AdapterName 是适配器名称

}

pAdapterInfo = pAdapterInfo->Next;

}while(pAdapterInfo);

}

delete pAdapterInfoBkp;

/

在Vs2005下的实现如下

ULONG  ulAdapterInfoSize  =  sizeof(IP_ADAPTER_INFO); 

IP_ADAPTER_INFO  *pAdapterInfoBkp,  *pAdapterInfo  =  (IP_ADAPTER_INFO*)new  char[ulAdapterInfoSize]; 

if(  GetAdaptersInfo(pAdapterInfo,  &ulAdapterInfoSize)  ==  ERROR_BUFFER_OVERFLOW  )  //  缓冲区不够大 

            delete  pAdapterInfo; 

            pAdapterInfo  =  (IP_ADAPTER_INFO*)new  char[ulAdapterInfoSize]; 

            pAdapterInfoBkp  =  pAdapterInfo; 

if(  GetAdaptersInfo(pAdapterInfo,  &ulAdapterInfoSize)  ==  ERROR_SUCCESS  ) 

            do{  //  遍历所有适配器 

                        if(pAdapterInfo->Type  ==  MIB_IF_TYPE_ETHERNET)            //  判断是否为以太网接口 

                        { 

         CString tmp(pAdapterInfo->Description) ;//  是适配器描述 
        
         if(tmp.Find(L"JLHW")!=-1 )
         {
                                ::AfxMessageBox(tmp);
        CString AdapterName(pAdapterInfo->AdapterName);
        RegSetIP(AdapterName,L"192.168.0.101",L"255.255.255.0",L"192.168.0.1");
        NotifyIPChange(AdapterName,0,L"192.168.0.101",L"255.255.255.0");
         }

                                    //  pAdapterInfo->AdapterName  是适配器名称 

                        } 

                        pAdapterInfo  =  pAdapterInfo->Next; 

            }while(pAdapterInfo); 

delete  pAdapterInfoBkp; 

//


  1.2 读取注册表取得适配器名称



  在Windows2000中可以通过遍历 HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Class/{4d36e972-e325-11ce-bfc1-08002be10318}/000n/
(n是从0开始编号的数字)所有接口, 在Windows NT中可以读取HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows
NT/CurrentVersion/NetworkCards中的信息,下面以Windows2000为例:

HKEY hKey, hSubKey, hNdiIntKey;



if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

"System//CurrentControlSet//Control//Class//{4d36e972-e325-11ce-bfc1-08002be10318}",

0,

KEY_READ,

&hKey) != ERROR_SUCCESS)

return FALSE;



DWORD dwIndex = 0;

DWORD dwBufSize = 256;

DWORD dwDataType;

char szSubKey[256];

unsigned char szData[256];



while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS)

{

if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)

{

if(RegOpenKeyEx(hSubKey, "Ndi//Interfaces", 0, KEY_READ, &hNdiIntKey)
== ERROR_SUCCESS)

{

dwBufSize = 256;

if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData,
&dwBufSize) == ERROR_SUCCESS)

{

if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡

{

dwBufSize = 256;

if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData,
&dwBufSize) == ERROR_SUCCESS)

{

// szData 中便是适配器详细描述

dwBufSize = 256;

if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType,
szData, &dwBufSize) == ERROR_SUCCESS)

{

// szData 中便是适配器名称

}

}

}

}

RegCloseKey(hNdiIntKey);

}

RegCloseKey(hSubKey);

}



dwBufSize = 256;

} /* end of while */



RegCloseKey(hKey);

 2、将IP信息写入注册表



  代码如下:


BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress,
LPCTSTR pNetMask, LPCTSTR pNetGate)

{

HKEY hKey;

string strKeyName = "SYSTEM//CurrentControlSet//Services//Tcpip//Parameters//Interfaces//";

strKeyName += lpszAdapterName;

if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

strKeyName.c_str(),

0,

KEY_WRITE,

&hKey) != ERROR_SUCCESS)

return FALSE;



char mszIPAddress[100];

char mszNetMask[100];

char mszNetGate[100];



strncpy(mszIPAddress, pIPAddress, 98);

strncpy(mszNetMask, pNetMask, 98);

strncpy(mszNetGate, pNetGate, 98);



int nIP, nMask, nGate;



nIP = strlen(mszIPAddress);

nMask = strlen(mszNetMask);

nGate = strlen(mszNetGate);



*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0

nIP += 2;



*(mszNetMask + nMask + 1) = 0x00;

nMask += 2;



*(mszNetGate + nGate + 1) = 0x00;

nGate += 2;



RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress,
nIP);

RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask,
nMask);

RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate,
nGate);



RegCloseKey(hKey);



return TRUE;

}


//

Vs005下实现


BOOL  CTestIPDlg::RegSetIP(LPCTSTR  lpszAdapterName,  LPCTSTR  pIPAddress,  LPCTSTR  pNetMask,  LPCTSTR  pNetGate) 

            HKEY  hKey; 

            CString  strKeyName;
   //=  L"SYSTEM//CurrentControlSet//Services";
   // "
//Tcpip//Parameters//Tcpip//"; 

            strKeyName  = CString(L"SYSTEM//CurrentControlSet//Services//")+ lpszAdapterName;
   strKeyName+=L"
//Parameters//Tcpip//"; 

            if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, 

                                                strKeyName, 

                                                0, 

                                                KEY_WRITE, 

                                                &hKey)  !=  ERROR_SUCCESS) 

                        return  FALSE; 

             

            CString  mszIPAddress; 

            CString  mszNetMask; 

            CString  mszNetGate; 

 
   mszIPAddress.Format(L"%s",pIPAddress);
   mszNetMask.Format(L"%s",pNetMask);
   mszNetGate.Format(L"%s",pNetGate);


            int  nIP,  nMask,  nGate; 
 

   nIP  =  mszIPAddress.GetLength(); 

            nMask  = mszNetMask.GetLength(); 

            nGate  = mszNetGate.GetLength(); 
 

   wchar_t *tmp=mszIPAddress.LockBuffer();
      RegSetValueEx(hKey,  L"IPAddress",  0,  REG_MULTI_SZ,  (const BYTE *)tmp,  nIP*2+2); 
   mszIPAddress.UnlockBuffer();

   tmp=mszNetMask.LockBuffer();
            RegSetValueEx(hKey,  L"SubnetMask",  0,  REG_MULTI_SZ,  (const BYTE *)tmp,  nMask*2+2); 
   mszNetMask.UnlockBuffer();

   tmp=mszNetGate.LockBuffer();
            RegSetValueEx(hKey,  L"DefaultGateway",  0,  REG_MULTI_SZ,  (const BYTE *)tmp,  nGate*2+2); 
   mszNetGate.UnlockBuffer();

            RegCloseKey(hKey); 

 

            return  TRUE; 

} 

///

  3、调用DhcpNotifyConfigChange通知配置的改变



  未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下:

BOOL
DhcpNotifyConfigChange(

LPWSTR lpwszServerName, // 本地机器为NULL

LPWSTR lpwszAdapterName, // 适配器名称

BOOL bNewIpAddress, // TRUE表示更改IP

DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0

DWORD dwIpAddress, // IP地址

DWORD dwSubNetMask, // 子网掩码

int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP




  具体调用代码如下:

BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex,
LPCTSTR pIPAddress, LPCTSTR pNetMask)

{

BOOL bResult = FALSE;

HINSTANCE hDhcpDll;

DHCPNOTIFYPROC pDhcpNotifyProc;

WCHAR wcAdapterName[256];



MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);



if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)

return FALSE;



if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange"))
!= NULL)

if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress),
inet_addr(pNetMask), 0) == ERROR_SUCCESS)

bResult = TRUE;



FreeLibrary(hDhcpDll);

return bResult;

}

/

VS2005下实现:


char *w2c(char *pcstr,const wchar_t *pwstr, size_t len)
{
int nlength=wcslen(pwstr);
//获取转换后的长度
int nbytes = WideCharToMultiByte( 0, // specify the code page used to perform the conversion
0,         // no special flags to handle unmapped characters
pwstr,     // wide character string to convert
nlength,   // the number of wide characters in that string
NULL,      // no output buffer given, we just want to know how long it needs to be
0,
NULL,      // no replacement character given
NULL );    // we don't want to know if a character didn't make it through the translation
// make sure the buffer is big enough for this, making it larger if necessary
if(nbytes>len)   nbytes=len;
// 通过以上得到的结果,转换unicode 字符为ascii 字符
WideCharToMultiByte( 0, // specify the code page used to perform the conversion
0,         // no special flags to handle unmapped characters
pwstr,   // wide character string to convert
nlength,   // the number of wide characters in that string
pcstr, // put the output ascii characters at the end of the buffer
nbytes,                           // there is at least this much space there
NULL,      // no replacement character given
NULL );
return pcstr ;
}

BOOL  CTestIPDlg::NotifyIPChange(LPCTSTR  lpszAdapterName,  int  nIndex,  LPCTSTR  pIPAddress,  LPCTSTR  pNetMask) 

            BOOL                                    bResult  =  FALSE; 

            HINSTANCE                        hDhcpDll; 

            DHCPNOTIFYPROC            pDhcpNotifyProc; 

            WCHAR  wcAdapterName[256]; 

              char tmppIPAddress[100];
     char tmppNetMask[100];
 
w2c(tmppNetMask,(LPWSTR)pNetMask,wcslen(pNetMask));
w2c(tmppIPAddress,(LPWSTR)pIPAddress,wcslen(pIPAddress));
tmppNetMask[wcslen(pNetMask)]=0;
tmppIPAddress[wcslen(pIPAddress)]=0;

            if((hDhcpDll  =  LoadLibrary(L"dhcpcsvc"))  ==  NULL) 

                        return  FALSE; 

 

            if((pDhcpNotifyProc  =  (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll,  "DhcpNotifyConfigChange"))  !=  NULL) 

                        if((pDhcpNotifyProc)(NULL,  (LPWSTR)lpszAdapterName,  TRUE,  nIndex,  inet_addr(tmppIPAddress),  inet_addr(tmppNetMask),  0)  ==  ERROR_SUCCESS) 
      {
       DWORD ttt=GetLastError();
                                    bResult  =  TRUE; 
      }

 

            FreeLibrary(hDhcpDll); 

            return  bResult; 

 

/


 二、修改注册表:网卡重启



  更改Windows网卡属性选项中IP地址, 通过对比前后注册表, 可以发现以下几处发生变化


>[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services

/Tcpip/Parameters/Interfaces/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]


"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"



[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}/Parameters/Tcpip]


"IPAddress"

"SubnetMask"

"DefaultGateway"



[HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Services/Tcpip/Parameters/Interfaces/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]


"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"



[HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Services/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}/Parameters/Tcpip]


"IPAddress"

"SubnetMask"

"DefaultGateway"




  其中{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}是网卡名称(AdapterName), 不同的网卡, 不同的接入位置,
不同的接入的时间, 对应的值都不一样, 它的值是第一次接入系统时, 由系统生成的GUID值.



  此处CurrentControlSet实际是ControlSet001的别名.

>[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/

Tcpip/Parameters/Interfaces/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]


"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"




  是主要的设置处.

>[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}/Parameters/Tcpip]


"IPAddress"

"SubnetMask"

"DefaultGateway"




  对一些服务有影响, 如不设置, 用netstat可以看到原来的IP地址仍处于监听状态(?).



  但为了使设置生效, 还有很重要的一步, 即重启网卡.


更改网卡的配置, 一般而言需要重启网卡, 如Linux系统, 只需运行


  #ifconfig eth0 down

  #ifconfig eht0 up


  就可以实现网卡的重启.



  Windows环境下的步骤与之类似: 先禁用本地连接(网卡), 再启用本地连接(网卡). 但没有相应的命令或者直接的API. 所幸的是DDK提供一套设备安装函数,
用于控制系统设备, 包括控制设备的状态改变.(点击查看详细代码 href="images/4.txt" target="_blank">附件)



  总结: 通过网卡重启更改IP的方法有两个步骤: 修改注册表, 重启网卡. 重启网卡的全过程上面已作描述. 注册表修改的内容为文中列出四个主要项,
如{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}的网卡名称即是内部设备名, 在adapter结构中已给出.
整个注册表修改的过程比较简单, 本文不加叙述.


  三、使用"iphlpapi"一卡多IP


  除以上两个方法外, 笔者再介绍一种方法. 无论是在Windows下还是在Linux下, 一块网卡都可同时具有多个IP地址. 根据TCP/IP原理,
在网络层标识通信节点是IP地址, 在链路层上的则是MAC地址. 只要通过ARP, 将多个IP与一个MAC对应起来, 就可实现一网卡多IP(其实是一MAC多IP).
系统本身也有相应的设置选项, 如windows是通过TCP/IP属性的高级选项添加的, Linux下可由ifconfig命令添加.



  iphlpapi提供AddIPAddress和DelIPAddress. 如果能先加入新的IP, 再去除原来的IP, 即可实现IP地址的更改.


1、获取适配器名称

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 1. 使用ifconfig命令查看网络接口名字 ``` ifconfig ``` 2. 使用编辑器打开网络配置文件 ``` sudo nano /etc/network/interfaces ``` 3. 更新配置文件以指定网络接口的IP地址和相关参数 ``` auto eth0 iface eth0 inet static address 192.168.1.10 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 8.8.8.8 8.8.4.4 ``` 4. 重启网络服务 ``` sudo /etc/init.d/networking restart ``` 5. 确认IP配置 ``` ifconfig ``` ### 回答2: 在Linux设置IP地址通常可以通过命令行工具来完成,可以使用命令行工具ifconfig或ip addr来查看和设置网络接口的IP地址。 1. 使用ifconfig命令设置IP地址: 打开终端窗口,并使用以下命令之一来编辑网络接口配置文件(root权限): sudo nano /etc/network/interfaces sudo vi /etc/network/interfaces 找到要配置的网络接口的配置行(如eth0)。 添加以下行来设置静态IP地址: address 192.168.1.100 netmask 255.255.255.0 gateway 192.168.1.1 保存文件并关闭编辑器。 然后重启网络服务以应用更改: sudo /etc/init.d/networking restart 2. 使用ip addr命令设置IP地址: 打开终端窗口,并使用以下命令列出当前网络接口的信息: ip addr show 找到要配置的网络接口(如eth0)。 使用以下命令设置静态IP地址: sudo ip addr add 192.168.1.100/24 dev eth0 sudo ip route add default via 192.168.1.1 这将设置IP地址为192.168.1.100,子网掩码为255.255.255.0,并将默认网关设置为192.168.1.1。 请注意,上述方法是设置静态IP地址。如果你想使用动态IP地址(DHCP),则应使用其他命令行工具,如dhclient或NetworkManager。 以上是设置IP地址的基本方法,根据你的Linux发行版和网络环境的不同,可能还有其他设置方式。如果有特殊需求或疑问,建议查阅相关文档或咨询Linux社区的专业人士。 ### 回答3: 在Linux设置IP地址可以使用命令行工具来完成。以下是一种常用的方法: 1. 打开终端,以root用户身份登录,输入以下命令进入网络配置目录: ``` cd /etc/sysconfig/network-scripts/ ``` 2. 列出网络配置文件,查找要配置的网卡文件名,例如eth0或enp0s3: ``` ls ifcfg-* ``` 3. 编辑对应的网卡配置文件,比如使用vim编辑器打开eth0的配置文件: ``` vim ifcfg-eth0 ``` 4. 在配置文件找到或添加以下行,设置静态IP地址、子网掩码和网关: ``` BOOTPROTO=static IPADDR=<IP地址> NETMASK=<子网掩码> GATEWAY=<网关地址> ``` 5. 保存并退出编辑器。 6. 重启网卡以使配置生效,输入以下命令: ``` service network restart ``` 7. 使用`ifconfig`命令来确认IP地址是否已成功配置: ``` ifconfig ``` 注意:以上步骤假定系统使用的是CentOS或RHEL发行版,不同发行版可能具有稍微不同的配置文件路径或网络服务管理命令。在不同版本的Linux,请查阅相应的文档或使用适用于特定发行版的命令进行网络设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值