找回密码
 注册
查看: 5239|回复: 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地址的详细方法介绍如下:" `7 v5 H3 B; v! C5 J

% p4 i0 y/ W0 m* n+ P5 X9 n5 G1 q一、获取适配器名称' T& ]- P) e1 b! b/ L5 i0 D8 q
0 Y: {4 ]7 U3 T
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
3 E8 }' k: t" I7 o6 I9 O' y! {9 v8 g' k$ K
1.1 调用IP helper API取得适配器名称
$ B$ w: O# r& y
" V& n) N2 ~1 P! OULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
! ?# X* {( \" Y4 {IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];& }3 _( q* O  c/ a' }/ F( f
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
/ C& Y. F4 E/ Z6 w  j# |- q+ S{
8 e. C  p/ M; m    delete pAdapterInfo;
# L  T" H* F& T8 p9 d  k+ N    pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
: ?) G6 q/ J! z9 z* S) D2 a    pAdapterInfoBkp = pAdapterInfo;
! n1 f" g% e: ^0 D}2 i8 u) O  R9 x% \) Q
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
; l0 c9 [" q, `- w2 A( j8 Z) w* r{5 t8 g5 k7 f' Q6 P% m6 w' T: M8 J% \
   do{ // 遍历所有适配器6 d' W& N) l" {5 B
       if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)    // 判断是否为以太网接口
) I: T& a9 j% b+ w7 g! {, {        {  {0 F( K5 ^/ ?* C* Z
           // pAdapterInfo->Description 是适配器描述& D) \6 y  w- ?; v6 p; q
           // pAdapterInfo->AdapterName 是适配器名称/ l" y9 ]% r/ t% v0 K  [
       }% D4 H# [9 e! N) j9 A$ M% A; h
       pAdapterInfo = pAdapterInfo->Next;# C  `+ ~7 q" q# ~) K1 R0 Q
   }while(pAdapterInfo);
# _! L( o% w8 h3 [3 F) a}2 I8 C; Z% e3 {, V( l9 N6 Q
delete pAdapterInfoBkp;
6 s* ]  Q6 r- U
& f; R( W$ R- K4 U; A" I1.2 读取注册表取得适配器名称
  {; W5 q: J$ R, T. E; u
4 q# W! X& ~( o$ R" @在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;  z$ Z4 b. J5 G/ i+ ~; m
- p$ E) C3 C5 o2 f: I  J4 ]
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
! ~7 }4 [$ d$ J! A; g            "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",* t% s8 o" f! o  j7 x# C
           0,
- T) M' z5 r, y3 v            KEY_READ,; D/ I! \5 E  v8 p7 `% w. ]
           &hKey) != ERROR_SUCCESS)# O8 _  T* f7 a  O7 j& Q
   return FALSE;
3 j$ }9 a1 ~/ b# Q
' |2 n/ D" h# N% F: kDWORD dwIndex = 0;# R2 p# g% d4 m* i3 E! r: I
DWORD dwBufSize = 256;+ ^/ P. q+ @! U6 C3 k: ?( S6 u
DWORD dwDataType;% I! O6 q6 ~- {: o  e
char szSubKey[256];$ T% l6 B3 j4 X  I2 b0 ~' n$ I% r
unsigned char szData[256];
" Q" e+ ^* u1 }2 L5 v1 u% b0 C( R4 \) P: c$ K
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS), w1 r' {4 u+ ^8 R6 j# P
{. ]1 q* f* r5 g3 A5 H# [
   if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
1 ]# [, E+ K/ ~( P: z    {        / A0 Y, Y, V  x% k
       if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)# V" Q" r: O% `& _8 q8 W# T1 a
       {3 X: y3 L( c) U% |
           dwBufSize = 256;
. Z/ U* o- o/ z% E. k            if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
; ?+ Q  I" K: \: U/ N0 D            {
# ^% t/ Z) B# Z: k) J" `7 y                if(strcmp((char*)szData, "ethernet") == 0)        //    判断是不是以太网卡
! ]8 |1 r6 k) e1 L) N                {- ~  c9 q6 f# S
                   dwBufSize = 256;$ B# W6 ?' S; y/ i+ O
                   if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
& A/ f; S+ t" h, [. K1 D& G                    {
; g; o1 S& [  L+ }! |                        // szData 中便是适配器详细描述
" d* ]3 F% t9 f& t) t5 Z& S9 U# f                        dwBufSize = 256;8 t) t; r- `- E# p8 q/ U) x. \, z& I
                       if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)4 n( ^" V$ I4 b: d+ s
                       {7 ~. A  n3 r- C/ x( B
                           // szData 中便是适配器名称6 @9 x7 n1 [) J% |: j1 V( _
                       }
; e: H+ A0 L/ D                    }
' `  T* k; O7 o$ X- J                }" P9 [9 z* K2 U$ J; x, ~
           }+ |% |" w- @5 R0 A" ~9 f; ~
           RegCloseKey(hNdiIntKey);
' j! C3 i) y; L& f8 _, [( V5 b7 N        }
: d4 D% B& A- V7 b) J/ l. P, |- O        RegCloseKey(hSubKey);+ E% ~5 T4 R2 ?( d1 }
   }" j! O6 Q2 C+ I  |, J6 S2 }
