分享
 
 
 

Windows下不重启机器程序修改IP的三种方法

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Windows下程序修改IP的三种方法

以下讨论的平台依据是Window XP + SP1, 不考虑Windows其它版本的兼容性问题, 但对NT系列的系统, 理论上是通用的.

方法一: 网卡重启

更改Windows网卡属性选项中IP地址, 通过对比前后注册表, 可以发现以下几处发生变化

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]

"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}\Parameters\Tcpip]

"IPAddress"

"SubnetMask"

"DefaultGateway"

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Tcpip\Parameters\Interfaces\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]

"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}\Parameters\Tcpip]

"IPAddress"

"SubnetMask"

"DefaultGateway"

其中{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}是网卡名称(AdapterName), 不同的网卡, 不同的接入位置, 不同的接入的时间, 对应的值都不一样, 它的值是第一次接入系统时, 由系统生成的GUID值.

此处CurrentControlSet实际是ControlSet001的别名.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}]

"IPAddress"

"SubnetMask"

"DefaultGateway"

"NameServer"

是主要的设置处.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}\Parameters\Tcpip]

"IPAddress"

"SubnetMask"

"DefaultGateway"

对一些服务有影响, 如不设置, 用netstat可以看到原来的IP地址仍处于监听状态(?).

但为了使设置生效, 还有很重要的一步, 即重启网卡.

更改网卡的配置, 一般而言需要重启网卡, 如

Linux系统, 只需运行

#ifconfig eth0 down

#ifconfig eht0 up

就可以实现网卡的重启.

Windows环境下的步骤与之类似: 先禁用本地连接(网卡), 再启用本地连接(网卡). 但没有相应的命令或者直接的API. 所幸的是DDK提供一套设备安装函数, 用于控制系统设备, 包括控制设备的状态改变.

/****************************************************************************************

Purpose: change state of the selected device

Input : hDevInfo device info set

pDeviceInfoData selected device info

NewState one of enable/disable

Output : TRUE for success, FALSE for failed

****************************************************************************************/

BOOL ChangeDeviceState(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDeviceInfoData, DWORD NewState)

{

SP_PROPCHANGE_PARAMS PropChangeParams = {sizeof(SP_CLASSINSTALL_HEADER)};

SP_DEVINSTALL_PARAMS devParams;

if (!pDeviceInfoData) {

return FALSE;

}

PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);

PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;

PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;

PropChangeParams.StateChange = NewState;

PropChangeParams.HwProfile = 0;

if (!SetupDiSetClassInstallParams(hDevInfo,pDeviceInfoData,

(SP_CLASSINSTALL_HEADER *)&PropChangeParams,sizeof(PropChangeParams))

|| !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,pDeviceInfoData)) {

return FALSE;

}

reutrn TRUE;

}

/* hDevInfo如何得到***********************************************************/

m_hDevInfo = SetupDiGetClassDevs(

(LPGUID) &GUID_DEVCLASS_NET, /* GUID_DEVCLASS_NET表示仅列出网络设备 */

NULL,

this->m_hWnd,

DIGCF_PRESENT);

if (INVALID_HANDLE_VALUE == m_hDevInfo) {

return FALSE;

}

/* pDeviceInfoData如何得到**************************************************/

k = 0;

while (SetupDiEnumDeviceInfo(m_hDevInfo, k ,&DeviceInfoData)) {

k++;

if (CR_SUCCESS != CM_Get_DevNode_Status(&Status, &Problem,

DeviceInfoData.DevInst,0)) {

continue;

}

if ((Status & DN_NO_SHOW_IN_DM)) {

continue;

}

if (GetRegistryProperty(m_hDevInfo,

&DeviceInfoData,

SPDRP_FRIENDLYNAME,

&pBuffer,

&Length)) {

m_Adapter[adapter_num].index = k - 1; /* 当前网卡在设备信息集中的索引 */

_tcscpy(m_Adapter[adapter_num].desc, pBuffer); /* 当前网卡 */

GetRegistryProperty(m_hDevInfo,

&DeviceInfoData,

SPDRP_DRIVER,

&pBuffer,

&Length);

_tcscpy(m_Adapter[adapter_num].driver, pBuffer);

adapter_num++;

}

}

/* GetRegistryProperty是对SetupDiGetDeviceRegistryProperty封装***************/

BOOL GetRegistryProperty(HDEVINFO DeviceInfoSet,

PSP_DEVINFO_DATA DeviceInfoData,

ULONG Property,

LPTSTR* Buffer,

PULONG Length)

{

while (!SetupDiGetDeviceRegistryProperty(

DeviceInfoSet,

DeviceInfoData,

Property,

NULL,

(PBYTE)(*Buffer),

*Length,

Length

))

{

if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

if (*(LPTSTR *)Buffer)

LocalFree(*(LPTSTR *)Buffer);

*Buffer = (LPTSTR)LocalAlloc(LPTR, *Length);

}else {

return FALSE;

}

}

