• 在程序中修改IP win7 winXP(参考1)


    https://blog.csdn.net/bbdxf/article/details/7548443

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

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

    方法一: 网卡重启 
        更改Windows网卡属性选项中IP地址, 通过对比前后注册表, 可以发现以下几处发生变化 
    [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParametersInterfaces{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}] 
    "IPAddress" 
    "SubnetMask" 
    "DefaultGateway" 
    "NameServer" 

    [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}ParametersTcpip] 
    "IPAddress" 
    "SubnetMask" 
    "DefaultGateway" 

    [HKEY_LOCAL_MACHINESYSTEMControlSet001ServicesTcpipParametersInterfaces{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}] 
    "IPAddress" 
    "SubnetMask" 
    "DefaultGateway" 
    "NameServer" 

    [HKEY_LOCAL_MACHINESYSTEMControlSet001Services{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}ParametersTcpip] 
    "IPAddress" 
    "SubnetMask" 
    "DefaultGateway" 

        其中{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}是网卡名称(AdapterName), 不同的网卡, 不同的接入位置, 不同的接入的时间, 对应的值都不一样, 它的值是第一次接入系统时, 由系统生成的GUID值. 
        此处CurrentControlSet实际是ControlSet001的别名.     
    [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParametersInterfaces{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}] 
    "IPAddress" 
    "SubnetMask" 
    "DefaultGateway" 
    "NameServer" 
        是主要的设置处. 

    [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}ParametersTcpip] 
    "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}011  
        实际完整的键名为System\CurrentControlSet\Control\Class{4D36E972-E325-11CE-BFC1-08002BE10318}011  
        该键包含的内容与SetupDiGetDeviceRegistryProperty得到的设备属性基本相同 
        如NetCfgInstanceId即为内部设备名 DriverDesc为设备描述    */ 
        int index; 
    }adapter_info_t; 
         


    /***************************************************************************** 
     用何名称区分不同的网卡 
     有如下名称可供选择 
        本地连接名, 这是系统使用的方法, 调用的是netman.dll中的未公开函数HrLanConnectionNameFromGuidOrPath(其原型笔者正在调试之中, 成功之后会另行撰文); 其实也可从注册表中获得HKLMSystemCurrentControlSetControlNetwork{4D36E972-E325-11CE-BFC1-08002BE10318}{97EFDAD8-EB2D-4F40-9B07-0FCD706FCB6D}ConnectionName 
        网卡类型描述 
        设备友好名        它与网卡类型描述基本相同, 当存在同种类型的网卡, 它会加#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"的使用
    ————————————————
    版权声明:本文为CSDN博主「笨笨D幸福」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/bbdxf/article/details/7548443

  • 相关阅读:
    NumPy线性代数
    NumPy矩阵库
    NumPy副本和视图
    NumPy字节交换
    NumPy排序、搜索和计数函数
    NumPy统计函数
    NumPy算数运算
    NumPy数学算数函数
    NumPy
    dp 动规 最佳加法表达式
  • 原文地址:https://www.cnblogs.com/liuzhaoyzz/p/11703173.html
Copyright © 2020-2023  润新知