|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动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} |
|