找回密码
 注册
搜索
查看: 4989|回复: 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地址的详细方法介绍如下:" u2 Q- o3 L. D/ w5 t, Y' l- o9 L

( I& y7 s0 N. L! Y; V一、获取适配器名称
& X4 h( O2 n' Y7 j' m8 i7 w+ U: X- J& H2 i: z/ G
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:3 ^6 N2 t8 W8 v' T
: o0 O! M, e/ I7 k' x. r4 R6 u
1.1 调用IP helper API取得适配器名称
& s6 a% I2 g: s$ L- G$ Q' A7 r
$ v' \! H' ^) e+ B# X8 {5 Z$ P/ IULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
3 `: U0 k4 y7 _$ h1 r' M2 H$ fIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];. Q0 q: \0 f2 f
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大; l9 ~) I/ Y2 |6 H
{3 o' q- B' p, k) L' U# a
   delete pAdapterInfo;
* ^# q. u7 \! [- _5 K! S- h    pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];9 B/ s% M0 E+ Z' l; v; c) |
   pAdapterInfoBkp = pAdapterInfo;0 o, }8 M! A2 V- t) O6 ?
}
) S$ _; I  u/ `2 {, w' zif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )7 Q) v% l. g% @
{
/ l6 A1 _7 i, b- a0 K0 Z6 G& ^& O4 E    do{ // 遍历所有适配器4 e" ?3 ?( c7 b! }! G
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
- R6 U: E' o* i" k, V        {) h: i: g4 l4 r6 D* Q0 W) k
           // pAdapterInfo->Description 是适配器描述& a2 M: V( u9 i% s" y% }# S" h
           // pAdapterInfo->AdapterName 是适配器名称9 T! l7 i: @% L% ]& z' _8 C6 Z/ E* P
       }
, @; a- l. ]1 t% g" _% q7 n7 q" W        pAdapterInfo = pAdapterInfo->Next;+ D8 `/ Q. i; z9 M; X9 B
   }while(pAdapterInfo);
" B' V7 J! p9 J}
2 c  x' z# ~" H6 J$ G/ Mdelete pAdapterInfoBkp;
! b& m* O6 g$ k( A2 Q) P4 J! b$ i- K5 ~* Q" g) {% }
1.2 读取注册表取得适配器名称
; U3 ~; ]& n2 u& c  z: W( |4 g3 B3 Y
: B: Z/ k* ?6 t# L6 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;( k8 r, {% N2 O2 C4 |+ Y# I) N

! V9 j; K/ R- U) pif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,+ k: \8 h8 i6 n, b% j: ?* U4 T
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",% ~8 Z1 A: Y0 ~6 c7 k
           0,
' c# i$ A9 c4 U6 \- r8 N# a' z- D            KEY_READ,( y* w0 C" K1 u8 Z) P0 |
           &hKey) != ERROR_SUCCESS)
/ [8 P7 T4 z0 ?+ W( C    return FALSE;9 Z+ q% \& S1 W' ?9 m* d; Y
) A; J2 z4 z) U  v$ d$ z7 y0 h
DWORD dwIndex = 0;
/ y4 n" Z$ l; j3 I! n8 RDWORD dwBufSize = 256;
2 h3 f8 ?* T8 G  Q& ^6 a0 I0 YDWORD dwDataType;+ {& M& p6 I6 @. u3 A
char szSubKey[256];" d$ I: I5 t4 U# e/ d
unsigned char szData[256];
9 U' k8 P! }$ F% U9 t* }8 w) k' B9 C
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
4 I( C5 a9 l2 t4 N9 {{7 D7 v4 B1 ^, W' m5 q% J
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS); ?4 }" `* H" B& j' q* U
   {        0 c4 n7 M9 g9 g! L' y
       if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)! z; Z6 Q# Y9 v3 ]+ p1 b: x
       {
. B& U& C# o/ x            dwBufSize = 256;2 `8 Q0 C* r; U% x" T- K
           if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
" S. z7 j9 W6 _7 `, `9 q) s0 J            {) _; O2 P3 r: g
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡' a9 A" `9 a" m8 q' F
               {
: r$ A$ k4 S) ~- t1 x                    dwBufSize = 256;
% w; L  N8 r+ J. w! T/ n, p                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)* Y- q' `$ t' \& R9 B. m0 |! D
                   {
+ Y3 ]& b- h/ _: ~& Q9 ~                        // szData 中便是适配器详细描述, D% r" p- C0 ~7 l4 q
                       dwBufSize = 256;
; w  w% Z4 a. F' n# `+ Y+ `5 E) d                        if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)% a! g  R4 s# G
                       {
# V! Z3 U3 _& F. l- V# x, w, N                            // szData 中便是适配器名称
# e( r1 T- L! ]. w% d8 `7 R& y                        }  _% r' U4 ]/ M# U6 F
                   }
- ?! m* p! b" ~& [- h                }9 }! u. b) Q/ b! F6 a! x2 ^. U
           }
, E% g* U0 |, K/ K# t            RegCloseKey(hNdiIntKey);+ b, `9 A+ b$ B% [* _$ s6 K; u' ~
       }7 S) o4 F- [" |1 o+ e9 g
       RegCloseKey(hSubKey);" G5 w" y+ a1 `, v
   }) {+ a* N- W% @# d. K+ A1 ~/ W

9 ~1 i% V7 t7 y    dwBufSize = 256;
; z4 F% Z# A  Q% l. W}    /* end of while */
5 F5 i1 ]/ b8 P) I% }2 v        9 q2 I4 P# I' f# u' n/ Q, s6 ?, a8 m
RegCloseKey(hKey);7 v( r% _4 C3 g7 E$ Y/ I2 P
二、将IP信息写入注册表
4 J# s5 x' g$ n' g) i
' `3 a* ?1 X: J, P) ]; Y, A代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate): x- T7 ?* F1 l, l& a. I. D, Z
{
4 }  C3 ^: P' t2 v( w    HKEY hKey;. a$ p: C$ h6 d3 O" Q9 G) S- \
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";6 T9 C3 x0 g7 W  a. F
   strKeyName += lpszAdapterName;
