//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997-2001. // // File: S I P C F G . C P P // // Contents: The rendering of the UI for the network status monitor's state // page. Most of them are ipconfig info // // Notes: // // Author: NSun Dec 2000 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "sminc.h" #include "smpsh.h" #include "smhelp.h" #include "ncui.h" #include "ncreg.h" #include "ncperms.h" #include "windutil.h" extern "C" { #include extern DWORD DhcpStaticRefreshParams(IN LPWSTR Adapter); } #include #include #include "..\lanui\lanui.h" #include "repair.h" #define LOCAL_WINS_ADDRESS 0x7f000000 // 127.0.0.0 DWORD WINAPI IPAddrListenProc( LPVOID lpParameter // thread data ); DWORD WINAPI IPAddrListenProc( LPVOID lpParameter // thread data ); void DwordToIPAddrString(DWORD dw, tstring * pstr); const WCHAR c_szTcpipInterfaces[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; const WCHAR c_szAddressType[] = L"AddressType"; const WCHAR c_szActiveConfigurations[] = L"ActiveConfigurations"; const WCHAR c_szAlternate[] = L"Alternate_"; const WCHAR c_szNameServer[] = L"NameServer"; const WCHAR c_szDhcpNameServer[] = L"DhcpNameServer"; const WCHAR c_szNbtDevicePrefix[] = L"\\Device\\NetBT_Tcpip_"; //////////////////////////////////////////////////////////////////////////////////////// // Implementation CPspStatusMonitorIpcfg // //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::~CPspStatusMonitorIpcfg( // // Purpose: constructor // CPspStatusMonitorIpcfg::CPspStatusMonitorIpcfg(VOID) : m_adwHelpIDs(NULL), m_ncmType(NCM_NONE), m_pConn(NULL), m_fDhcp(TRUE), m_dhcpAddrType(NORMAL_ADDR), m_fListenAddrChange(FALSE), m_fEnableOpButtons(TRUE), m_fIsFirstPage(FALSE) { TraceFileFunc(ttidStatMon); ZeroMemory(&m_guidConnection, sizeof(m_guidConnection)); //Create events that are used to control the thread listening to //address change notifications m_hEventAddrListenThreadStopCommand = CreateEvent(NULL, TRUE, FALSE, NULL); m_hEventAddrListenThreadStopNotify = CreateEvent(NULL, TRUE, FALSE, NULL); } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::~CPspStatusMonitorIpcfg( // // Purpose: destructor // CPspStatusMonitorIpcfg::~CPspStatusMonitorIpcfg(VOID) { if (m_hEventAddrListenThreadStopCommand) { CloseHandle(m_hEventAddrListenThreadStopCommand); } if (m_hEventAddrListenThreadStopNotify) { CloseHandle(m_hEventAddrListenThreadStopNotify); } CleanupPage(); } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::HrInitPage // // Purpose: Initialize the Network State page class before the page has been // created // // Arguments: pnConnection - The connection associated with this monitor // dwHelpIDs - The context sensitive help ID array // // Returns: Error code // HRESULT CPspStatusMonitorIpcfg::HrInitPage( INetConnection * pnConnection, const DWORD * adwHelpIDs) { TraceFileFunc(ttidStatMon); HRESULT hr = S_OK; Assert(pnConnection); m_adwHelpIDs = adwHelpIDs; NETCON_PROPERTIES* pProps; hr = pnConnection->GetProperties(&pProps); if (SUCCEEDED(hr)) { m_strConnectionName = pProps->pszwName; m_guidConnection = pProps->guidId; m_ncmType = pProps->MediaType; m_dlgAdvanced.InitDialog(m_guidConnection, g_aHelpIDs_IDD_DIALOG_ADV_IPCFG); FreeNetconProperties(pProps); if (m_pConn) { m_pConn->Release(); } m_pConn = pnConnection; ::AddRefObj(m_pConn); } return hr; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::CleanupPage // // Purpose: Cleanup the INetConnection ref count we are holding // // Arguments: pnConnection - The connection associated with this monitor // dwHelpIDs - The context sensitive help ID array // // Returns: Error code // VOID CPspStatusMonitorIpcfg::CleanupPage() { TraceFileFunc(ttidStatMon); if (m_pConn) { m_pConn->Release(); m_pConn = NULL; } } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnInitDialog // // Purpose: Do the initialization required when the page has just been created // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { TraceFileFunc(ttidStatMon); m_fEnableOpButtons = FHasPermission(NCPERM_Repair); if (m_fIsFirstPage) { // get window handle to propertysheet HWND hwndParent=GetParent(); Assert(hwndParent); // center the property sheet on desktop FCenterWindow (hwndParent, NULL); // hide the "ok" button // ::ShowWindow(::GetDlgItem(hwndParent, IDOK), FALSE); } //The initialization is in the OnActive method so that we will update the UI //when the user active this page return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnActive // // Purpose: Refresh the UI and start listening to the address change notification // when the page has just been created // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnActive(int idCtrl, LPNMHDR pnmh, BOOL& fHandled) { TraceFileFunc(ttidStatMon); RefreshUI(); if (m_hEventAddrListenThreadStopCommand && m_hEventAddrListenThreadStopNotify) { ResetEvent(m_hEventAddrListenThreadStopCommand); ResetEvent(m_hEventAddrListenThreadStopNotify); QueueUserWorkItem(IPAddrListenProc, this, WT_EXECUTELONGFUNCTION); m_fListenAddrChange = TRUE; } return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnKillActive // // Purpose: Do the operation required when the page is no longer the active one // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnKillActive(int idCtrl, LPNMHDR pnmh, BOOL& fHandled) { TraceFileFunc(ttidStatMon); //If the advanced dialog is there, we need to close it //This happens when the connection is disabled or media disconnected when //we still have the connection status dialog open. HWND hwndAdv = m_dlgAdvanced.m_hWnd; if (hwndAdv) { ::SendMessage(hwndAdv, WM_CLOSE, 0, 0); } //Stop listening to the address change if (m_fListenAddrChange) { StopAddressListenThread(); m_fListenAddrChange = FALSE; } return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnDestroy // // Purpose: Do the operation required when the page is destroyed. // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TraceFileFunc(ttidStatMon); //If the advanced dialog is there, we need to close it //This happens when the connection is disabled or media disconnected when //we still have the connection status dialog open. HWND hwndAdv = m_dlgAdvanced.m_hWnd; if (hwndAdv) { ::SendMessage(hwndAdv, WM_CLOSE, 0, 0); } //Stop listening to the address change if (m_fListenAddrChange) { StopAddressListenThread(); m_fListenAddrChange = FALSE; } CleanupPage(); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnUpdateDisplay // // Purpose: Handling the user defined PWM_UPDATE_IPCFG_DISPLAY message // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnUpdateDisplay(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TraceFileFunc(ttidStatMon); //The thread listening to address changes will post a PWM_UPDATE_IPCFG_DISPLAY //message to us once the IP address is changed. //We need refresh the UI. RefreshUI(); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnRepair // // Purpose: Repair the connection if the "Repair" button is pressed // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnRepair( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& fHandled) { TraceFileFunc(ttidStatMon); tstring strMessage = L""; HRESULT hr = S_OK; { CWaitCursor cursorWait; CLanConnectionUiDlg dlg; HWND hwndDlg = NULL; HWND hwndPsh = GetParent(); Assert(hwndPsh); //bring up the dialog to tell the user we're doing the fix Assert(m_pConn); if (m_pConn) { dlg.SetConnection(m_pConn); hwndDlg = dlg.Create(hwndPsh); PCWSTR szw = SzLoadIds(IDS_FIX_REPAIRING); ::SetDlgItemText(hwndDlg, IDC_TXT_Caption, szw); } //do the fix hr = HrTryToFix(m_guidConnection, strMessage); if (NULL != hwndDlg) { ::DestroyWindow(hwndDlg); } } //tell users the results NcMsgBox(_Module.GetResourceInstance(), NULL, IDS_FIX_CAPTION, IDS_FIX_MESSAGE, MB_OK, strMessage.c_str()); //We may get new settings. So need to refresh the UI. RefreshUI(); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnDetails // // Purpose: Open the Advanced Ipconfig dialog if the "Advanced" button is pressed // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CPspStatusMonitorIpcfg::OnDetails( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& fHandled) { TraceFileFunc(ttidStatMon); //Since the status dialog will be automatically closed if the connection becomes //disconnected or disabled, we also need to force the Advanced dialog to close in //such case. //So We cannot launch the Advanced dialog as a modal dialog. Instead, we launch the //dialog in another thread. QueueUserWorkItem(AdvIpCfgProc, this, WT_EXECUTEDEFAULT); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnContextMenu // // Purpose: When right click a control, bring up help // // Arguments: Standard command parameters // // Returns: Standard return // LRESULT CPspStatusMonitorIpcfg::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled) { TraceFileFunc(ttidStatMon); if (m_adwHelpIDs != NULL) { ::WinHelp(m_hWnd, c_szNetCfgHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)m_adwHelpIDs); } return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnHelp // // Purpose: When drag context help icon over a control, bring up help // // Arguments: Standard command parameters // // Returns: Standard return // LRESULT CPspStatusMonitorIpcfg::OnHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled) { TraceFileFunc(ttidStatMon); LPHELPINFO lphi = reinterpret_cast(lParam); Assert(lphi); if ((m_adwHelpIDs != NULL) && (HELPINFO_WINDOW == lphi->iContextType)) { ::WinHelp(static_cast(lphi->hItemHandle), c_szNetCfgHelpFile, HELP_WM_HELP, (ULONG_PTR)m_adwHelpIDs); } return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::InitializeData // // Purpose: Cleanup the saved IP settings // // Arguments: None // // Returns: None // VOID CPspStatusMonitorIpcfg::InitializeData() { TraceFileFunc(ttidStatMon); m_strIPAddress = L""; m_strSubnetMask = L""; m_strGateway = L""; m_fDhcp = TRUE; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::StopAddressListenThread // // Purpose: Stop the thread that listens to address changes // // Arguments: None // // Returns: None // VOID CPspStatusMonitorIpcfg::StopAddressListenThread() { TraceFileFunc(ttidStatMon); if (m_hEventAddrListenThreadStopCommand && m_hEventAddrListenThreadStopNotify) { Assert(m_hEventAddrListenThreadStopNotify); SetEvent(m_hEventAddrListenThreadStopCommand); WaitForSingleObject(m_hEventAddrListenThreadStopNotify, 5000); } } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::GetIPConfigInfo // // Purpose: Load the TCP/IP running settings of this connection // // Arguments: None // // Returns: error code // HRESULT CPspStatusMonitorIpcfg::GetIPConfigInfo() { TraceFileFunc(ttidStatMon); HRESULT hr = S_OK; PIP_ADAPTER_INFO pAdapterInfo = NULL; DWORD dwOutBufLen = 0; DWORD dwRet = ERROR_SUCCESS; dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (dwRet == ERROR_BUFFER_OVERFLOW) { pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen); if (NULL == pAdapterInfo) return E_OUTOFMEMORY; } else if (ERROR_SUCCESS == dwRet) { return E_FAIL; } else { return HRESULT_FROM_WIN32(dwRet); } dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (ERROR_SUCCESS != dwRet) { CoTaskMemFree(pAdapterInfo); return HRESULT_FROM_WIN32(dwRet); } WCHAR wszGuid[c_cchGuidWithTerm]; ::StringFromGUID2(m_guidConnection, wszGuid, c_cchGuidWithTerm); BOOL fFound = FALSE; PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo; while (pAdapterInfoEnum) { USES_CONVERSION; if (lstrcmp(wszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0) { m_strIPAddress = A2W(pAdapterInfoEnum->IpAddressList.IpAddress.String); m_strSubnetMask = A2W(pAdapterInfoEnum->IpAddressList.IpMask.String); m_strGateway = A2W(pAdapterInfoEnum->GatewayList.IpAddress.String); m_fDhcp = pAdapterInfoEnum->DhcpEnabled; fFound = TRUE; break; } pAdapterInfoEnum = pAdapterInfoEnum->Next; } CoTaskMemFree(pAdapterInfo); if (!fFound) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } else { if (m_fDhcp) { hr = HrGetAutoNetSetting(wszGuid, &m_dhcpAddrType); } } return hr; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::RefreshUI // // Purpose: refresh the UI // // Arguments: none // // Returns: none // VOID CPspStatusMonitorIpcfg::RefreshUI() { TraceFileFunc(ttidStatMon); HRESULT hr = S_OK; BOOL fZeroIP = FALSE; InitializeData(); hr = GetIPConfigInfo(); if (FAILED(hr)) { ::SetWindowText(GetDlgItem(IDC_STATE_SOURCE), SzLoadString(_Module.GetResourceInstance(), IDS_ADDRESS_UNAVALABLE)); ::SetWindowText(GetDlgItem(IDC_STATE_IPADDR), SzLoadString(_Module.GetResourceInstance(), IDS_ADDRESS_UNAVALABLE)); ::SetWindowText(GetDlgItem(IDC_STATE_SUBNET), SzLoadString(_Module.GetResourceInstance(), IDS_ADDRESS_UNAVALABLE)); ::SetWindowText(GetDlgItem(IDC_STATE_GATEWAY), SzLoadString(_Module.GetResourceInstance(), IDS_ADDRESS_UNAVALABLE)); ::EnableWindow(GetDlgItem(IDC_STATE_BTN_REPAIR), FALSE); ::EnableWindow(GetDlgItem(IDC_STATE_BTN_DETAIL), FALSE); return; } else { ::EnableWindow(GetDlgItem(IDC_STATE_BTN_REPAIR), TRUE); ::EnableWindow(GetDlgItem(IDC_STATE_BTN_DETAIL), TRUE); } fZeroIP = (m_strIPAddress == L"0.0.0.0"); ::SetWindowText(GetDlgItem(IDC_STATE_IPADDR), m_strIPAddress.c_str()); ::SetWindowText(GetDlgItem(IDC_STATE_SUBNET), m_strSubnetMask.c_str()); ::SetWindowText(GetDlgItem(IDC_STATE_GATEWAY), m_strGateway.c_str()); if (!m_fDhcp) { ::SetWindowText(GetDlgItem(IDC_STATE_SOURCE), SzLoadString(_Module.GetResourceInstance(), IDS_STATIC_CFG)); } else { UINT idString = IDS_DHCP; switch(m_dhcpAddrType) { case NORMAL_ADDR: idString = IDS_DHCP; break; case AUTONET_ADDR: idString = IDS_AUTONET; break; case ALTERNATE_ADDR: idString = IDS_ALTERNATE_ADDR; break; } ::SetWindowText(GetDlgItem(IDC_STATE_SOURCE), SzLoadString(_Module.GetResourceInstance(), idString)); } if (fZeroIP) { ::SetWindowText(GetDlgItem(IDC_STATE_SOURCE), SzLoadString(_Module.GetResourceInstance(), IDS_INVALID_ADDR)); } if (!m_fEnableOpButtons) { ::EnableWindow(GetDlgItem(IDC_STATE_BTN_REPAIR), FALSE); } } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::IPAddrListenProc // // Purpose: the call back proc to launch the thead to listen to address changes // // Arguments: lpParameter - the CPspStatusMonitroIpcfg instance // // Returns: 0 // DWORD WINAPI CPspStatusMonitorIpcfg::IPAddrListenProc( LPVOID lpParameter // thread data ) { TraceFileFunc(ttidStatMon); HANDLE hEvents[2]; OVERLAPPED NotifyAddrOverLapped; HANDLE hNotifyAddr = NULL; DWORD dwRet = 0; CPspStatusMonitorIpcfg * pDialog = (CPspStatusMonitorIpcfg*) lpParameter; hEvents[0] = pDialog->m_hEventAddrListenThreadStopCommand; ZeroMemory(&NotifyAddrOverLapped, sizeof(OVERLAPPED)); NotifyAddrOverLapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NotifyAddrOverLapped.hEvent) { if (ERROR_IO_PENDING == NotifyAddrChange(&hNotifyAddr, &NotifyAddrOverLapped)) { hEvents[1] = NotifyAddrOverLapped.hEvent; do { dwRet = WaitForMultipleObjects( celems(hEvents), hEvents, FALSE, INFINITE); if (WAIT_OBJECT_0 + 1 == dwRet) { ResetEvent(hEvents[1]); ::PostMessage(pDialog->m_hWnd, PWM_UPDATE_IPCFG_DISPLAY, 0, 0); HWND hwndAdv = pDialog->m_dlgAdvanced.m_hWnd; if (hwndAdv) { ::PostMessage(hwndAdv, PWM_UPDATE_IPCFG_DISPLAY, 0, 0); } hNotifyAddr = NULL; if (ERROR_IO_PENDING != NotifyAddrChange(&hNotifyAddr, &NotifyAddrOverLapped)) { TraceTag(ttidStatMon, "Could not register for IP address change notifications"); break; } } else { break; } }while (TRUE); } else { TraceTag(ttidStatMon, "Could not register for IP address change notifications"); } } if (hNotifyAddr) { CancelIo(hNotifyAddr); } SetEvent(pDialog->m_hEventAddrListenThreadStopNotify); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::AdvIpCfgProc // // Purpose: the call back proc to launch the advanced dialog in another thread // // Arguments: lpParameter - the CPspStatusMonitroIpcfg instance // // Returns: 0 // DWORD WINAPI CPspStatusMonitorIpcfg::AdvIpCfgProc( LPVOID lpParameter // thread data ) { TraceFileFunc(ttidStatMon); CPspStatusMonitorIpcfg * pMainDialog = (CPspStatusMonitorIpcfg*) lpParameter; Assert(pMainDialog); //disable the status propsheet HWND hwndPsh = pMainDialog->GetParent(); Assert(hwndPsh); pMainDialog->m_dlgAdvanced.DoModal(hwndPsh); return 0; } /////////////////////////////////////////////////////////////////////// // Implementation of CAdvIpcfgDlg // //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::CAdvIpcfgDlg // // Purpose: constructor // CAdvIpcfgDlg::CAdvIpcfgDlg() : m_hList(NULL), m_adwHelpIDs(NULL) { TraceFileFunc(ttidStatMon); } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::OnInitDialog // // Purpose: do the initialize required when the dialog is created // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CAdvIpcfgDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled ) { TraceFileFunc(ttidStatMon); const UINT c_nColumns = 2; LV_COLUMN lvCol = {0}; RECT rect; int iIndex = 0; int iParamColWidth = 0; m_hList = GetDlgItem(IDC_LIST_IPCFG); ::GetClientRect(m_hList, &rect); iParamColWidth = (rect.right/c_nColumns); lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT ; lvCol.fmt = LVCFMT_LEFT; // left-align column lvCol.cx = iParamColWidth; lvCol.pszText = (PWSTR) SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_PRAMETER); iIndex = ListView_InsertColumn(m_hList, iIndex, &lvCol); iIndex++; lvCol.cx = rect.right - iParamColWidth; lvCol.pszText = (PWSTR) SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_VALUE); iIndex = ListView_InsertColumn(m_hList, iIndex, &lvCol); ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT); PopulateListControl(); return 0; } VOID CAdvIpcfgDlg::AddToListControl(int iIndex, LPWSTR szFirst, LPWSTR szSecond) { TraceFileFunc(ttidStatMon); LV_ITEM lvi = {0}; lvi.mask = LVIF_PARAM; lvi.lParam = 0; lvi.iItem = iIndex; ListView_InsertItem(m_hList, &lvi); ListView_SetItemText(m_hList, iIndex, 0, szFirst); ListView_SetItemText(m_hList, iIndex, 1, szSecond); } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::PopulateListControl // // Purpose: load the connection running settings and show them up in // the list control // // Arguments: none // // Returns: error code // HRESULT CAdvIpcfgDlg::PopulateListControl() { TraceFileFunc(ttidStatMon); HRESULT hr = S_OK; PIP_ADAPTER_INFO pAdapterInfo = NULL; DWORD dwOutBufLen = 0; DWORD dwRet = ERROR_SUCCESS; tstring strDns = L""; WCHAR wszGuid[c_cchGuidWithTerm] = {0}; tstring strTemp = L""; tstring strTemp2 = L""; BOOL fDisplayDhcpItems = TRUE; ListView_DeleteAllItems(m_hList); ::StringFromGUID2(m_guidConnection, wszGuid, c_cchGuidWithTerm); //Get other settings dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (dwRet == ERROR_BUFFER_OVERFLOW) { pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen); if (NULL == pAdapterInfo) return E_OUTOFMEMORY; } else if (ERROR_SUCCESS == dwRet) { return E_FAIL; } else { return HRESULT_FROM_WIN32(dwRet); } dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (ERROR_SUCCESS != dwRet) { CoTaskMemFree(pAdapterInfo); return HRESULT_FROM_WIN32(dwRet); } BOOL fFound = FALSE; PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo; while (pAdapterInfoEnum) { USES_CONVERSION; if (lstrcmp(wszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0) { fFound = TRUE; break; } pAdapterInfoEnum = pAdapterInfoEnum->Next; } if (!fFound) { CoTaskMemFree(pAdapterInfo); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } int iTemp = 0; int iIndex = 0; struct tm * ptmLocalTime = NULL; WCHAR szBuf[8]; fDisplayDhcpItems = !!pAdapterInfoEnum->DhcpEnabled; if (fDisplayDhcpItems) { DHCP_ADDRESS_TYPE AddrType; if (SUCCEEDED(HrGetAutoNetSetting(wszGuid, &AddrType))) { fDisplayDhcpItems = (AUTONET_ADDR != AddrType && ALTERNATE_ADDR != AddrType); } } LV_ITEM lvi = {0}; lvi.mask = LVIF_PARAM; lvi.lParam = 0; //Physical Address strTemp = L""; for (UINT i = 0; i < pAdapterInfoEnum->AddressLength; i++) { if (i > 0) { strTemp += L"-"; } wsprintf(szBuf, L"%02X", pAdapterInfoEnum->Address[i]); strTemp += szBuf; } AddToListControl(iIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_PH_ADDR), (LPWSTR)strTemp.c_str()); iIndex++; //IP Address and subnet mask iTemp = IPAddrToString(&pAdapterInfoEnum->IpAddressList, &strTemp, &strTemp2); //if the ip is zero, don't display DHCP items if (L"0.0.0.0" == strTemp) { fDisplayDhcpItems = FALSE; } iIndex += AddIPAddrToListControl(iIndex, &pAdapterInfoEnum->IpAddressList, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_IPADDR), (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_SUBNET), TRUE ); //Default Gateway iTemp = IPAddrToString(&pAdapterInfoEnum->GatewayList, &strTemp); iIndex += AddIPAddrToListControl(iIndex, &pAdapterInfoEnum->GatewayList, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), (iTemp > 1) ? IDS_IPCFG_DEFGW_PL : IDS_IPCFG_DEFGW) ); //Dhcp Server if (fDisplayDhcpItems) { IPAddrToString(&pAdapterInfoEnum->DhcpServer, &strTemp); AddToListControl(iIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_DHCP), (LPWSTR)strTemp.c_str()); iIndex++; } //Lease Obtain time if (fDisplayDhcpItems) { if (SUCCEEDED(FormatTime(pAdapterInfoEnum->LeaseObtained, strTemp))) { AddToListControl(iIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_LEASE_OBT), (LPWSTR)strTemp.c_str()); iIndex++; } //Lease expire time if (SUCCEEDED(FormatTime(pAdapterInfoEnum->LeaseExpires, strTemp))) { AddToListControl(iIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_LEASE_EXP), (LPWSTR)strTemp.c_str()); iIndex++; } } //Get the DNS servers HKEY hkeyInterface = NULL; tstring strInterfaceKey = c_szTcpipInterfaces; strInterfaceKey += wszGuid; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strInterfaceKey.c_str(), KEY_QUERY_VALUE, &hkeyInterface); if (SUCCEEDED(hr)) { BOOL fStaticDns = TRUE; int iPos = 0; Assert(hkeyInterface); hr = HrRegQueryString(hkeyInterface, c_szNameServer, &strTemp); if (0 == strTemp.size() || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { HrRegQueryString(hkeyInterface, c_szDhcpNameServer, &strTemp); fStaticDns = FALSE; } //the static DNS server list is in the format "x.x.x.x,y.y.y.y" and //the dhcp DNS server list is in the format "x.x.x.x y.y.y.y". We need to //re-format them to the same style //fFirst is used to identify whether this is the first DNS server int fFirst = TRUE; while(tstring::npos != (iPos = strTemp.find(fStaticDns ? L',' :L' '))) { strDns = strTemp.substr(0, iPos); strTemp = strTemp.erase(0, iPos + 1); AddToListControl(iIndex, fFirst ? (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_DNS_PL) : L"", (LPWSTR)strDns.c_str());; iIndex++; fFirst = FALSE; } strDns = strTemp; AddToListControl(iIndex, fFirst ? (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_DNS) : L"", (LPWSTR)strDns.c_str());; iIndex++; RegCloseKey(hkeyInterface); } iIndex += AddWinsServersToList(iIndex); if (pAdapterInfo) { CoTaskMemFree(pAdapterInfo); } return hr; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::OnClose // // Purpose: handle the WM_CLOSE message // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CAdvIpcfgDlg::OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled ) { TraceFileFunc(ttidStatMon); EndDialog(IDCANCEL); return 0; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::OnOk // // Purpose: close the dialog when the OK button is pressed // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CAdvIpcfgDlg::OnOk( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& fHandled ) { TraceFileFunc(ttidStatMon); EndDialog(IDOK); return 0; } LRESULT CAdvIpcfgDlg::OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& fHandled ) { TraceFileFunc(ttidStatMon); EndDialog(IDCANCEL); return 0; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::OnUpdateDisplay // // Purpose: Handling the user defined PWM_UPDATE_IPCFG_DISPLAY message // // Arguments: Standard window messsage parameters // // Returns: Standard window message return value // LRESULT CAdvIpcfgDlg::OnUpdateDisplay(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TraceFileFunc(ttidStatMon); //The thread listening to address changes will post a PWM_UPDATE_IPCFG_DISPLAY //message to us once the IP address is changed. //We need refresh the UI. PopulateListControl(); return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnContextMenu // // Purpose: When right click a control, bring up help // // Arguments: Standard command parameters // // Returns: Standard return // LRESULT CAdvIpcfgDlg::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled) { TraceFileFunc(ttidStatMon); if (m_adwHelpIDs != NULL) { ::WinHelp(m_hWnd, c_szNetCfgHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)m_adwHelpIDs); } return 0; } //+--------------------------------------------------------------------------- // // Member: CPspStatusMonitorIpcfg::OnHelp // // Purpose: When drag context help icon over a control, bring up help // // Arguments: Standard command parameters // // Returns: Standard return // LRESULT CAdvIpcfgDlg::OnHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled) { TraceFileFunc(ttidStatMon); LPHELPINFO lphi = reinterpret_cast(lParam); Assert(lphi); if ((m_adwHelpIDs != NULL) && (HELPINFO_WINDOW == lphi->iContextType)) { ::WinHelp(static_cast(lphi->hItemHandle), c_szNetCfgHelpFile, HELP_WM_HELP, (ULONG_PTR)m_adwHelpIDs); } return 0; } LRESULT CAdvIpcfgDlg::OnListKeyDown(int idCtrl, LPNMHDR pnmh, BOOL& fHandled) { TraceFileFunc(ttidStatMon); LPNMLVKEYDOWN pnmlv = (LPNMLVKEYDOWN) pnmh; if (NULL == pnmlv) return 0; if (IDC_LIST_IPCFG != idCtrl) return 0; BOOL fControlDown = (GetKeyState(VK_CONTROL) < 0); switch (pnmlv->wVKey) { case VK_INSERT: case 'c': case 'C': CopyListToClipboard(); break; } return 0; } VOID CAdvIpcfgDlg::CopyListToClipboard() { TraceFileFunc(ttidStatMon); WCHAR szBuff[256] = {0}; int iIndex = -1; tstring str = L""; BOOL fFirst = TRUE; while(-1 != (iIndex = ListView_GetNextItem(m_hList, iIndex, LVNI_ALL))) { szBuff[0] = 0; ListView_GetItemText(m_hList, iIndex, 0, szBuff, celems(szBuff) - 1); if (0 == lstrlen(szBuff)) { str += L", "; } else { if (!fFirst) { str += L"\r\n"; } else { fFirst = FALSE; } str += szBuff; str += L": "; } szBuff[0] = 0; ListView_GetItemText(m_hList, iIndex, 1, szBuff, celems(szBuff) -1); str += szBuff; } int nLength = str.length() + 1; nLength *= sizeof(WCHAR); HLOCAL hMem = LocalAlloc(LPTR, nLength); if (hMem) { memcpy(hMem, str.c_str(), nLength); if (!OpenClipboard()) { LocalFree(hMem); } else { EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hMem); CloseClipboard(); } } } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::AddIPAddrToListControl // // Purpose: helper routine to add a list of IP address/mask pairs to the list control // // Arguments: iStartIndex [in] the starting index of the list control // pszAddrDescription [in] the description of the address // pszMaskDescription [in] the description of the mask, this can be null // fShowDescriptionForMutliple [in] whether show the description for each entry if we have multiple entris // pAddrList [in] the address/mask pair list // // Returns: number of IP addresses in the string // int CAdvIpcfgDlg::AddIPAddrToListControl(int iStartIndex, PIP_ADDR_STRING pAddrList, LPWSTR pszAddrDescription, LPWSTR pszMaskDescription, BOOL fShowDescriptionForMutliple ) { TraceFileFunc(ttidStatMon); Assert(pAddrList); Assert(pszAddrDescription); if (NULL == pAddrList || NULL == pszAddrDescription) return 0; tstring strTmp = L""; BOOL fFirst = TRUE; int iIndex = iStartIndex; PIP_ADDR_STRING pCurrentAddr = NULL; for (pCurrentAddr = pAddrList; NULL != pCurrentAddr; pCurrentAddr = pCurrentAddr->Next) { USES_CONVERSION; strTmp = A2W(pCurrentAddr->IpAddress.String); AddToListControl(iIndex, (fFirst || fShowDescriptionForMutliple) ? pszAddrDescription : L"", (LPWSTR) strTmp.c_str()); iIndex++; if (pszMaskDescription) { strTmp = A2W(pCurrentAddr->IpMask.String); AddToListControl(iIndex, (fFirst || fShowDescriptionForMutliple) ? pszMaskDescription : L"", (LPWSTR) strTmp.c_str()); iIndex++; } if (fFirst) { fFirst = FALSE; } } return iIndex - iStartIndex; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::IPAddrToString // // Purpose: helper routine to convert IP_ADDR_STRING to a string // // Arguments: pAddrList - the IP_ADDR_STRING // pstrAddr [out] the string contains the IP address // pstrMask [out] the string contains the Mask // // Returns: number of IP addresses in the string // int CAdvIpcfgDlg::IPAddrToString( PIP_ADDR_STRING pAddrList, tstring * pstrAddr, tstring * pstrMask ) { TraceFileFunc(ttidStatMon); int i = 0; PIP_ADDR_STRING pCurrentAddr = NULL; if (pstrAddr) { *pstrAddr = L""; } if (pstrMask) { *pstrMask = L""; } for (pCurrentAddr = pAddrList; NULL != pCurrentAddr; pCurrentAddr = pCurrentAddr->Next) { USES_CONVERSION; if (pstrAddr) { if (0 != i) { (*pstrAddr) += L", "; } (*pstrAddr) += A2W(pCurrentAddr->IpAddress.String); } if (pstrMask) { if (0 != i) { (*pstrMask) += L", "; } (*pstrMask) += A2W(pCurrentAddr->IpMask.String); } i++; } return i; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::AddWinsServersToList // // Purpose: Get the list of WINS servers from the NBT driver and add them // into the list control // // Arguments: iStartIndex [in] - the starting index of the list control // that we should use to add the WINS servers // // Returns: number of entris added to the list control // int CAdvIpcfgDlg::AddWinsServersToList(int iStartIndex) { TraceFileFunc(ttidStatMon); int iIndex = iStartIndex; WCHAR wszGuid[c_cchGuidWithTerm] = {0}; ::StringFromGUID2(m_guidConnection, wszGuid, c_cchGuidWithTerm); HANDLE hNbt = INVALID_HANDLE_VALUE; tWINS_NODE_INFO NodeInfo = {0}; int nCount = 0; tstring strTemp = L""; if (FAILED(OpenNbt(wszGuid, &hNbt))) { AddToListControl(iStartIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_WINS), (LPWSTR)L""); return 1; } do { NTSTATUS status = 0; DWORD dwSize = 0; if (!DeviceIoControl(hNbt, IOCTL_NETBT_GET_WINS_ADDR, NULL, 0, (LPVOID)&NodeInfo, sizeof(NodeInfo), &dwSize, NULL)) { break; } if( LOCAL_WINS_ADDRESS == NodeInfo.NameServerAddress || INADDR_ANY == NodeInfo.NameServerAddress || INADDR_BROADCAST == NodeInfo.NameServerAddress ) { break; } BOOL fHaveSecondWins = !(LOCAL_WINS_ADDRESS == NodeInfo.BackupServer || INADDR_ANY == NodeInfo.BackupServer || INADDR_BROADCAST == NodeInfo.BackupServer); DwordToIPAddrString(NodeInfo.NameServerAddress, &strTemp); AddToListControl(iIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), fHaveSecondWins ? IDS_IPCFG_WINS_PL : IDS_IPCFG_WINS), (LPWSTR)strTemp.c_str()); iIndex++; if (!fHaveSecondWins) { break; } DwordToIPAddrString(NodeInfo.BackupServer, &strTemp); AddToListControl(iIndex, (LPWSTR)L"", (LPWSTR)strTemp.c_str()); iIndex++; int NumOfServers = (NodeInfo.NumOtherServers <= MAX_NUM_OTHER_NAME_SERVERS) ? NodeInfo.NumOtherServers : MAX_NUM_OTHER_NAME_SERVERS; for (int i = 0; i < NumOfServers; i++) { if( LOCAL_WINS_ADDRESS == NodeInfo.Others[i] || INADDR_ANY == NodeInfo.Others[i] || INADDR_BROADCAST == NodeInfo.Others[i] ) { break; } DwordToIPAddrString(NodeInfo.Others[i], &strTemp); AddToListControl(iIndex, (LPWSTR)L"", (LPWSTR)strTemp.c_str()); iIndex++; } } while (FALSE); NtClose(hNbt); int iRet = iIndex - iStartIndex; //if somehow we didn't add any WINS entris to the list, we need to add an empty "WINS Server" entry to the list if (0 == iRet) { AddToListControl(iStartIndex, (LPWSTR)SzLoadString(_Module.GetResourceInstance(), IDS_IPCFG_WINS), (LPWSTR)L""); iRet = 1; } return iRet; } //+--------------------------------------------------------------------------- // // Member: CAdvIpcfgDlg::FormatTime // // Purpose: convert time_t to a string. // // Arguments: pAddrList - the IP_ADDR_STRING // pstrAddr [out] the string contains the IP address // pstrMask [out] the string contains the Mask // // Returns: error code // // Note: _wasctime has some localization problems. So we do the formatting ourselves HRESULT CAdvIpcfgDlg::FormatTime(time_t t, tstring & str) { TraceFileFunc(ttidStatMon); time_t timeCurrent = time(NULL); LONGLONG llTimeDiff = 0; FILETIME ftCurrent = {0}; FILETIME ftLocal = {0}; SYSTEMTIME SysTime; WCHAR szBuff[256] = {0}; str = L""; GetSystemTimeAsFileTime(&ftCurrent); llTimeDiff = (LONGLONG)t - (LONGLONG)timeCurrent; llTimeDiff *= 10000000; *((LONGLONG UNALIGNED64 *)&ftCurrent) += llTimeDiff; if (!FileTimeToLocalFileTime(&ftCurrent, &ftLocal )) { return HRESULT_FROM_WIN32(GetLastError()); } if (!FileTimeToSystemTime( &ftLocal, &SysTime )) { return HRESULT_FROM_WIN32(GetLastError()); } if (0 == GetDateFormat(LOCALE_USER_DEFAULT, 0, &SysTime, NULL, szBuff, celems(szBuff))) { return HRESULT_FROM_WIN32(GetLastError()); } str = szBuff; str += L" "; ZeroMemory(szBuff, sizeof(szBuff)); if (0 == GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SysTime, NULL, szBuff, celems(szBuff))) { return HRESULT_FROM_WIN32(GetLastError()); } str += szBuff; return S_OK; } //+--------------------------------------------------------------------------- // // Function: HrGetAutoNetSetting // // Purpose: Query the Autonet settings // // Arguments: pszGuid - guid of the connection // pAddrType [out] - contains the type of the address // // Returns: error code // HRESULT HrGetAutoNetSetting(PWSTR pszGuid, DHCP_ADDRESS_TYPE * pAddrType) { TraceFileFunc(ttidStatMon); Assert(pszGuid); Assert(pAddrType); *pAddrType = UNKNOWN_ADDR; HRESULT hr = S_OK; DWORD dwType = 0; HKEY hkeyInterface = NULL; tstring strInterfaceKey = c_szTcpipInterfaces; strInterfaceKey += pszGuid; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strInterfaceKey.c_str(), KEY_QUERY_VALUE, &hkeyInterface); if (SUCCEEDED(hr)) { Assert(hkeyInterface); hr = HrRegQueryDword(hkeyInterface, c_szAddressType, &dwType); if (SUCCEEDED(hr)) { if (0 == dwType) { *pAddrType = NORMAL_ADDR; } else { tstring strConfigurationName = c_szAlternate; strConfigurationName += pszGuid; //assume default is AUTONET_ADDR *pAddrType = AUTONET_ADDR; // if ActiveConfigurations contain a string "Alternate_{Interface GUID}" // then there is customized fall-back settings, otherwise Autonet vector vstrTmp; hr = HrRegQueryColString( hkeyInterface, c_szActiveConfigurations, &vstrTmp); if (SUCCEEDED(hr)) { for (int i = 0; i < (int)vstrTmp.size(); i++) { if (strConfigurationName == *vstrTmp[i]) { *pAddrType = ALTERNATE_ADDR; break; } } DeleteColString(&vstrTmp); } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { hr = S_OK; } } } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { //if the value is not there, assume the default (No autonet) *pAddrType = NORMAL_ADDR; hr = S_OK; } RegSafeCloseKey(hkeyInterface); } return hr; } HRESULT HrGetAutoNetSetting(REFGUID pGuidId, DHCP_ADDRESS_TYPE * pAddrType) { TraceFileFunc(ttidStatMon); Assert(pAddrType); *pAddrType = UNKNOWN_ADDR; WCHAR wszGuid[MAX_PATH]; ::StringFromGUID2(pGuidId, wszGuid, MAX_PATH); HRESULT hr = S_OK; PIP_ADAPTER_INFO pAdapterInfo = NULL; DWORD dwOutBufLen = 0; DWORD dwRet = ERROR_SUCCESS; dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (dwRet == ERROR_BUFFER_OVERFLOW) { pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen); if (NULL == pAdapterInfo) return E_OUTOFMEMORY; } else if (ERROR_SUCCESS == dwRet) { return E_FAIL; } else { return HRESULT_FROM_WIN32(dwRet); } dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen); if (ERROR_SUCCESS != dwRet) { CoTaskMemFree(pAdapterInfo); return HRESULT_FROM_WIN32(dwRet); } BOOL fFound = FALSE; PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo; while (pAdapterInfoEnum) { USES_CONVERSION; if (lstrcmp(wszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0) { fFound = TRUE; break; } pAdapterInfoEnum = pAdapterInfoEnum->Next; } if (fFound) { if (pAdapterInfoEnum->DhcpEnabled) { hr = HrGetAutoNetSetting(wszGuid, pAddrType); } else { *pAddrType = STATIC_ADDR; hr = S_OK; } } else { hr = S_FALSE; } CoTaskMemFree(pAdapterInfo); return hr; } void DwordToIPAddrString(DWORD dw, tstring * pstr) { TraceFileFunc(ttidStatMon); WCHAR szBuff[32] = {0}; Assert(pstr); _itow((dw & 0xff000000) >> 24, szBuff, 10); *pstr = szBuff; *pstr += L"."; _itow((dw & 0x00ff0000) >> 16, szBuff, 10); *pstr += szBuff; *pstr += L"."; _itow((dw & 0x0000ff00) >> 8, szBuff, 10); *pstr += szBuff; *pstr += L"."; _itow(dw & 0x000000ff, szBuff, 10); *pstr += szBuff; }