( [" G9 S: H# f: |
   dwBufSize = 256;
# N5 u4 A2 Q; M3 E7 ]}    /* end of while */
! x# V, d9 o* S% u4 B        . ^, z( v0 L( @
RegCloseKey(hKey);! M4 D) i" O. Y
二、将IP信息写入注册表
0 @$ O% f% J) h  g  z6 ]% I3 w  S) ^
0 G' C+ F8 t! ]& x代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)# H) p2 C1 h) T0 P
{
& q9 S3 o8 U% o1 a8 A    HKEY hKey;6 |" r. w' a4 c" Y+ m- e( k5 Q
   string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
6 Y9 q: K% H* A: n# t8 p( T+ |' O    strKeyName += lpszAdapterName;7 b6 f* \5 P; Q4 T) S0 F$ U2 Z
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 J+ L8 I4 F  f" c6 O) ]& o
               strKeyName.c_str(),
) D! s1 b' v6 P                0,
) I% }; Y  q; A                KEY_WRITE,- G% t, k. j  V8 s% f. a3 i
               &hKey) != ERROR_SUCCESS)
3 \$ L0 G$ |& ^& I        return FALSE;. c1 V6 N* o- `& {
   
* q' H8 P0 R4 H    char mszIPAddress[100];& P5 W) F  H8 |& r2 o  f' |$ ?
   char mszNetMask[100];; }$ J; _! X$ `8 i3 y: k2 t
   char mszNetGate[100];
/ q) H+ n, n2 x+ k; {
6 f7 o. U9 z' i5 E    strncpy(mszIPAddress, pIPAddress, 98);  M) S+ B0 P& |% `! @5 I  j
   strncpy(mszNetMask, pNetMask, 98);
6 P' R0 Q, V) M( M% A! J( B    strncpy(mszNetGate, pNetGate, 98);. S* D( Z4 H" r6 O" B
- b: ?0 n1 T- n6 }/ {" d
   int nIP, nMask, nGate;& A5 n6 y* S" ?. }7 ^% ]
8 B% S1 H/ g  Q
   nIP = strlen(mszIPAddress);( c8 u4 P( t* O8 [) y4 `4 D
   nMask = strlen(mszNetMask);$ N6 }7 l+ i( j5 H4 V1 l5 L5 {
   nGate = strlen(mszNetGate);4 g1 E. A0 N3 A' N' n# X
: X( }/ n( ?: Q# H) G: d
   *(mszIPAddress + nIP + 1) = 0x00;    // REG_MULTI_SZ数据需要在后面再加个08 k1 u3 h1 A: A
   nIP += 2;( j0 x/ v. b4 {+ J
5 H$ G4 a9 f- W. j% o
   *(mszNetMask + nMask + 1) = 0x00;0 D! w; U) X, W% X! S' I
   nMask += 2;
, J7 ^! T# M% Z( s1 j. g. U/ p
+ M# b( H: L# K" U+ l$ _    *(mszNetGate + nGate + 1) = 0x00;
9 B3 M& ]3 A6 K$ W/ u3 @5 H    nGate += 2;2 k8 c0 S* k9 ?& @6 O( k
   
6 z3 H! I' P9 u8 W: z. ?    RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);- \' r! ?% j' C( q7 y5 O1 B
   RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);5 j% V# p: v1 f8 I; s7 C7 f
   RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);& P( ], k1 t2 q5 [

6 o' W$ j; l) C& b    RegCloseKey(hKey);
' n& Y1 o/ U; {) @
! J7 q$ e0 F4 o, c" U3 g    return TRUE;
4 G5 q# U" ~7 t: U6 x; q2 `}; S' j4 I9 W7 h5 M: H1 t
2 U  ^6 V: c. w) ^  w' _
三、调用DhcpNotifyConfigChange通知配置的改变
/ K6 q- o6 s( C2 T% B/ ?/ ^! I& |; A0 P( v/ m9 D
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
& {6 p5 i6 y" _& R) d    LPWSTR lpwszServerName, // 本地机器为NULL
. T, `9 Q" V9 \4 G+ E! d& J    LPWSTR lpwszAdapterName, // 适配器名称) m6 j! u3 Y7 ^" {6 _8 |9 L0 N
   BOOL bNewIpAddress, // TRUE表示更改IP5 l( Q  l5 ?7 G6 X9 m
   DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
$ P7 A. O, l( [2 l    DWORD dwIpAddress, // IP地址
* d4 |: h0 {) O$ l    DWORD dwSubNetMask, // 子网掩码7 f5 i+ n5 e( ^- W- e* c# h9 h
   int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP: x. {9 B4 }8 ~0 W- b  b  j

2 ~5 l+ T1 p( X' m. |具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
* }. A1 V* ^1 g% ]; f{
+ r) }: s3 k' D( z7 s" u    BOOL            bResult = FALSE;7 m3 p, x% x* d) J: W# U
   HINSTANCE        hDhcpDll;
" i+ U3 u, w4 i  A2 q. b" Z    DHCPNOTIFYPROC    pDhcpNotifyProc;
- j, `4 |8 o1 G$ `9 _0 k! `9 Y+ W0 ?    WCHAR wcAdapterName[256];1 |5 @" w4 o% W6 B
   " K1 z! x5 u7 }8 Y) @. X4 k
   MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);6 o$ d  D0 b( n; ^  Z# ]) k

4 I1 D: h4 X3 ^/ X- Y4 q$ ~5 b    if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
, k" \# a: K4 B( o  P  ?# L        return FALSE;5 Y) v5 {5 e, q3 G" Y6 b7 [

" D( B. _* _% s) w    if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
4 W  V  j6 S( g0 `4 H( T        if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)5 D( b/ G- k/ M6 T! R0 U7 }
           bResult = TRUE;
6 T6 S! Y: H) ~0 w8 f, l' n8 d5 ^' g
   FreeLibrary(hDhcpDll);' t+ \; t! {& ?
   return bResult;
# o! E3 |& Q4 Q( q. x( e: b$ f- u}
发表于 2005-7-26 02:44:28 | 显示全部楼层
楼主厉害 我只知道 改了IP后 禁用网卡 在启用 就算在win98都可以不重起让新IP生效
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-2 03:04 , Processed in 0.018511 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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