找回密码
 注册
查看: 5236|回复: 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地址的详细方法介绍如下:6 h5 M: I. ~5 F+ `5 n& C

4 j) D+ i' t( B. a4 [1 V$ D. w! m8 M一、获取适配器名称5 c1 r( @4 H, o$ k* T9 a* J! J. b
) [) w3 r) C# D  w7 |* a
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:8 A' L' E- ~) B+ K, W# |

; d/ ~) [8 F) ~. A, n1.1 调用IP helper API取得适配器名称 1 F- `% P4 C! Y$ {" f

6 H3 Z: H6 n9 aULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);3 J( K* q6 S8 z. I  K& N6 ?
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
8 C2 \: S  X" t7 m, C: `if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
4 d: D# u9 [; e$ M1 U{
9 X; W# S( ^' \! z$ \( ]2 {    delete pAdapterInfo;
. ~7 G* J4 r: x4 i. J    pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
) @3 ~# R% C! s4 a+ Y3 `. |5 Y3 k    pAdapterInfoBkp = pAdapterInfo;3 v7 W# J% H$ s0 S* Y5 Y
}8 C  k" d0 N. x6 J; k; j
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
4 X2 r& C+ c5 L8 q, s4 w{( A& J% l1 w5 v( c
   do{ // 遍历所有适配器5 u8 @* g$ c+ \6 n: Y
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
0 P7 K4 q' Z% P+ c6 M        {
: u3 `( |1 h# v            // pAdapterInfo->Description 是适配器描述
& `6 E% z) [3 C! l            // pAdapterInfo->AdapterName 是适配器名称
7 N# j0 n+ K/ J/ l$ G        }7 @3 F" y1 Y  T  G
       pAdapterInfo = pAdapterInfo->Next;" @: W3 f, I. [5 r. H1 o) L% _: y
   }while(pAdapterInfo);
. g# x2 b7 a* m% {6 }) `$ {}- ^2 V4 t8 X" l" F
delete pAdapterInfoBkp;, e# V) S; j0 H- i% U
& k, v$ T8 r0 a
1.2 读取注册表取得适配器名称1 }$ D. m2 `$ M3 k; u& |

# S6 [! M9 D: U# A0 T# P% 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;
5 n! X, I% z! h* b$ d
$ Q* a- T( u6 z9 Z1 Aif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,1 l! o/ `% N! C. ~, v. l5 _7 t- B
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",/ F1 D8 D2 h1 O" a  |+ ]
           0,8 k3 O8 h; F# g6 T9 ?, G; J  Q
           KEY_READ,3 A7 x8 k5 q1 e0 t; @8 K: Q9 R8 q
           &hKey) != ERROR_SUCCESS)" o1 x2 A. e/ I) s
   return FALSE;
0 [% k% q: A% b! q
" B! z9 x3 }0 J* H7 hDWORD dwIndex = 0;9 y3 n+ S  P( P1 J. f) u
DWORD dwBufSize = 256;: p1 T1 p% O1 {
DWORD dwDataType;
! l5 V" _) z3 N- Y3 x' r' t$ ~char szSubKey[256];7 W: i# f" {' ^, {$ C
unsigned char szData[256];
0 x" |/ b0 q2 f, c2 F) E6 @5 i# a% E  Z; w& h9 h2 Y* T
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)" z9 f1 B/ V  b# t
{% ]9 A5 ]/ S* T9 C
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS). z$ ~% ~0 L! q& |& h
   {        - L# I/ e; e6 Q
       if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)) I0 a. ?  t+ t/ @3 t9 I
       {+ E! K# T  f/ M" M7 @1 ?/ ~& L
           dwBufSize = 256;
) i0 n2 Y! @; M: a# R            if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# J2 S, H/ H: g! u$ B6 u  f9 {9 F
           {4 B4 C3 g# \/ L; n/ r
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡6 c  D& D# _6 l  e- |* Z2 R
               {
7 j- Y1 X; ^; d                    dwBufSize = 256;
, u, f5 P# s9 H4 |7 D! d                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# `2 I, o- J3 C' K: C, N, S
                   {& C) I: l! c. y* i
                       // szData 中便是适配器详细描述
2 g! n  c; F+ [% S6 b6 j/ I4 [                        dwBufSize = 256;
4 Y; Q: G/ }- e3 ]1 i8 C                        if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
7 }7 U+ j2 P0 h1 Q8 Q                        {, D  B+ }, I3 u! Q/ m9 L/ g
                           // szData 中便是适配器名称* H4 p2 S. J' x; P3 G
                       }
$ C4 [; ~$ T. J                    }" r% A0 P- i3 @0 D; `' O
               }) P5 e/ q$ Z. Q; t8 j
           }
0 t+ Q  A$ z+ `3 @: ?& o# C            RegCloseKey(hNdiIntKey);
1 x: ~5 _7 T3 c        }2 J" A( B9 `# N8 T
       RegCloseKey(hSubKey);+ z0 X& ]; q( v; v
   }  h' ^6 V, X  s; x0 G
' w. o! i$ n* z7 z$ r
   dwBufSize = 256;
