|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:6 h5 M: I. ~5 F+ `5 n& C
4 j) D+ i' t( B. a4 [1 V$ D. w! m8 M一、获取适配器名称5 c1 r( @4 H, o$ k* T9 a* J! J. b
) [) w3 r) C# D w7 |* a
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:8 A' L' E- ~) B+ K, W# |
; d/ ~) [8 F) ~. A, n1.1 调用IP helper API取得适配器名称 1 F- `% P4 C! Y$ {" f
6 H3 Z: H6 n9 aULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);3 J( K* q6 S8 z. I K& N6 ?
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
8 C2 \: S X" t7 m, C: `if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
4 d: D# u9 [; e$ M1 U{
9 X; W# S( ^' \! z$ \( ]2 { delete pAdapterInfo;
. ~7 G* J4 r: x4 i. J pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
) @3 ~# R% C! s4 a+ Y3 `. |5 Y3 k pAdapterInfoBkp = pAdapterInfo;3 v7 W# J% H$ s0 S* Y5 Y
}8 C k" d0 N. x6 J; k; j
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
4 X2 r& C+ c5 L8 q, s4 w{( A& J% l1 w5 v( c
do{ // 遍历所有适配器5 u8 @* g$ c+ \6 n: Y
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
0 P7 K4 q' Z% P+ c6 M {
: u3 `( |1 h# v // pAdapterInfo->Description 是适配器描述
& `6 E% z) [3 C! l // pAdapterInfo->AdapterName 是适配器名称
7 N# j0 n+ K/ J/ l$ G }7 @3 F" y1 Y T G
pAdapterInfo = pAdapterInfo->Next;" @: W3 f, I. [5 r. H1 o) L% _: y
}while(pAdapterInfo);
. g# x2 b7 a* m% {6 }) `$ {}- ^2 V4 t8 X" l" F
delete pAdapterInfoBkp;, e# V) S; j0 H- i% U
& k, v$ T8 r0 a
1.2 读取注册表取得适配器名称1 }$ D. m2 `$ M3 k; u& |
# S6 [! M9 D: U# A0 T# P% 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;
5 n! X, I% z! h* b$ d
$ Q* a- T( u6 z9 Z1 Aif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,1 l! o/ `% N! C. ~, v. l5 _7 t- B
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",/ F1 D8 D2 h1 O" a |+ ]
0,8 k3 O8 h; F# g6 T9 ?, G; J Q
KEY_READ,3 A7 x8 k5 q1 e0 t; @8 K: Q9 R8 q
&hKey) != ERROR_SUCCESS)" o1 x2 A. e/ I) s
return FALSE;
0 [% k% q: A% b! q
" B! z9 x3 }0 J* H7 hDWORD dwIndex = 0;9 y3 n+ S P( P1 J. f) u
DWORD dwBufSize = 256;: p1 T1 p% O1 {
DWORD dwDataType;
! l5 V" _) z3 N- Y3 x' r' t$ ~char szSubKey[256];7 W: i# f" {' ^, {$ C
unsigned char szData[256];
0 x" |/ b0 q2 f, c2 F) E6 @5 i# a% E Z; w& h9 h2 Y* T
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)" z9 f1 B/ V b# t
{% ]9 A5 ]/ S* T9 C
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS). z$ ~% ~0 L! q& |& h
{ - L# I/ e; e6 Q
if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)) I0 a. ? t+ t/ @3 t9 I
{+ E! K# T f/ M" M7 @1 ?/ ~& L
dwBufSize = 256;
) i0 n2 Y! @; M: a# R if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# J2 S, H/ H: g! u$ B6 u f9 {9 F
{4 B4 C3 g# \/ L; n/ r
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡6 c D& D# _6 l e- |* Z2 R
{
7 j- Y1 X; ^; d dwBufSize = 256;
, u, f5 P# s9 H4 |7 D! d if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# `2 I, o- J3 C' K: C, N, S
{& C) I: l! c. y* i
// szData 中便是适配器详细描述
2 g! n c; F+ [% S6 b6 j/ I4 [ dwBufSize = 256;
4 Y; Q: G/ }- e3 ]1 i8 C if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
7 }7 U+ j2 P0 h1 Q8 Q {, D B+ }, I3 u! Q/ m9 L/ g
// szData 中便是适配器名称* H4 p2 S. J' x; P3 G
}
$ C4 [; ~$ T. J }" r% A0 P- i3 @0 D; `' O
}) P5 e/ q$ Z. Q; t8 j
}
0 t+ Q A$ z+ `3 @: ?& o# C RegCloseKey(hNdiIntKey);
1 x: ~5 _7 T3 c }2 J" A( B9 `# N8 T
RegCloseKey(hSubKey);+ z0 X& ]; q( v; v
} h' ^6 V, X s; x0 G
' w. o! i$ n* z7 z$ r
dwBufSize = 256;
3 h) u- t6 d* y5 @7 B} /* end of while */
$ ~5 j3 ]# A7 ?$ Y& ^, Q5 O3 p* x 1 H. Y+ c* n4 W& g
RegCloseKey(hKey);
0 m! a8 s u$ T. a, E9 G5 i二、将IP信息写入注册表# d J5 `0 V, M( }
2 x" z" A- q, E0 ^
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)% V6 y# y6 w- x5 a: |& _) @; \
{
/ o7 t$ j3 D/ X0 H# D5 E( x HKEY hKey;& V8 d$ J7 _2 U/ I1 p2 p+ P g
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";, Z" `( v* i+ {% R* n
strKeyName += lpszAdapterName;& p3 M Q3 q# R' X' r3 ~
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,& C" @9 j2 s" B0 l+ G3 B# i+ i
strKeyName.c_str(), k: p! _# u" [4 b5 Y* a& `* {- B
0,( n8 N- Z) C b& x
KEY_WRITE,
* x. Z- Y9 T* z5 Z &hKey) != ERROR_SUCCESS)- b: w, s3 n0 r7 B- M) W+ D( @
return FALSE;
% q2 x& o% V ]- B
2 Z' o- O) d+ K) k- F9 | char mszIPAddress[100];
$ c! S# j0 J9 K# _9 U char mszNetMask[100];
/ m" e8 j$ w+ @4 O- I char mszNetGate[100];0 k4 W0 n7 \% M+ e; L/ ^) \/ q
! @+ G6 p) H; O$ Y( \( c5 g strncpy(mszIPAddress, pIPAddress, 98);
- X% ?) W# {7 k6 s& ^4 m, f* E strncpy(mszNetMask, pNetMask, 98);
d C! Z- ^" z4 n2 Z strncpy(mszNetGate, pNetGate, 98);1 M. [/ T. F+ {1 ^" o
# S2 y9 K6 V5 [) v, @, I: }" l2 U
int nIP, nMask, nGate;
: V; h) K I3 ]0 n7 m0 S7 X5 y G/ V
nIP = strlen(mszIPAddress);9 U: O4 a! ^* N& \" p% d4 n
nMask = strlen(mszNetMask);% z5 T6 N" U$ e) I9 Q
nGate = strlen(mszNetGate);& G! f! e% y# I ?$ O
, s5 L2 k' M' X *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0- n* u2 i. Z% x* f9 O+ r
nIP += 2;
7 z: F* |9 G: x+ w0 s" `+ u [8 l4 }- _3 h8 V" N( a3 [3 V4 T- l
*(mszNetMask + nMask + 1) = 0x00;
' z# J9 W' r. n5 f nMask += 2;2 n5 G: |/ Q1 N4 P6 B4 e
( A. R; N) j$ c+ u5 o6 d *(mszNetGate + nGate + 1) = 0x00;
2 W$ Z) e+ S! Z nGate += 2;, F9 M8 ]- @8 z* j
7 C: F1 N. V7 x. e- l RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
: I* {$ \3 D0 [3 W' c RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);* u0 l+ q. ^6 x* w7 S
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
. D! y5 r9 [& l2 ?' O" {/ a" _+ l& S" }. j
RegCloseKey(hKey);
X8 Y* X# G; ]7 g& d+ \
& ^4 a% R2 x P* Y2 T" c return TRUE;
# t! ?% W. @8 @}
( ^5 ~( a" D3 r# ~3 Y3 F+ k" q2 [$ t: ?/ N, F( ?. C& {) K; b
三、调用DhcpNotifyConfigChange通知配置的改变
4 T" M8 }2 f& g/ ~( u) L6 n- B- Y# k8 j) E3 g$ g
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
! ]/ R' w( w8 ?' C; c$ o7 t! F LPWSTR lpwszServerName, // 本地机器为NULL
( A& S# x& t4 F; I1 {% I LPWSTR lpwszAdapterName, // 适配器名称
8 @2 `1 k( F& d; {0 I( ? BOOL bNewIpAddress, // TRUE表示更改IP
% w- l+ b( d1 v8 E! x DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为04 Q( L9 ~ X5 Z8 k* Y) L; z. B; Z9 p- ]
DWORD dwIpAddress, // IP地址
( X3 P: t- T5 ?& i, p. T DWORD dwSubNetMask, // 子网掩码
, p0 ?7 t8 T% K. N int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
. n/ u' O3 ]% ^$ i# x1 Q3 Q0 H& k% Q ]/ p: E+ U
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)% M8 r, I: {9 p) V J
{
9 M8 }+ f7 |2 |( q0 W0 A BOOL bResult = FALSE;# V4 h1 S2 d" }5 _+ j
HINSTANCE hDhcpDll;, Z7 A/ A2 p: D7 R+ [" u
DHCPNOTIFYPROC pDhcpNotifyProc;
0 g5 Z# R b+ l! X* |& U* ` WCHAR wcAdapterName[256];
! p8 b/ h& ~; F! H- H) ?$ x 4 u! p# ?4 w9 K! V/ n0 C
MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
0 p( o- ~$ H& H! O% k2 Y- ?
: ? C/ F0 Z! m( S6 T9 H$ A. S5 U if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)* K/ \+ f A. w% R
return FALSE;; L5 t8 t6 H& Q* C3 A- V# b0 K
3 Z- ~) S/ x& `7 U1 G8 ]
if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)% G5 b( w7 D( K' n
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
8 h3 k) m1 h5 n0 H u/ Z+ A bResult = TRUE;
+ `/ B K' W$ {* {. T2 p. t; D. L' f# ~# x8 x- f
FreeLibrary(hDhcpDll);" s S1 d: _1 q% E: y0 A0 L/ C
return bResult;0 h+ d* B% b! c) M0 l6 b( k0 Y8 [
} |
|