導讀:
不重起Windows直接更改IP地址
作者:浙江省溫嶺電信局 王駿
註:本文適用於WINDOWS NT/2000/XP/2003
下載本文樣本工程
原始碼運行如下:
設定IP地址只需要更改註冊表中關於適配器的相應設定,但更改後需要重新啟動系統才會生效,而AddIPAddress函數只能添加IP而不是更改當前的IP,我們在Windows NT/2000介面上操作不需要重新啟動就可以生效,那系統到底做了什麼額外的工作才使IP設定直接生效呢?筆者通過跟蹤explorer.exe中API的調用發現在netcfgx.dll中調用了dhcpcsvc.dll中一個未公開的API:DhcpNotifyConfigChange,現將不重新啟動WINDOWS直接更改IP地址的詳細方法介紹如下:
一、擷取適配器名稱
這裡指的適配器名稱要區別於適配器描述,比如我的一塊網卡,適配器描述是: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);
二、將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資料需要在後面再加個0nIP += 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;}
三、調用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){BOOLbResult = FALSE;HINSTANCEhDhcpDll;DHCPNOTIFYPROCpDhcpNotifyProc;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;}
(全文完)
本文轉自
http://www.vckbase.com/document/viewdoc/?id=851