return TRUE;

}

/* m_Adapter的数据结构 */

typedef struct adapter_info_s {

char name[NAME_LEN]; /* 内部设备名, UUID的字符串形式 */

char desc[NAME_LEN]; /* 网卡描述 */

char driver[NAME_LEN]; /* 网卡在注册表中的位置, 如{4D36E972-E325-11CE-BFC1-08002BE10318}\0011

实际完整的键名为System\\CurrentControlSet\\Control\\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0011

该键包含的内容与SetupDiGetDeviceRegistryProperty得到的设备属性基本相同

如NetCfgInstanceId即为内部设备名 DriverDesc为设备描述 */

int index;

}adapter_info_t;

/*****************************************************************************

用何名称区分不同的网卡

有如下名称可供选择

本地连接名, 这是系统使用的方法, 调用的是netman.dll中的未公开函数HrLanConnectionNameFromGuidOrPath(其原型笔者正在调试之中, 成功之后会另行撰文); 其实也可从注册表中获得HKLM\System\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}\Connection\Name

网卡类型描述

设备友好名 它与网卡类型描述基本相同, 当存在同种类型的网卡, 它会加#n(n = 2, 3, 4...)以示区分

如本程序中笔者即以设备友好名区分网卡

*****************************************************************************/

/* 重启网卡的过程************************************************************/

k = pAdapter->GetCurSel(); /* m_Adapter[k]即当前网卡 */

if (SetupDiEnumDeviceInfo(m_hDevInfo, m_Adapter[k].index ,&DeviceInfoData))

{

hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

ChangeDeviceState(m_hDevInfo, &DeviceInfoData, DICS_DISABLE); /* 禁用网卡 */

ChangeDeviceState(m_hDevInfo, &DeviceInfoData, DICS_ENABLE); /* 启用网卡 */

/* 重启网卡, 一般情况下, 以下命令相当于前两命令的组合. 但我仍建议使用前者 */

// ChangeDeviceState(m_hDevInfo, &DeviceInfoData, DICS_PROPCHANGE);

SetCursor(hCursor);

}

/* 扫尾工作 */

SetupDiDestroyDeviceInfoList(m_hDevInfo);

总结: 通过网卡重启更改IP的方法有两个步骤: 修改注册表, 重启网卡. 重启网卡的全过程上面已作描述. 注册表修改的内容为文中列出四个主要项, 如{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}的网卡名称即是内部设备名, 在adapter结构中已给出. 整个注册表修改的过程比较简单, 本文不加叙述.

方法二:未公开函数

Windows系统中, 更改Windows网卡属性选项中IP地址, 可以即时使更改生效, 并且没有重启网卡的过程. 系统自带的netsh也能通过命令行或脚本文件的形式, 完成更改IP的功能时, 也不需要重启网卡

同时也有很多共享软件, 可以实现同样的功能, 常见IP地址更改软件有IPFreeSet, IPChanger, IPProfile, IPHelp, IPSet, SNet等.

笔者通过分析netsh发现一个未公开函数, 即用netcfgx.dll封装的dhcpcsvc.dll中DhcpNotifyConfigChange函数

具体的方法参见VCKB 25期 王骏先生的 "不重起Windows直接更改IP地址", 他得到的函数原型比我准确, 思路也很清晰.

分析上述共享软件时, 发现其技术要点不外乎三种: 使用未公开函数, 调用netsh命令, 重启网卡硬件. 调用netsh命令的实质还是使用未公开函数

使用未公开函数的有: IPFreeSet, IPChanger

调用netsh命令的有 : IPHelp, IPSet. 两者都是用Delphi开发的.

重启网卡硬件: IPSwitcher

速度比较: 因为netsh本身的实现是调用netcfgx.dll, netcfgx.dll封装了对未公开函数的使用, 故效率相对较低. 在一台CPU:PIII500/RAM:256/XP的系统中, IPHelp需要6~7秒才能完成, 而IPFreeSet只需要1~2秒.

方法三:一卡多IP

除以上两个方法外, 笔者再介绍一种方法. 无论是在Windows下还是在Linux下, 一块网卡都可同时具有多个IP地址. 根据TCP/IP原理, 在网络层标识通信节点是IP地址, 在链路层上的则是MAC地址. 只要通过ARP, 将多个IP与一个MAC对应起来, 就可实现一网卡多IP(其实是一MAC多IP). 系统本身也有相应的设置选项, 如windows是通过TCP/IP属性的高级选项添加的, Linux下可由ifconfig命令添加.

iphlpapi提供AddIPAddress和DelIPAddress. 如果能先加入新的IP, 再去除原来的IP, 即可实现IP地址的更改.

具体内容参见我下篇文章"iphlpapi"的使用.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有