|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
& c ~, N5 S# x- r' ^ `/ w& v
3 J$ f! c; x* K1 V" w5 C$ L一、获取适配器名称
; H9 i9 V8 [$ ~; o: m- |1 s7 v1 N+ d5 f4 E; s
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:# I6 c5 Y/ ~- i! ]
4 X1 O, X) b( s6 Z
1.1 调用IP helper API取得适配器名称 7 T7 S5 f6 ^0 g" i! Z1 R% W3 T2 V
9 S' N/ h0 j) [ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);, K( s- W: O( i- p0 f2 m% \
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
8 a' }2 M) A; e* U8 jif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
- L+ t- [3 r1 U' {; u{
7 O& \, n# e. w |, o6 a: o delete pAdapterInfo;
3 X, n/ t! |6 L! d( } pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];! `4 _; j4 h% ^/ y, w8 k
pAdapterInfoBkp = pAdapterInfo;
/ |% c% ^# G/ M \& q, n9 I}3 }- z" b ~5 {) E5 O3 Y
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )$ H3 v! V A) ^/ f
{9 a1 c2 Q3 ?. e G
do{ // 遍历所有适配器
9 e$ m- e) Y/ F f3 e8 ? if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口% ?$ Q2 g6 N# |8 i4 v9 d2 X
{. r9 R( }+ U5 J/ U- a+ l
// pAdapterInfo->Description 是适配器描述7 n( {+ O+ O8 d
// pAdapterInfo->AdapterName 是适配器名称$ ~- S8 b- V" p# t4 J
}1 q# @: [ ^* n9 V% W
pAdapterInfo = pAdapterInfo->Next;. g6 h: y& p4 G9 H7 ]/ T
}while(pAdapterInfo);1 N4 @! ~: {$ d, g {. D
}
6 O M2 `; v$ `8 Xdelete pAdapterInfoBkp;
: J5 R- E0 e$ |+ b+ d2 O0 Z! F% F8 s% J# B# w* H8 S+ |/ B
1.2 读取注册表取得适配器名称( _1 ?, N$ n9 O
* j- ^4 C8 I1 x; N' l. Z; J% W* u
在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;( n) E9 M5 K2 b7 }7 Y; y2 B
1 Z+ o3 y0 Q6 K% \/ a$ B
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 K8 Q- X# z3 Q8 w R& d& M! K& |+ [
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
& y7 x5 Z# {8 ~ 0,8 C6 H$ m3 n/ Y, N+ D
KEY_READ,
5 }5 x6 v+ d1 f+ o &hKey) != ERROR_SUCCESS)! H7 ~9 m* B, I4 U* ~, T
return FALSE;' p4 s3 e+ y) f0 |" H0 ]
# B" ?7 {/ o6 f& qDWORD dwIndex = 0;
, x& g2 G' e$ n) ^* a! Q" J1 LDWORD dwBufSize = 256;8 ?9 y/ e5 o& {* [4 r9 s
DWORD dwDataType;' Y- a1 @, y# T: u. P
char szSubKey[256];
/ D: K* n, o9 m, A: S6 ]- z$ j- `unsigned char szData[256];4 z1 }1 F d2 O0 T% r' K
6 |1 V0 G0 `8 z8 _
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
: W' x$ v& A3 Y- x{
5 _( R5 |2 W$ ~" q8 E6 H if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
: W. ] N) i( A( V {
% _( D2 S6 N$ z/ c1 T7 V if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
2 B* l$ R' w/ _1 h+ @- d* n { Z( `% t/ {- l( O: g
dwBufSize = 256;/ S$ A1 C6 u- b6 R$ r( T
if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)5 x( e8 m1 B) A4 }* k, g) B
{7 x1 I, e- t: f( V* E
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
. K1 T4 M2 M. p' H {
) k! u% Q2 i- J6 f' \; `! [, d dwBufSize = 256;
% V0 p% E" V" u/ H8 o; } if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
. W; G i9 A( T- P {" {6 y& U' S0 \) r+ p
// szData 中便是适配器详细描述
) y" L' X+ b1 q5 h# Q* q) g, L3 i dwBufSize = 256;8 s% e r( k( d; ~
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
( e4 ^6 \9 Z/ I: K3 `+ F* K {& ~# R* v x, N- x8 E
// szData 中便是适配器名称
4 B' ^2 a/ f) N' q' @4 ?5 P& } }
+ q6 _# R+ i# o' t: C) z x; [ }* ~- M9 p% v7 F6 W9 U
}
# @, M( ]3 `* l+ q# A }
- t+ U. K! g* u6 Y% g RegCloseKey(hNdiIntKey);. a; u# f$ |6 l4 N$ J
}
" \/ b4 r8 i& p RegCloseKey(hSubKey);$ w: a0 Z% r* C# P+ f) U, ]3 I9 `. X
}
2 f4 _# ]( h+ g6 G! |0 g& n, L
' T5 h2 r$ I: A: j0 \* d. _ dwBufSize = 256;0 @+ Y; N6 y V( c
} /* end of while */; q: I, A' t( u1 P6 X
! j# l3 x4 _% F' YRegCloseKey(hKey);
" T( R8 u3 m7 b, \二、将IP信息写入注册表. Z! a u9 J; ~/ A, Z" a
4 E! Z: [8 [1 T+ s% Y6 I. R
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
+ P3 W' \! [* R; j+ H; ]7 P{
9 P: ^0 F) G; m, @ U" m9 {: E/ h HKEY hKey;% h, }; D" u4 W$ |) F6 e
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";' e6 a% ]/ b% U) T- h$ m _; `2 S
strKeyName += lpszAdapterName;/ b* P" W+ t& c1 h, K6 l+ I
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
& s+ R' F% M: O7 [& ~ strKeyName.c_str(),7 a( y" l' U/ J+ K
0,
# D2 T8 ~7 J' P KEY_WRITE,* T) T9 k' \' T4 i& U6 \: H
&hKey) != ERROR_SUCCESS)- D, V) E5 ?' k) O0 I4 y
return FALSE;
" P- B( b+ n* s
( D# a, X) Y. C/ n, p7 Q7 A char mszIPAddress[100];
8 K( u; E2 ~: @/ X7 P char mszNetMask[100];; H4 i; J4 [7 U# \; L
char mszNetGate[100]; `+ w3 u" q3 J' S
3 D: }7 J/ Z( S7 j( u1 Q1 n! c strncpy(mszIPAddress, pIPAddress, 98);
; V1 ?. v* V* M H ]1 y; ]' m, u strncpy(mszNetMask, pNetMask, 98);
. H& x* D4 j2 J+ Z2 w+ R4 F& e strncpy(mszNetGate, pNetGate, 98);5 @, R. l! h9 g& D
8 c* N& P5 }/ b
int nIP, nMask, nGate;
4 J/ B6 V# E* y4 S1 z4 I% a; k, e' U4 v" A
nIP = strlen(mszIPAddress);4 B6 k; W" ? g' H8 @& }5 @
nMask = strlen(mszNetMask);9 ]9 ]- |2 i& o P2 \# j0 B
nGate = strlen(mszNetGate);
. n% v" V/ _( Z
4 }4 u) U& n; y5 D$ z *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0; ? F5 V' k& `1 C0 H
nIP += 2;( R+ W6 E( f z, X
' q: ?! V* d+ E: c" A$ T% v
*(mszNetMask + nMask + 1) = 0x00;
' t/ X `9 j" n" T1 J6 F' ` nMask += 2;4 y, [! h; l/ b1 t6 t; [
3 c% g/ c" s3 e- U. I1 p *(mszNetGate + nGate + 1) = 0x00;( j/ g5 @ m% S% A0 u" C, E6 d! \; s
nGate += 2;5 y: N3 ]7 M7 w7 [5 p% u( m1 [! R* o
$ V$ r: G* c w, s RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
! A; k3 Z. E' N2 e RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
) i; p) I5 z" ^3 p( w( ^ RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);; B. L0 b. N1 j+ U
4 T. k6 t3 f/ J& l RegCloseKey(hKey);
% y) ]0 d; {) I. R- S$ {: F
/ @1 ^, d, l! j/ \ return TRUE;9 }3 }2 P. z7 d2 T" J% r. i
}6 K& c8 n |" O, S d& F; @ } V# v
; C5 I9 S6 @3 O+ N! G1 }三、调用DhcpNotifyConfigChange通知配置的改变" g! l8 `( u% P; K: ~" j9 ?
( Y# P% x9 M$ f. m
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
+ _) M! G5 C! ^. ~/ b, u, V; t LPWSTR lpwszServerName, // 本地机器为NULL
- ?/ i, G& l A4 W LPWSTR lpwszAdapterName, // 适配器名称1 O. k6 f4 d' m5 ?. N5 t
BOOL bNewIpAddress, // TRUE表示更改IP
8 D( B9 f4 z$ |- I DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0/ P( I3 f5 j" @
DWORD dwIpAddress, // IP地址" O# h- {6 `9 M4 s4 q
DWORD dwSubNetMask, // 子网掩码1 c/ l( ^- c/ x9 R' c9 L
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
' o9 a+ N0 y. @; w( f. Y9 ], {
' @7 n2 h" \: L5 ^$ j* w. c, B% b a具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)9 J/ V9 s6 W* U- h4 J
{1 e7 e" k; r) z1 c5 r/ J
BOOL bResult = FALSE;
) c1 j. W" {' V: \ HINSTANCE hDhcpDll;
, s' x3 \- k. A# W m DHCPNOTIFYPROC pDhcpNotifyProc;
+ P9 _: ^0 ^8 }4 x: m1 Z, _ WCHAR wcAdapterName[256];
9 B% C4 j0 f1 V$ U; |0 R! ]1 N; W
, D1 V7 N' f' Z& P. ` MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
5 A, ?6 z! {9 r: [7 |* b
) x* l3 w W8 h3 t' \* U* U if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)( `/ g+ d4 I) O) X" ^# r
return FALSE;
! ?/ _ T8 M6 a, o* J, c
+ g8 R$ I3 \ T# r. x& z if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
; a2 S* q9 }+ M1 c6 p. x if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 ~. T# L0 p" U# E- j bResult = TRUE;5 X7 J4 n, N! T2 ]- u# a2 C3 S; q
, r3 t! t9 Y6 e6 m+ V' ^! |7 K8 Q
FreeLibrary(hDhcpDll);: K+ e1 ?. n2 T: v1 f: S
return bResult;
- z1 M. e" y; h0 Y4 C} |
|