有很多网友都遇到过更改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地址的详细方法介绍如下:
1、获取适配器名称
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是: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;
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;
}
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;
}
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;
}
二、修改注册表:网卡重启
更改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提供一套设备安装函数,
用于控制系统设备,
包括控制设备的状态改变.(点击查看详细代码附件)
总结: 通过网卡重启更改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地址的更改.
一、未公开函数:DhcpNotifyConfigChange
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows
1、获取适配器名称
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek
1.1
ULONG
IP_ADAPTER_INFO
if(
{
delete
pAdapterInfo
pAdapterInfoBkp
}
if(
{
do{
if(pAdapterInfo->Type
{
//
//
}
pAdapterInfo
}while(pAdapterInfo);
}
delete
1.2
在Windows2000中可以通过遍历
HKEY
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
System\\\\CurrentControlSet\\\\Control\\\\Class\\\\{4d36e972-e325-11ce-bfc1-08002be10318},
0,
KEY_READ,
& hKey)
return
DWORD
DWORD
DWORD
char
unsigned
while(RegEnumKeyEx(hKey,
{
if(RegOpenKeyEx(hKey,
{
if(RegOpenKeyEx(hSubKey,
{
dwBufSize
if(RegQueryValueEx(hNdiIntKey,
{
if(strcmp((char*)szData,
{
dwBufSize
if(RegQueryValueEx(hSubKey,
{
//
dwBufSize
if(RegQueryValueEx(hSubKey,
{
//
}
}
}
}
RegCloseKey(hNdiIntKey);
}
RegCloseKey(hSubKey);
}
dwBufSize
}
RegCloseKey(hKey);
2、将IP信息写入注册表
代码如下:
BOOL
{
HKEY
string
strKeyName
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
strKeyName.c_str(),
0,
KEY_WRITE,
& hKey)
return
char
char
char
strncpy(mszIPAddress,
strncpy(mszNetMask,
strncpy(mszNetGate,
int
nIP
nMask
nGate
*(mszIPAddress
nIP
*(mszNetMask
nMask
*(mszNetGate
nGate
RegSetValueEx(hKey,
RegSetValueEx(hKey,
RegSetValueEx(hKey,
RegCloseKey(hKey);
return
}
3、调用DhcpNotifyConfigChange通知配置的改变
未公开函数DhcpNotifyConfigChange位于
BOOL
LPWSTR
LPWSTR
BOOL
DWORD
DWORD
DWORD
int
具体调用代码如下:
BOOL
{
BOOL
HINSTANCE
DHCPNOTIFYPROC
WCHAR
MultiByteToWideChar(CP_ACP,
if((hDhcpDll
return
if((pDhcpNotifyProc
if((pDhcpNotifyProc)(NULL,
bResult
FreeLibrary(hDhcpDll);
return
}
二、修改注册表:网卡重启
更改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),
此处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
对一些服务有影响,
但为了使设置生效,
更改网卡的配置,
#ifconfig
#ifconfig
就可以实现网卡的重启.
Windows环境下的步骤与之类似:
总结:
三、使用iphlpapi一卡多IP
除以上两个方法外,
iphlpapi提供AddIPAddress和DelIPAddress.