// ATlkObj.cpp : Implementation of CATlkObj #include "pch.h" #pragma hdrstop #include #include "atlkobj.h" #include "ncatlui.h" #include "ncmisc.h" #include "ncreg.h" #include "ncpnp.h" #include "ncsvc.h" #include 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\ 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(&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; idxPAdapterInfo(), 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\) 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, ®batch, (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\ 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::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(&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]*@ 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; }