|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:" u2 Q- o3 L. D/ w5 t, Y' l- o9 L
( I& y7 s0 N. L! Y; V一、获取适配器名称
& X4 h( O2 n' Y7 j' m8 i7 w+ U: X- J& H2 i: z/ G
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:3 ^6 N2 t8 W8 v' T
: o0 O! M, e/ I7 k' x. r4 R6 u
1.1 调用IP helper API取得适配器名称
& s6 a% I2 g: s$ L- G$ Q' A7 r
$ v' \! H' ^) e+ B# X8 {5 Z$ P/ IULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
3 `: U0 k4 y7 _$ h1 r' M2 H$ fIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];. Q0 q: \0 f2 f
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大; l9 ~) I/ Y2 |6 H
{3 o' q- B' p, k) L' U# a
delete pAdapterInfo;
* ^# q. u7 \! [- _5 K! S- h pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];9 B/ s% M0 E+ Z' l; v; c) |
pAdapterInfoBkp = pAdapterInfo;0 o, }8 M! A2 V- t) O6 ?
}
) S$ _; I u/ `2 {, w' zif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )7 Q) v% l. g% @
{
/ l6 A1 _7 i, b- a0 K0 Z6 G& ^& O4 E do{ // 遍历所有适配器4 e" ?3 ?( c7 b! }! G
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
- R6 U: E' o* i" k, V {) h: i: g4 l4 r6 D* Q0 W) k
// pAdapterInfo->Description 是适配器描述& a2 M: V( u9 i% s" y% }# S" h
// pAdapterInfo->AdapterName 是适配器名称9 T! l7 i: @% L% ]& z' _8 C6 Z/ E* P
}
, @; a- l. ]1 t% g" _% q7 n7 q" W pAdapterInfo = pAdapterInfo->Next;+ D8 `/ Q. i; z9 M; X9 B
}while(pAdapterInfo);
" B' V7 J! p9 J}
2 c x' z# ~" H6 J$ G/ Mdelete pAdapterInfoBkp;
! b& m* O6 g$ k( A2 Q) P4 J! b$ i- K5 ~* Q" g) {% }
1.2 读取注册表取得适配器名称
; U3 ~; ]& n2 u& c z: W( |4 g3 B3 Y
: B: Z/ k* ?6 t# L6 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;( k8 r, {% N2 O2 C4 |+ Y# I) N
! V9 j; K/ R- U) pif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,+ k: \8 h8 i6 n, b% j: ?* U4 T
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",% ~8 Z1 A: Y0 ~6 c7 k
0,
' c# i$ A9 c4 U6 \- r8 N# a' z- D KEY_READ,( y* w0 C" K1 u8 Z) P0 |
&hKey) != ERROR_SUCCESS)
/ [8 P7 T4 z0 ?+ W( C return FALSE;9 Z+ q% \& S1 W' ?9 m* d; Y
) A; J2 z4 z) U v$ d$ z7 y0 h
DWORD dwIndex = 0;
/ y4 n" Z$ l; j3 I! n8 RDWORD dwBufSize = 256;
2 h3 f8 ?* T8 G Q& ^6 a0 I0 YDWORD dwDataType;+ {& M& p6 I6 @. u3 A
char szSubKey[256];" d$ I: I5 t4 U# e/ d
unsigned char szData[256];
9 U' k8 P! }$ F% U9 t* }8 w) k' B9 C
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
4 I( C5 a9 l2 t4 N9 {{7 D7 v4 B1 ^, W' m5 q% J
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS); ?4 }" `* H" B& j' q* U
{ 0 c4 n7 M9 g9 g! L' y
if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)! z; Z6 Q# Y9 v3 ]+ p1 b: x
{
. B& U& C# o/ x dwBufSize = 256;2 `8 Q0 C* r; U% x" T- K
if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
" S. z7 j9 W6 _7 `, `9 q) s0 J {) _; O2 P3 r: g
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡' a9 A" `9 a" m8 q' F
{
: r$ A$ k4 S) ~- t1 x dwBufSize = 256;
% w; L N8 r+ J. w! T/ n, p if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)* Y- q' `$ t' \& R9 B. m0 |! D
{
+ Y3 ]& b- h/ _: ~& Q9 ~ // szData 中便是适配器详细描述, D% r" p- C0 ~7 l4 q
dwBufSize = 256;
; w w% Z4 a. F' n# `+ Y+ `5 E) d if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)% a! g R4 s# G
{
# V! Z3 U3 _& F. l- V# x, w, N // szData 中便是适配器名称
# e( r1 T- L! ]. w% d8 `7 R& y } _% r' U4 ]/ M# U6 F
}
- ?! m* p! b" ~& [- h }9 }! u. b) Q/ b! F6 a! x2 ^. U
}
, E% g* U0 |, K/ K# t RegCloseKey(hNdiIntKey);+ b, `9 A+ b$ B% [* _$ s6 K; u' ~
}7 S) o4 F- [" |1 o+ e9 g
RegCloseKey(hSubKey);" G5 w" y+ a1 `, v
}) {+ a* N- W% @# d. K+ A1 ~/ W
9 ~1 i% V7 t7 y dwBufSize = 256;
; z4 F% Z# A Q% l. W} /* end of while */
5 F5 i1 ]/ b8 P) I% }2 v 9 q2 I4 P# I' f# u' n/ Q, s6 ?, a8 m
RegCloseKey(hKey);7 v( r% _4 C3 g7 E$ Y/ I2 P
二、将IP信息写入注册表
4 J# s5 x' g$ n' g) i
' `3 a* ?1 X: J, P) ]; Y, A代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate): x- T7 ?* F1 l, l& a. I. D, Z
{
4 } C3 ^: P' t2 v( w HKEY hKey;. a$ p: C$ h6 d3 O" Q9 G) S- \
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";6 T9 C3 x0 g7 W a. F
strKeyName += lpszAdapterName;
, g- J. ]5 J; s8 z if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
7 v1 e) K$ ^8 d% H strKeyName.c_str(),
8 E2 ^. d7 `+ x! I7 Y' v/ K$ D0 p 0," n; ^& k3 x: e* }6 ^4 l
KEY_WRITE,
! z+ {8 F' E V+ V0 E+ X/ j5 ]; |; n &hKey) != ERROR_SUCCESS)7 R; ]( [7 q4 @0 |
return FALSE;
3 D. D N- i6 N, x% p1 I# P
/ T) ?4 R4 u8 @2 Y, }: e4 Y" n char mszIPAddress[100];
/ G( b2 E7 M# |; @4 O char mszNetMask[100];
( P$ B% Z3 o0 C/ p( b9 E, i char mszNetGate[100];
6 F- G Q/ O3 f, w8 D1 G$ P1 Z
% U3 e5 G0 ?" I& w; _9 R6 P; ~ strncpy(mszIPAddress, pIPAddress, 98);: F2 X8 |& R8 I& t
strncpy(mszNetMask, pNetMask, 98);
z. _8 k# A8 S% g; \ strncpy(mszNetGate, pNetGate, 98);1 n0 p9 h9 e/ F+ A/ Y
f4 t9 p8 Q8 j1 {. k int nIP, nMask, nGate;
) P1 y1 I5 s( X) r- \0 C& D# B. H% Z" W+ w) }8 u) l3 I
nIP = strlen(mszIPAddress); j7 z ]9 O8 R( t
nMask = strlen(mszNetMask);. ~1 t" C& p/ y7 F
nGate = strlen(mszNetGate);& V7 O+ D2 C3 D% c0 K1 |# N/ j8 {
4 q* Z4 K4 }1 i6 W
*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0* j7 M! A/ ^" ^5 {! u2 |+ H
nIP += 2;
1 H) c# a( }1 Y& ]" c8 o( ?& a" q; {/ X- S! Q! {4 n7 D
*(mszNetMask + nMask + 1) = 0x00;
Y! I- X& B( w6 ~ nMask += 2;# E i- `( C: b, P
8 `) `1 V: x/ E6 l" O n6 b3 n: G* v2 v *(mszNetGate + nGate + 1) = 0x00;
4 L4 A1 M- z- A! ~( f2 ? nGate += 2;4 k4 x2 @! D; T0 \5 v
9 I# w7 C1 ~6 Q3 I4 `: d. ?2 x RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);0 ^' m$ Y( s/ ]+ [: |& d7 k: Y7 d
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);) t" b7 ~/ o; s# I+ A4 M9 q
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
9 V6 q# ]2 c1 E8 c, V+ U
4 A5 o7 U$ c6 _9 p RegCloseKey(hKey);1 E0 R8 v7 g3 E+ N: t) S5 N% b5 C% {/ V+ u
% w7 } ~5 r0 b& N( k. }! |3 T
return TRUE;
6 `% |1 t4 Y9 ~3 P8 f) {}
7 L' s" [- p! ^# d5 C y% a5 x& s
三、调用DhcpNotifyConfigChange通知配置的改变
# Y& w- X: o& ]" c ^: X; r/ K! E2 a
8 |/ N. y1 |6 D7 M未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(8 A- [0 M1 q8 m6 Z
LPWSTR lpwszServerName, // 本地机器为NULL
* _9 x& y! m8 j) Y" K LPWSTR lpwszAdapterName, // 适配器名称
; |# s: M, U# i$ b: E! j$ S BOOL bNewIpAddress, // TRUE表示更改IP
9 C' G& O9 W5 y7 X- r7 s( n. Q DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0' ~! \/ Z4 R% E; U: D
DWORD dwIpAddress, // IP地址
# n; K" k" o6 j6 G8 v DWORD dwSubNetMask, // 子网掩码1 c+ c7 C! Q1 Q; o/ u- u
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
6 B! A/ |9 ^# L- H) E+ P
& S y! Q5 v6 s C具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
2 m j) T$ i" u) w{
/ v- m( b" R# e) u: r BOOL bResult = FALSE;. D% k1 ~9 ~) |: d* D5 B
HINSTANCE hDhcpDll;
8 C; k& W2 V" u2 C, R DHCPNOTIFYPROC pDhcpNotifyProc; D! w/ |6 [( M+ e$ W
WCHAR wcAdapterName[256];
' Y) ~& Z+ D/ O, U' @ / W: Q! B. C8 N4 s$ T
MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);% @, c2 t: f r8 ?: w9 A# Y
! d: [7 ^1 S; M; ^7 Z if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
* v- R5 l' X0 l$ `# r% f return FALSE;1 U7 w! N5 p& `
% J& b6 ]* M+ D if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
$ ^5 S$ k z/ n, q" Z if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)# h, m9 b p4 r& u" r7 _
bResult = TRUE;
6 O& b- n$ J9 m' }8 a
, v e! O: ^2 B$ N% j/ w' z! A FreeLibrary(hDhcpDll);
+ g" T+ B3 v6 X( m& d return bResult;
% U2 g; |( K+ ~} |
|