Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2430 lines
64 KiB

// ATlkObj.cpp : Implementation of CATlkObj
#include "pch.h"
#pragma hdrstop
#include <atalkwsh.h>
#include "atlkobj.h"
#include "ncatlui.h"
#include "ncmisc.h"
#include "ncreg.h"
#include "ncpnp.h"
#include "ncsvc.h"
#include <netconp.h>
extern const WCHAR c_szAdapterSections[];
//extern const WCHAR c_szAdapters[];
extern const WCHAR c_szBackslash[];
extern const WCHAR c_szDevice[];
extern const WCHAR c_szSpecificTo[];
extern const WCHAR c_szInfId_MS_NdisWanAtalk[];
extern const WCHAR c_szEmpty[];
// Registry Paths
static const WCHAR c_szAtlk[] = L"AppleTalk";
static const WCHAR c_szATLKParameters[] = L"System\\CurrentControlSet\\Services\\AppleTalk\\Parameters";
static const WCHAR c_szATLKAdapters[] = L"System\\CurrentControlSet\\Services\\AppleTalk\\Parameters\\Adapters";
// Values under the Adapter component's "Parameters" key
static const WCHAR c_szMediaType[] = L"MediaType"; //$ REVIEW duplicate string
// Values under AppleTalk\Parameters
static const WCHAR c_szDefaultPort[] = L"DefaultPort"; // REG_SZ
static const WCHAR c_szDesiredZone[] = L"DesiredZone"; // REG_SZ
static const WCHAR c_szEnableRouter[] = L"EnableRouter"; // REG_DWORD
// Values under AppleTalk\Parameters\Adapters\<AdapterId>
static const WCHAR c_szAarpRetries[] = L"AarpRetries"; // REG_DWORD
static const WCHAR c_szDdpCheckSums[] = L"DdpCheckSums"; // REG_DWORD
static const WCHAR c_szDefaultZone[] = L"DefaultZone"; // REG_SZ
static const WCHAR c_szNetworkRangeLowerEnd[] = L"NetworkRangeLowerEnd";// REG_DWORD
static const WCHAR c_szNetworkRangeUpperEnd[] = L"NetworkRangeUpperEnd";// REG_DWORD
static const WCHAR c_szPortName[] = L"PortName"; // REG_SZ
static const WCHAR c_szRouterPramNode[] = L"RouterPramNode"; // REG_DWORD
static const WCHAR c_szSeedingNetwork[] = L"SeedingNetwork"; // REG_DWORD
static const WCHAR c_szUserPramNode1[] = L"UserPramNode1"; // REG_DWORD
static const WCHAR c_szUserPramNode2[] = L"UserPramNode2"; // REG_DWORD
static const WCHAR c_szZoneList[] = L"ZoneList"; // REG_MULTI_SZ
// Useful default constant
const WCHAR c_chAt = L'@';
static const WCHAR c_dwZero = 0L;
static const WCHAR c_dwTen = 10L;
//static const WCHAR c_szMacPrint[] = L"MacPrint";
// Declare structure for reading/writing AppleTalk\Parameters values
static const REGBATCH regbatchATLKParams[] = {
{HKEY_LOCAL_MACHINE, c_szATLKParameters, c_szDefaultPort, REG_SZ,
offsetof(ATLK_PARAMS,szDefaultPort), (BYTE *)&c_szEmpty},
{HKEY_LOCAL_MACHINE, c_szATLKParameters, c_szDesiredZone, REG_SZ,
offsetof(ATLK_PARAMS,szDesiredZone), (BYTE *)&c_szEmpty},
{HKEY_LOCAL_MACHINE, c_szATLKParameters, c_szEnableRouter, REG_DWORD,
offsetof(ATLK_PARAMS,dwEnableRouter), (BYTE *)&c_szEmpty}};
static const REGBATCH regbatchATLKAdapters[] = {
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szAarpRetries, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwAarpRetries), (BYTE *)&c_dwTen},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szDdpCheckSums, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwDdpCheckSums), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szNetworkRangeLowerEnd, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwNetworkRangeLowerEnd), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szNetworkRangeUpperEnd, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwNetworkRangeUpperEnd), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szRouterPramNode, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwRouterPramNode), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szSeedingNetwork, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwSeedingNetwork), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szUserPramNode1, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwUserPramNode1), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szUserPramNode2, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwUserPramNode2), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szMediaType, REG_DWORD,
offsetof(ATLK_ADAPTER,m_dwMediaType), (BYTE *)&c_dwZero},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szDefaultZone, REG_SZ,
offsetof(ATLK_ADAPTER,m_szDefaultZone), (BYTE *)&c_szEmpty},
{HKEY_LOCAL_MACHINE, c_szEmpty, c_szPortName, REG_SZ,
offsetof(ATLK_ADAPTER,m_szPortName), (BYTE *)&c_szEmpty}};
// Local utility functions
HRESULT HrQueryAdapterComponentInfo(INetCfgComponent *pncc,
CAdapterInfo * pAI);
HRESULT HrPortNameFromAdapter(INetCfgComponent *pncc, tstring * pstr);
// Prototype from nwlnkcfg\nwlnkutl.h
HRESULT HrAnswerFileAdapterToPNCC(INetCfg *pnc, PCWSTR pszAdapterId,
INetCfgComponent** ppncc);
//
// Function: CATlkObj::CATlkObj
//
// Purpose: ctor for the CATlkObj class
//
// Parameters: none
//
// Returns: none
//
CATlkObj::CATlkObj() : m_pNetCfg(NULL),
m_pNCC(NULL),
m_eInstallAction(eActUnknown),
m_pspObj(NULL),
m_pATLKEnv(NULL),
m_pATLKEnv_PP(NULL),
m_pUnkPropContext(NULL),
m_nIdxAdapterSelected(CB_ERR),
m_fAdapterListChanged(FALSE),
m_fPropertyChange(FALSE),
m_fFirstTimeInstall(FALSE)
{
}
//
// Function: CATlkObj::CATlkObj
//
// Purpose: dtor for the CATlkObj class
//
// Parameters: none
//
// Returns: none
//
CATlkObj::~CATlkObj()
{
// Should always be cleaned up in advance of reach this dtor
Assert(NULL == m_pATLKEnv_PP);
ReleaseObj(m_pUnkPropContext);
ReleaseObj(m_pNetCfg);
ReleaseObj(m_pNCC);
CleanupPropPages();
delete m_pATLKEnv;
}
// INetCfgNotify
STDMETHODIMP CATlkObj::Initialize ( INetCfgComponent* pnccItem,
INetCfg* pNetCfg, BOOL fInstalling )
{
Validate_INetCfgNotify_Initialize(pnccItem, pNetCfg, fInstalling);
ReleaseObj(m_pNCC);
m_pNCC = pnccItem;
AddRefObj(m_pNCC);
ReleaseObj(m_pNetCfg);
m_pNetCfg = pNetCfg;
AddRefObj(m_pNetCfg);
m_fFirstTimeInstall = fInstalling;
// Read the current configuration
HRESULT hr = CATLKEnv::HrCreate(&m_pATLKEnv, this);
TraceError("CATlkObj::Initialize",hr);
return hr;
}
STDMETHODIMP CATlkObj::ReadAnswerFile(PCWSTR pszAnswerFile,
PCWSTR pszAnswerSection )
{
Validate_INetCfgNotify_ReadAnswerFile(pszAnswerFile, pszAnswerSection );
HRESULT hr = S_OK;
m_eInstallAction = eActInstall;
// Only process answer file and install sub-components if the answer file
// is present. If the answer file is not present we should already be installed.
if (NULL != pszAnswerFile)
{
hr = HrProcessAnswerFile(pszAnswerFile, pszAnswerSection);
}
TraceError("CATlkObj::ReadAnswerFile",hr);
return hr;
}
//
// Function: CATlkObj::HrProcessAnswerFile
//
// Purpose: Process the answer file information, merging
// its contents into the internal information
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATlkObj::HrProcessAnswerFile(PCWSTR pszAnswerFile,
PCWSTR pszAnswerSection)
{
TraceFileFunc(ttidDefault);
CSetupInfFile csif;
BOOL fValue;
HRESULT hr = S_OK;
INFCONTEXT infctx;
tstring str;
AssertSz(pszAnswerFile, "Answer file string is NULL!");
AssertSz(pszAnswerSection, "Answer file sections string is NULL!");
// Open the answer file.
hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
if (FAILED(hr))
{
goto Error;
}
// Read the property containing the list of adapter sections
hr = ::HrSetupFindFirstLine(csif.Hinf(), pszAnswerSection,
c_szAdapterSections, &infctx);
if (S_OK == hr)
{
DWORD dwIdx;
DWORD dwCnt = SetupGetFieldCount(&infctx);
// For each adapter in the list read the adapter information
for (dwIdx=1; dwIdx <= dwCnt; dwIdx++)
{
hr = ::HrSetupGetStringField(infctx, dwIdx, &str);
if (FAILED(hr))
{
TraceError("CATlkObj::HrProcessAnswerFile - Failed to read adapter section name",hr);
break;
}
hr = HrReadAdapterAnswerFileSection(&csif, str.c_str());
if (FAILED(hr))
{
goto Error;
}
}
}
TraceTag(ttidDefault, "***Appletalk processing default port***");
// Read the default port property (REG_SZ)
hr = csif.HrGetString(pszAnswerSection, c_szDefaultPort, &str);
if (SUCCEEDED(hr))
{
tstring strNew = str;
// If the \device\ prefix is present, strip it off
//
if (0 == _wcsnicmp(str.c_str(), c_szDevice, wcslen(c_szDevice)))
{
strNew = ((PWSTR)str.c_str()) + wcslen(c_szDevice);
TraceTag(ttidDefault, "Removing the device prefix. Device=%S",strNew.c_str());
}
// Convert the Adapter0x to \Device\{bind-name}
INetCfgComponent* pncc = NULL;
hr = ::HrAnswerFileAdapterToPNCC(PNetCfg(), strNew.c_str(), &pncc);
if (S_OK == hr)
{
PWSTR pszBindName;
hr = pncc->GetBindName(&pszBindName);
ReleaseObj(pncc);
if (FAILED(hr))
{
goto Error;
}
str = c_szDevice;
str += pszBindName;
CoTaskMemFree(pszBindName);
TraceTag(ttidDefault, "Port located and configured");
m_pATLKEnv->SetDefaultPort(str.c_str());
}
}
TraceTag(ttidDefault, "***Appletalk finished processing default port***");
// Read the default zone property (REG_SZ)
hr = csif.HrGetString(pszAnswerSection, c_szDesiredZone, &str);
if (SUCCEEDED(hr))
{
m_pATLKEnv->SetDesiredZone(str.c_str());
}
// Read the EnableRouter property (DWORD used as a boolean)
hr = csif.HrGetStringAsBool(pszAnswerSection, c_szEnableRouter, &fValue);
if (SUCCEEDED(hr))
{
m_pATLKEnv->EnableRouting(fValue);
}
// Determine the best default port overriding the recorded default only
// if the default port cannot be found
m_pATLKEnv->InitDefaultPort();
hr = S_OK;
m_fPropertyChange = TRUE;
Error:
TraceError("CATlkObj::HrProcessAnswerFile", hr);
return hr;
}
//
// Function: CATlkObj::HrReadAdapterAnswerFileSection
//
// Purpose: Read the adapter answer file section and create
// the adapter info section if successful
//
// Parameters:
//
// Returns:
//
HRESULT
CATlkObj::HrReadAdapterAnswerFileSection(CSetupInfFile * pcsif,
PCWSTR pszSection)
{
HRESULT hr = S_OK;
CAdapterInfo * pAI = NULL;
tstring str;
INetCfgComponent* pncc = NULL;
// Read the SpecificTo adapter name
hr = pcsif->HrGetString(pszSection, c_szSpecificTo, &str);
if (FAILED(hr))
{
goto Error;
}
// Search for the specified adapter in the set of existing adapters
hr = ::HrAnswerFileAdapterToPNCC(PNetCfg(), str.c_str(), &pncc);
if (FAILED(hr))
{
goto Error;
}
// if we found the adapter component object (pncc != NULL) process
// the adapter section
if (pncc)
{
DWORD dwData;
DWORD dwDataUpper;
INFCONTEXT infctx;
pAI = new CAdapterInfo();
Assert(NULL != pAI);
pAI->SetDirty(TRUE);
// Get the adapter component info (media type, description, ...)
hr = ::HrQueryAdapterComponentInfo(pncc, pAI);
if (FAILED(hr))
{
goto Error;
}
// Read the NetworkRangeUpperEnd
hr = pcsif->HrGetDword(pszSection, c_szNetworkRangeUpperEnd, &dwDataUpper);
if (FAILED(hr))
{
dwDataUpper = pAI->DwQueryNetRangeUpper();
TraceTag(ttidDefault, "CATlkObj::HrReadAdapterAnswerFileSection - Defaulting property %S",c_szNetworkRangeUpperEnd);
}
// Read the NetworkRangeLowerEnd
hr = pcsif->HrGetDword(pszSection, c_szNetworkRangeLowerEnd, &dwData);
if (FAILED(hr))
{
dwData = pAI->DwQueryNetRangeLower();
TraceTag(ttidDefault, "CATlkObj::HrReadAdapterAnswerFileSection - Defaulting property %S",c_szNetworkRangeLowerEnd);
}
pAI->SetAdapterNetRange(dwData, dwDataUpper);
// Read the DefaultZone
hr = pcsif->HrGetString(pszSection, c_szDefaultZone, &str);
if (SUCCEEDED(hr))
{
pAI->SetDefaultZone(str.c_str());
}
// Read the SeedingNetwork
hr = pcsif->HrGetDword(pszSection, c_szNetworkRangeLowerEnd, &dwData);
if (SUCCEEDED(hr))
{
pAI->SetSeedingNetwork(!!dwData);
}
// Generate the PortName
hr = ::HrPortNameFromAdapter(pncc, &str);
if (FAILED(hr))
{
goto Error;
}
pAI->SetPortName(str.c_str());
// Read the ZoneList
hr = HrSetupFindFirstLine(pcsif->Hinf(), pszSection, c_szZoneList,
&infctx);
if (S_OK == hr)
{
DWORD dwIdx;
DWORD dwCnt = SetupGetFieldCount(&infctx);
// For each adapter in the list read the adapter information
for (dwIdx=1; dwIdx <= dwCnt; dwIdx++)
{
hr = ::HrSetupGetStringField(infctx, dwIdx, &str);
if (FAILED(hr))
{
TraceError("CATlkObj::HrProcessAnswerFile - Failed to read adapter section name",hr);
goto Error;
}
if (!str.empty())
{
pAI->LstpstrZoneList().push_back(new tstring(str));
}
}
}
pAI->SetDirty(TRUE);
m_pATLKEnv->AdapterInfoList().push_back(pAI);
MarkAdapterListChanged();
}
// Normalize any errors
hr = S_OK;
Done:
ReleaseObj(pncc);
return hr;
Error:
delete pAI;
TraceError("CATlkObj::HrReadAdapterAnswerFileSection",hr);
goto Done;
}
STDMETHODIMP CATlkObj::Install (DWORD)
{
CAdapterInfo * pAI;
ATLK_ADAPTER_INFO_LIST::iterator iter;
m_eInstallAction = eActInstall;
// Mark all the initially detected adapters as dirty
for (iter = m_pATLKEnv->AdapterInfoList().begin();
iter != m_pATLKEnv->AdapterInfoList().end();
iter++)
{
pAI = *iter;
pAI->SetDirty(TRUE);
}
return S_OK;
}
STDMETHODIMP CATlkObj::Removing ()
{
m_eInstallAction = eActRemove;
return S_OK;
}
STDMETHODIMP CATlkObj::Validate ()
{
return S_OK;
}
STDMETHODIMP CATlkObj::CancelChanges ()
{
return S_OK;
}
STDMETHODIMP CATlkObj::ApplyRegistryChanges ()
{
HRESULT hr = S_OK;
// Have any changes been validated?
switch(m_eInstallAction)
{
case eActInstall:
hr = HrCommitInstall();
if (SUCCEEDED(hr))
{
m_fFirstTimeInstall = FALSE;
hr = HrAtlkReconfig();
}
break;
case eActRemove:
hr = HrCommitRemove();
break;
default: // eActUnknown
if (m_fAdapterListChanged || m_fPropertyChange)
{
// Update the registry if the adapter list changed
Assert(NULL != m_pATLKEnv);
hr = m_pATLKEnv->HrUpdateRegistry();
if (SUCCEEDED(hr))
{
hr = HrAtlkReconfig();
}
}
break;
}
TraceError("CATlkObj::ApplyRegistryChanges",hr);
return hr;
}
// INetCfgProperties
STDMETHODIMP CATlkObj::SetContext(IUnknown * pUnk)
{
ReleaseObj(m_pUnkPropContext);
m_pUnkPropContext = pUnk;
if (m_pUnkPropContext)
{
AddRefObj(m_pUnkPropContext);
}
return S_OK;
}
STDMETHODIMP CATlkObj::MergePropPages (
IN OUT DWORD* pdwDefPages,
OUT LPBYTE* pahpspPrivate,
OUT UINT* pcPages,
IN HWND hwndParent,
OUT PCWSTR* pszStartPage)
{
Validate_INetCfgProperties_MergePropPages (
pdwDefPages, pahpspPrivate, pcPages, hwndParent, pszStartPage);
HRESULT hr = S_OK;
HPROPSHEETPAGE *ahpsp = NULL;
CAdapterInfo * pAI = NULL;
Assert(pahpspPrivate);
Assert(NULL == *pahpspPrivate); // Out param init done via Validate above
*pcPages = 0;
Assert(NULL != m_pATLKEnv);
if (NULL != m_pATLKEnv_PP)
{
TraceError("CATlkObj::MergePropPages - multiple property page instances requested.", hr);
return E_UNEXPECTED;
}
// AppleTalk requires "complete" installation before property changes are
// allowed. If we've just installed but Apply has not yet been pressed,
// disallow property page display
if (m_fFirstTimeInstall)
{
NcMsgBox(::GetFocus(), IDS_ATLK_CAPTION, IDS_ATLK_INSTALL_PENDING,
MB_OK | MB_ICONEXCLAMATION);
return S_FALSE;
}
// Start with new property pages each time.
CleanupPropPages();
// Locate the adapter referenced in the connection we stashed away
if (NULL != m_pUnkPropContext)
{
INetLanConnectionUiInfo * pLanConn = NULL;
ATLK_ADAPTER_INFO_LIST::iterator iter;
hr = m_pUnkPropContext->QueryInterface(IID_INetLanConnectionUiInfo,
reinterpret_cast<LPVOID *>(&pLanConn));
if (S_OK == hr)
{
GUID guid;
hr = pLanConn->GetDeviceGuid(&guid);
ReleaseObj(pLanConn);
if (SUCCEEDED(hr))
{
// Find the adapter in our adapter list
for (iter = m_pATLKEnv->AdapterInfoList().begin();
iter != m_pATLKEnv->AdapterInfoList().end();
iter++)
{
CAdapterInfo * pAITmp = *iter;
if (guid == *pAITmp->PInstanceGuid())
{
// Copy the adapter data
hr = pAITmp->HrCopy(&pAI);
break;
}
}
}
}
if (SUCCEEDED(hr))
{
// If no adapter in this connection or it's
// disabled/hidden/deleted we show no pages
if ((NULL == pAI) || pAI->FDeletePending() ||
pAI->FDisabled() || pAI->FHidden())
{
Assert(0 == *pcPages);
hr = S_FALSE;
goto cleanup;
}
}
}
else
{
// m_pUnkPropContext should have been set first
hr = E_UNEXPECTED;
}
if (FAILED(hr))
{
goto Error;
}
// Create a copy of the enviroment for property page usage
hr = m_pATLKEnv->HrCopy(&m_pATLKEnv_PP);
if (FAILED(hr))
{
goto Error;
}
Assert(NULL != m_pATLKEnv_PP);
Assert(NULL != pAI);
// Query the zonelist every time, only for non-Seeding adapters.
if (!pAI->FSeedingNetwork() || !m_pATLKEnv_PP->FRoutingEnabled())
{
(void) m_pATLKEnv->HrGetAppleTalkInfoFromNetwork(pAI);
}
// Add the adapter to the property sheet's list
m_pATLKEnv_PP->AdapterInfoList().push_back(pAI);
// Allocate the CPropSheetPage object for the "General" page
m_pspObj = new CATLKGeneralDlg(this, m_pATLKEnv_PP);
// Allocate a buffer large enough to hold the handle to the Appletalk config.
// property page.
ahpsp = (HPROPSHEETPAGE *)CoTaskMemAlloc(sizeof(HPROPSHEETPAGE));
if (!ahpsp)
{
hr = E_OUTOFMEMORY;
goto cleanup; // Alloc failed to no need to free ahpsp
}
// Create the actual PROPSHEETPAGE for each object.
ahpsp[0] = m_pspObj->CreatePage(DLG_ATLK_GENERAL, 0);
// Validate what we've created
if (NULL == ahpsp[0])
{
hr = E_OUTOFMEMORY;
goto Error;
}
else
{
*pahpspPrivate = (LPBYTE)ahpsp;
*pcPages = 1;
}
cleanup:
TraceError("CATlkObj::MergePropPages", hr);
return hr;
Error:
CoTaskMemFree(ahpsp);
delete m_pATLKEnv_PP;
m_pATLKEnv_PP = NULL;
goto cleanup;
}
//
// Function: CATlkObj::CleanupPropPages
//
// Purpose:
//
// Parameters:
//
// Returns: nothing
//
VOID CATlkObj::CleanupPropPages()
{
delete m_pspObj;
m_pspObj = NULL;
}
//
// Function: CATlkObj::ValidateProperties
//
// Purpose:
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
STDMETHODIMP CATlkObj::ValidateProperties (HWND)
{
return S_OK;
}
//
// Function: CATlkObj::CancelProperties
//
// Purpose:
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
STDMETHODIMP CATlkObj::CancelProperties ()
{
// Discard any changes made via the property pages
delete m_pATLKEnv_PP;
m_pATLKEnv_PP = NULL;
return S_OK;
}
//
// Function: CATlkObj::ApplyProperties
//
// Purpose:
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
STDMETHODIMP CATlkObj::ApplyProperties ()
{
// Extract the adapter info from the property sheet's
// enviroment block
Assert(!m_pATLKEnv_PP->AdapterInfoList().empty());
CAdapterInfo * pAICurrent = m_pATLKEnv_PP->AdapterInfoList().front();
m_pATLKEnv_PP->AdapterInfoList().pop_front();
Assert(NULL != pAICurrent);
// Remove the current adapter from the original enviroment
CAdapterInfo * pAI;
ATLK_ADAPTER_INFO_LIST::iterator iter;
for (iter = m_pATLKEnv->AdapterInfoList().begin();
iter != m_pATLKEnv->AdapterInfoList().end();
iter++)
{
pAI = *iter;
if (0 == _wcsicmp(pAI->SzBindName(), pAICurrent->SzBindName()))
{
m_pATLKEnv->AdapterInfoList().erase(iter, iter);
break;
}
}
// Add pAICurrent to the base enviroment block
m_pATLKEnv->AdapterInfoList().push_back(pAICurrent);
// Update the base enviroment from the property sheet's enviroment
m_pATLKEnv->SetDefaultMediaType(m_pATLKEnv_PP->DwDefaultAdaptersMediaType());
m_pATLKEnv->EnableRouting(m_pATLKEnv_PP->FRoutingEnabled());
m_pATLKEnv->SetDefaultPort(m_pATLKEnv_PP->SzDefaultPort());
m_pATLKEnv->SetDesiredZone(m_pATLKEnv_PP->SzDesiredZone());
m_pATLKEnv->SetRouterChanged(m_pATLKEnv_PP->FRouterChanged());
m_pATLKEnv->SetDefAdapterChanged(m_pATLKEnv_PP->FDefAdapterChanged());
// Delete the property pages enviroment block
delete m_pATLKEnv_PP;
m_pATLKEnv_PP = NULL;
// Properties changed
m_fPropertyChange = TRUE;
return S_OK;
}
// INetCfgBindNotify
STDMETHODIMP
CATlkObj::QueryBindingPath (
DWORD dwChangeFlag,
INetCfgBindingPath* pncbpItem )
{
Validate_INetCfgBindNotify_QueryBindingPath( dwChangeFlag, pncbpItem );
return S_OK;
}
STDMETHODIMP
CATlkObj::NotifyBindingPath (
DWORD dwChangeFlag,
INetCfgBindingPath* pncbpItem )
{
HRESULT hr = S_OK;
INetCfgComponent *pnccFound = NULL;
Validate_INetCfgBindNotify_NotifyBindingPath( dwChangeFlag, pncbpItem );
Assert(NULL != m_pATLKEnv);
// Only Interested in lower binding Add's and Remove's
if (dwChangeFlag & (NCN_ADD | NCN_REMOVE | NCN_ENABLE | NCN_DISABLE))
{
CIterNetCfgBindingInterface ncbiIter(pncbpItem);
INetCfgBindingInterface *pncbi;
// Enumerate the binding interfaces looking for the last Adapter
while (SUCCEEDED(hr) &&
(S_OK == (hr = ncbiIter.HrNext (&pncbi))))
{
INetCfgComponent *pncc;
hr = pncbi->GetLowerComponent(&pncc);
if (S_OK == hr)
{
GUID guidClass;
hr = pncc->GetClassGuid(&guidClass);
if ((S_OK == hr) && (GUID_DEVCLASS_NET == guidClass))
{
ULONG ulStatus = 0;
hr = pncc->GetDeviceStatus(&ulStatus);
if(S_OK == hr)
{
ReleaseObj(pnccFound);
pnccFound = pncc; // Transfer Ownership
pncc = NULL;
}
else
{
ReleaseObj(pncc);
}
}
else
{
ReleaseObj(pncc);
}
}
ReleaseObj(pncbi);
}
if (FAILED(hr))
{
goto Error;
}
// Did we find the Adapter?
if (pnccFound)
{
BOOL fFound = FALSE;
PWSTR pszBindName = NULL;
CAdapterInfo * pAI;
ATLK_ADAPTER_INFO_LIST::iterator iterAdapterInfo;
Assert(NULL != m_pATLKEnv);
ATLK_ADAPTER_INFO_LIST pAI_List = m_pATLKEnv->AdapterInfoList();
hr = pnccFound->GetBindName(&pszBindName);
if (S_OK != hr)
{
goto Error;
}
// Search the adapter list
for (iterAdapterInfo = pAI_List.begin();
iterAdapterInfo != pAI_List.end();
iterAdapterInfo++)
{
pAI = *iterAdapterInfo;
if (0 == lstrcmpiW(pszBindName, pAI->SzBindName()))
{
fFound = TRUE;
break;
}
}
Assert(NULL != pszBindName);
CoTaskMemFree(pszBindName);
// Apply the appropriate delta to the adapter list
if (fFound && (dwChangeFlag & NCN_REMOVE))
{
// Delete the adapter from the list
pAI->SetDeletePending(TRUE);
m_fAdapterListChanged = TRUE;
}
else if (!fFound && (dwChangeFlag & NCN_ADD))
{
// Add the adapter to the list
hr = m_pATLKEnv->HrAddAdapter(pnccFound);
m_fAdapterListChanged = TRUE;
}
else if (fFound && (dwChangeFlag & NCN_ADD))
{
// Re-enable the adapters existance
pAI->SetDeletePending(FALSE);
}
if (fFound)
{
if (dwChangeFlag & NCN_ENABLE)
{
pAI->SetDisabled(FALSE);
m_fAdapterListChanged = TRUE;
}
else if (dwChangeFlag & NCN_DISABLE)
{
pAI->SetDisabled(TRUE);
m_fAdapterListChanged = TRUE;
}
}
}
if (SUCCEEDED(hr))
{
hr = S_OK; // Normalize return value
}
}
Error:
::ReleaseObj(pnccFound);
TraceError("CATlkObj::NotifyBindingPath",hr);
return hr;
}
//
// Function: CATlkObj::HrCommitInstall
//
// Purpose: Commit Installation registry changes to the registry
//
// Parameters: None
//
// Returns: HRESULT, S_OK on success
//
//
HRESULT CATlkObj::HrCommitInstall()
{
HRESULT hr;
Assert(NULL != m_pATLKEnv);
hr = m_pATLKEnv->HrUpdateRegistry();
TraceError("CATlkObj::HrCommitInstall",hr);
return hr;
}
//
// Function: CATlkObj::HrCommitRemove
//
// Purpose: Remove from the registry settings which were created by this
// component's installation.
//
// Parameters: None
//
// Returns: HRESULT, S_OK on success
//
//
HRESULT CATlkObj::HrCommitRemove()
{
// Everything is removed via the inf file presently
return S_OK;
}
//
// Function: CATLKEnv::HrCreate
//
// Purpose: Construct the AppleTalk Enviroment tracking object
//
// Paramaters: ppATLKEnv [out] - AppleTalk Enviroment Object created
// pmsc [in] - AppleTalk notification object
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrCreate(CATLKEnv **ppATLKEnv, CATlkObj *pmsc)
{
HRESULT hr = S_OK;
CATLKEnv *pATLKEnv = NULL;
*ppATLKEnv = NULL;
// Construct the new enviroment object
pATLKEnv = new CATLKEnv(pmsc);
if (pATLKEnv == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
// Read AppleTalk Info
hr = pATLKEnv->HrReadAppleTalkInfo();
if (FAILED(hr))
{
goto Error;
}
*ppATLKEnv = pATLKEnv;
Done:
return hr;
Error:
TraceError("CATLKEnv::HrCreate",hr);
delete pATLKEnv;
goto Done;
}
//
// Function: CATLKEnv::CATLKEnv
//
// Purpose: ctor for the CATLKEnv class
//
// Parameters: none
//
// Returns: none
//
CATLKEnv::CATLKEnv(CATlkObj *pmsc) :
m_pmsc(pmsc),
m_fATrunning(FALSE),
m_dwDefaultAdaptersMediaType(MEDIATYPE_ETHERNET),
m_fRouterChanged(FALSE),
m_fDefAdapterChanged(FALSE)
{
ZeroMemory(&m_Params, sizeof(m_Params));
}
//
// Function: CATLKEnv::~CATLKEnv
//
// Purpose: dtor for the CATLKEnv class
//
// Parameters: none
//
// Returns: none
//
CATLKEnv::~CATLKEnv()
{
// Cleanup the AppleTalk\Parameters internal data structure
delete [] m_Params.szDefaultPort;
delete [] m_Params.szDesiredZone;
// Cleanup the contents of the Adapter Info List
while (!m_lstpAdapters.empty())
{
delete m_lstpAdapters.front();
m_lstpAdapters.pop_front();
}
}
//
// Function: CATLKEnv::HrCopy
//
// Purpose: Creates a copy of the current Enviroment
//
// Parameters: ppEnv [out] - If the function succeeds, ppEnv will contain a
// copy of the enviroment.
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrCopy(CATLKEnv **ppEnv)
{
HRESULT hr = S_OK;
CATLKEnv * pEnv;
// Allocate a new enviroment object
*ppEnv = NULL;
pEnv = new CATLKEnv(m_pmsc);
if (NULL != pEnv)
{
// Copy the members
pEnv->m_fATrunning = m_fATrunning;
pEnv->SetDefaultMediaType(DwDefaultAdaptersMediaType());
pEnv->EnableRouting(FRoutingEnabled());
pEnv->SetDefaultPort(SzDefaultPort());
pEnv->SetDesiredZone(SzDesiredZone());
pEnv->SetRouterChanged(FRouterChanged());
pEnv->SetDefAdapterChanged(FDefAdapterChanged());
*ppEnv = pEnv;
}
else
{
hr = E_OUTOFMEMORY;
}
TraceError("CATLKEnv::HrCopy",hr);
return S_OK;
}
//
// Function: CATLKEnv::HrReadAppleTalkInfo
//
// Purpose: Retrieve the AppleTalk registry Settings
//
// Parameters: none
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrReadAppleTalkInfo()
{
HRESULT hr;
// Read the AppleTalk\Parameters values
RegReadValues(celems(regbatchATLKParams), regbatchATLKParams,
(BYTE *)&m_Params, KEY_READ);
// Read info for each adapter listed under AppleTalk\Parameters\Adapters
hr = HrGetAdapterInfo();
TraceError("CATLKEnv::HrReadAppleTalkInfo",hr);
return hr;
}
//
// Function: CATLKEnv::HrGetOneAdaptersInfo
//
// Purpose: Retrieve the AppleTalk Adapter information for one adapter
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrGetOneAdaptersInfo(INetCfgComponent* pncc,
CAdapterInfo **ppAI)
{
HKEY hkeyAdapterRoot = NULL;
HKEY hkeyAdapter = NULL;
HRESULT hr;
INT idx;
CAdapterInfo * pAI = NULL;
REGBATCH regbatch;
tstring strKey;
tstring strKeyPath = c_szATLKAdapters;
*ppAI = NULL;
// Construct the adapter info object
pAI = new CAdapterInfo;
if (pAI == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
// Get the adapter component info (media type, description, ...)
hr = ::HrQueryAdapterComponentInfo(pncc, pAI);
if (FAILED(hr))
{
goto Error;
}
hr = ::HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strKeyPath.c_str(),
KEY_READ, &hkeyAdapterRoot);
if (S_OK == hr)
{
strKey = pAI->SzBindName();
// Try to open the key for this specific adapter
hr = ::HrRegOpenKeyEx(hkeyAdapterRoot, pAI->SzBindName(),
KEY_READ, &hkeyAdapter);
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
// We weren't able to find this in the registry, write it out
// when we can (self repair)
pAI->SetDirty(TRUE);
}
strKeyPath += c_szBackslash;
strKeyPath += strKey.c_str();
// If we located the key query the data
if (S_OK == hr)
{
hr = HrRegQueryColString(hkeyAdapter, c_szZoneList,
&pAI->LstpstrZoneList());
// Since CAdapterInfo defaults allocations, need to free
// them before RegReadValues writes over them and causes a leak.
//
delete [] pAI->m_AdapterInfo.m_szDefaultZone;
delete [] pAI->m_AdapterInfo.m_szPortName;
pAI->m_AdapterInfo.m_szDefaultZone = NULL;
pAI->m_AdapterInfo.m_szPortName = NULL;
// Read the adapter information
for (idx=0; idx<celems(regbatchATLKAdapters); idx++)
{
regbatch = regbatchATLKAdapters[idx];
regbatch.pszSubkey = strKeyPath.c_str();
RegReadValues(1, &regbatch, (BYTE *)pAI->PAdapterInfo(), KEY_READ);
}
}
}
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr))
{
// Something other than a "not found" error
goto Error;
}
// Normalize return value
hr = S_OK;
// If the port name was not found then generate one
if (0 == wcslen(pAI->SzPortName()))
{
tstring str;
hr = ::HrPortNameFromAdapter(pncc, &str);
if (FAILED(hr))
{
goto Error;
}
pAI->SetPortName(str.c_str());
}
// Set the return value
*ppAI = pAI;
Done:
::RegSafeCloseKey(hkeyAdapter);
::RegSafeCloseKey(hkeyAdapterRoot);
return hr;
Error:
TraceError("CATLKEnv::HrGetOneAdaptersInfo",hr);
delete pAI;
goto Done;
}
//
// Function: CATLKEnv::HrGetAdapterInfo
//
// Purpose: Retrieve the AppleTalk Adapter information
//
// Parameters: none
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrGetAdapterInfo()
{
HRESULT hr = S_OK;
CAdapterInfo * pAI = NULL;
INetCfgComponent* pncc = NULL;
INetCfgComponent* pnccUse = NULL;
// Find each netcard, to do so, trace the bindings to their end
// If the endpoint is a netcard then add it to the list
CIterNetCfgBindingPath ncbpIter(m_pmsc->PNCComponent());
INetCfgBindingPath* pncbp;
while (SUCCEEDED(hr) &&
(S_OK == (hr = ncbpIter.HrNext (&pncbp))))
{
// Iterate the binding interfaces of this path.
CIterNetCfgBindingInterface ncbiIter(pncbp);
INetCfgBindingInterface* pncbi;
while (SUCCEEDED(hr) &&
(S_OK == (hr = ncbiIter.HrNext (&pncbi))))
{
// Retrieve the lower component
hr = pncbi->GetLowerComponent(&pncc);
if (S_OK == hr)
{
GUID guidClass;
// Is it an Adapter?
hr = pncc->GetClassGuid(&guidClass);
if ((S_OK == hr) && (guidClass == GUID_DEVCLASS_NET))
{
ULONG ulStatus = 0;
hr = pncc->GetDeviceStatus(&ulStatus);
if(SUCCEEDED(hr))
{
ReleaseObj(pnccUse);
pnccUse = pncc;
pncc = NULL;
}
else
{
// Release the lower component
ReleaseObj(pncc);
hr = S_OK;
break;
}
}
else
{
// Release the lower component
ReleaseObj(pncc);
}
}
// Release the binding interface
ReleaseObj (pncbi);
}
if (NULL != pnccUse)
{
// Query the Adapter information
hr = HrGetOneAdaptersInfo(pnccUse, &pAI);
if (SUCCEEDED(hr))
{
if (S_FALSE == pncbp->IsEnabled())
{
pAI->SetDisabled(TRUE);
}
// Add this Adapter to the list
m_lstpAdapters.push_back(pAI);
}
ReleaseObj(pnccUse);
pnccUse = NULL;
}
// Release the binding path
ReleaseObj (pncbp);
}
if (FAILED(hr))
{
goto Error;
}
// Initialize the default port, etc
InitDefaultPort();
// Normalize the HRESULT. (i.e. don't return S_FALSE)
hr = S_OK;
Error:
TraceError("CATLKEnv::HrGetAdapterInfo",hr);
return hr;
}
//
// Function: CATLKEnv::HrGetAppleTalkInfoFromNetwork
//
// Purpose: ???
//
// Parameters: none
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrGetAppleTalkInfoFromNetwork(CAdapterInfo * pAI)
{
SOCKADDR_AT address;
HRESULT hr = S_FALSE;
BOOL fWSInitialized = FALSE;
SOCKET mysocket = INVALID_SOCKET;
WSADATA wsadata;
DWORD wsaerr = 0;
tstring strPortName;
// Create the socket/bind
wsaerr = WSAStartup(0x0101, &wsadata);
if (0 != wsaerr)
{
goto Error;
}
// Winsock successfully initialized
fWSInitialized = TRUE;
mysocket = socket(AF_APPLETALK, SOCK_DGRAM, DDPPROTO_ZIP);
if (INVALID_SOCKET == mysocket)
{
goto Error;
}
address.sat_family = AF_APPLETALK;
address.sat_net = 0;
address.sat_node = 0;
address.sat_socket = 0;
wsaerr = bind(mysocket, (struct sockaddr *)&address, sizeof(address));
if (wsaerr != 0)
{
goto Error;
}
// Mark AppleTalk as running
SetATLKRunning(TRUE);
// For each known adapter, create a device name by merging the "\\device\\"
// prefix and the adapter's bind name.
strPortName = c_szDevice;
strPortName += pAI->SzBindName();
// Failures from query the zone list for a given adapter can be from
// the adapter not connected to the network, zone seeder not running, etc.
// Because we want to process all the adapters, we ignore these errors.
(void)pAI->HrGetAndSetNetworkInformation(mysocket,strPortName.c_str());
// Success, or at least not a critical failure
hr = S_OK;
Done:
if (INVALID_SOCKET != mysocket)
{
closesocket(mysocket);
}
if (fWSInitialized)
{
WSACleanup();
}
TraceError("CATLKEnv::HrGetAppleTalkInfoFromNetwork",(S_FALSE == hr ? S_OK : hr));
return hr;
Error:
wsaerr = ::WSAGetLastError();
goto Done;
}
//
// Function: CATLKEnv::HrAddAdapter
//
// Purpose: Add and adapter to the list of currently bound adapters
//
// Parameters: pnccFound - Notification object for the bound adapter to add
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrAddAdapter(INetCfgComponent * pnccFound)
{
HRESULT hr;
CAdapterInfo * pAI = NULL;
Assert(NULL != pnccFound);
// Create an AdapterInfo instance for the adapter
hr = HrGetOneAdaptersInfo(pnccFound, &pAI);
if (FAILED(hr))
{
goto Error;
}
// Add this Adapter to the list
m_lstpAdapters.push_back(pAI);
pAI->SetDirty(TRUE);
// If there is now only one adapter in the list, update the defaults
if (1 == m_lstpAdapters.size())
{
tstring str;
str = c_szDevice;
str += m_lstpAdapters.front()->SzBindName();
SetDefaultPort(str.c_str());
SetDefaultMediaType(m_lstpAdapters.front()->DwMediaType());
}
Error:
TraceError("CATLKEnv::HrAddAdapter",hr);
return hr;
}
//
// Function: CATLKEnv::SetDefaultPort
//
// Purpose: Change the default port name
//
// Parameters: psz [in] - The new default port name
//
// Returns: HRESULT, S_OK on success
//
void CATLKEnv::SetDefaultPort(PCWSTR psz)
{
Assert(psz);
delete [] m_Params.szDefaultPort;
m_Params.szDefaultPort = new WCHAR[wcslen(psz)+1];
wcscpy(m_Params.szDefaultPort, psz);
}
//
// Function: CATLKEnv::SetDesiredZone
//
// Purpose: Change the desired zone
//
// Parameters: sz [in] - The new desired zone
//
// Returns: HRESULT, S_OK on success
//
void CATLKEnv::SetDesiredZone(PCWSTR psz)
{
Assert(psz);
delete [] m_Params.szDesiredZone;
m_Params.szDesiredZone = new WCHAR[wcslen(psz)+1];
wcscpy(m_Params.szDesiredZone, psz);
}
CAdapterInfo * CATLKEnv::PAIFindDefaultPort()
{
CAdapterInfo * pAI = NULL;
ATLK_ADAPTER_INFO_LIST::iterator iter;
// Find the default port
//
for (iter = m_lstpAdapters.begin();
iter != m_lstpAdapters.end();
iter++)
{
tstring strPortName;
pAI = *iter;
// Retain adapter selection as the default port
strPortName = c_szDevice;
strPortName += pAI->SzBindName();
if (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden() ||
pAI->IsRasAdapter())
{
continue;
}
if (0 == _wcsicmp(SzDefaultPort(), strPortName.c_str()))
{
return pAI;
}
}
return NULL;
}
//
// Function: CATLKEnv::HrUpdateRegistry
//
// Purpose: Write the AppleTalk local (internal) data back to the registry
//
// Parameters: none
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrUpdateRegistry()
{
HRESULT hr = S_OK;
CAdapterInfo * pAI = NULL;
HKEY hkeyAdapter;
DWORD dwDisposition;
ATLK_ADAPTER_INFO_LIST::iterator iter;
// If the current default port is unavailable, find an alternate
pAI = PAIFindDefaultPort();
if (NULL == pAI)
{
InitDefaultPort();
pAI = PAIFindDefaultPort();
}
// If the default adapter changed then three specific values for that
// adapter need to be reset to zero.
//
if (pAI && FDefAdapterChanged())
{
pAI->ZeroSpecialParams();
pAI->SetDirty(TRUE);
}
// Commit the registry changes
hr = ::HrRegWriteValues(celems(regbatchATLKParams), regbatchATLKParams,
(BYTE *)&m_Params, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS);
if (S_OK != hr)
{
goto Error;
}
// Create the Adapters key AppleTalk\Parameters\Adapters)
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szATLKAdapters,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hkeyAdapter, &dwDisposition);
if (S_OK == hr)
{
// Enumerate the bound adapters and write the internal adapter list
for (iter = m_lstpAdapters.begin();
(iter != m_lstpAdapters.end()) && (SUCCEEDED(hr));
iter++)
{
pAI = *iter;
if (pAI->FDeletePending())
{
// Remove the AppleTalk\Adapter\{bindname} tree
hr = ::HrRegDeleteKeyTree(hkeyAdapter, pAI->SzBindName());
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr))
{
goto Error;
}
}
else if (pAI->IsDirty())
{
hr = HrWriteOneAdapter(pAI);
}
}
RegCloseKey (hkeyAdapter);
}
Error:
TraceError("CATLKEnv::HrUpdateRegistry",hr);
return hr;
}
//
// Function: CATLKEnv::HrWriteOneAdapter
//
// Purpose: Write one adapter instance to the registry
//
// Parameters: pAI [in] - The adapter to presist in the registry
//
// Returns: HRESULT, S_OK on success
//
HRESULT CATLKEnv::HrWriteOneAdapter(CAdapterInfo *pAI)
{
DWORD dwDisposition;
HKEY hkeyAdapter = NULL;
HRESULT hr;
INT idx;
REGBATCH regbatch;
tstring str;
str = c_szATLKAdapters;
str += c_szBackslash;
str += pAI->SzBindName();
// Create the key described in str (AppleTalk\Parameters\Adapters\<adapter>)
hr = ::HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, str.c_str(),
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hkeyAdapter, &dwDisposition);
if (FAILED(hr))
{
goto Error;
}
// Write out the adapter parameters
for (idx = 0; idx < celems(regbatchATLKAdapters); idx++)
{
regbatch = regbatchATLKAdapters[idx];
regbatch.pszSubkey = str.c_str();
hr = ::HrRegWriteValues(1, &regbatch, (BYTE *)pAI->PAdapterInfo(),
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS);
if (FAILED(hr))
{
goto Error;
}
}
// Write out the zone list multi-sz (managed seperately)
hr = ::HrRegSetColString(hkeyAdapter, c_szZoneList, pAI->LstpstrZoneList());
Error:
::RegSafeCloseKey(hkeyAdapter);
TraceError("CATLKEnv::HrWriteOneAdapter",hr);
return S_OK;
}
//
// Function: CATLKEnv::DwMediaPriority
//
// Purpose: When determining the appropriate adapter for use as the
// "DefaultPort" certain mediatype's are faster. So all
// other things being equal, selecting a faster mediatype
// benefits the user the most.
//
// Parameters: dwMediaType [in] - MediaType used to determine priority ranking
//
// Returns: DWORD, value (1-5) with the lowest value representing the
// highest priority.
//
DWORD CATLKEnv::DwMediaPriority(DWORD dwMediaType)
{
switch(dwMediaType)
{
case MEDIATYPE_ETHERNET:
return 2;
case MEDIATYPE_TOKENRING:
return 3;
case MEDIATYPE_FDDI:
return 1;
case MEDIATYPE_LOCALTALK:
return 4;
default:
return 5;
}
}
//
// Function: CATLKEnv::InitDefaultPort
//
// Purpose: Select a default port if none yet has been selected. Retain
// some select information for assisting in dialog display issues.
//
// Parameters: none
//
// Returns: nothing
//
void CATLKEnv::InitDefaultPort()
{
CAdapterInfo * pAI = NULL;
tstring str;
ATLK_ADAPTER_INFO_LIST::iterator iter;
// If DefaultPort is set, does the associated adapter exist?
if (wcslen(SzDefaultPort()))
{
// Search for the adapter in the list
for (iter = AdapterInfoList().begin();
iter != AdapterInfoList().end();
iter++)
{
pAI = *iter;
if (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden() ||
pAI->IsRasAdapter())
{
pAI = NULL;
continue;
}
str = c_szDevice;
str += pAI->SzBindName();
if (0 == wcscmp(str.c_str(), SzDefaultPort()))
{
break;
}
pAI = NULL;
}
}
// If DefaultPort is not set locate the best candidate
if (NULL == pAI)
{
CAdapterInfo * pAIBest = NULL;
SetDefaultPort(c_szEmpty);
// Search through the adapter list for the adapter
// with the fastest media type.
for (iter = AdapterInfoList().begin();
iter != AdapterInfoList().end();
iter++)
{
pAI = *iter;
if (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden() ||
pAI->IsRasAdapter())
{
continue;
}
if ((NULL == pAIBest) ||
(DwMediaPriority(pAIBest->DwMediaType()) >
DwMediaPriority(pAI->DwMediaType())))
{
SetDefAdapterChanged(TRUE);
pAIBest = pAI;
}
}
pAI = pAIBest;
}
if (NULL != pAI)
{
// retain the selected adapter as the default port
str = c_szDevice;
str += pAI->SzBindName();
SetDefaultPort(str.c_str());
// retain the default media type
SetDefaultMediaType(pAI->DwMediaType());
}
else
{
SetDefaultPort(c_szEmpty);
}
}
//
// Function: CAdapterInfo::CAdapterInfo
//
// Purpose: ctor for the CAdapters class
//
// Parameters: none
//
// Returns: nothing
//
CAdapterInfo::CAdapterInfo() :
m_fDeletePending(FALSE),
m_fDisabled(FALSE),
m_fDirty(FALSE),
m_fRasAdapter(FALSE),
m_fRouterOnNetwork(FALSE),
m_fZoneListValid(FALSE),
m_dwNetworkUpper(0),
m_dwNetworkLower(0),
m_dwCharacteristics(0)
{
ZeroMemory(&m_guidInstance, sizeof(m_guidInstance));
// Initialize the AdapterInfo default values
ZeroMemory(&m_AdapterInfo, sizeof(m_AdapterInfo));
m_AdapterInfo.m_dwAarpRetries = c_dwTen;
m_AdapterInfo.m_dwMediaType = MEDIATYPE_ETHERNET;
SetDefaultZone(c_szEmpty);
SetPortName(c_szEmpty);
}
//
// Function: CAdapterInfo::~CAdapterInfo
//
// Purpose: ctor for the CAdapters class
//
// Parameters: none
//
// Returns: nothing
//
CAdapterInfo::~CAdapterInfo()
{
// Cleanup the AppleTalk\Adapters\<adapter> internal data structure
delete [] m_AdapterInfo.m_szDefaultZone;
delete [] m_AdapterInfo.m_szPortName;
DeleteColString(&m_lstpstrDesiredZoneList);
DeleteColString(&m_lstpstrZoneList);
}
//
// Function: CAdapterInfo::SetDefaultZone
//
// Purpose: Set the default zone for this adapter
//
// Parameters: sz - The new default zone
//
// Returns: nothing
//
void CAdapterInfo::SetDefaultZone(PCWSTR psz)
{
Assert(psz);
delete [] m_AdapterInfo.m_szDefaultZone;
m_AdapterInfo.m_szDefaultZone = NULL;
m_AdapterInfo.m_szDefaultZone = new WCHAR[wcslen(psz)+1];
wcscpy(m_AdapterInfo.m_szDefaultZone, psz);
}
//
// Function: CAdapterInfo::SetPortName
//
// Purpose: Set the port name for this adapter
//
// Parameters: sz - The new port name
//
// Returns: nothing
//
void CAdapterInfo::SetPortName(PCWSTR psz)
{
Assert(psz);
delete [] m_AdapterInfo.m_szPortName;
m_AdapterInfo.m_szPortName = NULL;
m_AdapterInfo.m_szPortName = new WCHAR[wcslen(psz)+1];
wcscpy(m_AdapterInfo.m_szPortName, psz);
}
//
// Function: CAdapterInfo::HrGetAndSetNetworkInformation
//
// Purpose:
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
#define PARM_BUF_LEN 512
#define ASTERISK_CHAR "*"
HRESULT
CAdapterInfo::HrGetAndSetNetworkInformation (
SOCKET socket,
PCWSTR pszDevName)
{
HRESULT hr = FALSE;
CHAR *pZoneBuffer = NULL;
CHAR *pDefParmsBuffer = NULL;
CHAR *pZoneListStart;
INT BytesNeeded ;
WCHAR *pwDefZone = NULL;
tstring strTmpZone;
INT ZoneLen = 0;
DWORD wsaerr = 0;
CHAR *pDefZone = NULL;
PWSH_LOOKUP_ZONES pGetNetZones;
PWSH_LOOKUP_NETDEF_ON_ADAPTER pGetNetDefaults;
Assert(pszDevName);
pZoneBuffer = new CHAR [ZONEBUFFER_LEN + sizeof(WSH_LOOKUP_ZONES)];
Assert(pZoneBuffer);
if (pZoneBuffer == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
pGetNetZones = (PWSH_LOOKUP_ZONES)pZoneBuffer;
wcscpy((WCHAR *)(pGetNetZones+1), pszDevName);
BytesNeeded = ZONEBUFFER_LEN;
wsaerr = getsockopt(socket, SOL_APPLETALK, SO_LOOKUP_ZONES_ON_ADAPTER,
(char *)pZoneBuffer, &BytesNeeded);
if (0 != wsaerr)
{
//$ REVIEW - error mapping
#ifdef DBG
DWORD dwErr = WSAGetLastError();
TraceTag(ttidError, "CAdapterInfo::HrGetAndSetNetworkInformation getsocketopt returned: %08X",dwErr);
#endif
hr = E_UNEXPECTED;
goto Error;
}
pZoneListStart = pZoneBuffer + sizeof(WSH_LOOKUP_ZONES);
if (!lstrcmpA(pZoneListStart, ASTERISK_CHAR))
{
// Success, wildcard zone set.
goto Done;
}
hr = HrConvertZoneListAndAddToPortInfo(pZoneListStart,
((PWSH_LOOKUP_ZONES)pZoneBuffer)->NoZones);
if (FAILED(hr))
{
goto Error;
}
SetRouterOnNetwork(TRUE);
//
// Get the DefaultZone/NetworkRange Information
pDefParmsBuffer = new CHAR[PARM_BUF_LEN+sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER)];
Assert(pDefParmsBuffer);
if (pDefParmsBuffer == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
pGetNetDefaults = (PWSH_LOOKUP_NETDEF_ON_ADAPTER)pDefParmsBuffer;
BytesNeeded = PARM_BUF_LEN + sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER);
wcscpy((WCHAR*)(pGetNetDefaults+1), pszDevName);
pGetNetDefaults->NetworkRangeLowerEnd = pGetNetDefaults->NetworkRangeUpperEnd = 0;
wsaerr = getsockopt(socket, SOL_APPLETALK, SO_LOOKUP_NETDEF_ON_ADAPTER,
(char*)pDefParmsBuffer, &BytesNeeded);
if (0 != wsaerr)
{
#ifdef DBG
DWORD dwErr = WSAGetLastError();
#endif
hr = E_UNEXPECTED;
goto Error;
}
// Save the default information to PORT_INFO
SetExistingNetRange(pGetNetDefaults->NetworkRangeLowerEnd,
pGetNetDefaults->NetworkRangeUpperEnd);
pDefZone = pDefParmsBuffer + sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER);
ZoneLen = lstrlenA(pDefZone) + 1;
pwDefZone = new WCHAR [sizeof(WCHAR) * ZoneLen];
Assert(NULL != pwDefZone);
if (pwDefZone == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
mbstowcs(pwDefZone, pDefZone, ZoneLen);
strTmpZone = pwDefZone;
SetNetDefaultZone(strTmpZone.c_str());
if (pZoneBuffer != NULL)
{
delete [] pZoneBuffer;
}
if (pwDefZone != NULL)
{
delete [] pwDefZone;
}
if (pDefParmsBuffer != NULL)
{
delete [] pDefParmsBuffer;
}
Done:
Error:
TraceError("CAdapterInfo::HrGetAndSetNetworkInformation",hr);
return hr;
}
//
// Function: CAdapterInfo::HrConvertZoneListAndAddToPortInfo
//
// Purpose:
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
//
HRESULT CAdapterInfo::HrConvertZoneListAndAddToPortInfo(CHAR * szZoneList, ULONG NumZones)
{
INT cbAscii = 0;
WCHAR *pszZone = NULL;
tstring *pstr;
Assert(NULL != szZoneList);
DeleteColString(&m_lstpstrDesiredZoneList);
while(NumZones--)
{
cbAscii = lstrlenA(szZoneList) + 1;
pszZone = new WCHAR [sizeof(WCHAR) * cbAscii];
Assert(NULL != pszZone);
if (pszZone == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
mbstowcs(pszZone, szZoneList, cbAscii);
pstr = new tstring(pszZone);
Assert(NULL != pstr);
m_lstpstrDesiredZoneList.push_back(pstr);
szZoneList += cbAscii;
delete [] pszZone;
}
return S_OK;
}
//
// Function: CAdapterInfo::HrCopy
//
// Purpose: Create a duplicate copy of 'this'
//
// Parameters: ppAI [out] - if the function succeeds, ppAI will contain the
// copy of 'this'.
//
// Returns: HRESULT, S_OK on success
//
HRESULT CAdapterInfo::HrCopy(CAdapterInfo ** ppAI)
{
CAdapterInfo *pAI;
list<tstring*>::iterator iter;
tstring * pstr;
Assert(NULL != ppAI);
// Create an adapter info structure
pAI = new CAdapterInfo;
Assert(pAI);
if (pAI == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
// Make a copy of everything
pAI->SetDisabled(FDisabled());
pAI->SetDeletePending(FDeletePending());
pAI->SetCharacteristics(GetCharacteristics());
pAI->SetMediaType(DwMediaType());
pAI->SetBindName(SzBindName());
pAI->SetDisplayName(SzDisplayName());
pAI->SetNetDefaultZone(SzNetDefaultZone());
pAI->SetRouterOnNetwork(FRouterOnNetwork());
pAI->SetExistingNetRange(DwQueryNetworkLower(), DwQueryNetworkUpper());
pAI->SetDirty(IsDirty());
pAI->SetRasAdapter(IsRasAdapter());
// Free the default data set by the constructor before overwriting it.
// (this whole thing is not a very good approach.)
//
delete [] pAI->m_AdapterInfo.m_szDefaultZone;
delete [] pAI->m_AdapterInfo.m_szPortName;
pAI->m_AdapterInfo = m_AdapterInfo;
// Cleanup the 'allocated' data cause by the bit copy
// so that SetDefaultZone and SetPortName don't try to free bogus
// stuff. (more "programming by side-affect")
//
pAI->m_AdapterInfo.m_szDefaultZone = NULL;
pAI->m_AdapterInfo.m_szPortName = NULL;
// Now copy the 'allocated' data
pAI->SetDefaultZone(SzDefaultZone());
pAI->SetPortName(SzPortName());
for (iter = LstpstrZoneList().begin();
iter != LstpstrZoneList().end();
iter++)
{
pstr = *iter;
pAI->LstpstrZoneList().push_back(new tstring(pstr->c_str()));
}
for (iter = LstpstrDesiredZoneList().begin();
iter != LstpstrDesiredZoneList().end();
iter++)
{
pstr = *iter;
pAI->LstpstrDesiredZoneList().push_back(new tstring(pstr->c_str()));
}
*ppAI = pAI;
return S_OK;
}
//
// Function: HrQueryAdapterComponentInfo
//
// Purpose: Fill out an CAdapterInfo instance with the data retrieved
// specifically from the component itself.
//
// Parameters: pncc [in] - The component object (adapter) to query
// pAI [in/out] - Where to place the queried info
//
// Returns: HRESULT, S_OK on success
//
HRESULT HrQueryAdapterComponentInfo(INetCfgComponent *pncc,
CAdapterInfo * pAI)
{
PWSTR psz = NULL;
DWORD dwCharacteristics;
HRESULT hr;
Assert(NULL != pncc);
Assert(NULL != pAI);
// Retrieve the component's name
hr = pncc->GetBindName(&psz);
if (FAILED(hr))
{
goto Error;
}
Assert(psz && *psz);
pAI->SetBindName(psz);
CoTaskMemFree(psz);
psz = NULL;
hr = pncc->GetInstanceGuid(pAI->PInstanceGuid());
if (FAILED(hr))
{
goto Error;
}
// Get the Adapter's display name
hr = pncc->GetDisplayName(&psz);
if (FAILED(hr))
{
goto Error;
}
Assert(psz);
pAI->SetDisplayName(psz);
CoTaskMemFree(psz);
psz = NULL;
// Get the Component ID so we can check if this is a RAS adapter
//
hr = pncc->GetId(&psz);
if (FAILED(hr))
{
goto Error;
}
Assert(psz && *psz);
pAI->SetRasAdapter(0 == _wcsicmp(c_szInfId_MS_NdisWanAtalk, psz));
CoTaskMemFree(psz);
psz = NULL;
// Failure is non-fatal
hr = pncc->GetCharacteristics(&dwCharacteristics);
if (SUCCEEDED(hr))
{
pAI->SetCharacteristics(dwCharacteristics);
}
// Get the media type (Optional key)
{
DWORD dwMediaType = MEDIATYPE_ETHERNET ;
INetCfgComponentBindings* pnccBindings = NULL;
hr = pncc->QueryInterface(IID_INetCfgComponentBindings,
reinterpret_cast<void**>(&pnccBindings));
if (S_OK == hr)
{
static const struct
{
PCWSTR pszInterface;
DWORD dwInterface;
DWORD dwFlags;
} InterfaceMap[] = {{L"ethernet", MEDIATYPE_ETHERNET, NCF_LOWER},
{L"tokenring", MEDIATYPE_TOKENRING, NCF_LOWER},
{L"fddi", MEDIATYPE_FDDI, NCF_LOWER},
{L"localtalk", MEDIATYPE_LOCALTALK, NCF_LOWER},
{L"wan", MEDIATYPE_WAN, NCF_LOWER}};
for (UINT nIdx=0; nIdx < celems(InterfaceMap); nIdx++)
{
hr = pnccBindings->SupportsBindingInterface(InterfaceMap[nIdx].dwFlags,
InterfaceMap[nIdx].pszInterface);
if (S_OK == hr)
{
dwMediaType = InterfaceMap[nIdx].dwInterface;
break;
}
}
::ReleaseObj(pnccBindings);
}
pAI->SetMediaType(dwMediaType);
hr = S_OK;
}
Error:
TraceError("HrQueryAdapterComponentInfo",hr);
return hr;
}
//
// Function: HrPortNameFromAdapter
//
// Purpose: Create a port name, for use as an adapters PortName
//
// Parameters: pncc [in] - The component object (adapter) to query
// pstr [in/out] - On success will contain the PortName
//
// Returns: HRESULT, S_OK on success
//
HRESULT HrPortNameFromAdapter(INetCfgComponent *pncc, tstring * pstr)
{
HRESULT hr;
PWSTR psz;
PWSTR pszBindName = NULL;
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize = sizeof(szComputerName) / sizeof(WCHAR);
Assert(NULL != pstr);
Assert(NULL != pncc);
if (!GetComputerName(szComputerName, &dwSize))
{
hr = ::HrFromLastWin32Error();
goto Error;
}
hr = pncc->GetBindName(&pszBindName);
if (FAILED(hr))
{
goto Error;
}
// Replace the instances of '-' and '{' with '0' so the constructed
// portname is of the form [a-zA-Z0-9]*@<Computer Name> and is less
// than MAX_ZONE_NAME_LEN long.
psz = pszBindName;
while (*psz)
{
if ((*psz == L'-') || (*psz == L'{'))
{
*psz = L'0';
}
psz++;
}
*pstr = pszBindName;
if (pstr->size() + 1 + dwSize > MAX_ZONE_NAME_LEN)
{
pstr->resize(MAX_ZONE_NAME_LEN - (dwSize + 1));
}
*pstr += c_chAt;
*pstr += szComputerName;
Assert( MAX_ZONE_NAME_LEN >= pstr->size());
Error:
CoTaskMemFree(pszBindName);
TraceError("HrPortNameFromAdapter",hr);
return hr;
}
HRESULT CATlkObj::HrAtlkReconfig()
{
CServiceManager csm;
CService svr;
HRESULT hr = S_OK;
HRESULT hrRet;
BOOL fDirty = FALSE;
CAdapterInfo * pAI;
CAdapterInfo * pAIDefault = NULL;
ATLK_ADAPTER_INFO_LIST::iterator iter;
ATALK_PNP_EVENT Config;
if (m_pATLKEnv->AdapterInfoList().empty())
{
return hr;
}
ZeroMemory(&Config, sizeof(Config));
// If routing changed notify appletalk and return. No need to do the
// per adapter notifications.
if (m_pATLKEnv->FRouterChanged())
{
// notify atlk
Config.PnpMessage = AT_PNP_SWITCH_ROUTING;
hrRet = HrSendNdisPnpReconfig(NDIS, c_szAtlk, c_szEmpty,
&Config, sizeof(ATALK_PNP_EVENT));
if (FAILED(hrRet) &&
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet))
{
hr = NETCFG_S_REBOOT;
}
m_pATLKEnv->SetRouterChanged(FALSE);
return hr;
}
// Find the default adapter and also if any adapter's have changed
for (iter = m_pATLKEnv->AdapterInfoList().begin();
iter != m_pATLKEnv->AdapterInfoList().end();
iter++)
{
pAI = *iter;
tstring strPortName = c_szDevice;
strPortName += pAI->SzBindName();
if (pAI->FDeletePending() || pAI->FDisabled())
{
continue;
}
// Locate the default port
if (0 == _wcsicmp(strPortName.c_str(), m_pATLKEnv->SzDefaultPort()))
{
pAIDefault = pAI;
}
if (pAI->IsDirty())
{
fDirty = TRUE;
}
}
if ((NULL != pAIDefault) && m_pATLKEnv->FDefAdapterChanged())
{
// notify atlk
Config.PnpMessage = AT_PNP_SWITCH_DEFAULT_ADAPTER;
hrRet = HrSendNdisPnpReconfig(NDIS, c_szAtlk, NULL,
&Config, sizeof(ATALK_PNP_EVENT));
if (FAILED(hrRet) &&
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet))
{
hr = NETCFG_S_REBOOT;
}
// Clear the dirty state
m_pATLKEnv->SetDefAdapterChanged(FALSE);
pAIDefault->SetDirty(FALSE);
}
Config.PnpMessage = AT_PNP_RECONFIGURE_PARMS;
for (iter = m_pATLKEnv->AdapterInfoList().begin();
iter != m_pATLKEnv->AdapterInfoList().end();
iter++)
{
pAI = *iter;
if (pAI->FDeletePending() || pAI->FDisabled())
{
continue;
}
if (pAI->IsDirty())
{
// Now submit the reconfig notification
hrRet = HrSendNdisPnpReconfig(NDIS, c_szAtlk, pAI->SzBindName(),
&Config, sizeof(ATALK_PNP_EVENT));
if (FAILED(hrRet) &&
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet))
{
hr = NETCFG_S_REBOOT;
}
// Clear the dirty state
pAI->SetDirty(FALSE);
}
}
TraceError("CATLKObj::HrAtlkReconfig",hr);
return hr;
}