|
|
设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API hcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:3 q6 j1 ?$ o$ d
3 O/ e( |: Z4 _" I3 k' u: F
一、获取适配器名称
( D8 P) f/ Q4 h, y
q, m0 T0 J. ]& P4 p这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}。获取适配器名称的方法有多种:
$ q* x8 G$ K& b- j5 L& y6 u+ A0 Y! u- }6 q- G
1.1 调用IP helper API取得适配器名称 1 U+ n; P3 I6 i% p, H
3 s8 i/ f0 D9 ~' w
ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);
! ] w& P% p( _: E; H( [4 MIP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];& Y2 Y, m5 Y' h6 |7 R
if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大
" _9 x; j% {0 x; B g) N; c{4 x7 d8 \% ]( L" p2 p L+ v
delete pAdapterInfo;6 }# g4 c/ o% B5 ~& N) Y) x
pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];
u. A# o2 J3 ~" v) @ pAdapterInfoBkp = pAdapterInfo;
! _0 R. S/ `! ~1 L" q}
1 }' g L5 b5 T& y n6 B1 \if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )
9 W. G' t' ?# L# D4 K{1 I) M" {$ F+ K
do{ // 遍历所有适配器- S) U2 b4 O" T! h0 m' R/ D% X: O
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口
5 k! d- ]- w" g6 F6 V1 ? {
/ N1 e8 Z, F5 M& O // pAdapterInfo->Description 是适配器描述
0 G6 v$ g4 \8 W/ I // pAdapterInfo->AdapterName 是适配器名称9 s8 D! ~; c/ k
}
" F- d% L( G3 G8 e6 h pAdapterInfo = pAdapterInfo->Next;
; Z- a9 O) d I) [ d2 Q8 k }while(pAdapterInfo);
1 p9 q4 n O5 n# A}
' v4 x- B) K3 y: E4 `" o- adelete pAdapterInfoBkp;: |; F V$ Z$ c) n1 ]$ y2 y
. d( T" V3 N: ]3 C1.2 读取注册表取得适配器名称6 F R) y9 x: m- v* i7 J6 j& U
2 `$ j( X/ a8 z, d* b
在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;+ k+ v. N" @- j' D$ r2 K
/ X% y0 E- {# u( b ]. Y& v% T' U
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,& D& ?# Z7 j H0 g, J# J5 n( s
"System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",- e; |1 s" u% M+ P, f2 Q
0,# v2 S- v- S7 [, j* `: ?2 C
KEY_READ,
# a& Z" g+ g/ g" m: M &hKey) != ERROR_SUCCESS)% _9 W) L1 J5 k- q f, j5 T% j9 U
return FALSE;) v3 x/ ~( I# F
# S) D) N$ o8 I- R* y7 C
DWORD dwIndex = 0;
: |# A% L8 d' I, h0 o4 RDWORD dwBufSize = 256;
3 y% E1 b& \4 b7 f0 wDWORD dwDataType;
% S \" L0 F6 x. ], y: [char szSubKey[256];
" R1 o C2 e8 ~3 B. p4 Z! Iunsigned char szData[256];* T2 i$ W4 B/ C- x& e
% x3 s2 X2 a/ ?: l" R9 D* J
while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
) \) R) p! v& { @- B9 p" V7 I! F# _7 F{
, t4 D8 g( f/ I! H; |( S5 `6 ` if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
' {. m% i b1 p" Q" k K9 X {
& @; {( g, Q- @9 n0 A2 D if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)9 `- \; u d1 W V& s
{. o* ^! J; }3 n
dwBufSize = 256;9 y$ }* I" K# t4 G9 ]
if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS); ?$ o/ f/ s; ^3 |( u c' `
{
]( r; m2 y' L0 H% r3 B if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡
- y9 C. [$ V; Y0 U R. T6 Z# ] {
# f: B0 H& `6 k' d dwBufSize = 256;
' @4 j, C* l* L: A0 I if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)
+ c2 G; _$ Y5 B; K {
$ R, a0 a5 R" D; r1 T% }, V8 E7 b // szData 中便是适配器详细描述9 K" a) W4 D3 o0 D
dwBufSize = 256;
7 Y0 }2 @* y1 f" v8 C; j+ T1 W: P if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)8 C0 m9 @% p9 d1 }, z2 U0 f
{
8 w$ X1 _2 j+ ?9 K! `, ] // szData 中便是适配器名称* F# N- s6 a# {( e+ M; ^
}
1 t$ k) @+ z. p0 ~ \! Y6 a3 ` }4 i, g3 j% v. U) t
}2 O& g! e. }# ^3 @9 u
}! s. D" D0 u# _$ Q8 b
RegCloseKey(hNdiIntKey);
. i0 i F% t' x: _1 X2 g }( X5 J9 x# k! v! U" I
RegCloseKey(hSubKey);
- y1 n5 _3 ], G( P/ p }8 U7 E/ D! ?2 A1 j' I' a* I
& p8 p3 g5 z9 e- ^" E9 X
dwBufSize = 256;7 |9 D2 d# q% z( J, n4 }% F
} /* end of while */
3 I1 Q5 M$ @) i' E/ z 4 [' V; U% N, {- M1 P
RegCloseKey(hKey);
' E* M7 r. i* T* g4 K二、将IP信息写入注册表
x3 T5 E1 g, Q( K( P8 s* \9 [
9 o. t/ a6 h" t! ~' [: S6 P. B代码如下:BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)
1 ]5 Z* c$ D8 g9 r{! b9 r7 Q$ G5 I& B
HKEY hKey; ]! Q7 u( O4 o/ z) o: z6 T! X' J
string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
1 F* n4 B; b* [- f% z strKeyName += lpszAdapterName;' w& `5 P4 X( K( [
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
5 E) W+ w7 p0 a. w8 n0 T strKeyName.c_str(),) k0 I# ^ S# T6 I$ ?! }
0,
3 c9 l @! P* F$ z4 w, p, |' v KEY_WRITE,, w' W* L, u S- G9 z7 w, J
&hKey) != ERROR_SUCCESS)1 [6 A8 [5 h8 x, v2 E- F
return FALSE;
% }( t# g' R# ?$ N$ |
9 G0 |- {& I4 ~) w4 a0 A4 i+ V char mszIPAddress[100];0 T' S7 l: g' l" P
char mszNetMask[100];( O4 n, @: Q. L* b( [
char mszNetGate[100];! p# F6 b: [+ R, \0 w
: }/ T* J' f+ C y/ @
strncpy(mszIPAddress, pIPAddress, 98);8 }9 i2 F/ M; n: S5 T J
strncpy(mszNetMask, pNetMask, 98);( G7 L6 I" Y5 X$ [( R- M" b
strncpy(mszNetGate, pNetGate, 98);
2 D8 F+ F- e, O# j! S9 R& L+ Q! m; O: z/ ?% D% |
int nIP, nMask, nGate;7 N" }& i' _0 U3 O
P0 B% a8 {9 k4 X7 O; ] nIP = strlen(mszIPAddress);
! A9 f7 d7 I' {! r' j' H nMask = strlen(mszNetMask);
1 }( V/ J! N" M, }0 m nGate = strlen(mszNetGate);" G1 D4 J5 s7 x) r% h' I
- _3 Z# Q& H, B! E0 z *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0
% T, f U% x! d+ B6 _( O0 t% P nIP += 2;
8 X4 ]) _! l1 \. O' b& w I; x& b3 u4 m; s
*(mszNetMask + nMask + 1) = 0x00;
: X# e* [0 ?4 Y$ D2 \& K A nMask += 2;
- o3 [7 i+ R! c3 \( w
& |% Z6 O- j) d *(mszNetGate + nGate + 1) = 0x00;$ }8 y `& ^0 j0 n
nGate += 2;# [2 k, h! Y4 {$ x) d' v) X( P9 b
3 k9 U! Q! d5 C! l+ D+ d) W# g RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);
# _0 N# f. i' u, ~ RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);4 @: Y6 o% z# r1 |
RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);
" h1 t4 R, R7 D: Y. v" ~, d9 Y; b; F3 j# |8 a
RegCloseKey(hKey);
$ |$ N {& _: [' ]' G# J
$ Y, J1 M: k: ~/ H, G return TRUE;
* s7 q/ V" b; V, ~* b( D: k2 m}
$ ] g, w/ v* d1 F
6 D* U1 {, R. [" f- J' S三、调用DhcpNotifyConfigChange通知配置的改变
2 n, O: M5 o# ]5 ]1 Q- q: p) H& W6 L- y4 S' z% l: Y5 C4 s3 y8 Q0 |( {
未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下: BOOL DhcpNotifyConfigChange(
7 B, P, J, X8 f LPWSTR lpwszServerName, // 本地机器为NULL
. I" }" Y! V9 p! ^ LPWSTR lpwszAdapterName, // 适配器名称
- Y/ X8 d* O: e1 {* S BOOL bNewIpAddress, // TRUE表示更改IP# F. n9 J& f0 Y/ Y9 ~: a2 a. A
DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0$ }$ }& c. E. h" u/ h2 \1 k
DWORD dwIpAddress, // IP地址 B* A5 ?; l! H/ x- }9 @9 i
DWORD dwSubNetMask, // 子网掩码" s, M( z" M% a) P# t9 q' |0 F
int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP6 [0 A: l0 |! H; X& s( w
" k3 s- M; F9 c( I; E! O0 K具体调用代码如下: BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)
# N2 B0 n9 s0 g5 _0 F4 [& k" F{) d/ W% N/ c; n c
BOOL bResult = FALSE;
$ N( J3 t5 J; K. l# f. } HINSTANCE hDhcpDll;( g$ X/ q! S, z/ X$ [" _
DHCPNOTIFYPROC pDhcpNotifyProc;
! k2 r6 h$ d, ]4 n- s WCHAR wcAdapterName[256];
5 f5 |% {9 [/ y) H6 }, S
$ U8 f4 E o6 ]0 m1 }4 ?2 l( t* G MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);; o7 e+ B& y9 {
7 y E: z. x. D1 o$ H1 ?( k
if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)( c! z* E: I( [
return FALSE;
1 p( ]! @5 c b$ ]
- ^' P& M; D* V+ o if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)- T- D2 w) ]4 _( b
if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)
' l- I2 h3 f7 C! t bResult = TRUE;, K2 s- N. g- P2 ]
; ?" k! p' _7 w FreeLibrary(hDhcpDll);; q) \1 Q, Z& i h: |5 n, Y9 ]
return bResult;( r! D4 K% ~' w; h8 {. p5 y
} |
|