找回密码
 注册
查看: 5241|回复: 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地址的详细方法介绍如下:2 m2 \6 W8 ~0 @4 l/ n$ l6 d: ^: `0 v

! G+ n2 G+ A, @) j8 U, Q3 d& y+ H一、获取适配器名称# [1 x# A7 L4 I8 o# h- w
/ z5 _: A, a" z) w. {
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
$ ^+ ?1 X  y" H& Q* [8 K
# n* T3 y# [5 P9 e( ^& z) [1.1 调用IP helper API取得适配器名称 & Z. e1 v) d9 k0 ^6 B9 U
; U: u- s# S* ~; e9 Q4 X
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
+ ~+ m2 t& m8 G9 F/ ZIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
- C: M9 `! n( B: }if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大% i5 D0 k8 [: o( ?
{( |- u0 W1 A3 ^7 c5 {/ g8 @" x& }
   delete pAdapterInfo;$ P' h! U& B, Q' y. ~
   pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];4 x% N2 S! T! }2 q: x3 F
   pAdapterInfoBkp = pAdapterInfo;
6 D! j+ u2 ]+ y$ ?" R! @) P}
1 q3 G0 u0 U9 ?& x+ rif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
& n. e$ [+ W) f& B# r) `' ]. q{
! ~1 k/ p$ X* q" j/ J! n0 J) I# B    do{ // 遍历所有适配器# F. s! Y$ l! B) k  C7 j0 u$ u1 J
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口3 j8 A- R( J7 y0 o% N
       {  ~6 y4 E' Z( Y6 D
           // pAdapterInfo->Description 是适配器描述
' S- o1 B! D8 t3 L2 m' J1 N            // pAdapterInfo->AdapterName 是适配器名称$ i+ X& l0 K: {/ D* y$ ~! B; A
       }
2 D. }! ?& A; l1 p8 _# o( i        pAdapterInfo = pAdapterInfo->Next;
3 ^6 ~: y% t( x0 P) \0 _; ?6 u. S    }while(pAdapterInfo);; X" r9 P" m: l
}
! [6 A# W( P/ k) B5 y( ddelete pAdapterInfoBkp;# A- X( j% h$ G/ C0 v* p

; z/ Y/ q# |6 Y7 W! E1.2 读取注册表取得适配器名称& ?9 G; C( L4 A1 h( H7 D; Y

: V7 ~8 X% M- \) u& F在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;
8 L0 k5 R- _/ U: r( x
% O' U6 `7 q; w) N0 Q+ ]8 c- S9 ~; Xif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,8 L* c/ H  {' g; o2 S9 |  s
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",: }' u9 @$ h" n: T$ c
           0,& u  M! ?! ?; S0 m" i0 ?
           KEY_READ,* K- i- z! G2 q
           &hKey) != ERROR_SUCCESS)8 g; D, u* m" }) ~  }$ M
   return FALSE;
' @+ k/ m* n7 V2 w! z& m+ H! q$ x! q- q
DWORD dwIndex = 0;
- @. C3 P: S0 i4 X, i, x: g( }# yDWORD dwBufSize = 256;  c  d1 E7 F, A& w2 g( s
DWORD dwDataType;
8 J% B7 `. M6 V' R0 Dchar szSubKey[256];: B; q. G: E- G# i3 @
unsigned char szData[256];
# J. G3 X+ {. `+ D, Q+ {4 ]1 C$ P* s. s* b" _* d# Q
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)' G: O# u2 l: x" R# K
{4 ?4 h! y$ f1 C
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
% Q/ V" U+ D5 a& t, ~9 \    {        * k6 S% V0 }" t  A0 h
       if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)5 C/ p4 [# M, j# a% f
       {
) M) f3 B7 h1 ?/ @            dwBufSize = 256;* ]/ F: `- h7 v$ S" N, @5 d
           if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)6 E+ O) b3 r$ G; T, a* ?6 v
           {" ]' A/ c6 {! s/ s
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
6 f6 U9 c' d/ U* L, [0 G                {, O8 b/ _1 R; Z
                   dwBufSize = 256;' r" t8 n  e7 P" k
                   if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
, X3 I  \! Y: o                    {
  h4 D+ {" X; [) r                        // szData 中便是适配器详细描述
* V3 R, L, U; e+ N5 g# s. v                        dwBufSize = 256;
( P# E& f2 a( T  S) i                        if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
7 f/ y. x% a* d& Q                        {" B2 U- ?% S% f2 G
                           // szData 中便是适配器名称
. P- a9 R, H4 D" J                        }4 z6 l7 k3 a  X: @7 a) e4 o
                   }  h3 x1 j  r- q! J+ K
               }
, `6 i& @& r: B3 o1 r            }$ w) ]7 m9 _: E8 N/ ^) v
           RegCloseKey(hNdiIntKey);
