不重啓Windows更改IP地址的多種實現

不重啓Windows更改IP地址的多種實現 2005-9-6 作者:王駿&pcdog 轉載自:互聯網收集 網友評論 0 條 點擊進入論壇  有很多網友都遇到過更改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地址的更改. 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/skyremember/archive/2008/09/24/2974301.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章