3 h) u- t6 d* y5 @7 B}    /* end of while */
$ ~5 j3 ]# A7 ?$ Y& ^, Q5 O3 p* x        1 H. Y+ c* n4 W& g
RegCloseKey(hKey);
0 m! a8 s  u$ T. a, E9 G5 i二、将IP信息写入注册表# d  J5 `0 V, M( }
2 x" z" A- q, E0 ^
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)% V6 y# y6 w- x5 a: |& _) @; \
{
/ o7 t$ j3 D/ X0 H# D5 E( x    HKEY hKey;& V8 d$ J7 _2 U/ I1 p2 p+ P  g
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";, Z" `( v* i+ {% R* n
   strKeyName += lpszAdapterName;& p3 M  Q3 q# R' X' r3 ~
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,& C" @9 j2 s" B0 l+ G3 B# i+ i
               strKeyName.c_str(),  k: p! _# u" [4 b5 Y* a& `* {- B
               0,( n8 N- Z) C  b& x
               KEY_WRITE,
* x. Z- Y9 T* z5 Z                &hKey) != ERROR_SUCCESS)- b: w, s3 n0 r7 B- M) W+ D( @
       return FALSE;
% q2 x& o% V  ]- B    
2 Z' o- O) d+ K) k- F9 |    char mszIPAddress[100];
$ c! S# j0 J9 K# _9 U    char mszNetMask[100];
/ m" e8 j$ w+ @4 O- I    char mszNetGate[100];0 k4 W0 n7 \% M+ e; L/ ^) \/ q

! @+ G6 p) H; O$ Y( \( c5 g    strncpy(mszIPAddress, pIPAddress, 98);
- X% ?) W# {7 k6 s& ^4 m, f* E    strncpy(mszNetMask, pNetMask, 98);
  d  C! Z- ^" z4 n2 Z    strncpy(mszNetGate, pNetGate, 98);1 M. [/ T. F+ {1 ^" o
# S2 y9 K6 V5 [) v, @, I: }" l2 U
   int nIP, nMask, nGate;
: V; h) K  I3 ]0 n7 m0 S7 X5 y  G/ V
   nIP = strlen(mszIPAddress);9 U: O4 a! ^* N& \" p% d4 n
   nMask = strlen(mszNetMask);% z5 T6 N" U$ e) I9 Q
   nGate = strlen(mszNetGate);& G! f! e% y# I  ?$ O

, s5 L2 k' M' X    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0- n* u2 i. Z% x* f9 O+ r
   nIP += 2;
7 z: F* |9 G: x+ w0 s" `+ u  [8 l4 }- _3 h8 V" N( a3 [3 V4 T- l
   *(mszNetMask + nMask + 1) = 0x00;
' z# J9 W' r. n5 f    nMask += 2;2 n5 G: |/ Q1 N4 P6 B4 e

( A. R; N) j$ c+ u5 o6 d    *(mszNetGate + nGate + 1) = 0x00;
2 W$ Z) e+ S! Z    nGate += 2;, F9 M8 ]- @8 z* j
   
7 C: F1 N. V7 x. e- l    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
: I* {$ \3 D0 [3 W' c    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);* u0 l+ q. ^6 x* w7 S
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
. D! y5 r9 [& l2 ?' O" {/ a" _+ l& S" }. j
   RegCloseKey(hKey);
  X8 Y* X# G; ]7 g& d+ \
& ^4 a% R2 x  P* Y2 T" c    return TRUE;
# t! ?% W. @8 @}
( ^5 ~( a" D3 r# ~3 Y3 F+ k" q2 [$ t: ?/ N, F( ?. C& {) K; b
三、调用DhcpNotifyConfigChange通知配置的改变
4 T" M8 }2 f& g/ ~( u) L6 n- B- Y# k8 j) E3 g$ g
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
! ]/ R' w( w8 ?' C; c$ o7 t! F    LPWSTR lpwszServerName, // 本地机器为NULL
( A& S# x& t4 F; I1 {% I    LPWSTR lpwszAdapterName, // 适配器名称
8 @2 `1 k( F& d; {0 I( ?    BOOL bNewIpAddress, // TRUE表示更改IP
% w- l+ b( d1 v8 E! x    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为04 Q( L9 ~  X5 Z8 k* Y) L; z. B; Z9 p- ]
   DWORD dwIpAddress, // IP地址
( X3 P: t- T5 ?& i, p. T    DWORD dwSubNetMask, // 子网掩码
, p0 ?7 t8 T% K. N    int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
. n/ u' O3 ]% ^$ i# x1 Q3 Q0 H& k% Q  ]/ p: E+ U
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)% M8 r, I: {9 p) V  J
{
9 M8 }+ f7 |2 |( q0 W0 A    BOOL            bResult = FALSE;# V4 h1 S2 d" }5 _+ j
   HINSTANCE        hDhcpDll;, Z7 A/ A2 p: D7 R+ [" u
   DHCPNOTIFYPROC    pDhcpNotifyProc;
0 g5 Z# R  b+ l! X* |& U* `    WCHAR wcAdapterName[256];
! p8 b/ h& ~; F! H- H) ?$ x    4 u! p# ?4 w9 K! V/ n0 C
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
0 p( o- ~$ H& H! O% k2 Y- ?
: ?  C/ F0 Z! m( S6 T9 H$ A. S5 U    if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)* K/ \+ f  A. w% R
       return FALSE;; L5 t8 t6 H& Q* C3 A- V# b0 K
3 Z- ~) S/ x& `7 U1 G8 ]
   if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)% G5 b( w7 D( K' n
       if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 h3 k) m1 h5 n0 H  u/ Z+ A            bResult = TRUE;
+ `/ B  K' W$ {* {. T2 p. t; D. L' f# ~# x8 x- f
   FreeLibrary(hDhcpDll);" s  S1 d: _1 q% E: y0 A0 L/ C
   return bResult;0 h+ d* B% b! c) M0 l6 b( k0 Y8 [
}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-1 20:48 , Processed in 0.018085 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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