% {& J. n6 ~; @% k% b; V( {        }
# `5 q2 @( s- n7 w& J        RegCloseKey(hSubKey);
; b5 b+ f* m2 Q9 Z    }9 A  ?0 \5 B; H
/ W8 g# Y; \6 e' D2 ?7 z
   dwBufSize = 256;
* Y/ ^' f1 b8 x8 [. h4 c3 x$ c}    /* end of while */
& V( g2 f* l0 p: l1 h        
+ ^) f8 M: F) J8 Q( w6 QRegCloseKey(hKey);
" F0 ]  z0 C5 a8 \9 F二、将IP信息写入注册表
% g0 q' L3 K# K
6 `2 Y9 z" `& o- l' k代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)* W6 X+ q% K0 m( V; o
{
/ ^! N2 o8 Y$ q    HKEY hKey;$ \) ^: O4 ^9 w1 c  b5 V
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";1 B) L( C" W; t) R0 ?/ {- i
   strKeyName += lpszAdapterName;
6 |/ B7 t' p; _6 N% l( F# u/ t    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 S/ |: Z9 G! M8 n% d1 P8 w$ Z5 _
               strKeyName.c_str(),
' y) [) C; @5 m* ?3 R                0,
) H- M  A2 h3 G8 @/ d  V( P                KEY_WRITE,- F0 J* ^. P. _+ X
               &hKey) != ERROR_SUCCESS)5 [% K2 k0 B' A0 E6 M4 H
       return FALSE;3 I  |8 }( H7 x/ U
   
- C/ A6 v/ d* z& M' }+ S- |" c    char mszIPAddress[100];8 T+ h( B7 y9 `) D
   char mszNetMask[100];
, Y- ]  a0 o) n1 p+ Z9 d    char mszNetGate[100];1 ^# n/ O: h2 k1 p! F
" T& T) h% A1 W, ?
   strncpy(mszIPAddress, pIPAddress, 98);
' b0 G2 i& C; G" f9 u7 I/ J    strncpy(mszNetMask, pNetMask, 98);( J+ f: t- F7 Y
   strncpy(mszNetGate, pNetGate, 98);6 |( r! @% d- ^+ o0 C' z: a

' F( C9 `9 l! K" a$ h    int nIP, nMask, nGate;
$ h7 B4 k- e8 j+ L5 T. M
5 J+ g. E- y9 D/ g* X  F9 {    nIP = strlen(mszIPAddress);& \3 |1 a) y' Z1 p5 Q' E- n
   nMask = strlen(mszNetMask);5 f& h7 h) V3 M2 @
   nGate = strlen(mszNetGate);% q1 y' j0 b& R1 ~. m

/ j+ }1 [) G  a+ P( F    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0, p4 |  J" K, I  f
   nIP += 2;
! u9 t; Z- x9 Z1 W( u) w" z  J0 H- ]2 a1 |
   *(mszNetMask + nMask + 1) = 0x00;- U$ K4 T+ k% d7 s; i
   nMask += 2;1 f8 J2 [6 k+ t* u# ]* f; Q
4 U) T: {8 x% k( s4 Y5 }+ r
   *(mszNetGate + nGate + 1) = 0x00;
+ o: B1 G, p. g& S1 J    nGate += 2;
; l4 J7 u. b5 ]  H! L    
' T, p, ^. V( p( [* q    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
( }* c( [9 ^% W0 c  i) o+ L% z    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
& x& h' z- ?( V2 L- U    RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);' i3 B$ V: c% F8 e+ Q

% m4 W; J  s+ Q    RegCloseKey(hKey);
6 ]4 u! e1 k' f+ p5 ^4 O
! T  h" C' o. y" o3 u* E. }/ m    return TRUE;
6 d6 ^) R% F* g' f9 Y9 Z) H. N& ]}
5 @0 \* l6 ^4 t1 c  ?# k. b
5 z4 F: u% ]3 v三、调用DhcpNotifyConfigChange通知配置的改变2 S* r/ n! _5 q- P6 f

6 `4 D) b' `3 R2 O$ q未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(7 U  P7 b+ @3 m: ]
   LPWSTR lpwszServerName, // 本地机器为NULL
& I+ L) k& F% U1 j' S( v4 Z    LPWSTR lpwszAdapterName, // 适配器名称
6 J3 |# {( k* t( n) m    BOOL bNewIpAddress, // TRUE表示更改IP
1 S- l% T# V5 [- |$ M$ h8 D    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
; }- O7 Z0 l. G5 W) R  u    DWORD dwIpAddress, // IP地址. h8 A" d5 m: [7 \
   DWORD dwSubNetMask, // 子网掩码$ t* V: C# N7 q
   int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
. S/ S9 I9 T& i8 U/ ]: a8 b
3 E% J# Q( _- ~# j; ~0 p5 w  w3 }具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask). Y6 _# I9 ]1 N; A6 K  @5 o
{
2 D% O, {4 c. A  D    BOOL            bResult = FALSE;
) D* r8 a/ [& S# f% ?5 R6 b    HINSTANCE        hDhcpDll;
4 T& l$ D& T. p7 V! f3 }3 A# a; V    DHCPNOTIFYPROC    pDhcpNotifyProc;
4 X& X' f+ `) o& C4 [    WCHAR wcAdapterName[256];3 S+ T- C& S2 B: m8 I! m
   % B, O* u: v" V+ C6 ?
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
" _+ u: {0 x) D+ B5 |4 h  ]" G7 _/ N) r( k+ ^$ X
   if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)' {  j. r. a8 c8 F- j' ^0 V
       return FALSE;4 q; H9 r. B' w. y+ ]' ]
1 F( Y' H. w" h# y4 f0 G5 d% h
   if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
4 O% z8 _+ I6 D* @        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
! V4 i- c' v1 P            bResult = TRUE;, d) L3 k$ n2 w$ L$ ]" r% ~

& B0 w4 C3 l8 ^# L- d% U    FreeLibrary(hDhcpDll);' D  |5 A8 g; q6 X9 E
   return bResult;
4 p9 g, t# m8 G- H" S. m}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-2 07:30 , Processed in 0.018052 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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