找回密码
 注册
搜索
查看: 4502|回复: 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地址的详细方法介绍如下:( }( e4 U4 U6 L, H& \

3 V' R6 o. |& a8 `一、获取适配器名称- ]- B/ s/ W7 c- @7 k; D

% I/ J1 X$ z( D9 E0 q9 P3 |- b+ z这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:3 t3 l  G* m5 D/ p$ A- c  ^
( y7 w: w/ s/ [; M" x
1.1 调用IP helper API取得适配器名称 2 F/ i$ ]# k! ?: {: {  |# D
5 v) H! \, u% v
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);+ v/ l) ]0 S! r
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
* `8 f) y  h' s, a, l* gif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大+ g/ L! T& h; k& E  q# v: U
{
/ G6 M* @! f. W3 O% p/ r    delete pAdapterInfo;
; p2 }/ p) V3 }    pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];' W; q& R5 V! H$ U- P* H
   pAdapterInfoBkp = pAdapterInfo;
, _: K. W) p# Q3 Z; W; O}0 f( o5 X* c% P& f; \; ?
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )5 c& U" ]9 J( p! g% M0 R
{: S* n# I0 C( Y9 L% g+ k
   do{ // 遍历所有适配器
/ `8 Q7 K7 ]6 @" Z. l        if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
' Y6 i+ [: A7 N6 Y' }+ u; F& R        {7 e" V. G7 A5 r0 B% s8 a
           // pAdapterInfo->Description 是适配器描述) \* D  w- r5 S* u  B6 J" u2 m) O
           // pAdapterInfo->AdapterName 是适配器名称7 A  _$ u) |$ ]0 Q! q+ m+ |
       }! _+ j# {* U$ ~) W6 V, S- _
       pAdapterInfo = pAdapterInfo->Next;
1 r4 `- z: O, ~    }while(pAdapterInfo);
4 A% P& [0 u2 B  D$ `% O- a- N}
  k9 M/ v- v$ [3 f8 P5 U+ |delete pAdapterInfoBkp;- m6 ]8 {- B. B& v. F4 M

, V3 w3 c$ d1 c4 @7 {" n' @# m% a1.2 读取注册表取得适配器名称
% ?: K) }; L" K' k/ `
6 t" n  C' g: L, t在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;- D/ }6 r6 v$ |7 A( c

6 E$ ~8 u  L7 Y7 U/ m) {if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,7 }" A- p. ~6 i3 |5 Z
           "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
6 ^6 N2 y5 g- c" s6 t/ k( Y            0,+ d5 A1 [9 ~5 s  n9 O2 N2 p, }$ H
           KEY_READ,8 d+ C/ C* C) t' |, P8 ?+ c
           &hKey) != ERROR_SUCCESS)% t4 L" z/ n( f; h& w; x) \+ D" z
   return FALSE;3 Y4 \4 l. ~8 j. P& O& l
