找回密码
 注册
搜索
查看: 4726|回复: 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地址的详细方法介绍如下:
1 r4 `- |7 K( D/ `& R* d+ G6 B: \# H+ s8 s0 {$ W
一、获取适配器名称
8 K/ P; `0 L" ^9 }# R5 L/ ^  m" O9 F6 K$ e
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:2 M8 C0 O) d3 _8 [
$ x+ f8 s' {+ E+ u! A1 p1 ^
1.1 调用IP helper API取得适配器名称
& E- q3 T' `. n8 _: v- U6 Q% |9 k
1 i0 p3 O4 F& \6 ^ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);' X. \& x/ A8 B2 D0 e8 c
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];6 h# W; m1 U& O5 ~' [! o4 a/ ?3 i
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大1 ~  v# h5 V2 Q" U- N4 e
{8 Y( X' D- e9 ?/ D
   delete pAdapterInfo;7 J) Y. ]3 d6 H
   pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
6 |6 P& ^, q$ K+ j' X& w    pAdapterInfoBkp = pAdapterInfo;
9 ]1 a1 s. M' [+ k}5 b7 ~, a( m* ]6 q4 V
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
6 I; d& X  J' d8 a8 F- }{/ P( F6 [" a; r/ f8 I$ m& O6 s
   do{ // 遍历所有适配器
6 O" j) \% J% ?3 f$ h        if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
6 n2 f5 q8 h! j# B# o& |# ?        {& p4 ~2 y+ ~3 ~/ h
           // pAdapterInfo->Description 是适配器描述
( R; A) r% s9 E# O( B            // pAdapterInfo->AdapterName 是适配器名称
( B4 l; {6 m4 {- H9 B        }# F1 m0 _/ S: R/ Z/ b& Z
       pAdapterInfo = pAdapterInfo->Next;% J5 @% f+ D! ^
   }while(pAdapterInfo);5 n! Y4 ^8 H, F% \' Z
}2 Z" X6 U) F8 j0 g% i
delete pAdapterInfoBkp;
# A5 {' c0 ~/ @5 n0 I3 y$ }" M& O7 u# Y/ m0 y# X/ C8 ^: m5 t
1.2 读取注册表取得适配器名称7 m1 g8 {" {  [9 u
2 n4 K1 S9 N: P
在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;6 O% Y2 x  Y; E
% @9 A. I" Q8 b$ T7 L/ Y# W7 E
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,% L# N6 @6 |; Q' ~( r
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
1 N7 C1 g4 L5 H! t, J* c            0,
" h+ U7 |1 U/ h6 U            KEY_READ,
! Y, i7 a/ @# F$ o! u            &hKey) != ERROR_SUCCESS)# `: p) g: y0 ]
   return FALSE;6 H9 {) s. h+ G9 w
8 U2 ]$ L0 I8 t9 R
DWORD dwIndex = 0;3 }& @& f) }# W) ]* ]( Y* q* T
DWORD dwBufSize = 256;
: p0 [' n1 k8 d0 {) C: PDWORD dwDataType;
  s" M# M6 S' G5 _char szSubKey[256];
/ F( T4 E. t# l$ m! Bunsigned char szData[256];
7 }4 |. F# T8 y' a5 B7 L1 ~
& n! ?' o$ b, Z! x3 Xwhile(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS): v. a0 f( V! R3 H* \% t2 Y
{7 T: r. T$ j/ e7 _
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
! H7 P  c  E" i! M$ G0 g( Y0 O    {        
8 F- V7 R% c. T$ D1 T' I/ |3 `* [        if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)  r1 O! c1 K+ ^* Q1 G( D
       {
. B& n0 s# c( A2 c. d            dwBufSize = 256;9 g( f) y. q$ l: p- `' s1 Q0 W
           if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
* i" Z9 ~6 s8 c( [" q            {4 [/ n+ @" m% L3 e# \
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
! r6 p" X4 ~( [7 x; M" M                {3 O/ t$ w. s' p2 x9 H
                   dwBufSize = 256;
* x, Y6 H; w2 B, p( [                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
# D1 \1 D+ y- n9 e  A                    {: a7 ?/ P/ b; ?, w4 O6 x
                       // szData 中便是适配器详细描述+ }* _5 n, v2 E6 c8 |( y
                       dwBufSize = 256;/ h( K8 Z+ L  e* l+ D
                       if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS). A" B! @  R; G; s' D
                       {
6 D; E, P7 n4 l& f0 f( r, G                            // szData 中便是适配器名称
0 d( Q2 N# N/ \4 e$ q2 N- l+ y                        }, C- U! V0 O3 b! @2 Q1 [- Y) W/ U
                   }/ c( }3 j( g: h( _
               }
- K  _/ k" _+ d1 B" Y            }7 B5 E2 V; ^: j5 K# ?. l
           RegCloseKey(hNdiIntKey);: L" r& e' m1 H$ H" `
       }
- P- Q3 M; Z% F) w0 ]5 f0 M) c" N        RegCloseKey(hSubKey);
) r3 ~1 \' S; m5 ^& t    }
* T) _2 H8 X7 g' ^/ s) {1 ~- u, C7 m' T# ?4 K" H
   dwBufSize = 256;9 e& c" y( Z& s1 D  S
}    /* end of while */
  i: T( F# ^! c        
' b; ]' ^* x& S! w! e1 lRegCloseKey(hKey);5 [# @3 {6 i9 [, [% K7 x
二、将IP信息写入注册表2 P) X8 e2 o$ ^1 a

. L# g7 x; W) X6 d2 x代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
) G5 X: ~8 t6 Y% V9 F8 t. P1 d{
% j8 }6 x4 k7 x, G& ?    HKEY hKey;/ v1 J; `( g4 }8 ]# z/ |8 @! Q
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";( e, z& b8 z0 M0 Z
   strKeyName += lpszAdapterName;
) ^  \: @6 P. g    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
( \7 O' S* Q# o4 a% a0 c                strKeyName.c_str(),
8 R6 {" N4 }, d( @3 Q& e( M                0,
5 y% b* [; M, K, H( S                KEY_WRITE,
9 H9 f2 j( S; a) x                &hKey) != ERROR_SUCCESS)
6 U, m( W7 d1 E1 \  Y        return FALSE;0 l$ i; ?% K, Q; v# e7 ?
   
3 P+ A; q9 z* @    char mszIPAddress[100];: T, ]  y* `& n5 B( h+ A
   char mszNetMask[100];  n- \6 ~9 _, \! X2 J0 Y  Y
   char mszNetGate[100];: U: W' x4 p$ f8 W6 H% H9 m

  O8 |& q8 T0 R! p5 \    strncpy(mszIPAddress, pIPAddress, 98);
2 T" r8 _) [" J9 x    strncpy(mszNetMask, pNetMask, 98);1 w9 b( h- r! E/ ~* _; e6 K( B+ z' K
   strncpy(mszNetGate, pNetGate, 98);  N; X0 a7 [: `; D7 |, y

7 x# ^( x' u( U2 y, G/ a& z! ?: ~    int nIP, nMask, nGate;7 O6 L% w) x2 ], h) H6 G

3 O. q# Y3 F; N    nIP = strlen(mszIPAddress);8 U$ d$ V" }' }) u+ R
   nMask = strlen(mszNetMask);6 {3 e% u0 L0 Q7 y( f7 o- L' K
   nGate = strlen(mszNetGate);; U! V( z, Y! ?3 v3 X  T0 I

- ~/ ]  A" a! J6 W4 U    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0! C* o) x1 y6 D5 F% p; T
   nIP += 2;
2 u% u  M9 S$ Q/ n5 q5 F
, w8 f3 ~, L' e! i    *(mszNetMask + nMask + 1) = 0x00;
1 X5 ]6 b( ]3 p- v    nMask += 2;1 J! j% ^' g4 ~: }" Q1 i0 f/ m

$ I: K. I! g  ?9 G" z    *(mszNetGate + nGate + 1) = 0x00;$ z. v* `: q: m$ r
   nGate += 2;
( L- R6 Z' o1 h' {) c    
! n, O* A1 S7 |0 {9 M0 }# q    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
& K  P; v! r/ a! H# H2 [9 S3 e    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);7 i' a6 T) u) j! j) M
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
1 |4 k% m( y* n. W$ T1 U
! x/ e/ G9 T& g1 k) [3 G    RegCloseKey(hKey);
- S. R& e5 j8 |1 a9 H
, ?) w2 d; s/ J+ v    return TRUE;
' E% `: v1 M3 x5 J0 n}- v- a3 k, c) b
  k$ C: d( u3 k/ e
三、调用DhcpNotifyConfigChange通知配置的改变
' Q4 }; V0 M: M3 N* G+ R2 ~- }; [/ b3 D, s
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(. R! c: ~4 ^' G5 n$ p2 E; t
   LPWSTR lpwszServerName, // 本地机器为NULL
. w; G+ B8 j; T( l% g& E    LPWSTR lpwszAdapterName, // 适配器名称
$ f4 @& C5 D: K1 }; U) J& C+ C- L    BOOL bNewIpAddress, // TRUE表示更改IP
3 |% @8 R& `! y4 ?+ S% @4 l    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
3 v$ F& V! R7 ?2 p0 J3 G: N- r2 K- U    DWORD dwIpAddress, // IP地址
) r$ ~: P0 ^; v    DWORD dwSubNetMask, // 子网掩码
5 U8 T+ y1 |1 }1 u) H    int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP! K! y" L1 l: n$ V

5 f9 g# i" ^; q* K% x具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)8 i6 O- m8 w& v) X  u
{
) |9 ?' _' A0 `    BOOL            bResult = FALSE;' ]# h3 X' w' }( C* G3 I# g: Y# s
   HINSTANCE        hDhcpDll;
4 g- ]5 W4 c0 {. S1 c2 J$ ?8 i    DHCPNOTIFYPROC    pDhcpNotifyProc;
( v5 m. v+ q1 M: ?3 {    WCHAR wcAdapterName[256];! [3 v. X6 z! z& O# {( D7 v. w& X
   6 |% E. b1 s/ F
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
8 v( S% }" W7 m, ]( I9 j6 \- Y' {6 w. }5 `, a1 I+ K" b* j
   if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
2 n& T0 A$ \6 M; h/ i8 V8 E7 ?/ A        return FALSE;
  C" g4 y' c- t, t
2 N$ m  E3 p# m    if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
% Y( U, Z2 E  C/ V. U$ \0 P3 j        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)% q# z$ M" Z4 K6 z7 t* @9 V4 R4 a
           bResult = TRUE;
' I" M4 @' O$ \) G6 o1 b9 Q; [. o$ i7 `* d5 n0 b) t
   FreeLibrary(hDhcpDll);
$ ^* W0 f/ A$ M8 n* j# B    return bResult;
+ H) w1 T1 f: R% Z" g}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-11-15 01:29 , Processed in 0.023853 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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