|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:# f& Y/ i+ B' N. D; }4 S
4 U! P' R7 ?+ t5 t9 q
一、获取适配器名称
7 ~8 o9 S7 m. _1 \. }: q& Y& c. D1 l8 ^; F: L" ~
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
7 i- V {, k/ s( N9 c) X$ K, z4 I- h9 O1 I: x: \" u
1.1 调用IP helper API取得适配器名称 0 ^8 R9 o! X. @/ K! f3 e8 F/ P
5 J0 e) V2 q( b3 B
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
0 f8 H+ N( e9 X. m% Y$ u; FIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
5 I2 i; f/ L. V# \- J. Xif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大4 I. M8 W/ ?# @9 d5 X& S: {
{
* S- r1 G, s5 f" d; ~% ]4 a/ Z2 D delete pAdapterInfo;
# U* W4 x! c6 v) A& c pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];4 ~8 t4 k& S- L) w
pAdapterInfoBkp = pAdapterInfo;
$ w4 j6 ?" j* d- x5 m}
; j2 [2 @# o$ Y/ h7 ]if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )# O+ T% X R$ `3 A' }+ v4 n9 ]- B+ u# H
{
2 g; ?! O) U, Z do{ // 遍历所有适配器( X( A: J( l. }$ h. E
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
3 X% J) M3 ?0 o9 P" D; F {
0 M; C, t* D- p' ]* i6 n // pAdapterInfo->Description 是适配器描述
; q( t2 j* m( q* x) n1 W // pAdapterInfo->AdapterName 是适配器名称
4 l% W1 [/ J; f ?' m' X: J2 j- | }+ B- m. w- A2 X6 C% V
pAdapterInfo = pAdapterInfo->Next;4 S& k" l" P" C" E# E8 f, {# z
}while(pAdapterInfo);6 c5 l: h! z2 L" k
}) r1 e1 d6 N! K# P" P
delete pAdapterInfoBkp;
) f6 l \' B' m0 q) G, b* J& Y6 u. @6 k5 B6 N2 h
1.2 读取注册表取得适配器名称7 H3 _* _4 w7 ` _
$ H3 O9 z3 P C7 { t5 F在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 B; L( K8 T3 D1 }) u+ P- |+ b9 ?) ?0 r
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- |) R; [: ?! t# j "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
6 l1 e" c6 _% _2 ` 0,
( q( y" a1 p1 z' W: ~; p- H& G) B KEY_READ,( B3 N- P* F+ e0 C- i9 W# x+ }. Y% v
&hKey) != ERROR_SUCCESS)
6 |8 V2 y! K, D$ i) l return FALSE;- d5 c3 g4 G6 o. X \0 v5 z
) g8 G; w7 j# K1 C0 RDWORD dwIndex = 0;) [3 A; E8 ?. W* Q
DWORD dwBufSize = 256;& X0 V% d0 Z) S" e5 [
DWORD dwDataType;
4 K- R$ i' C/ m: j/ E. y3 B" x* ~( ]char szSubKey[256];
$ d6 F; ~( C. Q+ _0 Y# d9 runsigned char szData[256];
# y N/ n4 ]) f0 Y7 @" o
2 l" j$ Y/ z3 C6 F, dwhile(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)- e! f _' N. D i7 V
{
" d: S+ F. i9 }+ O6 G g; ?1 @7 _- K, D if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS); I- M6 Z2 m4 K7 w8 A5 B
{ 7 J; J' s3 P o6 d7 |3 e$ M
if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)) [. U- K5 m" Z, w8 p+ s0 {
{7 ]$ ^0 B9 j0 X2 {
dwBufSize = 256;
; i! [$ b4 a# }* ]: f" X if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)1 ]- o! H6 t* U" x. x6 d
{9 T' | n/ D1 s1 @9 h
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡0 X( g6 P# n( x* R- E
{) N; y* ]+ D7 W5 I+ ?
dwBufSize = 256;8 X5 d* P1 B+ r& B" s6 n
if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
% H5 j m4 d, q {
' W, _! D) w& O" n; n2 @ // szData 中便是适配器详细描述- h& U/ ]3 ~ }* F
dwBufSize = 256;
+ n$ y4 M# ~' h# h7 h% p5 ]8 }$ r" S if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
$ y/ `5 v9 H6 c8 u3 b {; j; m+ D9 k# J5 F' l- u
// szData 中便是适配器名称/ P7 y$ o& }# Q% L+ G
}
# G! c2 `4 x9 P( P }2 L$ m, L p0 b7 \: v
}
0 v) S5 z% P. B# y0 ~# k0 ` }
$ W* r, R$ y8 v9 f; K0 E& l' q5 ` RegCloseKey(hNdiIntKey);
2 X! I4 u! |. J9 @1 g( X }8 B- h3 P) t6 j7 Q! P8 E
RegCloseKey(hSubKey);
# r& P( j- C+ {6 l } V6 n; p0 O. T P8 e6 R
' H0 N7 ]# j5 A$ l- s) Q dwBufSize = 256;
; c. {3 C0 N4 B) X* n- f9 z& Z} /* end of while */
2 u# n! \* F7 z! E' S5 J+ a 2 {/ G+ \+ {2 R; e- u# E% z
RegCloseKey(hKey);
* K5 D0 n( {' j" V二、将IP信息写入注册表
" U+ ^0 ~& l \1 q+ P1 V5 D; P* E9 ]6 V6 l8 J' J
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
& m. D% ^* h* ?7 Q{
8 k6 G7 l. b5 L" L HKEY hKey;7 @- Z* f. y8 i. B
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";% X! u+ t; T; E
strKeyName += lpszAdapterName;
9 x# T& D$ u6 K8 ?, q if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
, F; D' \2 x5 k$ E strKeyName.c_str(),
3 o. s3 f/ @. i, w 0,8 Q# ~0 r) S, Y8 m
KEY_WRITE,
# A9 o& v, j3 F$ x# F) ? &hKey) != ERROR_SUCCESS)
; @: Q- L8 U4 k0 s z; t return FALSE;
, a3 z0 a) X1 \- {. d
: v2 w/ \. H$ y4 N( N f char mszIPAddress[100];
5 j1 b; P$ @# z: g1 j char mszNetMask[100];
% @. T: V) W1 Q0 T7 `! Y2 t7 U) L char mszNetGate[100];
+ q9 u0 Y8 h. }/ h9 f$ m, R' v
+ N O w# b! b strncpy(mszIPAddress, pIPAddress, 98);( ~ E- c- _) a% Y
strncpy(mszNetMask, pNetMask, 98);
- G3 M" f3 ?0 T. k: D strncpy(mszNetGate, pNetGate, 98);8 j9 F/ C1 D6 Z2 u6 X; N( v
# A* V" Z9 W" W, Z1 z" A int nIP, nMask, nGate;
& A+ U# g0 \* O2 |* w3 J+ q8 Q' `( |5 g; h: N6 L+ R
nIP = strlen(mszIPAddress);4 J) T# \" N; } x
nMask = strlen(mszNetMask);
7 ]5 V# E4 o- r5 O- G9 k* N6 s nGate = strlen(mszNetGate);
4 t: X0 o' l$ W: E# W, Y
( ^1 E: e1 B+ b8 r1 G1 ] *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0
1 Z& ~8 a. J0 c3 h nIP += 2;
9 t4 }3 z6 D) S1 J
! |/ A2 a& C) x1 i) e! | *(mszNetMask + nMask + 1) = 0x00;
% ] E9 S' O* B4 m nMask += 2;) u/ q; a" v! ^
' g; L0 _% F/ d2 k/ I! L5 u
*(mszNetGate + nGate + 1) = 0x00;& j. a; W. h @( `0 {/ m
nGate += 2;5 r* }, f! ?+ ^8 ], K( i, Y2 M2 X
7 h o9 h) N% o2 ]' r0 P RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);9 S: Z0 r* ?! ~, O' @& o
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
2 X d8 Q, t0 V3 L5 v RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
- e$ v7 M+ ~1 T5 G- ~' m7 y
- P! {% \. X( {# A" a RegCloseKey(hKey);
" V$ @) W8 \3 `! t/ e: v" ]8 a% X- N5 c$ b; k8 N
return TRUE;
0 {# l& r0 F0 _/ u}
# H: z4 }6 y. c- Y
7 e# t$ P9 H( q& X/ f; d三、调用DhcpNotifyConfigChange通知配置的改变
3 A* |* u" q% @8 _
. O5 t P& H; _# i0 y! ]未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(6 U a: ]* p, Q8 \+ N; N4 Z& c
LPWSTR lpwszServerName, // 本地机器为NULL3 w# I% F4 m3 a
LPWSTR lpwszAdapterName, // 适配器名称
+ g. b6 K) _" X! W BOOL bNewIpAddress, // TRUE表示更改IP
4 U' l: |+ ~" C- e DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
! L& p/ M( X/ _) J( D j4 ]: _9 C DWORD dwIpAddress, // IP地址$ T* B( g. h: T7 D( Q
DWORD dwSubNetMask, // 子网掩码 z# M: t" l q) W1 G
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP6 W& u# j d# q3 x; k( t# O! ]
' ~4 _" ~& X- \! a* ~( ^具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
" _( Q' N6 s$ l2 Y) \' h0 E. ~{
3 h6 m" P& ?" Q1 C BOOL bResult = FALSE;
5 v6 a( m2 ?) H0 }1 j4 r HINSTANCE hDhcpDll;% H3 ]4 ^: f2 i7 d
DHCPNOTIFYPROC pDhcpNotifyProc;& T' q- E7 b( _ ?5 W
WCHAR wcAdapterName[256];) N' O+ I6 d ?4 n$ N
4 T g/ C1 D7 R4 f( f/ T MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);- q( v" V7 ?* N2 g3 b- K% v
3 S3 l; ~* G0 e0 @0 Y8 K4 V
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL). M, o5 i/ } v C' ^1 V
return FALSE;
) T. ~0 n+ x8 s2 |4 D! h. _: |
3 P4 O% X$ F- W6 u if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)& x J( n0 J8 S. j# K$ ?' u( x
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
: t( L) c* Z* X$ W' x) ?! M' R bResult = TRUE;$ ]$ S& x3 U! U/ c, f& O& G
" |7 Q! Z1 F) n# {- L
FreeLibrary(hDhcpDll);
9 U- W& H$ J/ K, K* M6 ~5 E return bResult;
0 [. Z! s) ?8 }5 N7 W) h( L} |
|