/ S9 }) j* Q; B! l- V( D1 Q
DWORD dwIndex = 0;) R4 u7 d+ S/ F% ?
DWORD dwBufSize = 256;# R# f( k% M2 P. s4 }
DWORD dwDataType;! X! R- H0 M0 \( O
char szSubKey[256];
7 V7 V$ p+ N# v3 @unsigned char szData[256];
$ i, P) U2 m- |- h/ S! g5 B% P  s" f& m! f; G2 c! |
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)0 {: U* w; O0 W
{% R2 j6 k& B8 K/ n& b1 U. c! g' X
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)5 q+ T- r8 O( \, L# ~1 F4 \
   {        6 H$ N9 n5 E' j# B" j8 t! r! Q
       if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)0 V+ r" I! j  R1 h8 G8 b7 X) }, k/ k  y
       {
$ Z8 ^  |; i7 z1 n/ `1 `1 \  L            dwBufSize = 256;
: q6 R& N7 a+ O7 S            if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
  R% L8 P- k' x$ }; O: p7 Q            {
$ M2 E+ P) a: J                if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
: m% E8 ~1 \+ w# y# B: }2 R                {. ]) P$ s" ?- A+ u0 Q6 F
                   dwBufSize = 256;
5 {( R' N$ X9 U' A5 w5 {                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)9 F" A4 G  C, U. u! \9 z
                   {
: a5 A8 q( f! c9 X- s0 t2 b                        // szData 中便是适配器详细描述
' s( e0 o' R2 o                        dwBufSize = 256;) ]: z0 m2 J) X* N, {/ r1 u8 e* j
                       if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)1 {" g4 \8 S; Y: R! Q. z# ]% r4 d
                       {: H" O3 m2 I7 @; P) e
                           // szData 中便是适配器名称
/ k+ x; U3 f4 E# t8 W0 G                        }! d  y; P; F& u9 h
                   }+ ~2 R4 J9 t- v) w( G4 R# ?' S
               }' R7 v/ a! h  M: U6 [! A) S2 P) _
           }, P# F* s0 M( _  y
           RegCloseKey(hNdiIntKey);
- w; w* k8 v- J        }+ B9 S! S8 R3 B+ B. p
       RegCloseKey(hSubKey);
+ ]4 Q+ c( \6 _# Y2 M    }* j1 E) l. p9 R4 N% F7 e( P2 k2 |

- d! ~% g- o% M# R0 G    dwBufSize = 256;$ N3 U4 Z( Y, |) q
}    /* end of while */
! U  _: u& F4 K* r5 E        : \/ }# P8 r; g2 p- V
RegCloseKey(hKey);) J: q. _  {9 J( j) x, j
二、将IP信息写入注册表
; h6 P  ?: B9 o% c+ D2 s" _9 e! x/ G( D! g9 j' A
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)7 I4 P: m0 F9 x$ G- I4 h. r3 G
{1 f* n" u( }3 K, ~) q: k. S  P5 p
   HKEY hKey;7 E1 F0 h- d9 e0 y# f
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";* |2 I* l9 E6 ?" M5 {, o
   strKeyName += lpszAdapterName;# @4 i- l5 `# g  ?1 `
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,: A) z0 r7 S, o6 K
               strKeyName.c_str(),
2 O$ @3 d1 a9 i+ s3 d7 i                0,1 e3 k$ ?# M& [0 n1 m  M
               KEY_WRITE,
6 O. g8 x. B9 f$ g! @4 [                &hKey) != ERROR_SUCCESS)
2 C. i) d" F4 q        return FALSE;
. ?9 K. s) P4 h  [0 F    
6 M: C# e  t/ i# _    char mszIPAddress[100];# r* z+ O. r/ s5 r+ D' T4 T  n
   char mszNetMask[100];/ Q. `+ y  v! ~: y/ V4 g1 K
   char mszNetGate[100];' o9 H+ }6 G! S) d/ x

1 Y, L# u2 L0 c, K" V/ ?& K    strncpy(mszIPAddress, pIPAddress, 98);/ P- [2 g2 y$ K  Q/ B
   strncpy(mszNetMask, pNetMask, 98);
! O6 L# t0 r7 O    strncpy(mszNetGate, pNetGate, 98);
/ r" X* U5 B- Y6 T
% v' |+ W- y7 U  b7 L: v    int nIP, nMask, nGate;
% r% r! _% e6 A2 M0 d5 a8 G  g- D! {( f5 ]0 O' w( V
   nIP = strlen(mszIPAddress);
0 s2 A2 A" S' t4 @% V    nMask = strlen(mszNetMask);" L' V* n- v% K8 X9 x
   nGate = strlen(mszNetGate);
+ f  b2 r2 [3 w, m7 ?) E; H  n  i2 J" ^0 K
   *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0: v  [, {4 }6 a; B& \, i% N
   nIP += 2;. R3 Z0 p, H! W# D7 }! j; Y
; s- c$ E/ X0 H9 X9 ^: k% H
   *(mszNetMask + nMask + 1) = 0x00;
4 e( O0 E% x# i, m* _    nMask += 2;" S+ I! R' b" c) v- `5 u- Q

( }; c# v" m3 [    *(mszNetGate + nGate + 1) = 0x00;0 \$ X$ u1 Q' _" F
   nGate += 2;2 ]- ^( A! ?6 i; V6 z/ y8 L+ {, `7 w
   
7 @5 H! O* j2 a    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
- z! j# W; C" _! ^/ k; ]- `% n3 ]    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);$ L' O" P* h$ v( m
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);- W- a8 C# c$ c+ X3 t* w8 i6 `8 ~

4 E* H. _7 S9 d* r; F5 z    RegCloseKey(hKey);1 n' F; A# F' d' ~/ i1 b# `

5 M! Q( B9 ]; {" }    return TRUE;6 d* O% G; b+ [8 ]* `. h+ t
}
# _& r1 U$ Y( ]1 y4 J
/ w' J$ x( i- a- X三、调用DhcpNotifyConfigChange通知配置的改变
8 S: B. j9 Y8 I/ @5 X/ _
  S, _+ W# e% h! C) W未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(& R5 R; j0 K( S; R0 O5 D
   LPWSTR lpwszServerName, // 本地机器为NULL8 s. b( J* q% N# s) O: B
   LPWSTR lpwszAdapterName, // 适配器名称/ A' S/ s" c( u( E& i9 ]
   BOOL bNewIpAddress, // TRUE表示更改IP
; u. m" P% u2 S3 _; z    DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为03 q) A7 `6 i& A, ?, n/ |* B1 \+ s
   DWORD dwIpAddress, // IP地址: w2 k* m1 [- e$ C9 i9 z4 Z
   DWORD dwSubNetMask, // 子网掩码
, G* K# n, z* z+ b2 P4 X    int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP& Z1 Q2 Y$ O6 x6 F( q) `- H
% A' x; K0 v4 f4 S5 Z* s
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)! p; r9 C& x0 L% ^4 E
{! {" v9 ~! q+ n1 K* }
   BOOL            bResult = FALSE;& |- r  Y+ X: L/ e8 w: a. k
   HINSTANCE        hDhcpDll;
% ~' @- c4 w; }9 z' q. z    DHCPNOTIFYPROC    pDhcpNotifyProc;
5 l8 S2 z8 o/ o9 w. |/ ~; ]9 r( A* o    WCHAR wcAdapterName[256];$ ^2 S( n" A; M# P
   
. P& R+ {8 `, k$ F, E$ h    MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
; n2 w# h8 A+ V7 e! _- l$ [3 x; ^3 P+ s- X9 N1 u3 v. h3 W0 h
   if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
$ ?: j* `7 X; k$ G7 j        return FALSE;' r; ~9 R! j( V
' v9 `5 d7 T5 Y0 ]4 d& S
   if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
  p( i9 z7 Z# S, S. j        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
# h6 n; H7 ]! i. L% T: S! u+ P) i            bResult = TRUE;/ h. c8 o5 P% c3 f: i" J- q5 D

, R5 I% L% o5 g4 I1 K" ^    FreeLibrary(hDhcpDll);; _7 [% o! n# y; G' r( L, E4 j5 M
   return bResult;( J% Z) K6 Q6 ~1 W0 P1 ~5 A) b
}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-5 04:39 , Processed in 0.016060 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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