闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鈧懓瀚崳纾嬨亹閹烘垹鍊炲銈嗗坊閸嬫挻娼诲┑瀣拺闂侇偆鍋涢懟顖涙櫠閹绢喗鐓涢悘鐐插⒔閵嗘帡鏌嶈閸撱劎绱為崱娑樼;闁告侗鍘鹃弳锔锯偓鍏夊亾闁告洦鍓涢崢鎼佹倵閸忓浜鹃梺閫炲苯澧寸€规洑鍗冲浠嬵敇濠ф儳浜惧ù锝囩《濡插牊淇婇姘Щ闁绘宀稿娲川婵犲倸顫庨梺绋款儐閹告瓕顣炬繝銏f硾椤戝嫮鎹㈤崱娑欑厽闁规澘鍚€缁ㄥ鏌嶈閸撴岸宕归崹顔炬殾闁哄洨鍠撶弧鈧┑顔斤供閸撴盯顢欓崱娑欌拺閻犳亽鍔屽▍鎰版煙閸戙倖瀚� (0) +1 闂傚倸鍊搁崐鎼佸磹閹间礁纾圭€瑰嫭鍣磋ぐ鎺戠倞鐟滃繘寮抽敃鍌涚厱妞ゎ厽鍨垫禍婵嬫煕濞嗗繒绠抽柍褜鍓欑粻宥夊磿闁秴绠悗锝庡枛鐟欙箓鎮楅敐搴℃灍闁绘挻娲熼弻宥夊煛娴e憡鐏撳┑鐐茬墑閸ㄥ綊婀佺紒缁㈠弮閺€杈┾偓姘炬嫹 (0) +1 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻鐔兼⒒閹绢喗顎栭梺绋款儐閸ㄥ潡骞冨Δ鈧埥澶娾枎鐎n剛绐楁俊鐐€愰弲婊堟偂閿熺姴钃熼柨婵嗩槸缁狅綁鏌ㄥ┑鍡橈紞婵☆偄瀚槐鎾存媴閸濆嫷鈧矂鏌涢妸銉у煟鐎殿喖顭锋俊鎼佸煛閸屾矮绨介梻浣呵归張顒傜矙閹达富鏁傞柨鐕傛嫹 (0) +1
闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鈧懓瀚崳纾嬨亹閹烘垹鍊炲銈嗗坊閸嬫挻娼诲┑瀣拺闂侇偆鍋涢懟顖涙櫠閹绢喗鐓涢悘鐐插⒔閵嗘帡鏌嶈閸撱劎绱為崱娑樼;闁告侗鍘鹃弳锔锯偓鍏夊亾闁告洦鍓涢崢鎼佹倵閸忓浜鹃梺閫炲苯澧寸€规洑鍗冲浠嬵敇濠ф儳浜惧ù锝囩《濡插牊淇婇姘Щ闁绘宀稿娲川婵犲倸顫庨梺绋款儐閹告瓕顣炬繝銏f硾椤戝嫮鎹㈤崱娑欑厽闁规澘鍚€缁ㄥ鏌嶈閸撴岸宕归崹顔炬殾闁哄洢鍨归拑鐔兼煏婢跺牆鍔氶柣搴弮濮婅櫣绮旈崱妤€顏存繛鍫熸閺岋箓宕橀鍕亪闂佸搫鐭夌紞浣割嚕椤曗偓瀹曞爼濡烽姀鐘卞闂侀€炲苯澧撮柡灞剧〒閳ь剨缍嗛崑鍛焊椤撱垺鐓冮柦妯侯樈濡叉悂鏌嶇拠鑼фい銏∏归ˇ杈╃磼閵娿儯鍋㈤柡宀€鍠愮粭鐔煎垂椤旂⒈娼庨柣搴ゎ潐濞叉﹢宕曟總鏉嗗洭顢氶埀顒勫蓟閿熺姴鐒垫い鎺戝閸ゅ秹鏌曟径娑氬缂併劌顭峰娲传閸曨剙绐涢梺绋款儑閸嬨倛妫㈤梺缁樺姉閸庛倝宕愰崹顐e弿婵☆垳鍘ф禍楣冩倵濮樼偓瀚�闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾剧懓顪冪€n亝鎹i柣顓炴閵嗘帒顫濋敐鍛婵°倗濮烽崑鐐烘偋閻樻眹鈧線寮撮姀鐘栄囨煕閳╁啨浠︾紒顔瑰墲娣囧﹪鎮欓鍕ㄥ亾閺嶎厼绀夌憸蹇曞垝婵犳艾绠i柣妯烘▕濡粓姊虹粔鍡楀濞堟洟鏌i幘瀛樼闁哄瞼鍠栭弻鍥晝閳ь剟鎮橀柆宥嗙厱闁靛牆鎷嬮崕鏃堟煛鐏炶鈧繂顕i崼鏇炵閹肩补鈧弶妯婇梻鍌欑閹碱偊寮甸鍌滅煓闁硅揪绠戦悡鈥愁熆鐠哄彿鍫ュ几鎼淬劍鐓欓梺顓ㄧ畱閺嬨倝鏌嶇拠鑼缂佽鲸鎹囧畷鎺戭潩椤戣棄浜惧瀣婵ジ鏌$仦璇插姎闁汇倝绠栭弻锝呂熷▎鎯ф闂佽棄鍟伴崰鏍蓟閿濆绫嶉柛灞绢殕鐎氭盯姊烘潪鎵槮缂佸鏁搁幑銏犫攽閸モ晝鐦堥梺绋挎湰绾板秹鎮橀幘缁樷拺闁告繂瀚敍宥夋煕濡亽鍋㈤柍銉︽瀹曟﹢顢欓崲澹洦鐓曢柟鎵虫櫅婵$厧鈹戦鎯у幋婵﹥妞介幃鐑藉级閹稿寒鍞ㄩ梻浣烘嚀閸ゆ牠骞忛敓锟�>>

