|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
. z2 F, N& H; d# r# G% y1 q2 w$ [0 {7 x" p/ K/ T
一、获取适配器名称4 Q5 H e2 @: K4 d! X0 Z% k
% Q8 f7 }5 O3 A, ]5 M这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
6 S- T6 l+ ?( ]1 N5 R% v$ j5 t# V* N8 P Z6 Y
1.1 调用IP helper API取得适配器名称 2 d5 G9 U$ Q9 \5 W
' d" n5 u9 T& C& c x5 a! p
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
, d- _4 \/ r! T, L( P" T7 ]/ NIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];4 j, p2 e6 N& a! E0 g- {8 ^
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大, W" e& n( A1 @; G
{
/ v8 ?+ Y: }5 o+ F& { delete pAdapterInfo;
6 {$ a0 l) A# F1 f2 [ pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];/ z! h9 O) X' g, t( ~) Q
pAdapterInfoBkp = pAdapterInfo;0 V4 l( r$ H1 j* I* N) a
}0 v4 M9 Y* r' O
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )" H1 {! G$ n. [/ J
{
8 ~% Q J; \/ E% h do{ // 遍历所有适配器
1 H9 C r# [1 i& Y* y if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
( L$ I* U# Z! l4 F2 y {
1 s; P! o! x1 j b- Y% a // pAdapterInfo->Description 是适配器描述
; ^/ P( J6 v7 h+ A' o6 Z) w // pAdapterInfo->AdapterName 是适配器名称
8 C# I6 \" `* E1 u) [1 | G/ K }2 c8 z& M" D0 a9 Z1 r* i4 s; V
pAdapterInfo = pAdapterInfo->Next;' X5 \9 M3 c/ c( v6 v% i
}while(pAdapterInfo);% ]9 y& r2 g& Y8 B B4 c
}
7 j, O* _1 S' u* Q6 jdelete pAdapterInfoBkp;+ _2 c. e" x( j' e/ D
$ R7 [1 | K( T1 M1.2 读取注册表取得适配器名称/ w. P$ |, X% P
6 z0 O" T Y9 I9 G7 ]* v
在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;8 w1 C0 U4 j6 `
" q7 y& Y5 y* @4 x- |+ R# S! U
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,! u$ w0 I+ N2 g! Y4 Y9 Z
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",4 [+ X+ a& s1 l( A, Y% y
0,7 s( J j, [) |3 z) ^' ]
KEY_READ," k: V0 a+ |( x! O1 U8 V+ Z( @4 a( P
&hKey) != ERROR_SUCCESS)7 L, O; b; h9 x9 G" _
return FALSE;
# F, S. a' Y) W. k3 `+ K/ Q, s# U& _$ V& g* T" Q) e& o
DWORD dwIndex = 0;
9 `4 |/ t. T+ [, LDWORD dwBufSize = 256;- h. c* U! @ R! P
DWORD dwDataType;
2 \2 F& {& n9 @6 w X* ]* X# |char szSubKey[256];
: `6 G+ s& o! B Nunsigned char szData[256];! L+ j8 c! e2 g
1 D1 H3 F* E, L2 K( t4 p8 I, G
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
7 B s2 T7 B0 [4 _{9 ?' W3 Y0 x$ N
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
& E# m( J0 o1 L# [$ q: g {
% s7 d6 G! [7 W1 l& x if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
, w- [7 Q; E$ f {
0 j$ i5 E/ l; K3 r. x' x0 j/ D1 S dwBufSize = 256;2 X/ }8 C- E; x1 X$ q3 }$ I& ]
if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
8 e6 m1 S# a6 z; C {
& H) E" i) j7 v if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
4 o3 ^1 t* Q, \ {
+ T) I v( J2 s! P. ?( a- q dwBufSize = 256;
v+ a$ O8 |+ z7 X if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
, ]: @6 o: c. p3 f {% ^9 w" s' Y$ B3 x4 q! w
// szData 中便是适配器详细描述
) a8 X3 p. w. |! h5 N5 m dwBufSize = 256;/ j* A @) R( l4 K4 D
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
: R2 v# d4 x+ V" ?- T! K {
( Q) L$ R- C8 h9 @6 j // szData 中便是适配器名称 T: O/ z, y: X/ ]9 V
}
- t% n. S6 v! ~ i) B }
* B* }- l2 z" z" O' f }
' m/ `% I4 g- o }0 _ G" E: w& s: I* m
RegCloseKey(hNdiIntKey);
* K- F: u) [# Q( y# g }
+ }7 V" Y! Q9 V# [ RegCloseKey(hSubKey);
9 W# `; \1 V) t- i$ m( D1 ~$ c }
7 N; i) L L# \, G7 M2 q
) \5 \1 O, s) ]8 F v- S dwBufSize = 256;
- v9 w: E/ d- Z( Y" T} /* end of while */; j8 }$ `$ s( h# V: z0 a7 H
a X1 v! @& e0 Z) qRegCloseKey(hKey);8 T3 l7 d* \, E$ H5 V8 ^; j8 N
二、将IP信息写入注册表0 o0 Z, w5 v+ z3 T. ^
$ Q+ y+ e4 i, x, O代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
4 u& S! i' l) G% p2 `{
0 a8 ]' b: C4 I( V2 M" l3 [. k# R/ z HKEY hKey;
1 F2 ^, d: X% `7 i4 N0 W0 G' X2 O string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";, {" r) ^6 c' s- K' Z2 h
strKeyName += lpszAdapterName;
- G' a b( n( ]# @& V+ @ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,- t U9 h7 J( ?# u! S: Z
strKeyName.c_str(),2 B" ]. E9 K& u% u$ W! c' g3 B' n5 S6 C
0,8 m1 B8 i _& [2 @; ?# p
KEY_WRITE,
. v) X, H$ _' v! v2 q( @2 \' j &hKey) != ERROR_SUCCESS)5 b* q4 Q- G' B9 A5 a
return FALSE;- G* \: Z8 h/ `# \9 |4 ~7 S( O X
! o- u4 x7 w4 |2 F! f; l
char mszIPAddress[100];
: V: F' b7 m7 v% R char mszNetMask[100];
" I4 \$ ^7 S9 w Z( e4 N char mszNetGate[100];+ I# J7 R1 X3 g- O
8 t( _( y+ Z8 c, t! v* e, F strncpy(mszIPAddress, pIPAddress, 98);, g) a) |( @+ n1 t9 j
strncpy(mszNetMask, pNetMask, 98);6 d! u$ P& i# P, X9 y( w0 s7 ^4 G
strncpy(mszNetGate, pNetGate, 98);
M$ S" L* m: G
5 v) w( n8 p' ]% y int nIP, nMask, nGate;
0 n" F' c) {" E! ~
) H- `3 ~& w3 P- ` ]( a nIP = strlen(mszIPAddress);% L. {$ Z* d# p0 |; ]- P: ?& M
nMask = strlen(mszNetMask);6 t+ a% W' O" b) v* c
nGate = strlen(mszNetGate);4 {2 R: \0 j$ z1 z. m
8 q, Z* U# h: H9 p( a0 W, N' y *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0! [% C8 ~ F' c4 i2 A3 t8 @& o5 `
nIP += 2;
" G/ K! [2 W6 x. j Z( j* R6 E* H9 v: C" F( c+ F' n" C$ e% P
*(mszNetMask + nMask + 1) = 0x00;( k. ?) g* r# `% u; a! P: E8 e2 L. @
nMask += 2; ~+ I1 d4 n1 @7 Z* L. Q
# E7 p: R# T9 z
*(mszNetGate + nGate + 1) = 0x00;, I8 Q/ O2 Y5 X9 j; b
nGate += 2;
& ^8 j; k" `; }* w! t : p% \9 T% B3 f4 V! b; I* ^0 o$ L, z
RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);9 M- c' m6 L9 w& h5 q" p$ ~
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);4 A$ n5 G, \* U- }+ A3 u. f. M8 v
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);% z% o( ~2 ^9 W& |& N9 i9 D
7 g/ ]6 H6 N8 u6 ` RegCloseKey(hKey);$ Y& ]# S" _2 t& [- t3 U1 b
$ g. Q& h& I* b, U6 P
return TRUE;) C; ~. f7 R2 t9 g# Q0 w
}
6 c6 R9 i' m# ^8 W6 d4 Q" U2 s' S/ ]2 z: o( T" h" j% f) U% S
三、调用DhcpNotifyConfigChange通知配置的改变7 ?0 [: X7 q7 d& B" p& A% C$ n
* V5 ]/ R+ S3 P+ N8 v" y: ^" O4 h
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
7 @/ _. f, y3 x LPWSTR lpwszServerName, // 本地机器为NULL
# ~1 e: A8 ^# l. K, l2 m LPWSTR lpwszAdapterName, // 适配器名称: N4 }9 t4 r4 c0 b' c
BOOL bNewIpAddress, // TRUE表示更改IP
: ?! G' Y% [; x3 m, [. n DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
a, ~ T! i/ L) U1 w K) e% }6 A DWORD dwIpAddress, // IP地址
$ y; o8 U/ {/ ]- @ DWORD dwSubNetMask, // 子网掩码# w* r0 c$ E* A* C- V
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
: u& `. }: p3 y" l6 S, B( A- h
- b) F. n L$ ]0 u! k; {具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)) \* m: L. R4 J; k
{, x) S# M" A/ w5 j: B* b5 _4 i
BOOL bResult = FALSE;
! ~' V7 a4 q( ?0 Q' z# F1 \1 ` HINSTANCE hDhcpDll;1 {* H9 _! s+ ]2 s% h
DHCPNOTIFYPROC pDhcpNotifyProc;4 M5 Y& C* B% p, K; n6 E; D' e6 ^" @+ s
WCHAR wcAdapterName[256];& E3 U& R* P- Z: M$ Z' V/ B: a
( S5 t3 l# b- D
MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);8 X9 ?. N% V% k& o
$ a( ~! @8 F6 g. q. ^% V if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)2 g3 {+ ]! u! k t
return FALSE;
6 ^7 A# t" N. @ | ] i7 a% [/ j: l1 O( ]6 u; o
if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)8 _4 p# ~3 c H7 d
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 h8 d& G/ G: k* Y) E7 E' y9 ~ bResult = TRUE;
T9 ?0 T F' p5 U6 d* b5 U* m
; Z% h- K3 D3 C2 @ FreeLibrary(hDhcpDll);% r) `, d7 z# c/ a3 K/ v3 X
return bResult;
6 x0 n/ F) o( r- i) s8 F& y} |
|