, g- J. ]5 J; s8 z    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
7 v1 e) K$ ^8 d% H                strKeyName.c_str(),
8 E2 ^. d7 `+ x! I7 Y' v/ K$ D0 p                0," n; ^& k3 x: e* }6 ^4 l
               KEY_WRITE,
! z+ {8 F' E  V+ V0 E+ X/ j5 ]; |; n                &hKey) != ERROR_SUCCESS)7 R; ]( [7 q4 @0 |
       return FALSE;
3 D. D  N- i6 N, x% p1 I# P    
/ T) ?4 R4 u8 @2 Y, }: e4 Y" n    char mszIPAddress[100];
/ G( b2 E7 M# |; @4 O    char mszNetMask[100];
( P$ B% Z3 o0 C/ p( b9 E, i    char mszNetGate[100];
6 F- G  Q/ O3 f, w8 D1 G$ P1 Z
% U3 e5 G0 ?" I& w; _9 R6 P; ~    strncpy(mszIPAddress, pIPAddress, 98);: F2 X8 |& R8 I& t
   strncpy(mszNetMask, pNetMask, 98);
  z. _8 k# A8 S% g; \    strncpy(mszNetGate, pNetGate, 98);1 n0 p9 h9 e/ F+ A/ Y

  f4 t9 p8 Q8 j1 {. k    int nIP, nMask, nGate;
) P1 y1 I5 s( X) r- \0 C& D# B. H% Z" W+ w) }8 u) l3 I
   nIP = strlen(mszIPAddress);  j7 z  ]9 O8 R( t
   nMask = strlen(mszNetMask);. ~1 t" C& p/ y7 F
   nGate = strlen(mszNetGate);& V7 O+ D2 C3 D% c0 K1 |# N/ j8 {
4 q* Z4 K4 }1 i6 W
   *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0* j7 M! A/ ^" ^5 {! u2 |+ H
   nIP += 2;
1 H) c# a( }1 Y& ]" c8 o( ?& a" q; {/ X- S! Q! {4 n7 D
   *(mszNetMask + nMask + 1) = 0x00;
  Y! I- X& B( w6 ~    nMask += 2;# E  i- `( C: b, P

8 `) `1 V: x/ E6 l" O  n6 b3 n: G* v2 v    *(mszNetGate + nGate + 1) = 0x00;
4 L4 A1 M- z- A! ~( f2 ?    nGate += 2;4 k4 x2 @! D; T0 \5 v
   
9 I# w7 C1 ~6 Q3 I4 `: d. ?2 x    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);0 ^' m$ Y( s/ ]+ [: |& d7 k: Y7 d
   RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);) t" b7 ~/ o; s# I+ A4 M9 q
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
9 V6 q# ]2 c1 E8 c, V+ U
4 A5 o7 U$ c6 _9 p    RegCloseKey(hKey);1 E0 R8 v7 g3 E+ N: t) S5 N% b5 C% {/ V+ u
% w7 }  ~5 r0 b& N( k. }! |3 T
   return TRUE;
6 `% |1 t4 Y9 ~3 P8 f) {}
7 L' s" [- p! ^# d5 C  y% a5 x& s
三、调用DhcpNotifyConfigChange通知配置的改变
# Y& w- X: o& ]" c  ^: X; r/ K! E2 a
8 |/ N. y1 |6 D7 M未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(8 A- [0 M1 q8 m6 Z
   LPWSTR lpwszServerName, // 本地机器为NULL
* _9 x& y! m8 j) Y" K    LPWSTR lpwszAdapterName, // 适配器名称
; |# s: M, U# i$ b: E! j$ S    BOOL bNewIpAddress, // TRUE表示更改IP
9 C' G& O9 W5 y7 X- r7 s( n. Q    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0' ~! \/ Z4 R% E; U: D
   DWORD dwIpAddress, // IP地址
# n; K" k" o6 j6 G8 v    DWORD dwSubNetMask, // 子网掩码1 c+ c7 C! Q1 Q; o/ u- u
   int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
6 B! A/ |9 ^# L- H) E+ P
& S  y! Q5 v6 s  C具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
2 m  j) T$ i" u) w{
/ v- m( b" R# e) u: r    BOOL            bResult = FALSE;. D% k1 ~9 ~) |: d* D5 B
   HINSTANCE        hDhcpDll;
8 C; k& W2 V" u2 C, R    DHCPNOTIFYPROC    pDhcpNotifyProc;  D! w/ |6 [( M+ e$ W
   WCHAR wcAdapterName[256];
' Y) ~& Z+ D/ O, U' @    / W: Q! B. C8 N4 s$ T
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);% @, c2 t: f  r8 ?: w9 A# Y

! d: [7 ^1 S; M; ^7 Z    if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
* v- R5 l' X0 l$ `# r% f        return FALSE;1 U7 w! N5 p& `

% J& b6 ]* M+ D    if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
$ ^5 S$ k  z/ n, q" Z        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)# h, m9 b  p4 r& u" r7 _
           bResult = TRUE;
6 O& b- n$ J9 m' }8 a
, v  e! O: ^2 B$ N% j/ w' z! A    FreeLibrary(hDhcpDll);
+ g" T+ B3 v6 X( m& d    return bResult;
% U2 g; |( K+ ~}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-18 06:56 , Processed in 0.018488 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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