|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:
$ P8 U! i. _2 u8 c; `) h" Y1 D' r8 o- W6 I, c$ C9 o/ x
一、获取适配器名称
$ ], i, Q! R; ?0 q8 T8 x* J# h3 q8 E% F. L% s: f; v
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:7 J6 a% B+ Z0 x: _$ r1 R
! F% N" J9 r2 W+ ]" q9 d: B1.1 调用IP helper API取得适配器名称 + `& [$ j4 t7 C! s- D
! u: k: ^" L- X: W0 m( i" k( U% c- \ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);3 `% N3 J+ R; r$ c/ H
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];- c/ j7 A4 n' r8 h6 N1 e* C* l
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
: E, [6 j+ S9 b( ]( a4 I" Q{0 s/ s1 e0 T' s' c+ _
delete pAdapterInfo;
( r% ~) Z9 g2 L) y$ }- r/ f pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];: G! q! n# h& O6 Q; E
pAdapterInfoBkp = pAdapterInfo;
6 W2 R* N; X! l; g! Y) D}+ J) l. ]$ Z, h$ n. W1 H
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS ), M% N9 N3 l# W; T
{
5 s1 R D) d0 d8 T3 c, v do{ // 遍历所有适配器* ]( i6 _9 Q2 l8 X6 w6 n2 s, Z
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
7 c) \0 r! K: Z( n& M) Q8 B {
( ?" U I1 v1 W6 j% z // pAdapterInfo->Description 是适配器描述6 s- r% K2 Z4 X. r' a/ ]
// pAdapterInfo->AdapterName 是适配器名称
& Y2 A7 L @, D6 H+ b }1 X, U' U; s0 F/ S* Q5 Y
pAdapterInfo = pAdapterInfo->Next;
. I* {3 L/ r+ l3 z8 d }while(pAdapterInfo);/ Q$ @5 [7 r, W, N9 f7 F% N9 c1 b
}
+ ] i8 s5 H3 L1 a+ K$ mdelete pAdapterInfoBkp;
: T- h9 S0 C, Q4 l+ M T8 C6 h c1 H& {) r8 h
1.2 读取注册表取得适配器名称* g% X- A% ~6 t/ O1 K" v5 d
. |; f' ^/ W& }3 V" n在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;6 Q9 U0 _9 [7 B% x
# N& y+ b$ R; d1 H) H* x
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
# }' F+ F! V/ V" O6 H "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
& C0 R7 I+ g, w% H9 j: l! F 0,& b2 R$ B' Q; q, V) `
KEY_READ,
0 n4 Q6 g ^) X0 O: B* [3 W &hKey) != ERROR_SUCCESS)4 }- Z: p$ Y3 U9 s, q" v
return FALSE;6 L3 q: l- k+ |, q- \* g7 s
0 }. t$ o% N4 N8 dDWORD dwIndex = 0;( B' x% x& |6 m4 j5 t
DWORD dwBufSize = 256;
& `& A5 ^ ?: T! v& B' X7 S/ x4 SDWORD dwDataType;- K/ S# U+ X- ^3 P; [% C
char szSubKey[256];
* }% x0 t! K L6 h* ounsigned char szData[256];
3 I2 I& v9 \* o2 q1 `! m* _5 n2 K/ [3 Z: i; e) [
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
! ?" x% d; Q, `; U{- J$ x% @- _; ~* @' g
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
" N- W4 Q3 q7 @" a {
$ W$ z+ `3 ~4 g; U8 u* W- S if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)9 v. G$ x- j9 r7 T6 `* Z5 y
{
" ~/ u6 @# C% m( s% x5 s; r, D; V dwBufSize = 256;
- r2 y2 i. k1 Z5 {- V, v5 Q if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)" w, ~5 q3 ?6 n- C( v* k
{% y$ a. p. H+ ^9 l9 F- S0 J% K! q
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡4 G+ e5 X3 o/ x* W9 h6 S
{ C0 R4 q, C$ U d# `) }# I4 y
dwBufSize = 256;
% X+ W1 r# ]2 ?* E3 A8 ?) x: ~% b+ Y if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
& @1 z8 Z3 Q$ b8 M {
/ O z& Q0 ]6 d2 ^4 v // szData 中便是适配器详细描述: d# B* L: s9 |, j$ ?
dwBufSize = 256;
9 f1 L# t& C% L/ F w9 x! a if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)' [: X' i, r1 B0 ^$ X
{
+ Q4 `, w- U/ j+ h // szData 中便是适配器名称% a! Q( A2 W+ v+ n% K
}
9 [5 Z4 R0 Y" z) \( G& Y }* Z# `3 {4 x$ n; h9 R
}5 n$ r$ U' V& t( e7 c
}
8 B# u; a9 }& S) H RegCloseKey(hNdiIntKey);; y# E$ _ P2 G1 x c I
}9 w2 w; x8 `- M3 X0 l
RegCloseKey(hSubKey);
; l% I' c! k1 W) q8 ~2 z }8 x$ x5 o8 J" b: `) D
( ?# b! A6 N( {
dwBufSize = 256;
" j( Z- q: C3 O1 B} /* end of while */
$ D/ X+ h5 T# l0 ] z2 o$ \1 H
0 L$ x s, s' q- J% }- ZRegCloseKey(hKey);
p. `, y. ^+ Y1 p. e二、将IP信息写入注册表
8 D: F7 ?# U: }. Q2 t
6 H% h8 Y4 h! p+ Z1 y) ?' `代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
3 j& }. q6 A2 c' t8 P: t- o( c{
* U W3 M" r x+ E- p HKEY hKey;% A; o3 ~, w, C" K. y' {# B* h6 J
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
+ m8 a0 q$ Z! O& t strKeyName += lpszAdapterName;
+ D3 Q* i- y$ Q! p, U; S: x/ \3 C if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
7 B) c1 N7 W! `3 W5 Z' I strKeyName.c_str(),
3 A* V# K3 m/ {7 o4 ?3 f* ?1 @; z 0,
: j, ~3 S3 Q: H$ Z$ ~ KEY_WRITE,
2 f( [# \! i. z4 r &hKey) != ERROR_SUCCESS)# i$ V6 A& f& Q
return FALSE;
2 O- z' }5 p/ }3 ^
! f, ?4 z4 |0 U. j- I5 Y char mszIPAddress[100];
& ?% I' o3 k/ x! U Q, H/ c char mszNetMask[100];6 c2 ]0 \1 S/ `: c; `& i$ W
char mszNetGate[100];( C6 x+ N) Z2 ?" a) z
( h+ k) \1 f9 X! \5 ^. Q strncpy(mszIPAddress, pIPAddress, 98);
; v" p; Y# h9 m" J# K& q strncpy(mszNetMask, pNetMask, 98);4 M7 N! @9 A! r6 l+ {4 |8 l
strncpy(mszNetGate, pNetGate, 98);
/ _) B `9 o4 E2 |' h8 P( |
; A1 E5 E( I, d ~ int nIP, nMask, nGate;0 a( P- R( b. {; f& a7 G
( x4 F9 W* t: J. r5 R nIP = strlen(mszIPAddress); c' B, u/ p' G0 k0 Y( T: V3 c7 X
nMask = strlen(mszNetMask);
/ p4 V ?& n. u0 }% @# v; @" M* p nGate = strlen(mszNetGate);1 q) \1 B3 C$ _
( K1 e r3 Z5 s; Y% Z: |% I
*(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0
* H0 a- |# M, N# I) H" y# ^9 e nIP += 2;
- |$ a1 h4 k+ x! v1 g
( d! K; `; R7 s4 e" q* F2 C+ A* C *(mszNetMask + nMask + 1) = 0x00;
/ s9 E/ E f3 F3 c0 A nMask += 2;$ `6 W4 }! o5 l
0 b' M' M: ] Y/ v; P0 Q
*(mszNetGate + nGate + 1) = 0x00;
7 K+ E! h. a, h) p+ v nGate += 2;
) t8 O! x9 H# P) W: A
5 x8 q2 J7 a! H. ~& T2 | RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);. x" v8 P5 P6 ~) T9 {1 p6 V
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);7 `/ g. h' O6 o+ J1 T
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
7 p% v" r6 n: o$ ?* U
: _" L# i( U0 I RegCloseKey(hKey);
6 E( \" y8 d4 V g7 S
& E2 ?. {" h2 `6 ~% ?* g return TRUE;7 F0 W/ G! _5 O2 E4 v; m4 ~2 O
}! ~+ f. @8 N5 Y* E7 ]
1 R9 C3 d1 `/ P2 K( n2 e% B
三、调用DhcpNotifyConfigChange通知配置的改变, ], l3 c+ i0 o9 P
3 v( v6 d, x5 d6 }7 o未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(% l4 k. {; }" d# A* D
LPWSTR lpwszServerName, // 本地机器为NULL
4 w+ g8 E( C+ ?. \& u LPWSTR lpwszAdapterName, // 适配器名称
) R& o3 D; r, a; y3 g BOOL bNewIpAddress, // TRUE表示更改IP8 [/ h' z5 \% O$ B
DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0) K- k' |1 ^7 f& ^: n9 ^3 u
DWORD dwIpAddress, // IP地址9 }2 D9 H" j% k6 h4 D
DWORD dwSubNetMask, // 子网掩码2 v( g5 J9 c4 d3 {$ d% e
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP
! j6 w0 O+ i' [4 e8 V8 j, Y$ b: }0 O/ }, Q( V6 _
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
4 S* j# v- @0 L9 D% |& w; O! r5 e{
3 |& f9 r* a8 R1 P# l) i9 g BOOL bResult = FALSE;& b" o1 w2 l5 S4 t J9 @& o" ^+ Z
HINSTANCE hDhcpDll;5 D5 G8 ]# o. Y! G" h: v" ]
DHCPNOTIFYPROC pDhcpNotifyProc;
) B/ w# `# `6 P% ` WCHAR wcAdapterName[256]; z9 |) s. o) t. E# l# H' i! A
: @2 e' K0 N. M* Z MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
4 o# W+ H3 z( q/ t* g
p% R4 V+ t( j6 U- | if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)
- H- X [* W% Z5 L& s% `( D return FALSE;
3 T1 G: F3 J1 p
) m% S, [+ y; Z0 t, U$ T if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)9 K* N6 i9 q) Y! @# N. `
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)# e3 u. m/ {2 L q' p0 W+ n
bResult = TRUE;2 w. R) _1 K3 F7 n5 W' z. ]/ w, R
" n1 }! z. L) @6 h( K
FreeLibrary(hDhcpDll);
6 s& w& _! d8 k/ N return bResult;
7 T5 N( o+ m) q# R3 N6 p' [5 T6 Y} |
|