|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
3 V& K# |8 y p* R8 A' e% Y
7 V2 k# i, R& T+ n( T一、获取适配器名称2 k. |4 h! V8 h# k
, `; o7 Z! B$ T' L E: A5 w这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:6 E- c" _/ e( K/ x3 n/ f! R3 n
! X, K4 R% f T3 ^! O1.1 调用IP helper API取得适配器名称 2 ]9 `/ q4 }0 N, H9 [0 _7 \9 @
0 _9 w8 M8 c9 A) T; {6 U* b* _
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
9 d+ j- F$ i% `( uIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];$ v f( o- q, F0 U4 V' H3 |4 e2 l
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
- q, Z l0 `: e7 f& g; y{
3 |1 q* Y- q9 x' [ delete pAdapterInfo;# f, L" i/ D' {( ]8 v& M
pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
! M) h- s6 A0 Q3 r& k+ T) ~ pAdapterInfoBkp = pAdapterInfo;1 ?% ]" @# o! ~
}
+ ?- }: k+ ? M+ Y+ z, bif( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS ) n; M7 @( \; w2 q4 W
{8 ~# G! b; G1 ?; ]6 _, R
do{ // 遍历所有适配器+ x# Z3 c' T" e7 z
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口9 t$ [" F" y8 p* M
{. |- o# ]/ R% |7 D( X! F) C
// pAdapterInfo->Description 是适配器描述7 W& a2 R& c; N
// pAdapterInfo->AdapterName 是适配器名称* L" `5 v+ Q' x$ Q& X% w
}2 I& g+ S, o' ]; ^
pAdapterInfo = pAdapterInfo->Next;9 |: q- i# u* b/ T8 o& o) t
}while(pAdapterInfo);
/ J+ Z1 ]4 R$ Y# k, D3 t, F}. D3 i; s; C! H4 h, l. r7 |; ^
delete pAdapterInfoBkp;
% O' ]8 ~* _9 o# U. s& q! R0 v0 s! E! N# c+ b' V
1.2 读取注册表取得适配器名称
* K7 |* q! \6 N: E' r; ], Z( v. n2 K
在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;: T: \$ i7 j; l! I' M" l
! e1 j. P0 q# W& a1 Qif(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
I- p6 v9 X, M7 W "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
6 G) E, H. t. O9 ] 0,, C- A2 t* N$ [2 h- P
KEY_READ,3 V. A Y y e* h4 _& v" T z" h, d( l
&hKey) != ERROR_SUCCESS)
$ Q9 j: L+ ?1 F1 m$ W return FALSE;0 `( D# Q! O) V \) w
: ?7 {3 A# @" O' U# D9 j- p
DWORD dwIndex = 0;" L2 k, F$ r( t' ?
DWORD dwBufSize = 256;
/ ^7 o+ |( |0 M# b* gDWORD dwDataType;
% b- g4 q6 E3 x* f3 X+ Y$ l( S% v) wchar szSubKey[256];; r; d, @7 p2 j8 o1 u' K J. J& Z
unsigned char szData[256];
9 r) {# I5 r2 k) C0 r; @
, q2 h8 a+ e0 ]% _: E. c7 z& Ewhile(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
2 Q& U4 ?3 \: X h- B+ z1 G7 O{
* v- H- a, {8 K# R' @2 H if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
, K; W: L' n7 n. O; o( C { + S" A3 E; O. a# P1 j0 K
if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)! A/ l" R0 C6 v% }2 T9 i+ h) j
{$ U. S. {" b: A. k& O
dwBufSize = 256;
5 N6 ^, x) P' y0 E3 p if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)* b+ _8 t4 Q1 s' s$ d! [( J
{# w5 R) r, T) `' ]7 `* ~
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
- J5 x i" J( X1 n( f, p {, E2 j' o+ ?2 _* u
dwBufSize = 256;5 T# t" I2 L) e, t O- [
if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
4 h; J0 r% q' B$ s$ v4 J! | {/ ~1 l6 g- n7 s$ Q8 c; k
// szData 中便是适配器详细描述: Y# T6 l* I! g- j9 W, ~% M
dwBufSize = 256;* f" D/ c7 `: F, g$ T& x0 q
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# Z: o1 R$ H7 V5 Z Q U
{2 V5 L+ Y( s, a' W& Y) e5 y
// szData 中便是适配器名称
8 @8 Z9 `* _9 C, i }
4 {- p$ e. A3 s' N }
$ D; e" O9 q6 N) g K& J) M }
3 ]* R. A1 t! z }; r" T" |& X2 P" F& P$ z, f2 @
RegCloseKey(hNdiIntKey);
4 C2 T5 h9 X& ~# f) k2 p }* r6 Q8 q/ R( J) W
RegCloseKey(hSubKey);
_1 k* f: U; _& e5 ? }
4 V- |% J5 ] M
! n v% b; w# y: O, X9 g dwBufSize = 256;: C* q( B( N/ F5 p8 \2 U
} /* end of while */
9 B1 d; n. }. R$ H# A2 w* n
, A# b7 j2 m ~/ }/ Q; vRegCloseKey(hKey);' F {, ^' T$ \/ @& D L
二、将IP信息写入注册表
3 m D( q, G# l
( k( J k' r0 O6 S: h7 a代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
# h0 F/ ?& q% }2 {1 c{
* L7 Y# W, O! y1 y9 n3 w! P HKEY hKey;
1 d, b7 O8 C. k' p5 q string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
, E+ E' I( d( L7 J: M strKeyName += lpszAdapterName;$ U. c$ p# w; Q9 v' V
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,6 g4 T9 L! y& G) m+ n
strKeyName.c_str(),% B. {# s, H+ `( o2 w' s
0,
5 X, V4 }0 t% M; Z. q: y: H4 \# d" V KEY_WRITE,+ [& I Y" H- W; f
&hKey) != ERROR_SUCCESS)
0 Y2 t% S; i& r# }4 a/ X2 K3 s Y return FALSE;) T) b; G& U) Y1 {6 n3 O( ^7 Q' {
2 e! g6 m- J+ G) J0 w, C4 ^
char mszIPAddress[100];, o2 {- p- T) f( l' H
char mszNetMask[100];2 ~# |8 v% t3 A$ Q; ^
char mszNetGate[100];% j$ u: j/ ~" [# W
" w+ K% O5 E& h$ a
strncpy(mszIPAddress, pIPAddress, 98);$ n" ~: s: a! Q1 R
strncpy(mszNetMask, pNetMask, 98);
& w2 |8 H- N5 P/ ^9 n8 G5 y/ ~! a strncpy(mszNetGate, pNetGate, 98);- S* h" J) n Z$ j' m
* m- V9 Y* [9 u# p9 r) D; l- i
int nIP, nMask, nGate;7 M, o3 a2 n" S& L7 V( j e; n0 @+ E
( U* y+ g* W1 L! r% D nIP = strlen(mszIPAddress);
1 `+ d. k4 ? g+ T" T3 E& E5 L nMask = strlen(mszNetMask);
3 i; b" Z& Y& V2 L: }" H nGate = strlen(mszNetGate);
: r8 {* ?0 ^$ D7 m: i! u) {6 c8 Q. K% d. ?# x" H$ |3 L& _5 R
*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0
! E: D4 R* i6 ?3 V1 Z) k nIP += 2;9 ]+ b/ P. n; k, y! ]
6 ^6 J) S4 R% `& B+ L9 U
*(mszNetMask + nMask + 1) = 0x00;- o3 N" U6 [# \; i
nMask += 2;. h: H0 K* A+ _1 g4 }
3 F' }- {. E/ L6 E *(mszNetGate + nGate + 1) = 0x00;8 H5 G' w5 b6 G8 H( b4 r
nGate += 2;3 b3 ?4 b e8 ^/ Q
/ T* U) Y6 R# |3 b: H m5 T
RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
7 W, v# t; {# k* d7 |/ | RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
4 w! @. M6 j* M1 I5 n" m. D9 R RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);" g; ]/ ?7 e- J4 [+ K, P
3 x. S- K8 d- \! z) f& w7 U0 t4 M RegCloseKey(hKey);9 b7 `1 g# l) p: Z i$ \: h, }
% h0 N1 ^7 i U5 e# V# v& ^, E return TRUE;
( b& O: |( P1 A}1 A* G. j) s" J! F* j
8 `) J( L& d' q: j P' K# h7 [# q" V
三、调用DhcpNotifyConfigChange通知配置的改变
! @9 N& Q7 S% Q7 o @& u( B0 Z- H! y3 C6 N# v
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
1 w9 @& ?" D0 n y0 n# }1 V LPWSTR lpwszServerName, // 本地机器为NULL
$ z, V- ?( Q' |& v; ` LPWSTR lpwszAdapterName, // 适配器名称
' Y* }* m5 o+ r2 w) ~ BOOL bNewIpAddress, // TRUE表示更改IP
1 c$ Q7 w2 ^9 L, d( ] DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0! L7 W: J- ^2 A! _
DWORD dwIpAddress, // IP地址$ g8 H _5 t/ Z; O) Q
DWORD dwSubNetMask, // 子网掩码) C, O* Y# f8 X
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP% w, m0 h' B9 @5 P8 B& ^
0 ?* m/ H! e: @6 [3 e0 b具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
$ B) i( @. L$ t/ ]: ]{' S8 K5 q' j! H& r" d% J
BOOL bResult = FALSE;6 T0 a/ } C( R4 |: u8 O
HINSTANCE hDhcpDll;( ?, |8 \$ ~7 j! I+ Y* o* r- l# U+ H
DHCPNOTIFYPROC pDhcpNotifyProc;6 x5 }$ g9 Z4 V- U w0 {. F, W: g/ I' q
WCHAR wcAdapterName[256];9 ~6 Y+ z& Y0 E6 V( g. T' f% }, C% ?
8 ^9 |; N6 k6 w+ Q( D! r* Q5 a MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
; R" Q6 ]+ l/ L" c M2 w1 E! c7 L" G9 _7 I
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)4 H. V: q% F/ E* I+ g! u: W4 O
return FALSE;
4 p0 D) D9 c! c7 _! s; ?0 u
0 Z7 s) v/ J& X8 h( g$ Q& l if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
& ?1 z* s( c% Q1 I8 w) Q if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)9 R& v e$ r1 ~% `0 \" G& u
bResult = TRUE;+ S' {- R* n- ^7 G" K3 M
- A* M& |( y3 [9 S FreeLibrary(hDhcpDll);5 _6 V6 ~4 o& U% N
return bResult;
* O8 w3 u5 O+ G) C& |) r5 N} |
|