|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:" L: K1 I) C3 N: u/ s1 y" @
+ O( _8 g1 c3 O1 N2 t. f一、获取适配器名称& E2 K! l5 H; E1 k! A" L
( B2 q; Z/ e+ O1 a
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:5 [8 \. J" w$ l: r9 x
! x/ s' D4 J% _& e8 u1.1 调用IP helper API取得适配器名称 9 x# L3 K; o6 g J( |0 ^9 p' {2 B
# R& r) a, [9 ?+ A1 `9 C% MULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);4 o$ c8 I4 X) |' \, x: _
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];5 |$ U$ @( G; c6 X$ Q' C
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大7 E8 i4 v+ i, Z! H0 p0 [
{( Y; o5 c) A' X: d+ V/ F" S% R
delete pAdapterInfo;: F# A/ x# g0 p) N9 h7 I
pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
+ G- ?/ ]8 { V+ L- d+ S7 m7 a pAdapterInfoBkp = pAdapterInfo;! z, s/ w8 e5 G# I5 Z
}
& o+ D3 P* w4 `7 n: Z" lif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )$ R' E, U- H$ ?
{
$ g( v! p1 K. Z6 b' R! x do{ // 遍历所有适配器
8 B$ d; N$ L: g- a if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口* o% J' c \# E
{; J! ]+ K1 d0 r$ v, [# ^& l
// pAdapterInfo->Description 是适配器描述) U, i) M N1 w! z& ~! t
// pAdapterInfo->AdapterName 是适配器名称$ l& }0 p8 g1 C) T% ~" v. a
}2 y5 r4 W( ^, n/ L7 v/ M% ?
pAdapterInfo = pAdapterInfo->Next;
3 |. d: R4 j) B9 `2 i }while(pAdapterInfo);# V- C3 H# j! u& s$ M1 x6 C3 u
}
8 f, |. Z3 U6 d' V' x4 G/ g( D0 ?delete pAdapterInfoBkp;- r, A* l6 r; E9 T
. f8 A" k& i5 l4 [
1.2 读取注册表取得适配器名称
% X! Y- o: o# v7 X3 q! d. r% `' v$ r9 g/ X3 g
在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;# W* G2 V0 s7 E% F6 Q
+ j2 t8 O3 J4 [, o& m- q* g
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
0 W0 i- r$ P5 _/ q( O! d "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",/ x: L5 \2 \2 F+ u9 S8 G
0,
- A, _0 A; L8 Z KEY_READ,
( ]- C! ~. e" x &hKey) != ERROR_SUCCESS)) ~: F5 S% \% T* |- S3 H+ O4 B
return FALSE;
% X# o$ O8 |1 ]& K
2 H, |( J8 E, D/ V @$ `DWORD dwIndex = 0;, g2 q* F% S1 z0 T5 l# `
DWORD dwBufSize = 256;4 U9 [6 Z/ Q4 a9 R& W! G- G
DWORD dwDataType;4 G4 ^% O: ~: ]* Y+ b p+ B4 _- O
char szSubKey[256];1 G4 x0 u9 e: n. C/ d( B1 n$ @: X
unsigned char szData[256];
* }; g) r% ]. u+ W1 L
) i1 R7 j2 R+ x* q( Iwhile(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) Y$ q3 p G, t2 E `5 _" _
{0 _) X: s5 b# p: M
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
/ s- v* N7 E- N {
$ L9 A" K) E% R& `. Z if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS); O4 F' {" `3 ~9 D, x: P' _8 L+ B
{8 H$ s# @! r7 P2 h: F
dwBufSize = 256;
0 Y+ D2 z8 @, ? if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
9 F* D1 g- F( _0 d% f {" M2 p5 c3 Y& C G# D
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
; m: K$ ]4 A0 Z, L {4 n# G" c f7 V& F( E
dwBufSize = 256;
) Q; A% d8 q+ s, q) {5 f2 O if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
6 x$ x. b( |7 ]; A& ^1 M {
8 b$ |" r' S% T) P // szData 中便是适配器详细描述
1 f" E/ b& W6 c; V% G8 E dwBufSize = 256;
6 W/ s) r W3 a if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)- i @' g6 o1 _% \" w& y
{" k; z2 r7 a( K; |
// szData 中便是适配器名称
; y$ g9 q" k) n+ _8 i }, K4 C6 x8 R# h1 K
}
4 _* n; B, r* |; l; ~8 f }- q. W$ O& ~6 r1 @1 N$ n
}
+ ~3 s. `: `( j9 {+ o RegCloseKey(hNdiIntKey);; x: S/ W' X% x
}+ }& ]7 p0 f$ k" C; u/ x8 L
RegCloseKey(hSubKey);
1 ~3 `, P, _- x: o! \; u }
5 z2 V9 h2 C7 m3 X- u1 Z7 m( W/ p: N- |2 @0 E; j
dwBufSize = 256;
3 J$ n5 Y2 B0 B0 Q( \} /* end of while */$ f2 m6 A7 S0 [ K5 h! }* |
3 e2 |; U3 B. ]. B& D
RegCloseKey(hKey);5 ~% f9 F4 r- \8 c; ]
二、将IP信息写入注册表0 z1 G: U# B) Y8 `) K K
" P* C# m( V& v2 M代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
- d) M! S. N, _7 r{
& k& W& }' b Q. V3 H HKEY hKey;
z( Z+ l/ A1 L$ w3 d0 A7 i2 B string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
/ q& v7 ^! [$ ^0 n strKeyName += lpszAdapterName;
# o1 J* P4 f0 ~' t8 a) \ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- n, J% N3 a3 w' I+ c5 F& g strKeyName.c_str(),
: V; s5 O/ h, f% g 0,
& s, a2 N8 L/ j. h7 ~6 f7 e KEY_WRITE,) d& f H* d3 s8 p! w1 P1 P, B# n
&hKey) != ERROR_SUCCESS)7 m( @' o* Q" v
return FALSE;
# s7 x- i: ~" Q9 I$ M; H , D' D% Z" w! X0 b0 }$ j. J ?
char mszIPAddress[100];
( j" b6 [6 x8 K& w char mszNetMask[100];6 H$ E+ K- d% K; b2 @' m" V ^
char mszNetGate[100];+ h( `$ }6 z5 l4 Q4 D
9 d+ V3 ^: ~( E9 R+ k: o strncpy(mszIPAddress, pIPAddress, 98);
4 Q* D: ~: a* v% B0 D strncpy(mszNetMask, pNetMask, 98);
, C$ x: `% f) w8 ]8 u% q strncpy(mszNetGate, pNetGate, 98);0 E# Y+ C! J7 n/ d0 i
! _2 p3 Z# X% U6 C* d
int nIP, nMask, nGate;% y' n: ^2 @* z2 `9 Q
2 a! h$ F5 M7 P, w/ T! n# c
nIP = strlen(mszIPAddress);$ i0 _9 Z* \6 o" w7 Y1 m$ S
nMask = strlen(mszNetMask);) f: A+ c' ^6 ^$ P8 d7 a
nGate = strlen(mszNetGate);8 k# |/ Z% T' j: R+ q
, Y9 t0 t) I( I4 J0 f6 Y# q1 Y
*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个08 ~) R: A" s" }4 i2 T- o8 ^0 E
nIP += 2;9 w5 M( v1 r7 G) f3 z
6 d. Z" A' d Z4 j
*(mszNetMask + nMask + 1) = 0x00;7 B; M& B. k0 ^- Q8 I) M3 L
nMask += 2;. V4 X- G8 d2 ^" i+ Y: j! Y% |2 U( r5 d
6 c& G. c" v2 _$ b8 Y- P+ Y" G9 c *(mszNetGate + nGate + 1) = 0x00;& |0 t! A% X7 i/ C8 V. y
nGate += 2;4 R! a2 z; L0 n
% P3 }2 I! y7 _
RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);8 ?* A% l R2 e8 n7 N9 q0 w
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
( o' L T6 R! w6 ? RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);6 n- [# a* x/ N! x. M) E2 _
+ _( n3 J: w# z V. P RegCloseKey(hKey);2 h4 k; l9 |# n/ N/ q
8 F: Q1 Q2 R( O
return TRUE;3 X" K) W+ r5 H% B5 m
}
& n# v1 v9 |4 j
; A0 @1 w( V! q6 N三、调用DhcpNotifyConfigChange通知配置的改变
/ c5 G: Q% }% u
t; t( D0 Q0 |; d8 g未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(' y' m1 z3 r y
LPWSTR lpwszServerName, // 本地机器为NULL
: a1 y' k6 a* x$ y8 ` LPWSTR lpwszAdapterName, // 适配器名称1 w& @5 ?% g B+ o! v; b6 D
BOOL bNewIpAddress, // TRUE表示更改IP
3 E+ z/ n* n7 I* P DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0 ?$ i% X0 g/ @" V1 v. @+ J
DWORD dwIpAddress, // IP地址, Q* M2 F3 Y1 W: q
DWORD dwSubNetMask, // 子网掩码
" P2 h/ o$ ?& [& d& V y int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP0 R, p; C% Z* y( V
% y5 C' m$ ~& \; S6 l
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
, f& D5 u; O+ t{
4 P' |6 f2 P' d8 ]% A3 w2 [ BOOL bResult = FALSE;; w0 _: S& x1 B6 X5 y7 R% @/ M
HINSTANCE hDhcpDll;, q' u+ z( ?9 R1 f* D; x
DHCPNOTIFYPROC pDhcpNotifyProc;6 T/ n- w( x! [7 S
WCHAR wcAdapterName[256];
; g( d; x4 M9 @, d( `- d6 N! J
( x" V% r$ g( E* }7 G$ c f MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);/ }8 _. {$ g7 F) l' ]& J1 R* S
/ r+ H# y3 |6 z8 l% D" X
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)! m0 V7 O5 v/ {
return FALSE;/ i6 P- A/ H$ X$ Z& U! n
) Z4 {7 o K; M" N) C' R
if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
0 d) }# O: A" X' D7 E8 d6 t if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 [1 s+ a1 r9 X bResult = TRUE;
$ P4 v' R/ Y9 g" a" l: x9 \: z0 f4 R8 O5 A2 @& J
FreeLibrary(hDhcpDll);) n. r8 {% f2 U: y- G# `
return bResult;
, N2 g- |9 k, X} |
|