找回密码
 注册
搜索
查看: 4626|回复: 1

[收藏]Windows NT/2000更改IP地址不需要重新启动就可以生效的方法探索

[复制链接]
发表于 2005-5-24 11:03:31 | 显示全部楼层 |阅读模式
  设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的APIhcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
& c  ~, N5 S# x- r' ^  `/ w& v
3 J$ f! c; x* K1 V" w5 C$ L一、获取适配器名称
; H9 i9 V8 [$ ~; o: m- |1 s7 v1 N+ d5 f4 E; s
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:# I6 c5 Y/ ~- i! ]
4 X1 O, X) b( s6 Z
1.1 调用IP helper API取得适配器名称 7 T7 S5 f6 ^0 g" i! Z1 R% W3 T2 V

9 S' N/ h0 j) [ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);, K( s- W: O( i- p0 f2 m% \
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
8 a' }2 M) A; e* U8 jif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
- L+ t- [3 r1 U' {; u{
7 O& \, n# e. w  |, o6 a: o    delete pAdapterInfo;
3 X, n/ t! |6 L! d( }    pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];! `4 _; j4 h% ^/ y, w8 k
   pAdapterInfoBkp = pAdapterInfo;
/ |% c% ^# G/ M  \& q, n9 I}3 }- z" b  ~5 {) E5 O3 Y
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )$ H3 v! V  A) ^/ f
{9 a1 c2 Q3 ?. e  G
   do{ // 遍历所有适配器
9 e$ m- e) Y/ F  f3 e8 ?        if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口% ?$ Q2 g6 N# |8 i4 v9 d2 X
       {. r9 R( }+ U5 J/ U- a+ l
           // pAdapterInfo->Description 是适配器描述7 n( {+ O+ O8 d
           // pAdapterInfo->AdapterName 是适配器名称$ ~- S8 b- V" p# t4 J
       }1 q# @: [  ^* n9 V% W
       pAdapterInfo = pAdapterInfo->Next;. g6 h: y& p4 G9 H7 ]/ T
   }while(pAdapterInfo);1 N4 @! ~: {$ d, g  {. D
}
6 O  M2 `; v$ `8 Xdelete pAdapterInfoBkp;
: J5 R- E0 e$ |+ b+ d2 O0 Z! F% F8 s% J# B# w* H8 S+ |/ B
1.2 读取注册表取得适配器名称( _1 ?, N$ n9 O
* j- ^4 C8 I1 x; N' l. Z; J% W* u
在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;( n) E9 M5 K2 b7 }7 Y; y2 B
1 Z+ o3 y0 Q6 K% \/ a$ B
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 K8 Q- X# z3 Q8 w  R& d& M! K& |+ [
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
& y7 x5 Z# {8 ~            0,8 C6 H$ m3 n/ Y, N+ D
           KEY_READ,
5 }5 x6 v+ d1 f+ o            &hKey) != ERROR_SUCCESS)! H7 ~9 m* B, I4 U* ~, T
   return FALSE;' p4 s3 e+ y) f0 |" H0 ]

# B" ?7 {/ o6 f& qDWORD dwIndex = 0;
, x& g2 G' e$ n) ^* a! Q" J1 LDWORD dwBufSize = 256;8 ?9 y/ e5 o& {* [4 r9 s
DWORD dwDataType;' Y- a1 @, y# T: u. P
char szSubKey[256];
/ D: K* n, o9 m, A: S6 ]- z$ j- `unsigned char szData[256];4 z1 }1 F  d2 O0 T% r' K
6 |1 V0 G0 `8 z8 _
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
: W' x$ v& A3 Y- x{
5 _( R5 |2 W$ ~" q8 E6 H    if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
: W. ]  N) i( A( V    {        
% _( D2 S6 N$ z/ c1 T7 V        if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
2 B* l$ R' w/ _1 h+ @- d* n        {  Z( `% t/ {- l( O: g
           dwBufSize = 256;/ S$ A1 C6 u- b6 R$ r( T
           if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)5 x( e8 m1 B) A4 }* k, g) B
           {7 x1 I, e- t: f( V* E
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
. K1 T4 M2 M. p' H                {
) k! u% Q2 i- J6 f' \; `! [, d                    dwBufSize = 256;
% V0 p% E" V" u/ H8 o; }                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
. W; G  i9 A( T- P                    {" {6 y& U' S0 \) r+ p
                       // szData 中便是适配器详细描述
) y" L' X+ b1 q5 h# Q* q) g, L3 i                        dwBufSize = 256;8 s% e  r( k( d; ~
                       if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
( e4 ^6 \9 Z/ I: K3 `+ F* K                        {& ~# R* v  x, N- x8 E
                           // szData 中便是适配器名称
4 B' ^2 a/ f) N' q' @4 ?5 P& }                        }
+ q6 _# R+ i# o' t: C) z  x; [                    }* ~- M9 p% v7 F6 W9 U
               }
# @, M( ]3 `* l+ q# A            }
- t+ U. K! g* u6 Y% g            RegCloseKey(hNdiIntKey);. a; u# f$ |6 l4 N$ J
       }
" \/ b4 r8 i& p        RegCloseKey(hSubKey);$ w: a0 Z% r* C# P+ f) U, ]3 I9 `. X
   }
2 f4 _# ]( h+ g6 G! |0 g& n, L
' T5 h2 r$ I: A: j0 \* d. _    dwBufSize = 256;0 @+ Y; N6 y  V( c
}    /* end of while */; q: I, A' t( u1 P6 X
       
