|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
% M+ S9 |* j! n# f- o6 w# W. y% r' K" c9 [
一、获取适配器名称% y" i4 [# Y6 b: V7 ^* e' }
W& q" h5 x; e4 E A1 y" K! E( h4 H这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:: C4 u' m; T3 I) N' F% g- X: D
0 E3 S" l ~3 K; Y2 Z7 G- x5 D1.1 调用IP helper API取得适配器名称
+ d+ e" w- c4 G9 ]
6 ]# y) h1 d* V* S8 K9 \3 rULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
: R v& g. [1 f: d$ V* d, ^# LIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
3 F$ A4 Z5 o' e# |8 Cif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大( [' U, _# x, g$ O0 ~# U
{7 D% V$ I; C/ U+ t4 N. j
delete pAdapterInfo; _" `9 T( H. n. N v/ i
pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];# ]7 V. g1 h* Q5 D. j: a6 A4 L
pAdapterInfoBkp = pAdapterInfo;! @/ j& f' _. }
}* V: O8 \4 @" m/ E5 {8 j& J
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )8 N8 {$ ?! t/ {1 y7 s2 }8 P
{
& |) q# x9 r. m; a" t! |; S do{ // 遍历所有适配器3 f5 }4 @3 T9 l* w
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口8 {" x, L0 I: x$ N- p# N4 b
{! z% V4 H: }2 |$ Q E2 o( b3 _
// pAdapterInfo->Description 是适配器描述3 b6 y$ {6 C. T# S/ R8 n0 c
// pAdapterInfo->AdapterName 是适配器名称
( v1 e- { F1 j5 z K4 }$ T2 x }8 b) K% V8 x9 x0 L9 y/ `6 |( W( [
pAdapterInfo = pAdapterInfo->Next;' X" i3 w5 o1 E) A/ q. D, j
}while(pAdapterInfo);
9 O4 c$ x& V$ d" W# h: X}
3 W: J+ a$ O7 K6 p, [5 x) o: Bdelete pAdapterInfoBkp;
3 _1 @2 c$ t7 S& K# A
. U! L; N# Z2 p: i8 b1.2 读取注册表取得适配器名称' |+ I6 I. a/ a* ~9 c2 ~
& l- X+ i8 n8 Q3 d& I" X. {' f; L在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;4 |) i. c! b& f3 j1 H6 f
2 E3 Q2 B2 v) y6 s- q1 w+ g7 ]if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,2 w: g7 ^1 v9 a2 a' \0 q0 \2 g
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
) h3 e* W$ _, t, k3 v5 v2 r2 j 0,6 b0 I6 G# O. P, J2 t
KEY_READ,0 @( f) X0 |# g& U" o R
&hKey) != ERROR_SUCCESS)
- ], I) r/ F/ P* N. `6 C( s return FALSE;
v5 e p4 [: L" R4 k3 c6 g: S- E; Z, d
DWORD dwIndex = 0;
9 F3 }3 i1 ~& g( G' b# vDWORD dwBufSize = 256;
1 Q! K9 O: }) W! _2 {' y, ADWORD dwDataType;
* `9 F# t; T; c! {& Hchar szSubKey[256];4 @9 l' y& r* p( p# B! W2 y/ Y
unsigned char szData[256];
7 x& D# b! q3 k. g4 u1 Z( q* D3 Z/ g: B6 M
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) g+ X0 l: S" ~6 f, ~. W4 q/ @. J. k
{
- u: ` F4 G+ v if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
3 j/ H0 G% _, @0 n j" D: F. ? {
3 ^ P+ @! C$ e if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
0 P: F! h' o b6 G U& j {
: o3 F7 h9 l1 L dwBufSize = 256;
+ h- ]: {+ s6 R% E/ p; x# ]* P3 A if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
0 f: L0 l4 [ p7 ]7 Y* ^! | {! T7 L1 o0 U' D, `1 k
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡 R. J8 Q- y& H5 c2 [
{# Z- a% F; i4 K7 [9 E1 m2 i
dwBufSize = 256;
; z/ U( I/ D( p; \+ K& m if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)* m, P Q7 N8 R+ {0 P; }, x3 P, ^
{! [7 y& [+ e0 P! @4 M
// szData 中便是适配器详细描述
' C" m j' ]0 O8 O, G dwBufSize = 256;. i5 P2 i) F+ C+ P z& K
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)+ P% T4 Q) V( O+ s: X4 s9 N8 L+ p( g
{3 l6 r- w3 b) i$ a7 c! M
// szData 中便是适配器名称
! V8 i1 v0 C1 E( v6 [ }6 \" R1 o. Z- w4 u
}& _" e7 X. F$ I& D; s* R
}% I5 ^) W& f P9 n2 i) R7 C, X
}
! `, w3 G+ T# N, _ RegCloseKey(hNdiIntKey);
) U' j1 U) t7 a }
" P1 e$ B: y) c; I6 d0 J RegCloseKey(hSubKey);
% B! h4 c/ t" i1 N, i }
/ l/ u5 J+ Q( Z/ [9 `$ N6 m3 G2 k& ?# p! z5 r/ i- k( s, W
dwBufSize = 256;
1 N$ B9 z% m' I. e f" F} /* end of while */
8 ~0 t5 F4 m4 c0 e4 x0 R 0 p, e) Y% @. h! \9 R" D
RegCloseKey(hKey);
' W8 s* R2 W4 v5 u二、将IP信息写入注册表
: H6 Y" n, d) E. o1 M. O3 p# m, J% I
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
! M; P* d7 q8 _1 [8 T$ @{, ?, L- P \ E+ @/ b4 C
HKEY hKey;
' N, W, Y% Z L- b! u string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";# _- T# S3 V5 N1 y3 H, j" B
strKeyName += lpszAdapterName;. W( P5 W, N! f, Y2 }4 }! U" |$ e
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,; R f& A* Z& _9 @6 N" X7 F
strKeyName.c_str(),
# W/ U; U4 R; j" B 0,
. l& x* @' M% {# J- v4 w) l$ V KEY_WRITE,
* @# O2 t8 v2 w- w: M2 b &hKey) != ERROR_SUCCESS)& p2 w# l/ p/ g: f! T1 O# I
return FALSE;
" W8 n \0 g8 o" v 2 M7 b2 @( D, S9 ?" Z
char mszIPAddress[100];+ ^% ^$ x/ B9 e9 Q
char mszNetMask[100];
{0 v( z0 {- K3 r9 i6 t3 B char mszNetGate[100];
6 ^( e! l4 j8 ]. I W5 N( N: d' @+ _; v8 |2 t! S
strncpy(mszIPAddress, pIPAddress, 98);
" v: F r d# d) X strncpy(mszNetMask, pNetMask, 98);1 t) D9 ~% U% ~ g% y
strncpy(mszNetGate, pNetGate, 98);
- `( r& e% u+ u; i
' x9 z* T+ I" c& ~/ Z$ e int nIP, nMask, nGate;0 Q4 x* L, g% i0 Y0 ^8 T
6 w) x; T1 H- \2 ]/ j( H1 D* j nIP = strlen(mszIPAddress);
0 t, k, _2 b$ v nMask = strlen(mszNetMask);
1 h0 U! t! w1 b l nGate = strlen(mszNetGate);5 }* `. y: m2 \
) ^ S" E* c; Q( y3 t *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0 [ M; @' M* M& a
nIP += 2;9 M& u+ O& c9 ?; e0 A1 P0 m( Z2 G
( F" z: a- @) K1 D. j8 F/ f8 G. | *(mszNetMask + nMask + 1) = 0x00;
: Z) p- u0 \( O, J4 V1 I1 P# k nMask += 2;2 |3 x* ?5 a* Y1 H8 f9 A- r) G
: I0 d% L. L$ R) N *(mszNetGate + nGate + 1) = 0x00;
, f2 s% r, K9 Q8 p% e2 n nGate += 2;% e3 B" L3 a8 k( u
' t ]* l, b( l1 J! L RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
0 P4 z8 D3 P w) h( M RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);$ J! c- O4 a5 }3 |. n% s8 y
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
1 |& L* |4 @$ b; l" ?" v( u* Y& d+ B
RegCloseKey(hKey);
) z/ V! u' k. W* S9 S
" Y8 _" ?! u1 B; z: o( B' ~ return TRUE;5 V+ M$ L% A7 Q6 p4 a
}5 D- A7 Z; V/ [4 [
7 Z* T7 `2 [ {8 S! N三、调用DhcpNotifyConfigChange通知配置的改变% a" x* e1 `) b; J0 Z, f6 G2 r* F9 O
$ f+ i3 d7 a) O6 T8 H
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
D) N( ]5 E6 W; n, D- Z" Q LPWSTR lpwszServerName, // 本地机器为NULL, V _8 T4 V% c) G2 P" g
LPWSTR lpwszAdapterName, // 适配器名称
# ~' o/ e( d1 \. E BOOL bNewIpAddress, // TRUE表示更改IP! \! k8 M7 W. m; b# X5 h; L6 B
DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
. m4 o* s3 h* _/ w0 e8 ]$ p DWORD dwIpAddress, // IP地址- X W# f! y! G* l7 \+ i# ?- W
DWORD dwSubNetMask, // 子网掩码
+ _ Y7 w3 y/ B7 G int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP- w) t3 I8 u8 o) M* i- x/ e6 f: @
8 b! D6 ]* U, @* ?" _3 K% C具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
/ ^& w: E7 K ]' e; [4 ?{/ w- Q: V) l/ R2 i1 B+ s8 T
BOOL bResult = FALSE;. O% n0 V, E) p6 ~4 @" }. ^
HINSTANCE hDhcpDll;
+ |5 e; |4 E9 R DHCPNOTIFYPROC pDhcpNotifyProc;5 A, N9 \9 B3 F. K1 ]
WCHAR wcAdapterName[256];* z7 k1 \0 Y/ E% `
7 C. H, t7 o0 t2 T% z
MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256); k" T% R& }) Y
' h9 x6 f8 A$ t3 x8 ~5 F) p+ f
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
, c! @" L; G/ c1 Q5 [" w return FALSE;3 I# O& D2 ^; K
+ T* p5 l% c/ j, ]! M if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL), E2 i5 ]+ C8 y+ _
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 y- V& o" k9 `4 M. d7 k bResult = TRUE;# z( S1 b# k0 k1 ?& L% U
7 p8 D' a; Q0 ], v } FreeLibrary(hDhcpDll);
9 U0 g- e4 s$ c0 e3 ]% ?+ S1 k return bResult;
2 t0 }& g' w: s* M- @} |
|