Setting DNS using iphelp and register, DhcpNotifyConfigChange and DnsFlushResolverCache
Setting DNS using iphelp and register, DhcpNotifyConfigChange and DnsFlushResolverCache
Introduction
This is one way of changing DNS in C++ using Iphlpapi.h, register, and two undocumented Windows APIs. It's a simple program, no UI for you, sorry...
- Use
GetAdaptersInfo
to get adapters information. - Then use
GetPerAdapterInfo
to get information for every ethernet network card. The information contains DNS list. - Use register to set the DNS by open HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\
Interfaces\\lpszAdapterName, the name is got fromGetAdaptersInfo
. - Use
DhcpNotifyConfigChange
to notify the IP change. - Use
DnsFlushResolverCache
to flush the DNS.
Using the Code
- Use
GetAdaptersInfo
:if( GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // out of buff { 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) // If type is etherent { //Here to use GetPerAdapterInfo } pAdapterInfo = pAdapterInfo->Next; }while(pAdapterInfo); FlushDNS(); }
- Use
GetPerAdapterInfo
:if( GetPerAdapterInfo( pAdapterInfo->Index, pPerAdapterInfo, &ulPerAdapterInfoSize) == ERROR_BUFFER_OVERFLOW ) // out of buff { delete pPerAdapterInfo; pPerAdapterInfo = (IP_PER_ADAPTER_INFO*)new char[ulPerAdapterInfoSize]; pPerAdapterInfoBkp = pPerAdapterInfo; } DWORD dwRet; if((dwRet = GetPerAdapterInfo( pAdapterInfo->Index, pPerAdapterInfo, &ulPerAdapterInfoSize)) == ERROR_SUCCESS) { AdaptInfo tmpadpif; pAddrStr = pPerAdapterInfo->DnsServerList.Next; strncpy(tmpadpif.AdapterName, pAdapterInfo->AdapterName, sizeof(pAdapterInfo->AdapterName)); tmpadpif.NameSever = pPerAdapterInfo->DnsServerList.IpAddress.String; cout<<pPerAdapterInfo->DnsServerList.IpAddress.String<<endl; char tmp[16]; strcpy( tmp, "172.16.227.4"); if ( strcmp(pPerAdapterInfo->DnsServerList.IpAddress.String, tmp) == 0 ) { return 0; } while(pAddrStr) { tmpadpif.NameSever += ","; tmpadpif.NameSever += pAddrStr->IpAddress.String; cout<<pAddrStr->IpAddress.String<<endl; pAddrStr = pAddrStr->Next; } vecAdpif.push_back( tmpadpif ); RegSetDNS( tmpadpif.AdapterName, tmp); NotifyIPChange(pAdapterInfo->AdapterName); }
- Open registry to set DNS or IP addr. For this part, please refer to the download code.
- We have something fresh here:
typedef int (CALLBACK* DNSFLUSHPROC)(); typedef int (CALLBACK* DHCPNOTIFYPROC) (LPWSTR, LPWSTR, BOOL, DWORD, DWORD, DWORD, int);
- After setting DNS in registy, we need to inform the system about the change. Now we use Windows undocumented API:
DhcpNotifyConfigChange
. It is located in dhcpcsvc.dll.BOOL DhcpNotifyConfigChange( LPWSTR lpwszServerName, // local machine should be NULL LPWSTR lpwszAdapterName, // Adapt name BOOL bNewIpAddress, // TRUE indicates changing ip DWORD dwIpIndex, // which IP addr, if only 1, it's 0 DWORD dwIpAddress, // IP addr DWORD dwSubNetMask, // mask int nDhcpAction ); // DHCP, 0 for not change, 1 for enable, 2 for disable DHCP
Please refer to the code.
- Flush DNS, use another Windows undocumented API:
DnsFlushResolverCache
, located in dnsapi.dll.DnsFlushResolverCache();
- It's ok now.
Points of Interest
I have not learned how to use WMI in VC++. Sigh, it's not a good way to change Ipaddr
and DNS in registy. netsh is not good too. If anyone has a better idea, please share with us.