找回密码
 注册
搜索
查看: 4629|回复: 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地址的详细方法介绍如下:  p1 x, a' ]1 R' N- h
2 O: y5 U; x! R% W6 O% w3 X7 O
一、获取适配器名称3 }0 ?4 e6 l. a

1 l- O9 W$ _/ y" \+ z0 W这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
/ A/ ~8 P, @5 y& B5 d2 O8 L* f' S' ~
1.1 调用IP helper API取得适配器名称 5 M. [% @5 P/ n1 Q$ p

$ E* B. U2 W% ~  l% @) B5 g8 ]ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
# Z0 I% |" [- P5 U5 _! K% L% xIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];; \9 y& h0 m/ {) D2 X5 ?
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
1 q- o) F0 d& e8 x{
6 Z" [2 V1 r7 g3 s    delete pAdapterInfo;! ^1 c% f$ f+ p4 x7 G  d. w
   pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
1 O' K) G7 j9 D7 e    pAdapterInfoBkp = pAdapterInfo;
8 _3 a+ f8 d8 i}
5 L" k. R2 C2 U0 j/ @: ]5 aif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )( F+ c1 k% X7 [( E  e# \8 D& O
{( S7 i9 W( J0 q( \' V$ l
   do{ // 遍历所有适配器5 h: }3 S, P* L" e% \2 N9 s. s% t
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
/ B8 L  V* l) P4 ]& t        {! D  T- q( r2 t+ k
           // pAdapterInfo->Description 是适配器描述/ {4 J; ^- G. n" x
           // pAdapterInfo->AdapterName 是适配器名称& V: D. c# R5 m4 v! w; V3 c' k, E( L3 O! \4 f
       }* w5 k7 J3 ~- n$ {
       pAdapterInfo = pAdapterInfo->Next;9 l& |: c( q; a
   }while(pAdapterInfo);8 Y  n' H2 r* }4 i- j3 C
}2 h% v: y1 D  E2 s- Q- u
delete pAdapterInfoBkp;' }3 a+ ]/ u' Y4 p% {  x
7 T- P. a% A$ D2 {
1.2 读取注册表取得适配器名称' g. ?/ S! |, }$ [2 ]: n1 P
, p) G$ d- ]1 V9 k% c7 \. ~
在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;3 d, u" _1 h: e4 G  s) D+ G5 ^

1 d# S/ v4 q4 y: [  l9 tif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
3 v% f6 q& o" c4 m/ i# ~" g3 L9 e            "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",5 H2 r# ]& [# t
           0,% u* K4 \9 B7 ]
           KEY_READ,: O6 }2 ~: [' G
           &hKey) != ERROR_SUCCESS)6 l* H" M0 b! Y
   return FALSE;
. w4 Y9 q/ P* y+ o: j' ~8 M3 c3 z; _; ^/ ^# T/ J! p
DWORD dwIndex = 0;
8 B2 S9 [& A* z: ~9 m9 gDWORD dwBufSize = 256;
  e" t  |9 y$ C3 KDWORD dwDataType;
, k4 m+ T  U% r. N- l. i& M. m6 w" Ychar szSubKey[256];$ u2 u0 ?7 `" C1 P0 G5 [6 r2 B
unsigned char szData[256];
3 u  e  k2 P( ^# Y. ^4 o( b# T7 }+ q8 f6 F! v# `; S
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
3 }+ N* G4 o, X, N. f& ?5 D2 ]{% y$ H+ g# X) D9 s" u- X
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)% H  e; k3 O) l
   {        
/ r! W0 H/ V2 @  u0 A; P) n" |        if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)0 a/ z: K7 r" n+ g
       {
- V% J& @2 G4 B5 O' S            dwBufSize = 256;1 g7 W! w3 e, q! F
           if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)' J/ ~1 j+ P- I/ B
           {1 Q. R9 O+ h" ^0 B) J" b
               if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
% n1 T6 p1 a" \' ~% _; @                {
! J' d- @  f  p& u# c                    dwBufSize = 256;
6 }9 p6 E) i5 D$ |2 j                    if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)9 F3 v7 }' I" }# G
                   {
+ M5 o% x1 _  T" q$ U                        // szData 中便是适配器详细描述9 H  l4 ^( X& g' X7 |
                       dwBufSize = 256;
. G' ]  i' f) Z7 s6 e. }" T- b# W                        if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
: k; p0 I8 s/ H9 S3 \                        {( N, a6 A. J/ h* U5 ^# W
                           // szData 中便是适配器名称
1 w: Q- J0 n6 u: m$ o4 F$ x: @                        }4 ^/ L, r; B9 w! Y! ?
                   }* }1 H/ S0 U/ S# \7 N+ M
               }( a/ {2 Q* ~4 U
           }
! ]5 u, p; h+ b/ Y9 X/ u  x* A7 [            RegCloseKey(hNdiIntKey);
+ R! m3 N' D: c& @2 l7 s' V4 h" j        }: z5 R9 m. m+ l
       RegCloseKey(hSubKey);
% C* T: r9 I4 a% \3 q    }; p! A; e! T6 z2 X2 B$ r
" {3 q, z$ H- i0 I, Y
   dwBufSize = 256;5 ~3 j, ], D# R/ m
}    /* end of while */3 ?5 [8 q+ a4 R& `- v. l( H( c
       / v9 O6 O. D) D( k6 K: x
RegCloseKey(hKey);# M7 d9 w# p1 }7 z6 }
二、将IP信息写入注册表) R# A" N( R/ B* H" N5 e' v
0 y6 ]5 U9 U9 L5 X9 X2 ]/ \6 Y# s
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
& @; K9 m  G. ^" [6 \( O! y* ?{" c1 R: d! R$ k& `1 Z, V8 y# b
   HKEY hKey;
0 L, z; T: j& ~' j: N# R+ w    string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
8 M( h# h. C' B. r- d    strKeyName += lpszAdapterName;
3 E! F7 t; l3 ?# M' Y& [: P    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
8 W" W) b0 v. F/ ^/ w( C8 Y                strKeyName.c_str(),  S# J$ W3 _) `
               0,1 q* X" K3 D" }. l8 D0 b6 a
               KEY_WRITE,
) u# x- i! h9 `0 {  t2 F                &hKey) != ERROR_SUCCESS)& `  @9 `6 x$ c) I
       return FALSE;; {$ [/ G/ [* b1 p* }
   
2 F  b4 s' U4 p) ?8 E" c# |( E    char mszIPAddress[100];
) O# h% h: F' P+ x. t    char mszNetMask[100];) s: o( V- ?$ B* q# m
   char mszNetGate[100];
( t! o; M' o$ H4 o% t) l( C! l# z2 u% R7 ~% a
   strncpy(mszIPAddress, pIPAddress, 98);7 C; A1 |' }7 g3 _/ G% H7 a
   strncpy(mszNetMask, pNetMask, 98);) f7 V- Z- [" ~& _2 P  c* l" R
   strncpy(mszNetGate, pNetGate, 98);6 G8 l* a& F" s* ^; o; A& e
5 x' Q# H0 d4 N6 b
   int nIP, nMask, nGate;
: e2 r' K2 O! |7 J. ^+ w
: M1 L+ o' Q* w. |* j: Z+ m( E$ X5 b    nIP = strlen(mszIPAddress);
- N% R+ B7 b4 U# O; `; G    nMask = strlen(mszNetMask);
4 i6 O" M8 w2 E! \( p# n, _$ \    nGate = strlen(mszNetGate);, }! Q7 o# n: T) |" j/ F* Z, y% N

2 I. u' Z; C6 \7 H$ k2 Y& b    *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个0  \& [- G% e+ J1 z( F
   nIP += 2;5 i8 I2 {6 `3 Y( t) U
  ?$ h% S. ], Z0 I6 t' ^
   *(mszNetMask + nMask + 1) = 0x00;
$ A% ?8 m2 U0 i. ?$ A2 n+ m    nMask += 2;
3 ^: C( b2 W5 c; D+ h- D' c  E4 K+ \- c3 o
   *(mszNetGate + nGate + 1) = 0x00;( B- p& h& Z' ]/ x
   nGate += 2;- }4 f# |. r1 p: o  y7 w$ X
   7 x! g* N8 w, L  O
   RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
0 {; X% `: P" l. C0 s    RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);" c/ L) l% w8 \5 C# X1 h
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
& N' y/ q5 e$ P
4 ]/ x  r' Q$ {3 p/ s& ]; I* S1 i# g    RegCloseKey(hKey);/ @/ G  C' j9 S  B
$ ^$ u7 b5 s  T( U% v' q1 R
   return TRUE;
1 W, i* f* W' m( r" I8 G  Y}- V) @8 u( d, J3 ~$ u7 P) [! u& @

0 |; S4 Q  e' \5 o1 x三、调用DhcpNotifyConfigChange通知配置的改变4 |7 K* a, g/ q  F. z

( x: e* I( j# E% \) g4 t+ E8 t* V3 A未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
& u/ {+ J5 f" J8 V# u    LPWSTR lpwszServerName, // 本地机器为NULL9 D3 [) a' ]  U  ^$ J7 o/ s
   LPWSTR lpwszAdapterName, // 适配器名称
* [) s8 w/ j- v8 k0 t    BOOL bNewIpAddress, // TRUE表示更改IP- y6 ^$ L5 J, T% B* F, p
   DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
( t0 c4 ?. `& z    DWORD dwIpAddress, // IP地址  h8 j! t$ a8 I: [' A1 e) w7 n
   DWORD dwSubNetMask, // 子网掩码
8 G' U" Q; r3 x# y0 U: w' n, }    int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP( w8 a: S9 Z+ Y! k: a; t: x' N9 l, L: v

6 }$ w2 @' b2 B; A( b% m! v具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask): I! H3 e+ M1 p0 F1 g  I
{
; }* O4 o/ A* B7 d: f# \    BOOL            bResult = FALSE;1 k( G' w" o+ B$ P4 q" U
   HINSTANCE        hDhcpDll;
, r, N0 l3 s& G  s( i    DHCPNOTIFYPROC    pDhcpNotifyProc;
5 c, l4 y  @  M6 B) i& w/ m8 X. J    WCHAR wcAdapterName[256];$ L, B3 E. u8 a
   
! g$ h. y! P6 B: a0 M    MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
8 S1 Y: @6 j! \/ N# J8 Y5 `; b( i* g
& f+ F1 }/ c& ^. Y- D% A    if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL). n2 Y6 I  v' e- h+ P6 K9 Q
       return FALSE;9 n6 W* Q' p/ \, o
: h+ I- R; k8 j+ s* D
   if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)6 q9 T) w9 ^3 r$ H1 @9 Q$ g1 |
       if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)1 c$ Y8 I+ ?5 m5 S. t4 E9 x
           bResult = TRUE;1 M3 T- j, L. |. D; S
4 s5 ~) F: s" N+ N* g7 [7 b
   FreeLibrary(hDhcpDll);
+ a) I& K+ B* w" D0 Y! s    return bResult;
3 [# j1 f7 R4 q( n, a}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-9 08:44 , Processed in 0.035534 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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