正在阅读:不重启Windows更改IP地址的多种实现不重启Windows更改IP地址的多种实现

2005-09-01 10:02 出处:其他 作者:王骏&pcdog 责任编辑:moningfeng

  有很多网友都遇到过更改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;
} /* 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;
}


  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地址的更改.

关注我们

最新资讯离线随时看 聊天吐槽赢奖品
闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾剧懓顪冪€n亝鎹i柣顓炴闇夐柨婵嗙墛椤忕姷绱掗埀顒佺節閸屾鏂€闂佺粯蓱瑜板啴鍩€椤掆偓椤曨厾妲愰幘鎰佹僵閺夊牄鍔岄弸鎴︽⒑閸濆嫬鏆欓柣妤€瀚伴崺鈧い鎴f硶缁愭梻鈧鍠曠划娆撱€佸鈧幃娆撴嚑閸ㄦ稑浜鹃柛顭戝枓閺€浠嬫煥濞戞ê顏╁ù鐘欏懐纾兼い鏇炴噹閻忥妇鈧鍣崑濠囧箖閳哄啰纾兼俊顖炴敱鐎氬ジ姊婚崒娆戣窗闁稿妫濆畷鎴濃槈閵忊€虫濡炪倖鐗楃粙鎺戔枍閻樼粯鐓欑紓浣靛灩閺嬬喖鏌i幘瀵告噭闁靛洤瀚板顕€鍩€椤掑嫷鏁勬繛鍡楃箘缂傛岸鏌熼幍顔碱暭闁绘挻鐟ч埀顒傛嚀鐎氼喗鏅跺Δ鍛惞闁搞儮鏂侀崑鎾舵喆閸曨剛锛橀梺鍛婃煥缁夊爼骞戦姀鐘斀閻庯綆浜為敍婊冣攽閻愬弶顥為柛鏃€鐗犻崺銏ゅ即閻旇櫣鐦堥梺姹囧灲濞佳冩毄婵$偑鍊х紞鈧俊顐㈠瀹撳嫰姊洪崨濠勨姇婵炲吋鐟ф竟鏇熺節濮橆厾鍘甸梺纭咁潐閸旓箓宕靛▎鎴犵<闁绘瑢鍋撻柛銊ョ埣瀵濡搁埡鍌氫簽闂佺ǹ鏈粙鎴︻敂閿燂拷闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌i幋锝呅撻柛濠傛健閺屻劑寮撮悙娴嬪亾閸濄儳涓嶉柡宥庡幗閻撴洘銇勯幇鍓佺ɑ缂佲偓閳ь剛绱掗悙顒€鍔ゆ繛纭风節瀵鎮㈤悡搴g暰闂佺粯顨呴悧婊兾涢崟顓犵<闁诡垎鍐f寖缂備緡鍣崹鎶藉箲閵忕姭妲堥柕蹇曞Х椤撳搫鈹戦悙鍙夘棞缂佺粯甯楃粋鎺撶附閸涘ň鎷洪梺鍛婄箓鐎氼剟顢旈妷鈺傜厱閹艰揪绲鹃弳顒侇殽閻愭彃鏆欐い顐g矒閸┾偓妞ゆ帒瀚粻鏍ㄧ箾閸℃ɑ灏紒鐙欏洦鐓曟い顓熷灥閺嬨倗鎲搁悧鍫濈仴闁宠鍨块幃娆撴嚑椤掍焦鍠栫紓鍌欑贰閸犳牜绮旈崼鏇炵闁圭儤顨呯粻濠氭偣閸ヮ亜钄奸柟鑺ユ礀閳规垿鎮欓弶鎴犱户闂佺硶鏅涚€氭澘顕i锕€绀冩い鏃傛櫕閸欏棗鈹戦悩缁樻锭婵☆偅鐟╄棢闁绘ḿ鍋ㄦ禍婊堟煥閺傛寧鎯堥柛鏃撻檮閹便劍绻濋崘鈹夸虎閻庤娲忛崝宥囨崲濠靛绀冮柣鎰靛墻濡繈姊婚崒娆掑厡闁硅櫕鎹囧畷鐢稿冀椤撶偟顔嗛梺璺ㄥ櫐閹凤拷