找回密码
 注册
查看: 5237|回复: 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地址的详细方法介绍如下:
% M+ S9 |* j! n# f- o6 w# W. y% r' K" c9 [
一、获取适配器名称% y" i4 [# Y6 b: V7 ^* e' }

  W& q" h5 x; e4 E  A1 y" K! E( h4 H这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:: C4 u' m; T3 I) N' F% g- X: D

0 E3 S" l  ~3 K; Y2 Z7 G- x5 D1.1 调用IP helper API取得适配器名称
+ d+ e" w- c4 G9 ]
6 ]# y) h1 d* V* S8 K9 \3 rULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
: R  v& g. [1 f: d$ V* d, ^# LIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
3 F$ A4 Z5 o' e# |8 Cif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大( [' U, _# x, g$ O0 ~# U
{7 D% V$ I; C/ U+ t4 N. j
   delete pAdapterInfo;  _" `9 T( H. n. N  v/ i
   pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];# ]7 V. g1 h* Q5 D. j: a6 A4 L
   pAdapterInfoBkp = pAdapterInfo;! @/ j& f' _. }
}* V: O8 \4 @" m/ E5 {8 j& J
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )8 N8 {$ ?! t/ {1 y7 s2 }8 P
{
& |) q# x9 r. m; a" t! |; S    do{ // 遍历所有适配器3 f5 }4 @3 T9 l* w
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口8 {" x, L0 I: x$ N- p# N4 b
       {! z% V4 H: }2 |$ Q  E2 o( b3 _
           // pAdapterInfo->Description 是适配器描述3 b6 y$ {6 C. T# S/ R8 n0 c
           // pAdapterInfo->AdapterName 是适配器名称
( v1 e- {  F1 j5 z  K4 }$ T2 x        }8 b) K% V8 x9 x0 L9 y/ `6 |( W( [
       pAdapterInfo = pAdapterInfo->Next;' X" i3 w5 o1 E) A/ q. D, j
   }while(pAdapterInfo);
9 O4 c$ x& V$ d" W# h: X}
3 W: J+ a$ O7 K6 p, [5 x) o: Bdelete pAdapterInfoBkp;
3 _1 @2 c$ t7 S& K# A
. U! L; N# Z2 p: i8 b1.2 读取注册表取得适配器名称' |+ I6 I. a/ a* ~9 c2 ~

& l- X+ i8 n8 Q3 d& I" X. {' f; L在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;4 |) i. c! b& f3 j1 H6 f

2 E3 Q2 B2 v) y6 s- q1 w+ g7 ]if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 w: g7 ^1 v9 a2 a' \0 q0 \2 g
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
) h3 e* W$ _, t, k3 v5 v2 r2 j            0,6 b0 I6 G# O. P, J2 t
           KEY_READ,0 @( f) X0 |# g& U" o  R
           &hKey) != ERROR_SUCCESS)
- ], I) r/ F/ P* N. `6 C( s    return FALSE;
  v5 e  p4 [: L" R4 k3 c6 g: S- E; Z, d
DWORD dwIndex = 0;
9 F3 }3 i1 ~& g( G' b# vDWORD dwBufSize = 256;
1 Q! K9 O: }) W! _2 {' y, ADWORD dwDataType;
* `9 F# t; T; c! {& Hchar szSubKey[256];4 @9 l' y& r* p( p# B! W2 y/ Y
unsigned char szData[256];
7 x& D# b! q3 k. g4 u1 Z( q* D3 Z/ g: B6 M
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) g+ X0 l: S" ~6 f, ~. W4 q/ @. J. k
{
- u: `  F4 G+ v    if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
3 j/ H0 G% _, @0 n  j" D: F. ?    {        
3 ^  P+ @! C$ e        if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
0 P: F! h' o  b6 G  U& j        {
: o3 F7 h9 l1 L            dwBufSize = 256;
+ h- ]: {+ s6 R% E/ p; x# ]* P3 A            if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
0 f: L0 l4 [  p7 ]7 Y* ^! |            {! T7 L1 o0 U' D, `1 k
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡  R. J8 Q- y& H5 c2 [
               {# Z- a% F; i4 K7 [9 E1 m2 i
                   dwBufSize = 256;
; z/ U( I/ D( p; \+ K& m                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)* m, P  Q7 N8 R+ {0 P; }, x3 P, ^
                   {! [7 y& [+ e0 P! @4 M
                       // szData 中便是适配器详细描述
' C" m  j' ]0 O8 O, G                        dwBufSize = 256;. i5 P2 i) F+ C+ P  z& K
                       if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)+ P% T4 Q) V( O+ s: X4 s9 N8 L+ p( g
                       {3 l6 r- w3 b) i$ a7 c! M
                           // szData 中便是适配器名称
! V8 i1 v0 C1 E( v6 [                        }6 \" R1 o. Z- w4 u
                   }& _" e7 X. F$ I& D; s* R
               }% I5 ^) W& f  P9 n2 i) R7 C, X
           }
! `, w3 G+ T# N, _            RegCloseKey(hNdiIntKey);
) U' j1 U) t7 a        }
" P1 e$ B: y) c; I6 d0 J        RegCloseKey(hSubKey);
% B! h4 c/ t" i1 N, i    }
/ l/ u5 J+ Q( Z/ [9 `$ N6 m3 G2 k& ?# p! z5 r/ i- k( s, W
   dwBufSize = 256;
1 N$ B9 z% m' I. e  f" F}    /* end of while */
8 ~0 t5 F4 m4 c0 e4 x0 R        0 p, e) Y% @. h! \9 R" D
RegCloseKey(hKey);
' W8 s* R2 W4 v5 u二、将IP信息写入注册表
: H6 Y" n, d) E. o1 M. O3 p# m, J% I
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
! M; P* d7 q8 _1 [8 T$ @{, ?, L- P  \  E+ @/ b4 C
   HKEY hKey;
' N, W, Y% Z  L- b! u    string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";# _- T# S3 V5 N1 y3 H, j" B
   strKeyName += lpszAdapterName;. W( P5 W, N! f, Y2 }4 }! U" |$ e
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,; R  f& A* Z& _9 @6 N" X7 F
               strKeyName.c_str(),
# W/ U; U4 R; j" B                0,
. l& x* @' M% {# J- v4 w) l$ V                KEY_WRITE,
* @# O2 t8 v2 w- w: M2 b                &hKey) != ERROR_SUCCESS)& p2 w# l/ p/ g: f! T1 O# I
       return FALSE;
" W8 n  \0 g8 o" v    2 M7 b2 @( D, S9 ?" Z
   char mszIPAddress[100];+ ^% ^$ x/ B9 e9 Q
   char mszNetMask[100];
  {0 v( z0 {- K3 r9 i6 t3 B    char mszNetGate[100];
6 ^( e! l4 j8 ]. I  W5 N( N: d' @+ _; v8 |2 t! S
   strncpy(mszIPAddress, pIPAddress, 98);
" v: F  r  d# d) X    strncpy(mszNetMask, pNetMask, 98);1 t) D9 ~% U% ~  g% y
   strncpy(mszNetGate, pNetGate, 98);
- `( r& e% u+ u; i
' x9 z* T+ I" c& ~/ Z$ e    int nIP, nMask, nGate;0 Q4 x* L, g% i0 Y0 ^8 T

6 w) x; T1 H- \2 ]/ j( H1 D* j    nIP = strlen(mszIPAddress);
0 t, k, _2 b$ v    nMask = strlen(mszNetMask);
1 h0 U! t! w1 b  l    nGate = strlen(mszNetGate);5 }* `. y: m2 \

) ^  S" E* c; Q( y3 t    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0  [  M; @' M* M& a
   nIP += 2;9 M& u+ O& c9 ?; e0 A1 P0 m( Z2 G

( F" z: a- @) K1 D. j8 F/ f8 G. |    *(mszNetMask + nMask + 1) = 0x00;
: Z) p- u0 \( O, J4 V1 I1 P# k    nMask += 2;2 |3 x* ?5 a* Y1 H8 f9 A- r) G

: I0 d% L. L$ R) N    *(mszNetGate + nGate + 1) = 0x00;
, f2 s% r, K9 Q8 p% e2 n    nGate += 2;% e3 B" L3 a8 k( u
   
' t  ]* l, b( l1 J! L    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
0 P4 z8 D3 P  w) h( M    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);$ J! c- O4 a5 }3 |. n% s8 y
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
1 |& L* |4 @$ b; l" ?" v( u* Y& d+ B
   RegCloseKey(hKey);
) z/ V! u' k. W* S9 S
" Y8 _" ?! u1 B; z: o( B' ~    return TRUE;5 V+ M$ L% A7 Q6 p4 a
}5 D- A7 Z; V/ [4 [

7 Z* T7 `2 [  {8 S! N三、调用DhcpNotifyConfigChange通知配置的改变% a" x* e1 `) b; J0 Z, f6 G2 r* F9 O
$ f+ i3 d7 a) O6 T8 H
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
  D) N( ]5 E6 W; n, D- Z" Q    LPWSTR lpwszServerName, // 本地机器为NULL, V  _8 T4 V% c) G2 P" g
   LPWSTR lpwszAdapterName, // 适配器名称
# ~' o/ e( d1 \. E    BOOL bNewIpAddress, // TRUE表示更改IP! \! k8 M7 W. m; b# X5 h; L6 B
   DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
. m4 o* s3 h* _/ w0 e8 ]$ p    DWORD dwIpAddress, // IP地址- X  W# f! y! G* l7 \+ i# ?- W
   DWORD dwSubNetMask, // 子网掩码
+ _  Y7 w3 y/ B7 G    int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP- w) t3 I8 u8 o) M* i- x/ e6 f: @

8 b! D6 ]* U, @* ?" _3 K% C具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
/ ^& w: E7 K  ]' e; [4 ?{/ w- Q: V) l/ R2 i1 B+ s8 T
   BOOL            bResult = FALSE;. O% n0 V, E) p6 ~4 @" }. ^
   HINSTANCE        hDhcpDll;
+ |5 e; |4 E9 R    DHCPNOTIFYPROC    pDhcpNotifyProc;5 A, N9 \9 B3 F. K1 ]
   WCHAR wcAdapterName[256];* z7 k1 \0 Y/ E% `
   7 C. H, t7 o0 t2 T% z
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);  k" T% R& }) Y
' h9 x6 f8 A$ t3 x8 ~5 F) p+ f
   if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
, c! @" L; G/ c1 Q5 [" w        return FALSE;3 I# O& D2 ^; K

+ T* p5 l% c/ j, ]! M    if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL), E2 i5 ]+ C8 y+ _
       if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 y- V& o" k9 `4 M. d7 k            bResult = TRUE;# z( S1 b# k0 k1 ?& L% U

7 p8 D' a; Q0 ], v  }    FreeLibrary(hDhcpDll);
9 U0 g- e4 s$ c0 e3 ]% ?+ S1 k    return bResult;
2 t0 }& g' w: s* M- @}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-1 22:01 , Processed in 0.017981 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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