|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:$ t; d, I& S3 U S2 S, y( ~
6 c: e. T; \5 _+ |% V一、获取适配器名称5 o6 X1 u2 e+ B& ~' y6 F
0 t0 D( X6 a" U9 }0 h5 Q5 s& b
这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:0 J& j+ g% ]& C' ]/ }
* `$ \) y/ G9 S/ D1.1 调用IP helper API取得适配器名称 9 k" u1 x8 x, ^) P& O
0 u! T+ |2 U8 l* N# _
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);$ f2 [9 n: H& D
IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];5 y2 |6 p% X7 f! F0 m. ^
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大3 O7 H4 h$ [( b# O+ X
{
0 G8 ^# s3 o0 k, \9 A delete pAdapterInfo;9 ~3 p2 R3 ^5 h* G" K5 V& W; a0 L
pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];" N2 y! |7 x6 M4 d9 @
pAdapterInfoBkp = pAdapterInfo;
3 _1 [. I' m8 |# r* F! ~4 x}- T) I: M' `) l3 F
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
/ e+ _* N! @9 U3 S{
. \3 r# i! d5 e& M- y6 J do{ // 遍历所有适配器
' P+ k: O; P# x) }2 f if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
5 h" N/ j3 n* f* K) c {0 N' p1 z+ T+ |4 X" c+ |
// pAdapterInfo->Description 是适配器描述
4 C% S9 n! @+ k& K* |. M // pAdapterInfo->AdapterName 是适配器名称/ J& W& Q; L1 x
}" k; G+ w( ?( e; h6 T5 T
pAdapterInfo = pAdapterInfo->Next;
8 `( S8 t1 L% ^$ `4 }5 [( t }while(pAdapterInfo);& ^ m' |' D- V# ^, \ I
}
2 u9 P. c' w% K) I' R; `delete pAdapterInfoBkp;
1 U) r J3 C. ~, A6 H: Y/ }: h! Y6 K1 ?. Z% T* l' ~4 \: v' |' \
1.2 读取注册表取得适配器名称: T5 v" k2 {8 u+ }" d# Z
0 x( G2 _) z6 m
在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;+ s# Z6 g- `! R, g. x/ o
$ T+ ^( }- S9 c$ }+ J
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE," p5 U4 P1 d* H3 z' k& r" {. H6 l' o' J
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",
, T: I ~; A# |: B0 M 0,, J6 k$ H/ G7 W" X `. P5 T0 Q5 Q0 u5 z
KEY_READ,
* M& l0 d; H* ?; V+ w &hKey) != ERROR_SUCCESS)
, y9 }- @1 S f: H& t0 E( _ return FALSE;
( a7 U7 {" o! _, }' M( Y; X- l+ g/ g# d
6 ^) M" W* w$ p, K9 a- |/ FDWORD dwIndex = 0;3 M+ r9 u7 O/ t1 A' s0 p
DWORD dwBufSize = 256;
* h7 F+ J y$ f$ K5 n% JDWORD dwDataType;! Y% ?4 `4 t; V6 V5 u# X" |
char szSubKey[256];
7 L2 Y |, R. F$ ]+ N( R8 P$ b' w9 Vunsigned char szData[256];( a9 ]0 V. o& ?* d# U6 M2 B
7 G" Z" h/ M, g9 T, p& Ewhile(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
8 U/ M& p/ _( w' e8 s6 Z{( P( J4 ?5 j: X) e7 m2 I
if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
, C* B$ a5 m# ^ J {
- b+ d! B8 j7 N( }) w- b$ k if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)
2 l. _, s, e4 a5 N {
) R! H1 }- Z5 m/ x. J9 B. H4 ] dwBufSize = 256;
$ Z K* o( f2 d: N4 X) d6 F, S if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
4 \0 b6 e, |2 c$ t( x# d {" o8 O9 G/ i- k) N8 r
if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡1 a! z1 O% H5 \
{
1 z4 W% A# u6 C4 J- ^1 G: V* c dwBufSize = 256;- G+ u/ [8 i( g# \5 Q
if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS) Q1 H5 K8 L* u* M8 ]: _
{
' h* Q7 j( z9 X3 L) G2 i, D // szData 中便是适配器详细描述
% j: w8 C( ^- E, ~( a9 w( _% _ dwBufSize = 256;* J" F- h" u, S
if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)# q* a; m* W! g. Q
{
" q @* X1 [& r3 ] // szData 中便是适配器名称
) A. Q' d+ A8 u3 T0 B. S- E }7 E" J/ T# x2 ]+ o0 q, a+ h
}, b8 K3 L5 v6 w2 _
}
1 e, D8 U5 p; E; v. I }8 z* i; c2 I8 A" b
RegCloseKey(hNdiIntKey);
. D4 e/ i" j Z7 ~( E" f }+ M- M, z8 {/ z) D) F( w! f9 K3 j
RegCloseKey(hSubKey);$ F7 U: n1 n+ v% j
}. m/ N8 z0 \. G) u/ N5 m" @( ?
2 c0 K$ U; x K( ?* _' @
dwBufSize = 256;( V0 B; v( W8 R
} /* end of while */) T; s& z2 A/ D# u
* T& P9 k/ ^4 D; p$ T1 I& h8 zRegCloseKey(hKey);# n* u7 h+ Z+ D, e* |! p
二、将IP信息写入注册表8 ?# ^! E- s8 Z! @# h% m
# h) @6 `$ {7 i2 g+ @& c; r代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate); H$ s) L# |* i: C2 W
{
- J8 ]3 F: L$ {& ~ HKEY hKey;+ Q* Y. M ~3 E x! h
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
3 M2 m9 p6 w+ S; o4 ~$ {) R strKeyName += lpszAdapterName;
5 T, M0 M% A: u+ S* c& S4 y5 D if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,) v B7 r# o" u& @: m* _
strKeyName.c_str(),
1 n% r; q9 v; N9 { 0,( ^6 W9 u) f" G5 F
KEY_WRITE,/ ?( Z% ]3 M' M- b; q6 g
&hKey) != ERROR_SUCCESS)
! _5 a! b5 U9 ~ V1 K return FALSE;2 {3 t; X' o, Y& Y
6 D; S' R7 M4 ?3 C4 P char mszIPAddress[100];3 r; M ] @9 T5 [$ q7 u: I$ s7 e
char mszNetMask[100];+ |- n2 }8 Y& s9 A* n
char mszNetGate[100];! w0 V% u" ^2 d* N8 `! @
3 C# u8 o6 u- i! I; v( |
strncpy(mszIPAddress, pIPAddress, 98);# E; D/ `8 X g( r& c0 {3 c+ H6 y! s
strncpy(mszNetMask, pNetMask, 98); i% F) z. Z# f/ U
strncpy(mszNetGate, pNetGate, 98);% i- M. B$ S$ S5 D
0 f1 S9 G0 E* [ int nIP, nMask, nGate;: h. ^0 X: F7 c8 V+ C# j, K6 @% B5 y
0 j/ V) P2 J0 {( i, V T3 P6 w: ~# N3 y
nIP = strlen(mszIPAddress);( T( ~9 `/ n7 F' K% ^
nMask = strlen(mszNetMask);
+ R' m/ q6 f8 g) b9 @3 O nGate = strlen(mszNetGate);. I# f& i. i8 f p2 u+ | ^) A; [
7 f, p: U; ?5 n1 m5 p# E% X& [ *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0# M5 I! K0 a# b; k8 s
nIP += 2;! x# U: s+ V5 C4 r" G1 ^
3 u3 A7 q; d8 Y *(mszNetMask + nMask + 1) = 0x00;
2 G! |6 g+ [& b1 b9 y& a/ z nMask += 2;
7 X$ Y- j2 W) f8 n0 m+ \3 j5 c& F' Z+ |! I' n8 s( @6 ?
*(mszNetGate + nGate + 1) = 0x00;
5 f9 G/ H& V0 U nGate += 2;
]3 ~5 Y3 e( E+ g
4 E; j7 O/ s. j0 E0 X) e RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);& a" d0 L/ v% G1 }; Z' u \7 d- Z
RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);
, f4 Z8 n: G$ p RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
, T$ Z% c* o' W! \- t
+ Y# [' d8 W" v1 D RegCloseKey(hKey);
$ H: i O) ^$ S( g
, A. K2 }7 H6 T- J! g2 L/ s return TRUE;
" Q* D- z' I$ |) @. N}7 ^& F$ J4 ?4 N4 `
- H' b8 n- O: T! _& |3 _
三、调用DhcpNotifyConfigChange通知配置的改变
' r9 H+ s" t/ G4 P3 X- E2 ~7 i* d" E
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(. m+ r' C: Y( z4 m
LPWSTR lpwszServerName, // 本地机器为NULL
' s; |$ C4 \8 S( l6 n' d LPWSTR lpwszAdapterName, // 适配器名称' r$ A- `" e7 A3 d! A3 z& E$ s$ a
BOOL bNewIpAddress, // TRUE表示更改IP: A4 A* |- K) Z( c! G1 x) s/ A
DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0
4 z) o3 T5 k! T8 K/ l- ` DWORD dwIpAddress, // IP地址
2 Y! `: D2 a+ A DWORD dwSubNetMask, // 子网掩码7 ]; f1 t0 k+ P1 V/ V7 S9 F0 A2 I
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP( H( o B2 _+ E1 R
- X9 U+ w6 P! F: G7 k! h
具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
' `* x& ]7 K% |{+ @/ ]8 n8 S% E1 v9 T! j9 a" z: C$ w
BOOL bResult = FALSE;
- B3 ^. C8 D4 Y HINSTANCE hDhcpDll;
! _4 A; {, L, H6 ], J- B DHCPNOTIFYPROC pDhcpNotifyProc;: P! w8 ]" I9 M! m _* V: S% b
WCHAR wcAdapterName[256];; a, p; N3 {- k# w
* k9 Y( L3 q8 }
MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);
8 V8 ?& R! E" S o7 s% I% U; A6 k8 q
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL), I. O0 a) U4 h( Z7 j
return FALSE;! j, z0 e7 J) M6 ]5 a1 p
. Z5 G1 O% k8 m4 l8 k! m' ^
if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)
P+ ~8 K8 @8 ]: @+ @ Z4 P7 u if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)+ J5 W7 R5 }7 W& r. a- V' S2 k7 K
bResult = TRUE;3 m( F& v, k( Y8 ]( T( G/ R/ s
4 d7 }! p: T7 c& i6 W: t& Y FreeLibrary(hDhcpDll);
( R3 _9 U6 W/ B: N return bResult;% Q+ {7 [" D0 O [/ t# v0 o( @* P
} |
|