分享

如何不重起Windows更改IP地址

 昵称225033 2014-02-24

如何不重起Windows更改IP地址2011-12-26 00:00 比特网 悠虎
关键字:Windows
  有很多网友都遇到过更改IP地址但是要重启机器的问题,在这里,为大家介绍几种不重启Windows直接更改IP地址的方法。首先是调用DhcpNotifyConfigChange的方法,后面还有修改注册表跟使用"iphlpapi"的方法。

  一、未公开函数:DhcpNotifyConfigChange

  设置IP地址只需要更改注册表中关于适配器的相应设置,但更改后需要重新启动系统才能生效,而AddIPAddress函数只能添加IP而不是更改当前的IP,我们在Windows NT/2000界面上操作不需要重新启动就可以生效,那系统到底做了什么额外的工作才使IP设置直接生效呢?笔者通过跟踪explorer.exe中API的调用发现在netcfgx.dll中调用了dhcpcsvc.dll中一个未公开的API:DhcpNotifyConfigChange,现将不重新启动WINDOWS直接更改IP地址的详细方法介绍如下:

  1、获取适配器名称

  这里指的适配器名称要区别于适配器描述,比如我的一块网卡,适配器描述是:Realtek RTL8139(A) PCI Fast Ethernet Adapter,适配器名称为:{66156DC3-44A4-434C-B8A9-0E5DB4B3EEAD}.获取适配器名称的方法有多种:

  1.1 调用IP helper API取得适配器名称

  ULONG ulAdapterInfoSize = sizeof(IP_ADAPTER_INFO);

  IP_ADAPTER_INFO *pAdapterInfoBkp, *pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];

  if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // 缓冲区不够大

  {

  delete pAdapterInfo;

  pAdapterInfo = (IP_ADAPTER_INFO*)new char[ulAdapterInfoSize];

  pAdapterInfoBkp = pAdapterInfo;

  }

  if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_SUCCESS )

  {

  do{ // 遍历所有适配器

  if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) // 判断是否为以太网接口

  {

  // pAdapterInfo->Description 是适配器描述

  // pAdapterInfo->AdapterName 是适配器名称

  }

  pAdapterInfo = pAdapterInfo->Next;

  }while(pAdapterInfo);

  }

  delete pAdapterInfoBkp;

  1.2 读取注册表取得适配器名称

  在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;

  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

  "System\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}",

  0,

  KEY_READ,

  &hKey) != ERROR_SUCCESS)

  return FALSE;

  DWORD dwIndex = 0;

  DWORD dwBufSize = 256;

  DWORD dwDataType;

  char szSubKey[256];

  unsigned char szData[256];

  while(RegEnumKeyEx(hKey, dwIndex++, szSubKey, &dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)

  {

  if(RegOpenKeyEx(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)

  {

  if(RegOpenKeyEx(hSubKey, "Ndi\\Interfaces", 0, KEY_READ, &hNdiIntKey) == ERROR_SUCCESS)

  {

  dwBufSize = 256;

  if(RegQueryValueEx(hNdiIntKey, "LowerRange", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)

  {

  if(strcmp((char*)szData, "ethernet") == 0) // 判断是不是以太网卡

  {

  dwBufSize = 256;

  if(RegQueryValueEx(hSubKey, "DriverDesc", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)

  {

  // szData 中便是适配器详细描述

  dwBufSize = 256;

  if(RegQueryValueEx(hSubKey, "NetCfgInstanceID", 0, &dwDataType, szData, &dwBufSize) == ERROR_SUCCESS)

  {

  // szData 中便是适配器名称

  }

  }

  }

  }

  RegCloseKey(hNdiIntKey);

  }

  RegCloseKey(hSubKey);

  }

  dwBufSize = 256;

  } /* end of while */

  RegCloseKey(hKey);

  2、将IP信息写入注册表

  代码如下:

  BOOL RegSetIP(LPCTSTR lpszAdapterName, LPCTSTR pIPAddress, LPCTSTR pNetMask, LPCTSTR pNetGate)

  {

  HKEY hKey;

  string strKeyName = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";

  strKeyName += lpszAdapterName;

  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

  strKeyName.c_str(),

  0,

  KEY_WRITE,

  &hKey) != ERROR_SUCCESS)

  return FALSE;

  char mszIPAddress[100];

  char mszNetMask[100];

  char mszNetGate[100];

  strncpy(mszIPAddress, pIPAddress, 98);

  strncpy(mszNetMask, pNetMask, 98);

  strncpy(mszNetGate, pNetGate, 98);

  int nIP, nMask, nGate;

  nIP = strlen(mszIPAddress);

  nMask = strlen(mszNetMask);

  nGate = strlen(mszNetGate);

  *(mszIPAddress + nIP + 1) = 0x00; // REG_MULTI_SZ数据需要在后面再加个0

  nIP += 2;

  *(mszNetMask + nMask + 1) = 0x00;

  nMask += 2;

  *(mszNetGate + nGate + 1) = 0x00;

  nGate += 2;

  RegSetValueEx(hKey, "IPAddress", 0, REG_MULTI_SZ, (unsigned char*)mszIPAddress, nIP);

  RegSetValueEx(hKey, "SubnetMask", 0, REG_MULTI_SZ, (unsigned char*)mszNetMask, nMask);

  RegSetValueEx(hKey, "DefaultGateway", 0, REG_MULTI_SZ, (unsigned char*)mszNetGate, nGate);

  RegCloseKey(hKey);

  return TRUE;

  }

  3、调用DhcpNotifyConfigChange通知配置的改变

  未公开函数DhcpNotifyConfigChange位于 dhcpcsvc.dll中,原型如下:

  BOOL DhcpNotifyConfigChange(

  LPWSTR lpwszServerName, // 本地机器为NULL

  LPWSTR lpwszAdapterName, // 适配器名称

  BOOL bNewIpAddress, // TRUE表示更改IP

  DWORD dwIpIndex, // 指明第几个IP地址,如果只有该接口只有一个IP地址则为0

  DWORD dwIpAddress, // IP地址

  DWORD dwSubNetMask, // 子网掩码

  int nDhcpAction ); // 对DHCP的操作 0:不修改, 1:启用 DHCP,2:禁用 DHCP

  具体调用代码如下:

  BOOL NotifyIPChange(LPCTSTR lpszAdapterName, int nIndex, LPCTSTR pIPAddress, LPCTSTR pNetMask)

  {

  BOOL bResult = FALSE;

  HINSTANCE hDhcpDll;

  DHCPNOTIFYPROC pDhcpNotifyProc;

  WCHAR wcAdapterName[256];

  MultiByteToWideChar(CP_ACP, 0, lpszAdapterName, -1, wcAdapterName,256);

  if((hDhcpDll = LoadLibrary("dhcpcsvc")) == NULL)

  return FALSE;

  if((pDhcpNotifyProc = (DHCPNOTIFYPROC)GetProcAddress(hDhcpDll, "DhcpNotifyConfigChange")) != NULL)

  if((pDhcpNotifyProc)(NULL, wcAdapterName, TRUE, nIndex, inet_addr(pIPAddress), inet_addr(pNetMask), 0) == ERROR_SUCCESS)

  bResult = TRUE;

  FreeLibrary(hDhcpDll);

  return bResult;

  }

  二、修改注册表:网卡重启

  更改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提供一套设备安装函数, 用于控制系统设备, 包括控制设备的状态改变。(点击查看详细代码附件)

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

  三、使用"iphlpapi"一卡多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地址的更改。


原文出自【比特网】,转载请保留原文链接:http://soft./os/309/12230809.shtml

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多