! j# l3 x4 _% F' YRegCloseKey(hKey);
" T( R8 u3 m7 b, \二、将IP信息写入注册表. Z! a  u9 J; ~/ A, Z" a
4 E! Z: [8 [1 T+ s% Y6 I. R
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
+ P3 W' \! [* R; j+ H; ]7 P{
9 P: ^0 F) G; m, @  U" m9 {: E/ h    HKEY hKey;% h, }; D" u4 W$ |) F6 e
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";' e6 a% ]/ b% U) T- h$ m  _; `2 S
   strKeyName += lpszAdapterName;/ b* P" W+ t& c1 h, K6 l+ I
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
& s+ R' F% M: O7 [& ~                strKeyName.c_str(),7 a( y" l' U/ J+ K
               0,
# D2 T8 ~7 J' P                KEY_WRITE,* T) T9 k' \' T4 i& U6 \: H
               &hKey) != ERROR_SUCCESS)- D, V) E5 ?' k) O0 I4 y
       return FALSE;
" P- B( b+ n* s    
( D# a, X) Y. C/ n, p7 Q7 A    char mszIPAddress[100];
8 K( u; E2 ~: @/ X7 P    char mszNetMask[100];; H4 i; J4 [7 U# \; L
   char mszNetGate[100];  `+ w3 u" q3 J' S

3 D: }7 J/ Z( S7 j( u1 Q1 n! c    strncpy(mszIPAddress, pIPAddress, 98);
; V1 ?. v* V* M  H  ]1 y; ]' m, u    strncpy(mszNetMask, pNetMask, 98);
. H& x* D4 j2 J+ Z2 w+ R4 F& e    strncpy(mszNetGate, pNetGate, 98);5 @, R. l! h9 g& D
8 c* N& P5 }/ b
   int nIP, nMask, nGate;
4 J/ B6 V# E* y4 S1 z4 I% a; k, e' U4 v" A
   nIP = strlen(mszIPAddress);4 B6 k; W" ?  g' H8 @& }5 @
   nMask = strlen(mszNetMask);9 ]9 ]- |2 i& o  P2 \# j0 B
   nGate = strlen(mszNetGate);
. n% v" V/ _( Z
4 }4 u) U& n; y5 D$ z    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0; ?  F5 V' k& `1 C0 H
   nIP += 2;( R+ W6 E( f  z, X
' q: ?! V* d+ E: c" A$ T% v
   *(mszNetMask + nMask + 1) = 0x00;
' t/ X  `9 j" n" T1 J6 F' `    nMask += 2;4 y, [! h; l/ b1 t6 t; [

3 c% g/ c" s3 e- U. I1 p    *(mszNetGate + nGate + 1) = 0x00;( j/ g5 @  m% S% A0 u" C, E6 d! \; s
   nGate += 2;5 y: N3 ]7 M7 w7 [5 p% u( m1 [! R* o
   
$ V$ r: G* c  w, s    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
! A; k3 Z. E' N2 e    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
) i; p) I5 z" ^3 p( w( ^    RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);; B. L0 b. N1 j+ U

4 T. k6 t3 f/ J& l    RegCloseKey(hKey);
% y) ]0 d; {) I. R- S$ {: F
/ @1 ^, d, l! j/ \    return TRUE;9 }3 }2 P. z7 d2 T" J% r. i
}6 K& c8 n  |" O, S  d& F; @  }  V# v

; C5 I9 S6 @3 O+ N! G1 }三、调用DhcpNotifyConfigChange通知配置的改变" g! l8 `( u% P; K: ~" j9 ?
( Y# P% x9 M$ f. m
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
+ _) M! G5 C! ^. ~/ b, u, V; t    LPWSTR lpwszServerName, // 本地机器为NULL
- ?/ i, G& l  A4 W    LPWSTR lpwszAdapterName, // 适配器名称1 O. k6 f4 d' m5 ?. N5 t
   BOOL bNewIpAddress, // TRUE表示更改IP
8 D( B9 f4 z$ |- I    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0/ P( I3 f5 j" @
   DWORD dwIpAddress, // IP地址" O# h- {6 `9 M4 s4 q
   DWORD dwSubNetMask, // 子网掩码1 c/ l( ^- c/ x9 R' c9 L
   int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
' o9 a+ N0 y. @; w( f. Y9 ], {
' @7 n2 h" \: L5 ^$ j* w. c, B% b  a具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)9 J/ V9 s6 W* U- h4 J
{1 e7 e" k; r) z1 c5 r/ J
   BOOL            bResult = FALSE;
) c1 j. W" {' V: \    HINSTANCE        hDhcpDll;
, s' x3 \- k. A# W  m    DHCPNOTIFYPROC    pDhcpNotifyProc;
+ P9 _: ^0 ^8 }4 x: m1 Z, _    WCHAR wcAdapterName[256];
9 B% C4 j0 f1 V$ U; |0 R! ]1 N; W    
, D1 V7 N' f' Z& P. `    MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
5 A, ?6 z! {9 r: [7 |* b
) x* l3 w  W8 h3 t' \* U* U    if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)( `/ g+ d4 I) O) X" ^# r
       return FALSE;
! ?/ _  T8 M6 a, o* J, c
+ g8 R$ I3 \  T# r. x& z    if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
; a2 S* q9 }+ M1 c6 p. x        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 ~. T# L0 p" U# E- j            bResult = TRUE;5 X7 J4 n, N! T2 ]- u# a2 C3 S; q
, r3 t! t9 Y6 e6 m+ V' ^! |7 K8 Q
   FreeLibrary(hDhcpDll);: K+ e1 ?. n2 T: v1 f: S
   return bResult;
- z1 M. e" y; h0 Y4 C}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2025-8-9 01:40 , Processed in 0.035287 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表