1808 lines
46 KiB
C++
1808 lines
46 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: T C P U T I L . C P P
|
|
//
|
|
// Contents: Utility functions used by tcpipcfg
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: tongl
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include <ncxbase.h>
|
|
#include <dsrole.h>
|
|
#include "ncatlui.h"
|
|
#include <time.h>
|
|
#include "ncreg.h"
|
|
#include "ncstl.h"
|
|
#include "ncui.h"
|
|
#include "tcpconst.h"
|
|
#include "tcputil.h"
|
|
#include "resource.h"
|
|
#include "tcpmacro.h"
|
|
#include "atmcommon.h"
|
|
|
|
#define MAX_NUM_DIGIT_MULTI_INTERFACES 10
|
|
|
|
extern const WCHAR c_szNetCfgHelpFile[];
|
|
|
|
// HrLoadSubkeysFromRegistry
|
|
// Gets the list of subkeys under a registry key
|
|
// hkey the root registry key
|
|
// pvstrAdapters returns the list of subkeykey names from hkey
|
|
|
|
HRESULT HrLoadSubkeysFromRegistry(const HKEY hkey,
|
|
OUT VSTR * const pvstrSubkeys)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
Assert(pvstrSubkeys);
|
|
|
|
// Initialize output parameter
|
|
FreeCollectionAndItem(*pvstrSubkeys);
|
|
|
|
WCHAR szBuf[256];
|
|
FILETIME time;
|
|
DWORD dwSize = celems(szBuf);
|
|
DWORD dwRegIndex = 0;
|
|
|
|
while(SUCCEEDED(hr = HrRegEnumKeyEx(hkey, dwRegIndex++, szBuf,
|
|
&dwSize, NULL, NULL, &time)))
|
|
{
|
|
dwSize = celems(szBuf);
|
|
Assert(szBuf);
|
|
pvstrSubkeys->push_back(new tstring(szBuf));
|
|
}
|
|
|
|
if(hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
|
|
hr = S_OK;
|
|
|
|
TraceError("HrLoadSubkeysFromRegistry", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
//HrIsComponentInstalled Given a Component ID, determins if the component
|
|
// is installed in the system
|
|
// Note: The net class of the component must be
|
|
//
|
|
//pnc the system's INetCfg
|
|
//rguidClass the Net Class of this component we are earching for
|
|
//pszInfId the Component ID
|
|
//pfInstalled returns a flag to determine if the component is installed
|
|
//
|
|
// Returns S_OK if succeed ( whether component found or not
|
|
// Other: ERROR
|
|
|
|
HRESULT HrIsComponentInstalled(INetCfg * pnc,
|
|
const GUID& rguidClass,
|
|
PCWSTR pszInfId,
|
|
OUT BOOL * const pfInstalled)
|
|
{
|
|
Assert(pnc);
|
|
Assert(pszInfId);
|
|
Assert(pfInstalled);
|
|
|
|
*pfInstalled = FALSE;
|
|
|
|
INetCfgComponent * pncc;
|
|
|
|
HRESULT hr = pnc->FindComponent(pszInfId, &pncc);
|
|
|
|
if(hr == S_OK)
|
|
{
|
|
Assert(pncc);
|
|
*pfInstalled = TRUE;
|
|
}
|
|
else if(hr == S_FALSE)
|
|
{
|
|
Assert(!pncc);
|
|
*pfInstalled = FALSE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
ReleaseObj(pncc);
|
|
|
|
TraceError("HrIsComponentInstalled", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// GetNodeNum
|
|
//
|
|
// Get an IP Address and return the 4 numbers in the IP address.
|
|
//
|
|
// pszIpAddress: IP Address
|
|
// ardw[4]: The 4 numbers in the IP Address
|
|
|
|
VOID GetNodeNum(PCWSTR pszIpAddress, DWORD ardw[4])
|
|
{
|
|
VSTR vstr;
|
|
|
|
tstring strIpAddress(pszIpAddress);
|
|
|
|
ConvertStringToColString(strIpAddress.c_str(),
|
|
CH_DOT,
|
|
vstr);
|
|
|
|
VSTR_ITER iter = vstr.begin();
|
|
// Go through each field and get the number value
|
|
|
|
ardw[0] = 0;
|
|
ardw[1] = 0;
|
|
ardw[2] = 0;
|
|
ardw[3] = 0;
|
|
|
|
if(iter != vstr.end())
|
|
{
|
|
ardw[0] = _ttol((*iter++)->c_str());
|
|
if(iter != vstr.end())
|
|
{
|
|
ardw[1] = _ttol((*iter++)->c_str());
|
|
if(iter != vstr.end())
|
|
{
|
|
ardw[2] = _ttol((*iter++)->c_str());
|
|
if(iter != vstr.end())
|
|
{
|
|
ardw[3] = _ttol((*iter++)->c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeCollectionAndItem(vstr);
|
|
}
|
|
|
|
//Check if the subnet mask is contiguous
|
|
//Return: TRUE contiguous
|
|
// FALSE uncontigous
|
|
BOOL IsContiguousSubnet(PCWSTR pszSubnet)
|
|
{
|
|
DWORD ardwSubnet[4];
|
|
|
|
GetNodeNum(pszSubnet, ardwSubnet);
|
|
|
|
DWORD dwMask = (ardwSubnet[0] << 24) + (ardwSubnet[1] << 16)
|
|
+ (ardwSubnet[2] << 8) + ardwSubnet[3];
|
|
|
|
|
|
DWORD i, dwContiguousMask;
|
|
|
|
// Find out where the first '1' is in binary going right to left
|
|
dwContiguousMask = 0;
|
|
for (i = 0; i < sizeof(dwMask)*8; i++)
|
|
{
|
|
dwContiguousMask |= 1 << i;
|
|
|
|
if (dwContiguousMask & dwMask)
|
|
break;
|
|
}
|
|
|
|
// At this point, dwContiguousMask is 000...0111... If we inverse it,
|
|
// we get a mask that can be or'd with dwMask to fill in all of
|
|
// the holes.
|
|
dwContiguousMask = dwMask | ~dwContiguousMask;
|
|
|
|
// If the new mask is different, correct it here
|
|
if (dwMask != dwContiguousMask)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
// Replace first element of a vector of tstrings
|
|
VOID ReplaceFirstAddress(VSTR * pvstr, PCWSTR pszIpAddress)
|
|
{
|
|
Assert(pszIpAddress);
|
|
|
|
if(pvstr->empty())
|
|
{
|
|
pvstr->push_back(new tstring(pszIpAddress));
|
|
}
|
|
else
|
|
{
|
|
*(*pvstr)[0] = pszIpAddress;
|
|
}
|
|
}
|
|
|
|
// Replace second element of a vector of tstrings
|
|
VOID ReplaceSecondAddress(VSTR * pvstr, PCWSTR pszIpAddress)
|
|
{
|
|
Assert(pszIpAddress);
|
|
|
|
if (pvstr->size()<2)
|
|
{
|
|
pvstr->push_back(new tstring(pszIpAddress));
|
|
}
|
|
else
|
|
{
|
|
*(*pvstr)[1] = pszIpAddress;
|
|
}
|
|
}
|
|
|
|
// Generate subnetmask for an IP address
|
|
BOOL GenerateSubnetMask(IpControl & ipAddress,
|
|
tstring * pstrSubnetMask)
|
|
{
|
|
BOOL bResult = TRUE;
|
|
|
|
if (!ipAddress.IsBlank())
|
|
{
|
|
tstring strAddress;
|
|
DWORD adwIpAddress[4];
|
|
|
|
ipAddress.GetAddress(&strAddress);
|
|
GetNodeNum(strAddress.c_str(), adwIpAddress);
|
|
|
|
DWORD nValue = adwIpAddress[0];
|
|
|
|
if(nValue <= SUBNET_RANGE_1_MAX)
|
|
{
|
|
*pstrSubnetMask = c_szBASE_SUBNET_MASK_1;
|
|
}
|
|
else if( nValue <= SUBNET_RANGE_2_MAX)
|
|
{
|
|
*pstrSubnetMask = c_szBASE_SUBNET_MASK_2;
|
|
}
|
|
else if( nValue <= SUBNET_RANGE_3_MAX)
|
|
{
|
|
*pstrSubnetMask = c_szBASE_SUBNET_MASK_3;
|
|
}
|
|
else
|
|
{
|
|
Assert(FALSE);
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
// BOOL fIsSameVstr
|
|
// Return TRUE is all strings in a vstr are the same and in same order
|
|
BOOL fIsSameVstr(const VSTR vstr1, const VSTR vstr2)
|
|
{
|
|
int iCount1 = vstr1.size();
|
|
int iCount2 = vstr2.size();
|
|
int idx =0;
|
|
|
|
if (iCount1 != iCount2)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else // same size
|
|
{
|
|
// For each string in both vstr1 and vstr2
|
|
for (idx=0; idx<iCount1; idx++)
|
|
{
|
|
// if mismatch found
|
|
if((*vstr1[idx] != *vstr2[idx]))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert((iCount1==iCount2) && (iCount1==idx));
|
|
return TRUE;
|
|
}
|
|
|
|
// Registry access help functions for Boolean type
|
|
// FRegQueryBool
|
|
// hkey the regisry key
|
|
// pszName the value in the registry key
|
|
// fValue the default vaule
|
|
//
|
|
// NOTE: If the function failed to read the value from the registry, it will return
|
|
// the default value.
|
|
|
|
BOOL FRegQueryBool(const HKEY hkey, PCWSTR pszName, BOOL fDefaultValue)
|
|
{
|
|
BOOL fRetValue = fDefaultValue;
|
|
DWORD dwValue;
|
|
|
|
HRESULT hr = HrRegQueryDword(hkey, pszName, &dwValue);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
fRetValue = !!dwValue;
|
|
}
|
|
#ifdef ENABLETRACE
|
|
else
|
|
{
|
|
const HRESULT hrNoRegValue = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
|
|
if (hr == hrNoRegValue)
|
|
{
|
|
TraceTag(ttidTcpip, "FRegQueryBool: registry key %S not found", pszName);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
TraceError("FRegQueryBool", hr);
|
|
return fRetValue;
|
|
}
|
|
|
|
|
|
|
|
// ResetLmhostsFile
|
|
// Called by Cancel and Cancelproperties to roll back changes to the file lmhosts
|
|
VOID ResetLmhostsFile()
|
|
{
|
|
WCHAR szSysPath[MAX_PATH] = {0};
|
|
WCHAR szSysPathBackup[MAX_PATH];
|
|
|
|
BOOL fSysPathFound = (GetSystemDirectory(szSysPath, MAX_PATH) != 0);
|
|
|
|
lstrcpyW(szSysPathBackup, szSysPath);
|
|
|
|
wcscat(szSysPath, RGAS_LMHOSTS_PATH);
|
|
wcscat(szSysPathBackup, RGAS_LMHOSTS_PATH_BACKUP);
|
|
|
|
WIN32_FIND_DATA FileData;
|
|
if (FindFirstFile(szSysPathBackup, &FileData) == INVALID_HANDLE_VALUE)
|
|
{
|
|
AssertSz(FALSE, "lmhosts.bak file not found");
|
|
}
|
|
else
|
|
{
|
|
BOOL ret;
|
|
|
|
// Rename lmhosts.bak file to lmhosts
|
|
ret = MoveFileEx(szSysPathBackup, szSysPath, MOVEFILE_REPLACE_EXISTING);
|
|
AssertSz(ret, "Failed to restore lmhosts file!");
|
|
}
|
|
}
|
|
|
|
//
|
|
// IPAlertPrintf() - Does a printf to a message box for IP address
|
|
//
|
|
// ids: message string, IDS_IPBAD_FIELD_VALUE
|
|
// iCurrent: value of the field
|
|
// iLow: Low range of the field
|
|
// iHigh: High range of the field
|
|
//
|
|
int IPAlertPrintf(HWND hwndParent, UINT ids,
|
|
int iCurrent, int iLow, int iHigh)
|
|
{
|
|
|
|
if (ids != IDS_IPNOMEM)
|
|
{
|
|
WCHAR szCurrent[3];
|
|
wsprintfW(szCurrent, c_szItoa, iCurrent);
|
|
|
|
WCHAR szLow[3];
|
|
wsprintfW(szLow, c_szItoa, iLow);
|
|
|
|
WCHAR szHigh[3];
|
|
wsprintfW(szHigh, c_szItoa, iHigh);
|
|
|
|
return NcMsgBox(hwndParent,
|
|
IDS_IPMBCAPTION,
|
|
ids,
|
|
MB_ICONEXCLAMATION,
|
|
szCurrent, szLow, szHigh);
|
|
}
|
|
else
|
|
return NcMsgBox(hwndParent,
|
|
IDS_IPMBCAPTION,
|
|
ids,
|
|
MB_ICONEXCLAMATION);
|
|
|
|
}
|
|
|
|
// IpRangeError
|
|
//
|
|
VOID IpCheckRange(LPNMIPADDRESS lpnmipa, HWND hWnd, int iLow, int iHigh, BOOL fCheckLoopback)
|
|
{
|
|
/*
|
|
// This is a workaround because the IP control will send this notification
|
|
// twice if I don't set the out of range value in this code. However there
|
|
// is no way to set the value of an individual field. Send request to strohma.
|
|
static BOOL fNotified = FALSE;
|
|
static int iNotifiedValue = 0;
|
|
|
|
if ((lpnmipa->iValue != c_iEmptyIpField) &&
|
|
((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
|
|
{
|
|
if (!fNotified) // If we havn't been notified yet
|
|
{
|
|
fNotified = TRUE;
|
|
iNotifiedValue = lpnmipa->iValue;
|
|
|
|
IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
|
|
lpnmipa->iValue, iLow, iHigh);
|
|
}
|
|
else // ignor the second notify
|
|
{
|
|
// Make sure we are alerted of change in the workaround from common control
|
|
AssertSz(iNotifiedValue == lpnmipa->iValue, "Common control behaviour changed!!");
|
|
fNotified = FALSE;
|
|
iNotifiedValue =0;
|
|
}
|
|
};
|
|
*/
|
|
/*
|
|
// This is a workaround because the IP control will send this notification
|
|
// twice if I don't set the out of range value in this code. However there
|
|
// is no way to set the value of an individual field. Send request to strohma.
|
|
if ((lpnmipa->iValue != c_iEmptyIpField) &&
|
|
((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
|
|
{
|
|
IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
|
|
lpnmipa->iValue, iLow, iHigh);
|
|
if (lpnmipa->iValue<iLow)
|
|
lpnmipa->iValue = iLow;
|
|
else
|
|
lpnmipa->iValue = iHigh;
|
|
|
|
};
|
|
*/
|
|
|
|
//$REVIEW (nsun) BUG171839 this is a workaround because the IP control will send this notifcation
|
|
// twice when I put a 3 digit value. I added a static value to make sure every error message
|
|
// is brought up only once
|
|
// The static values that should be able to uniquely identify a notification
|
|
static UINT idIpControl = 0;
|
|
static int iField = 0;
|
|
static int iValue = 0;
|
|
|
|
//we know the notification may be sent twice
|
|
//We only want to the second duplcate notifiction
|
|
//If we receive the third notification with the same control, field and value, it should
|
|
//be real notification and we shouldn't ignore it.
|
|
static UINT cRejectTimes = 0;
|
|
|
|
if(idIpControl != lpnmipa->hdr.idFrom ||
|
|
iField != lpnmipa->iField || iValue != lpnmipa->iValue || cRejectTimes > 0)
|
|
{
|
|
//update the static values
|
|
//(nsun) We have to update the static values before the error
|
|
// message box because there will be IPN_FIELDCHANGED notification
|
|
// sent out when the message box is brought up.
|
|
cRejectTimes = 0;
|
|
idIpControl = lpnmipa->hdr.idFrom;
|
|
iField = lpnmipa->iField;
|
|
iValue = lpnmipa->iValue;
|
|
|
|
if ((lpnmipa->iValue != c_iEmptyIpField) &&
|
|
((lpnmipa->iValue<iLow) || (lpnmipa->iValue>iHigh)))
|
|
{
|
|
IPAlertPrintf(hWnd, IDS_IPBAD_FIELD_VALUE,
|
|
lpnmipa->iValue, iLow, iHigh);
|
|
}
|
|
|
|
if (fCheckLoopback && lpnmipa->iValue == c_iIPADDR_FIELD_1_LOOPBACK
|
|
&& 0 == lpnmipa->iField)
|
|
{
|
|
IPAlertPrintf(hWnd, IDS_INCORRECT_IP_LOOPBACK,
|
|
lpnmipa->iValue, iLow, iHigh);
|
|
lpnmipa->iValue = iLow;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cRejectTimes++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: SetButtons
|
|
//
|
|
// Purpose: Enables/disables push buttons based on item count and current selection
|
|
// in the list.
|
|
// Used by DNS and ATM ARPC pages that have group of HANDLES
|
|
//
|
|
// Arguments:
|
|
// h [in] The group of handles
|
|
// nNumLimit [in] Limit of number of elements allowed in the list
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Author: tongl 9 July 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
VOID SetButtons(HANDLES& h, const int nNumLimit)
|
|
{
|
|
Assert(IsWindow(h.m_hList));
|
|
Assert(IsWindow(h.m_hAdd));
|
|
Assert(IsWindow(h.m_hEdit));
|
|
Assert(IsWindow(h.m_hRemove));
|
|
|
|
// $REVIEW(tongl):macro problem
|
|
int nCount = Tcp_ListBox_GetCount(h.m_hList);
|
|
|
|
// If there are currently no item in list, set focus to "Add" button
|
|
if (!nCount)
|
|
{
|
|
// remove the default on the remove button, if any
|
|
SendMessage(h.m_hRemove, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
|
|
|
|
// move focus to Add button
|
|
::SetFocus(h.m_hAdd);
|
|
}
|
|
|
|
// If number of items less than limit, enable "Add" button
|
|
// Otherwise disable it
|
|
if (nCount != nNumLimit)
|
|
::EnableWindow(h.m_hAdd, TRUE);
|
|
else
|
|
{
|
|
//disable the button and move focus only if the add button is currently enabled
|
|
if (::IsWindowEnabled(h.m_hAdd))
|
|
{
|
|
// disable "Add button"
|
|
::EnableWindow(h.m_hAdd, FALSE);
|
|
|
|
// remove the default on the add button, if any
|
|
SendMessage(h.m_hAdd, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
|
|
|
|
// move focus to edit button
|
|
::SetFocus(h.m_hEdit);
|
|
}
|
|
}
|
|
|
|
// If number of items >0, enable "Edit" and "Remove" buttons
|
|
// Otherwise disable them
|
|
|
|
::EnableWindow(h.m_hEdit, nCount);
|
|
::EnableWindow(h.m_hRemove, nCount);
|
|
|
|
// Enable/disable the "Up" and "Down" buttons
|
|
|
|
// determine Up and Down logic
|
|
if (nCount > 1)
|
|
{
|
|
int idxCurSel = Tcp_ListBox_GetCurSel(h.m_hList);
|
|
Assert(idxCurSel != CB_ERR );
|
|
|
|
BOOL fChangeFocus = FALSE;
|
|
|
|
if (idxCurSel == 0)
|
|
{
|
|
if (h.m_hUp == ::GetFocus())
|
|
fChangeFocus = TRUE;
|
|
|
|
::EnableWindow(h.m_hUp, FALSE);
|
|
::EnableWindow(h.m_hDown, TRUE);
|
|
|
|
// remove the default on the up button, if any
|
|
SendMessage(h.m_hUp, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
|
|
|
|
if (fChangeFocus)
|
|
::SetFocus(h.m_hDown);
|
|
}
|
|
else if (idxCurSel == (nCount-1))
|
|
{
|
|
if (h.m_hDown == ::GetFocus())
|
|
fChangeFocus = TRUE;
|
|
|
|
::EnableWindow(h.m_hUp, TRUE);
|
|
::EnableWindow(h.m_hDown, FALSE);
|
|
|
|
// remove the default on the down button, if any
|
|
SendMessage(h.m_hDown, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, TRUE );
|
|
|
|
if (fChangeFocus)
|
|
::SetFocus(h.m_hUp);
|
|
}
|
|
else
|
|
{
|
|
::EnableWindow(h.m_hUp, TRUE);
|
|
::EnableWindow(h.m_hDown, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
::EnableWindow(h.m_hUp, FALSE);
|
|
::EnableWindow(h.m_hDown, FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: ListBoxRemoveAt
|
|
//
|
|
// Purpose: Remove an item from a list box and save it to a tstring
|
|
// Used by DNS and ATM ARPC pages.
|
|
//
|
|
// Arguments:
|
|
// hListBox [in] Handle to the list box
|
|
// idx [in] Index of the item to remove
|
|
// pstrRemovedItem [out] The content of the removed item
|
|
//
|
|
// Returns: TRUE if succeeded, else FALSE
|
|
//
|
|
// Author: tongl 9 July 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
BOOL ListBoxRemoveAt(HWND hListBox, int idx, tstring * pstrRemovedItem)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
Assert(idx >=0);
|
|
Assert(hListBox);
|
|
|
|
WCHAR buf[MAX_PATH];
|
|
int len;
|
|
if((len = Tcp_ListBox_GetTextLen(hListBox, idx)) >= celems(buf))
|
|
{
|
|
Assert(FALSE);
|
|
return FALSE;
|
|
}
|
|
Assert(len != 0);
|
|
|
|
Tcp_ListBox_GetText(hListBox, idx, buf);
|
|
*pstrRemovedItem = buf;
|
|
|
|
if (len != 0)
|
|
{
|
|
if (::SendMessage(hListBox,
|
|
LB_DELETESTRING,
|
|
(WPARAM)(int)(idx), 0L) != LB_ERR)
|
|
|
|
bResult = TRUE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: ListBoxInsertAfter
|
|
//
|
|
// Purpose: Insert an item into a list box
|
|
// Used by DNS and ATM ARPC pages
|
|
//
|
|
// Arguments:
|
|
// hListBox [in] Handle to the list box
|
|
// idx [in] Index of the item to insert after
|
|
// pszItem [out] The item to insert
|
|
//
|
|
// Returns: TRUE if succeeded, else FALSE
|
|
//
|
|
// Author: tongl 9 July 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
BOOL ListBoxInsertAfter(HWND hListBox, int idx, PCWSTR pszItem)
|
|
{
|
|
#ifdef DBG
|
|
Assert(hListBox);
|
|
|
|
// validate the range
|
|
int nCount = Tcp_ListBox_GetCount(hListBox);
|
|
|
|
Assert(idx >=0);
|
|
Assert(idx <= nCount);
|
|
|
|
// insist there is a string
|
|
Assert(pszItem);
|
|
#endif
|
|
|
|
return (Tcp_ListBox_InsertString(hListBox, idx, pszItem) == idx);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: HrRegRenameTree
|
|
//
|
|
// Purpose: Rename a registr subkey
|
|
//
|
|
// Arguments:
|
|
// hkeyRoot [in] The root key where the subkey to be renamed exists
|
|
// pszOldName [in] The existing name of the sub key
|
|
// pszNewName [in] The new name of the sub key
|
|
//
|
|
// Returns: S_OK if succeeded,
|
|
// E_FAIL otherwise
|
|
//
|
|
// Author: tongl 7 Aug 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrRegRenameTree(HKEY hkeyRoot, PCWSTR pszOldName, PCWSTR pszNewName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hkeyNew = NULL;
|
|
HKEY hkeyOld = NULL;
|
|
DWORD dwDisposition;
|
|
|
|
//$REVIEW (nsun) make sure we don't rename the same tree
|
|
if(0 == lstrcmpiW (pszOldName, pszNewName))
|
|
return S_OK;
|
|
|
|
// Create new subkey
|
|
hr = HrRegCreateKeyEx(hkeyRoot,
|
|
pszNewName,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ_WRITE,
|
|
NULL,
|
|
&hkeyNew,
|
|
&dwDisposition);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Copy all items under old subkey to new subkey
|
|
hr = HrRegOpenKeyEx(hkeyRoot,
|
|
pszOldName,
|
|
KEY_READ_WRITE_DELETE,
|
|
&hkeyOld);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrRegCopyKeyTree(hkeyNew, hkeyOld);
|
|
RegSafeCloseKey(hkeyOld);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Delete old subkey
|
|
hr = HrRegDeleteKeyTree(hkeyRoot, pszOldName);
|
|
}
|
|
}
|
|
}
|
|
RegSafeCloseKey(hkeyNew);
|
|
|
|
TraceTag(ttidTcpip, "HrRegRenameTree failed to rename %S to %S", pszOldName, pszNewName);
|
|
|
|
TraceError("Tcpipcfg: HrRegRenameTree failed", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: HrRegCopyKeyTree
|
|
//
|
|
// Purpose: Copies a registry subtree to a new location
|
|
//
|
|
// Arguments:
|
|
// hkeyDest [in] The subkey to copy to
|
|
// hkeySrc [in] The subkey to copy from
|
|
//
|
|
// Returns: S_OK if succeeded,
|
|
// E_FAIL otherwise
|
|
//
|
|
// Author: tongl 7 Aug 1997
|
|
//
|
|
// Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
|
|
//
|
|
HRESULT HrRegCopyKeyTree(HKEY hkeyDest, HKEY hkeySrc )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FILETIME ftLastWrite;
|
|
|
|
DWORD cchMaxSubKeyLen;
|
|
DWORD cchMaxClassLen;
|
|
DWORD cchMaxValueNameLen;
|
|
DWORD cbMaxValueLen;
|
|
|
|
DWORD iItem;
|
|
PWSTR pszName;
|
|
PWSTR pszClass;
|
|
PBYTE pbData;
|
|
|
|
DWORD cchName;
|
|
DWORD cchClass;
|
|
DWORD cbData;
|
|
|
|
HKEY hkeyChildDest = NULL;
|
|
HKEY hkeyChildSrc = NULL;
|
|
|
|
DWORD dwDisposition;
|
|
|
|
// Find out the longest name and data field and create the buffers
|
|
// to store enumerations in
|
|
//
|
|
LONG lrt;
|
|
lrt = RegQueryInfoKeyW( hkeySrc,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cchMaxSubKeyLen,
|
|
&cchMaxClassLen,
|
|
NULL,
|
|
&cchMaxValueNameLen,
|
|
&cbMaxValueLen,
|
|
NULL,
|
|
&ftLastWrite );
|
|
do
|
|
{
|
|
if (ERROR_SUCCESS != lrt)
|
|
{
|
|
hr = HrFromLastWin32Error();
|
|
break;
|
|
}
|
|
|
|
// use only one buffer for all names, values or keys
|
|
cchMaxValueNameLen = max( cchMaxSubKeyLen, cchMaxValueNameLen );
|
|
|
|
// allocate buffers
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
pszName = new WCHAR[cchMaxValueNameLen + 1];
|
|
if (NULL == pszName)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pszClass = new WCHAR[cchMaxClassLen + 1];
|
|
if (NULL == pszClass)
|
|
{
|
|
delete [] pszName;
|
|
break;
|
|
}
|
|
|
|
pbData = new BYTE[ cbMaxValueLen ];
|
|
if (NULL == pbData)
|
|
{
|
|
delete [] pszName;
|
|
delete [] pszClass;
|
|
break;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
// enum all sub keys and copy them
|
|
//
|
|
iItem = 0;
|
|
do
|
|
{
|
|
cchName = cchMaxValueNameLen + 1;
|
|
cchClass = cchMaxClassLen + 1;
|
|
|
|
// Enumerate the subkeys
|
|
hr = HrRegEnumKeyEx(hkeySrc,
|
|
iItem,
|
|
pszName,
|
|
&cchName,
|
|
pszClass,
|
|
&cchClass,
|
|
&ftLastWrite );
|
|
iItem++;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// create key at destination
|
|
// Note: (tongl 8/7/97): Netcfg common code sets class to NULL ??
|
|
hr = HrRegCreateKeyEx( hkeyDest,
|
|
pszName,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ_WRITE,
|
|
NULL,
|
|
&hkeyChildDest,
|
|
&dwDisposition );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// open the key at source
|
|
hr = HrRegOpenKeyEx(hkeySrc,
|
|
pszName,
|
|
KEY_READ_WRITE,
|
|
&hkeyChildSrc );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
RegSafeCloseKey(hkeyChildDest);
|
|
break;
|
|
}
|
|
|
|
// copy this sub-tree
|
|
hr = HrRegCopyKeyTree(hkeyChildDest, hkeyChildSrc);
|
|
|
|
RegSafeCloseKey(hkeyChildDest);
|
|
RegSafeCloseKey(hkeyChildSrc);
|
|
}
|
|
|
|
} while (S_OK == hr);
|
|
|
|
// We are done with the subkeys, now onto copying values
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
// enum completed, no errors
|
|
//
|
|
|
|
DWORD dwType;
|
|
// enum all values and copy them
|
|
//
|
|
iItem = 0;
|
|
do
|
|
{
|
|
cchName = cchMaxValueNameLen + 1;
|
|
cbData = cbMaxValueLen;
|
|
|
|
hr = HrRegEnumValue(hkeySrc,
|
|
iItem,
|
|
pszName,
|
|
&cchName,
|
|
&dwType,
|
|
pbData,
|
|
&cbData );
|
|
iItem++;
|
|
if (S_OK == hr)
|
|
{
|
|
// write the value to the destination
|
|
hr = HrRegSetValueEx(hkeyDest,
|
|
pszName,
|
|
dwType,
|
|
pbData,
|
|
cbData );
|
|
}
|
|
} while (S_OK == hr);
|
|
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
// if we hit the end of the enum without error
|
|
// reset error code to success
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
// free our buffers
|
|
delete [] pszName;
|
|
delete [] pszClass;
|
|
delete [] pbData;
|
|
} while ( FALSE );
|
|
|
|
TraceError("HrRegCopyKeyTree failed.", hr);
|
|
return( hr );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: fQueryFirstAddress
|
|
//
|
|
// Purpose: Retrieves the first string in a vector of strings
|
|
//
|
|
// Arguments:
|
|
// vstr [in] The vector of strings
|
|
// pstr [in] The first string
|
|
//
|
|
// Returns: TRUE if succeeded,
|
|
// FALSE otherwise
|
|
//
|
|
// Author: tongl 10 Nov 1997
|
|
//
|
|
// Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
|
|
//
|
|
|
|
BOOL fQueryFirstAddress(const VSTR & vstr, tstring * const pstr)
|
|
{
|
|
if(vstr.empty())
|
|
{
|
|
*pstr = L"";
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pstr = *vstr[0];
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: fQuerySecondAddress
|
|
//
|
|
// Purpose: Retrieves the first string in a vector of strings
|
|
//
|
|
// Arguments:
|
|
// vstr [in] The vector of strings
|
|
// pstr [in] The second string
|
|
//
|
|
// Returns: TRUE if succeeded,
|
|
// FALSE otherwise
|
|
//
|
|
// Author: tongl 10 Nov 1997
|
|
//
|
|
// Notes: Modified from NetSetupRegCopyTree in ncpa1.1\netcfg\setup.cpp
|
|
//
|
|
|
|
BOOL fQuerySecondAddress(const VSTR & vstr, tstring * const pstr)
|
|
{
|
|
if(vstr.size()<2)
|
|
{
|
|
*pstr = L"";
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pstr = *vstr[1];
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Function that decides whether a string is a valid ATM address
|
|
// Return TRUE if Valid, return FALSE and the index of the first
|
|
// invalid character if invalid.
|
|
BOOL FIsValidAtmAddress(PCWSTR pszAtmAddress,
|
|
INT * piErrCharPos,
|
|
INT * pnId)
|
|
{
|
|
const WCHAR * pch;
|
|
*piErrCharPos =0;
|
|
*pnId =0;
|
|
|
|
// 1. Validate characters must be '+' (first character),
|
|
// '.', or hex digits '0'~'F'
|
|
for (pch=pszAtmAddress; *pch; pch++)
|
|
{
|
|
if (!(((*pch == L'+') && (pch == pszAtmAddress))||
|
|
(*pch == L'.')||
|
|
(((*pch >= L'0') && (*pch <= L'9'))||
|
|
((*pch >= L'A') && (*pch <= L'F'))||
|
|
((*pch >= L'a') && (*pch <= L'f')))))
|
|
{
|
|
*piErrCharPos = pch - pszAtmAddress;
|
|
*pnId = IDS_ATM_INVALID_CHAR;
|
|
return FALSE;
|
|
}
|
|
|
|
if (*pch == L'.')
|
|
{
|
|
// '.' is for punctuation, so it should not be at the beginning,
|
|
// end or have two in a row
|
|
|
|
if ((pch == pszAtmAddress) ||
|
|
(pch == pszAtmAddress+lstrlenW(pszAtmAddress)-1) ||
|
|
(*pch == *(pch+1)))
|
|
{
|
|
*piErrCharPos = pch-pszAtmAddress;
|
|
*pnId = IDS_ATM_INVALID_CHAR;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Strip off all punctuation characters ('.' characters)
|
|
PWSTR pszBuff = new WCHAR[lstrlenW(pszAtmAddress)+1];
|
|
if (NULL == pszBuff)
|
|
return TRUE;
|
|
|
|
PWSTR pchBuff = pszBuff;
|
|
pch = pszAtmAddress;
|
|
|
|
for (pch = pszAtmAddress; *pch; pch++)
|
|
{
|
|
if (*pch != L'.')
|
|
{
|
|
*pchBuff = *pch;
|
|
pchBuff++;
|
|
}
|
|
}
|
|
|
|
*pchBuff = L'\0';
|
|
|
|
// 3. Decide whether the address is E.164 or NSAP
|
|
// and check syntax accordingly
|
|
|
|
if ((lstrlenW(pszBuff) <= 15) ||
|
|
((*pszBuff == L'+') && (lstrlenW(pszBuff) <= 16)))
|
|
{
|
|
// The address is E.164;
|
|
// Check if string is empty
|
|
if (*pchBuff == L'+')
|
|
{
|
|
pchBuff++;
|
|
|
|
if (lstrlenW(pchBuff) == 0) // empty string
|
|
{
|
|
*pnId = IDS_ATM_EMPTY_ADDRESS;
|
|
delete pszBuff;
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Check that all characters are in range '0' through '9'
|
|
// i.e. (ASCII values)
|
|
pch = pszAtmAddress;
|
|
if (*pch == L'+')
|
|
{
|
|
pch++;
|
|
}
|
|
|
|
while (*pch)
|
|
{
|
|
if ((*pch != L'.') &&
|
|
(!((*pch >= L'0') && (*pch <= L'9'))))
|
|
{
|
|
*piErrCharPos = pch-pszAtmAddress;
|
|
*pnId = IDS_ATM_INVALID_CHAR;
|
|
|
|
delete pszBuff;
|
|
return FALSE;
|
|
}
|
|
pch++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The address is NSAP;
|
|
if (lstrlenW(pszBuff) != 40)
|
|
{
|
|
*pnId = IDS_ATM_INVALID_LENGTH;
|
|
|
|
delete pszBuff;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
delete pszBuff;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FIsIpInRange(PCWSTR pszIp)
|
|
{
|
|
BOOL fReturn = TRUE;
|
|
DWORD ardwIp[4];
|
|
GetNodeNum(pszIp, ardwIp);
|
|
|
|
if ((ardwIp[0] > c_iIPADDR_FIELD_1_HIGH) ||
|
|
(ardwIp[0] < c_iIPADDR_FIELD_1_LOW))
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
VOID ShowContextHelp(HWND hDlg, UINT uCommand, const DWORD* pdwHelpIDs)
|
|
{
|
|
if (pdwHelpIDs != NULL)
|
|
{
|
|
WinHelp(hDlg,
|
|
c_szNetCfgHelpFile,
|
|
uCommand,
|
|
(ULONG_PTR)pdwHelpIDs);
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: AddInterfacesToAdapterInfo
|
|
//
|
|
// Purpose: Add several interfaces IDs into the interface list
|
|
//
|
|
// Arguments:
|
|
// pAdapter [in] Adapter info to add interfaces to
|
|
// dwNumInterfaces [in] Number of interface IDs to be added
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Author: nsun 22 August 1998
|
|
//
|
|
//
|
|
VOID AddInterfacesToAdapterInfo(
|
|
ADAPTER_INFO* pAdapter,
|
|
DWORD dwNumInterfaces)
|
|
{
|
|
DWORD i;
|
|
GUID guid;
|
|
|
|
for (i = 0; i < dwNumInterfaces; i++)
|
|
{
|
|
if (SUCCEEDED(CoCreateGuid(&guid)))
|
|
{
|
|
pAdapter->m_IfaceIds.push_back(guid);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: GetGuidArrayFromIfaceColWithCoTaskMemAlloc
|
|
//
|
|
// Purpose: Get the data as a DWORD array from a DWORD list.
|
|
// The caller is responsible to free the array by
|
|
// calling CoTaskMemFree()
|
|
//
|
|
// Arguments:
|
|
// ldw [in] The DWORD list
|
|
// ppdw [out] Pointer to the array
|
|
// pcguid [out] The count of guids placed in the array.
|
|
//
|
|
// Returns: S_OK
|
|
// E_OUTOFMEMORY
|
|
//
|
|
// Author: nsun 22 August 1998
|
|
//
|
|
//
|
|
HRESULT GetGuidArrayFromIfaceColWithCoTaskMemAlloc(
|
|
const IFACECOL& Ifaces,
|
|
GUID** ppguid,
|
|
DWORD* pcguid)
|
|
{
|
|
Assert(pcguid);
|
|
|
|
// Initialize output parameters
|
|
//
|
|
if (ppguid)
|
|
{
|
|
*ppguid = NULL;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD cguid = Ifaces.size();
|
|
|
|
if ((cguid > 0) && ppguid)
|
|
{
|
|
GUID* pguid = (GUID*)CoTaskMemAlloc(cguid * sizeof(GUID));
|
|
if (pguid)
|
|
{
|
|
*ppguid = pguid;
|
|
*pcguid = cguid;
|
|
|
|
IFACECOL::const_iterator iter;
|
|
for (iter = Ifaces.begin();
|
|
iter != Ifaces.end();
|
|
iter++)
|
|
{
|
|
*(pguid++) = *iter;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Caller just wants the count.
|
|
//
|
|
*pcguid = 0;
|
|
}
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE, "GetGuidArrayFromIfaceColWithCoTaskMemAlloc");
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: GetInterfaceName
|
|
//
|
|
// Purpose: Get the interface name as <Adapter name>_<interface ID>
|
|
// to support multiple interface for WAN adapters.
|
|
//
|
|
// Arguments:
|
|
// pszAdapterName [in] The adapter name
|
|
// guidIfaceId [in] The interface ID
|
|
// pstrIfaceName [out] The interface name
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Author: nsun 12 Sept 1998
|
|
//
|
|
// Note: This function is also used to construct NetBt binding
|
|
// interface names from NetBt binding path
|
|
//
|
|
VOID GetInterfaceName(
|
|
PCWSTR pszAdapterName,
|
|
const GUID& guidIfaceId,
|
|
tstring* pstrIfaceName)
|
|
{
|
|
Assert(pszAdapterName);
|
|
Assert(pstrIfaceName);
|
|
|
|
WCHAR pszGuid [c_cchGuidWithTerm];
|
|
|
|
StringFromGUID2 (guidIfaceId, pszGuid, c_cchGuidWithTerm);
|
|
|
|
// pstrIfaceName->assign(pszAdapterName);
|
|
// pstrIfaceName->append(pszGuid);
|
|
pstrIfaceName->assign(pszGuid);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: RetrieveStringFromOptionList
|
|
//
|
|
// Purpose: Retrieve a substring from the option list of REMOTE_IPINFO
|
|
//
|
|
//
|
|
// Arguments:
|
|
// pszOption [in] The string of option list
|
|
// szIdentifier [in] The identifier of the substring to retrieve
|
|
// str [out] The substring
|
|
//
|
|
// Returns: S_OK
|
|
// HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
|
// E_INVALIDARG
|
|
//
|
|
// Author: nsun 01/11/99
|
|
//
|
|
//
|
|
HRESULT RetrieveStringFromOptionList(PCWSTR pszOption,
|
|
PCWSTR szIdentifier,
|
|
tstring & str)
|
|
{
|
|
Assert(szIdentifier);
|
|
|
|
HRESULT hr = S_OK;
|
|
WCHAR* pszBegin;
|
|
WCHAR* pszEnd;
|
|
PWSTR pszString = NULL;
|
|
|
|
str = c_szEmpty;
|
|
|
|
if (!pszOption)
|
|
{
|
|
goto LERROR;
|
|
}
|
|
|
|
pszBegin = wcsstr(pszOption, szIdentifier);
|
|
if (!pszBegin)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
goto LERROR;
|
|
}
|
|
|
|
pszString = (PWSTR) MemAlloc((wcslen(pszOption)+1) * sizeof(WCHAR));
|
|
if (NULL == pszString)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LERROR;
|
|
}
|
|
|
|
pszBegin += wcslen(szIdentifier);
|
|
|
|
wcscpy(pszString, pszBegin);
|
|
|
|
pszEnd = wcschr(pszString, c_chOptionSeparator);
|
|
if(!pszEnd)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
//set the end of the string
|
|
*pszEnd = 0;
|
|
str = pszString;
|
|
}
|
|
|
|
LERROR:
|
|
|
|
//it's ok to MemFree(NULL)
|
|
MemFree(pszString);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: ConstructOptionListString
|
|
//
|
|
// Purpose: Construct the option list of REMOTE_IPINFO
|
|
//
|
|
//
|
|
// Arguments:
|
|
// pAdapter [in] Pointer to info of the adapter
|
|
// strOptionList [out] The OptionList string
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Author: nsun 01/12/99
|
|
//
|
|
// Note: Syntax of the Option list:
|
|
// "<Identifier><data>;<Identifier><data>;...;"
|
|
// The order of identifiers does not matter.
|
|
//
|
|
// Example:
|
|
// "DefGw=111.111.111.111,222.222.222.222;GwMetric=1,2;IfMetric=1;DNS=1.1.1.1;WINS=2.2.2.2"
|
|
//
|
|
VOID ConstructOptionListString(ADAPTER_INFO* pAdapter,
|
|
tstring & strOptionList)
|
|
{
|
|
Assert(pAdapter);
|
|
|
|
strOptionList = c_szEmpty;
|
|
|
|
//add gateway list
|
|
tstring str = c_szEmpty;
|
|
tstring strGatewayList = c_szDefGw;
|
|
ConvertColStringToString(pAdapter->m_vstrDefaultGateway,
|
|
c_chListSeparator,
|
|
str);
|
|
strGatewayList += str;
|
|
strOptionList += strGatewayList;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
//add gateway metric list
|
|
tstring strMetricList = c_szGwMetric;
|
|
str = c_szEmpty;
|
|
ConvertColStringToString(pAdapter->m_vstrDefaultGatewayMetric,
|
|
c_chListSeparator,
|
|
str);
|
|
strMetricList += str;
|
|
strOptionList += strMetricList;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
//add interface metric info to option list
|
|
strOptionList += c_szIfMetric;
|
|
WCHAR szBuf[MAX_METRIC_DIGITS + 1];
|
|
_ltot(pAdapter->m_dwInterfaceMetric, szBuf, 10);
|
|
strOptionList += szBuf;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
//add DNS server list
|
|
strOptionList += c_szDNS;
|
|
str = c_szEmpty;
|
|
ConvertColStringToString(pAdapter->m_vstrDnsServerList,
|
|
c_chListSeparator,
|
|
str);
|
|
strOptionList += str;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
//add WINS server list
|
|
strOptionList += c_szWINS;
|
|
str = c_szEmpty;
|
|
ConvertColStringToString(pAdapter->m_vstrWinsServerList,
|
|
c_chListSeparator,
|
|
str);
|
|
strOptionList += str;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
//add DNS update parameters
|
|
strOptionList += c_szDynamicUpdate;
|
|
ZeroMemory(szBuf, sizeof(szBuf));
|
|
_ltot(pAdapter->m_fDisableDynamicUpdate ? 0 : 1, szBuf, 10);
|
|
strOptionList += szBuf;
|
|
strOptionList += c_chOptionSeparator;
|
|
|
|
strOptionList += c_szNameRegistration;
|
|
ZeroMemory(szBuf, sizeof(szBuf));
|
|
_ltot(pAdapter->m_fEnableNameRegistration ? 1 : 0, szBuf, 10);
|
|
strOptionList += szBuf;
|
|
strOptionList += c_chOptionSeparator;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: HrParseOptionList
|
|
//
|
|
// Purpose: Parse the option list string of REMOTE_IPINFO and load the
|
|
// settings to the adapter info struct
|
|
//
|
|
// Arguments:
|
|
// pszOption [in] The OptionList string
|
|
// pAdapter [in/out] Pointer to info of the adapter
|
|
//
|
|
// Returns: S_OK if succeed
|
|
// Otherwise, the hresult error
|
|
//
|
|
// Author: nsun 07/11/99
|
|
//
|
|
//
|
|
HRESULT HrParseOptionList(PCWSTR pszOption,
|
|
ADAPTER_INFO* pAdapter)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
Assert(pAdapter);
|
|
|
|
if (NULL == pszOption)
|
|
return hr;
|
|
|
|
HRESULT hrTmp = S_OK;
|
|
|
|
tstring str;
|
|
DWORD dwTemp = 0;
|
|
|
|
//Get default gateways
|
|
hr = RetrieveStringFromOptionList(pszOption,
|
|
c_szDefGw,
|
|
str);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ConvertStringToColString(str.c_str(),
|
|
c_chListSeparator,
|
|
pAdapter->m_vstrDefaultGateway);
|
|
|
|
|
|
//Get gateway metrics
|
|
hr = RetrieveStringFromOptionList(pszOption,
|
|
c_szGwMetric,
|
|
str);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ConvertStringToColString(str.c_str(),
|
|
c_chListSeparator,
|
|
pAdapter->m_vstrDefaultGatewayMetric);
|
|
}
|
|
}
|
|
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
//the option list doesn't have to have any of the tags
|
|
hr = S_OK;
|
|
}
|
|
|
|
//Get interface metric
|
|
hrTmp = RetrieveStringFromOptionList(pszOption,
|
|
c_szIfMetric,
|
|
str);
|
|
if(SUCCEEDED(hrTmp) && !str.empty())
|
|
{
|
|
DWORD dwIfMetric = _wtol(str.c_str());
|
|
pAdapter->m_dwInterfaceMetric = dwIfMetric;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
|
|
{
|
|
hrTmp = S_OK;
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = hrTmp;
|
|
|
|
//Get DNS servers
|
|
hrTmp = RetrieveStringFromOptionList(pszOption,
|
|
c_szDNS,
|
|
str);
|
|
if (SUCCEEDED(hrTmp))
|
|
{
|
|
ConvertStringToColString(str.c_str(),
|
|
c_chListSeparator,
|
|
pAdapter->m_vstrDnsServerList);
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
|
|
{
|
|
hrTmp = S_OK;
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = hrTmp;
|
|
|
|
//Get WINS servers
|
|
hrTmp = RetrieveStringFromOptionList(pszOption,
|
|
c_szWINS,
|
|
str);
|
|
if (SUCCEEDED(hrTmp))
|
|
{
|
|
ConvertStringToColString(str.c_str(),
|
|
c_chListSeparator,
|
|
pAdapter->m_vstrWinsServerList);
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
|
|
{
|
|
hrTmp = S_OK;
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = hrTmp;
|
|
|
|
//Get DNS dynamic update parameters
|
|
hrTmp = RetrieveStringFromOptionList(pszOption,
|
|
c_szDynamicUpdate,
|
|
str);
|
|
if (SUCCEEDED(hrTmp))
|
|
{
|
|
dwTemp = _wtol(str.c_str());
|
|
pAdapter->m_fDisableDynamicUpdate = !dwTemp;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
|
|
{
|
|
hrTmp = S_OK;
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = hrTmp;
|
|
|
|
|
|
hrTmp = RetrieveStringFromOptionList(pszOption,
|
|
c_szNameRegistration,
|
|
str);
|
|
if (SUCCEEDED(hrTmp))
|
|
{
|
|
dwTemp = _wtol(str.c_str());
|
|
pAdapter->m_fEnableNameRegistration = !!dwTemp;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrTmp)
|
|
{
|
|
hrTmp = S_OK;
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = hrTmp;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: HrGetPrimaryDnsDomain
|
|
//
|
|
// Purpose: Get the Primary Dns Domain name
|
|
//
|
|
//
|
|
// Arguments:
|
|
// pstr [out] The string contains the Primary Dns Domain name
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Author: nsun 03/03/99
|
|
HRESULT HrGetPrimaryDnsDomain(tstring *pstr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(pstr);
|
|
|
|
DWORD dwErr;
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
|
|
|
|
|
|
dwErr = DsRoleGetPrimaryDomainInformation( NULL,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *) &pPrimaryDomainInfo);
|
|
if (ERROR_SUCCESS == dwErr && NULL != pPrimaryDomainInfo )
|
|
{
|
|
if (pPrimaryDomainInfo->DomainNameDns)
|
|
*pstr = pPrimaryDomainInfo->DomainNameDns;
|
|
else
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
|
|
DsRoleFreeMemory(pPrimaryDomainInfo);
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
|
|
TraceError("CTcpipcfg::HrGetPrimaryDnsDomain:", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Name: WriteSetupErrorLog
|
|
//
|
|
// Purpose: Write an error to setuperr.log
|
|
//
|
|
//
|
|
// Arguments:
|
|
// nIdErrorFormat [in] The ID of the error format string
|
|
//
|
|
// Returns: None, but Error trace will be generated if fails to write setup
|
|
// error log
|
|
//
|
|
// Author: nsun 03/21/99
|
|
VOID WriteTcpSetupErrorLog(UINT nIdErrorFormat, ...)
|
|
{
|
|
PCWSTR pszFormat = SzLoadIds(nIdErrorFormat);
|
|
|
|
PWSTR pszText = NULL;
|
|
DWORD dwRet;
|
|
|
|
va_list val;
|
|
va_start(val, nIdErrorFormat);
|
|
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
pszFormat, 0, 0, (PWSTR)&pszText, 0, &val);
|
|
va_end(val);
|
|
|
|
if (dwRet && pszText)
|
|
{
|
|
tstring strMsg = L"";
|
|
|
|
//Add the current time at the begining of the error log
|
|
time_t tclock;
|
|
time(&tclock);
|
|
|
|
struct tm * ptmLocalTime;
|
|
ptmLocalTime = localtime(&tclock);
|
|
|
|
if (ptmLocalTime)
|
|
{
|
|
LPWSTR pwsz = _wasctime(ptmLocalTime);
|
|
if (pwsz)
|
|
{
|
|
strMsg = pwsz;
|
|
}
|
|
}
|
|
|
|
strMsg += pszText;
|
|
|
|
if (!SetupLogError(strMsg.c_str(), LogSevError))
|
|
{
|
|
TraceError("Tcpip: WriteSetupErrorLog", HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
LocalFree(pszText);
|
|
}
|
|
else
|
|
{
|
|
TraceError("Tcpip: WriteSetupErrorLog: unable to FormatMessage()", HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
|
|
DWORD IPStringToDword(LPCTSTR szIP)
|
|
{
|
|
if (NULL == szIP || 0 == lstrlenW(szIP))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
DWORD arrdwIp[4];
|
|
GetNodeNum(szIP, arrdwIp);
|
|
|
|
return (arrdwIp[0] << 24) + (arrdwIp[1] << 16)
|
|
+ (arrdwIp[2] << 8) + arrdwIp[3];
|
|
}
|
|
|
|
void DwordToIPString(DWORD dwIP, tstring & strIP)
|
|
{
|
|
if (0 == dwIP)
|
|
{
|
|
strIP = c_szEmpty;
|
|
return;
|
|
}
|
|
|
|
WCHAR szTemp[4];
|
|
|
|
wsprintf(szTemp, L"%d", dwIP >> 24);
|
|
strIP = szTemp;
|
|
strIP += CH_DOT;
|
|
|
|
wsprintf(szTemp, L"%d", (dwIP & 0x00FF0000) >> 16);
|
|
strIP += szTemp;
|
|
strIP += CH_DOT;
|
|
|
|
wsprintf(szTemp, L"%d", (dwIP & 0x0000FF00) >> 8);
|
|
strIP += szTemp;
|
|
strIP += CH_DOT;
|
|
|
|
wsprintf(szTemp, L"%d", (dwIP & 0x000000FF));
|
|
strIP += szTemp;
|
|
|
|
return;
|
|
}
|
|
|
|
//Seach a List view for an item contains the specified string
|
|
//Arguments:
|
|
// hListView [IN] Handle to the list view
|
|
// iSubItem [IN] Subitem to search
|
|
// psz [IN] The string to search
|
|
//Return
|
|
// -1 if no items are found
|
|
// otherwise the index of the first item matching the string
|
|
//
|
|
int SearchListViewItem(HWND hListView, int iSubItem, LPCWSTR psz)
|
|
{
|
|
int iRet = -1;
|
|
int nlvCount = ListView_GetItemCount(hListView);
|
|
|
|
WCHAR szBuf[256];
|
|
|
|
LV_ITEM lvItem;
|
|
lvItem.mask = LVIF_TEXT;
|
|
lvItem.pszText = szBuf;
|
|
lvItem.cchTextMax = celems(szBuf);
|
|
|
|
for (int i = 0; i < nlvCount; i++)
|
|
{
|
|
lvItem.iItem = i;
|
|
lvItem.iSubItem = iSubItem;
|
|
ListView_GetItem(hListView, &lvItem);
|
|
|
|
if (lstrcmpiW(psz, szBuf) == 0)
|
|
{
|
|
iRet = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
} |