|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:( }( e4 U4 U6 L, H& \
3 V' R6 o. |& a8 `一、获取适配器名称- ]- B/ s/ W7 c- @7 k; D
% I/ J1 X$ z( D9 E0 q9 P3 |- b+ z这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:3 t3 l G* m5 D/ p$ A- c ^
( y7 w: w/ s/ [; M" x
1.1 调用IP helper API取得适配器名称 2 F/ i$ ]# k! ?: {: { |# D
5 v) H! \, u% v
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);+ v/ l) ]0 S! r
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
* `8 f) y h' s, a, l* gif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大+ g/ L! T& h; k& E q# v: U
{
/ G6 M* @! f. W3 O% p/ r delete pAdapterInfo;
; p2 }/ p) V3 } pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];' W; q& R5 V! H$ U- P* H
pAdapterInfoBkp = pAdapterInfo;
, _: K. W) p# Q3 Z; W; O}0 f( o5 X* c% P& f; \; ?
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )5 c& U" ]9 J( p! g% M0 R
{: S* n# I0 C( Y9 L% g+ k
do{ // 遍历所有适配器
/ `8 Q7 K7 ]6 @" Z. l if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
' Y6 i+ [: A7 N6 Y' }+ u; F& R {7 e" V. G7 A5 r0 B% s8 a
// pAdapterInfo->Description 是适配器描述) \* D w- r5 S* u B6 J" u2 m) O
// pAdapterInfo->AdapterName 是适配器名称7 A _$ u) |$ ]0 Q! q+ m+ |
}! _+ j# {* U$ ~) W6 V, S- _
pAdapterInfo = pAdapterInfo->Next;
1 r4 `- z: O, ~ }while(pAdapterInfo);
4 A% P& [0 u2 B D$ `% O- a- N}
k9 M/ v- v$ [3 f8 P5 U+ |delete pAdapterInfoBkp;- m6 ]8 {- B. B& v. F4 M
, V3 w3 c$ d1 c4 @7 {" n' @# m% a1.2 读取注册表取得适配器名称
% ?: K) }; L" K' k/ `
6 t" n C' g: L, t在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;- D/ }6 r6 v$ |7 A( c
6 E$ ~8 u L7 Y7 U/ m) {if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,7 }" A- p. ~6 i3 |5 Z
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
6 ^6 N2 y5 g- c" s6 t/ k( Y 0,+ d5 A1 [9 ~5 s n9 O2 N2 p, }$ H
KEY_READ,8 d+ C/ C* C) t' |, P8 ?+ c
&hKey) != ERROR_SUCCESS)% t4 L" z/ n( f; h& w; x) \+ D" z
return FALSE;3 Y4 \4 l. ~8 j. P& O& l
/ S9 }) j* Q; B! l- V( D1 Q
DWORD dwIndex = 0;) R4 u7 d+ S/ F% ?
DWORD dwBufSize = 256;# R# f( k% M2 P. s4 }
DWORD dwDataType;! X! R- H0 M0 \( O
char szSubKey[256];
7 V7 V$ p+ N# v3 @unsigned char szData[256];
$ i, P) U2 m- |- h/ S! g5 B% P s" f& m! f; G2 c! |
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)0 {: U* w; O0 W
{% R2 j6 k& B8 K/ n& b1 U. c! g' X
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)5 q+ T- r8 O( \, L# ~1 F4 \
{ 6 H$ N9 n5 E' j# B" j8 t! r! Q
if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)0 V+ r" I! j R1 h8 G8 b7 X) }, k/ k y
{
$ Z8 ^ |; i7 z1 n/ `1 `1 \ L dwBufSize = 256;
: q6 R& N7 a+ O7 S if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
R% L8 P- k' x$ }; O: p7 Q {
$ M2 E+ P) a: J if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
: m% E8 ~1 \+ w# y# B: }2 R {. ]) P$ s" ?- A+ u0 Q6 F
dwBufSize = 256;
5 {( R' N$ X9 U' A5 w5 { if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)9 F" A4 G C, U. u! \9 z
{
: a5 A8 q( f! c9 X- s0 t2 b // szData 中便是适配器详细描述
' s( e0 o' R2 o dwBufSize = 256;) ]: z0 m2 J) X* N, {/ r1 u8 e* j
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)1 {" g4 \8 S; Y: R! Q. z# ]% r4 d
{: H" O3 m2 I7 @; P) e
// szData 中便是适配器名称
/ k+ x; U3 f4 E# t8 W0 G }! d y; P; F& u9 h
}+ ~2 R4 J9 t- v) w( G4 R# ?' S
}' R7 v/ a! h M: U6 [! A) S2 P) _
}, P# F* s0 M( _ y
RegCloseKey(hNdiIntKey);
- w; w* k8 v- J }+ B9 S! S8 R3 B+ B. p
RegCloseKey(hSubKey);
+ ]4 Q+ c( \6 _# Y2 M }* j1 E) l. p9 R4 N% F7 e( P2 k2 |
- d! ~% g- o% M# R0 G dwBufSize = 256;$ N3 U4 Z( Y, |) q
} /* end of while */
! U _: u& F4 K* r5 E : \/ }# P8 r; g2 p- V
RegCloseKey(hKey);) J: q. _ {9 J( j) x, j
二、将IP信息写入注册表
; h6 P ?: B9 o% c+ D2 s" _9 e! x/ G( D! g9 j' A
代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)7 I4 P: m0 F9 x$ G- I4 h. r3 G
{1 f* n" u( }3 K, ~) q: k. S P5 p
HKEY hKey;7 E1 F0 h- d9 e0 y# f
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";* |2 I* l9 E6 ?" M5 {, o
strKeyName += lpszAdapterName;# @4 i- l5 `# g ?1 `
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,: A) z0 r7 S, o6 K
strKeyName.c_str(),
2 O$ @3 d1 a9 i+ s3 d7 i 0,1 e3 k$ ?# M& [0 n1 m M
KEY_WRITE,
6 O. g8 x. B9 f$ g! @4 [ &hKey) != ERROR_SUCCESS)
2 C. i) d" F4 q return FALSE;
. ?9 K. s) P4 h [0 F
6 M: C# e t/ i# _ char mszIPAddress[100];# r* z+ O. r/ s5 r+ D' T4 T n
char mszNetMask[100];/ Q. `+ y v! ~: y/ V4 g1 K
char mszNetGate[100];' o9 H+ }6 G! S) d/ x
1 Y, L# u2 L0 c, K" V/ ?& K strncpy(mszIPAddress, pIPAddress, 98);/ P- [2 g2 y$ K Q/ B
strncpy(mszNetMask, pNetMask, 98);
! O6 L# t0 r7 O strncpy(mszNetGate, pNetGate, 98);
/ r" X* U5 B- Y6 T
% v' |+ W- y7 U b7 L: v int nIP, nMask, nGate;
% r% r! _% e6 A2 M0 d5 a8 G g- D! {( f5 ]0 O' w( V
nIP = strlen(mszIPAddress);
0 s2 A2 A" S' t4 @% V nMask = strlen(mszNetMask);" L' V* n- v% K8 X9 x
nGate = strlen(mszNetGate);
+ f b2 r2 [3 w, m7 ?) E; H n i2 J" ^0 K
*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0: v [, {4 }6 a; B& \, i% N
nIP += 2;. R3 Z0 p, H! W# D7 }! j; Y
; s- c$ E/ X0 H9 X9 ^: k% H
*(mszNetMask + nMask + 1) = 0x00;
4 e( O0 E% x# i, m* _ nMask += 2;" S+ I! R' b" c) v- `5 u- Q
( }; c# v" m3 [ *(mszNetGate + nGate + 1) = 0x00;0 \$ X$ u1 Q' _" F
nGate += 2;2 ]- ^( A! ?6 i; V6 z/ y8 L+ {, `7 w
7 @5 H! O* j2 a RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
- z! j# W; C" _! ^/ k; ]- `% n3 ] RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);$ L' O" P* h$ v( m
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);- W- a8 C# c$ c+ X3 t* w8 i6 `8 ~
4 E* H. _7 S9 d* r; F5 z RegCloseKey(hKey);1 n' F; A# F' d' ~/ i1 b# `
5 M! Q( B9 ]; {" } return TRUE;6 d* O% G; b+ [8 ]* `. h+ t
}
# _& r1 U$ Y( ]1 y4 J
/ w' J$ x( i- a- X三、调用DhcpNotifyConfigChange通知配置的改变
8 S: B. j9 Y8 I/ @5 X/ _
S, _+ W# e% h! C) W未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(& R5 R; j0 K( S; R0 O5 D
LPWSTR lpwszServerName, // 本地机器为NULL8 s. b( J* q% N# s) O: B
LPWSTR lpwszAdapterName, // 适配器名称/ A' S/ s" c( u( E& i9 ]
BOOL bNewIpAddress, // TRUE表示更改IP
; u. m" P% u2 S3 _; z DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为03 q) A7 `6 i& A, ?, n/ |* B1 \+ s
DWORD dwIpAddress, // IP地址: w2 k* m1 [- e$ C9 i9 z4 Z
DWORD dwSubNetMask, // 子网掩码
, G* K# n, z* z+ b2 P4 X int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP& Z1 Q2 Y$ O6 x6 F( q) `- H
% A' x; K0 v4 f4 S5 Z* s
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)! p; r9 C& x0 L% ^4 E
{! {" v9 ~! q+ n1 K* }
BOOL bResult = FALSE;& |- r Y+ X: L/ e8 w: a. k
HINSTANCE hDhcpDll;
% ~' @- c4 w; }9 z' q. z DHCPNOTIFYPROC pDhcpNotifyProc;
5 l8 S2 z8 o/ o9 w. |/ ~; ]9 r( A* o WCHAR wcAdapterName[256];$ ^2 S( n" A; M# P
. P& R+ {8 `, k$ F, E$ h MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
; n2 w# h8 A+ V7 e! _- l$ [3 x; ^3 P+ s- X9 N1 u3 v. h3 W0 h
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
$ ?: j* `7 X; k$ G7 j return FALSE;' r; ~9 R! j( V
' v9 `5 d7 T5 Y0 ]4 d& S
if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
p( i9 z7 Z# S, S. j if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
# h6 n; H7 ]! i. L% T: S! u+ P) i bResult = TRUE;/ h. c8 o5 P% c3 f: i" J- q5 D
, R5 I% L% o5 g4 I1 K" ^ FreeLibrary(hDhcpDll);; _7 [% o! n# y; G' r( L, E4 j5 M
return bResult;( J% Z) K6 Q6 ~1 W0 P1 ~5 A) b
} |
|