1203 lines
32 KiB
C++
1203 lines
32 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1999.
|
|
//
|
|
// File: L A N A M A P . C P P
|
|
//
|
|
// Contents: NetBios Lana map routines.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: billbe 17 Feb 1999
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.h>
|
|
#pragma hdrstop
|
|
|
|
#include "lanamap.h"
|
|
#include "nceh.h"
|
|
#include "ncerror.h"
|
|
#include "ncreg.h"
|
|
#include "ncsetup.h"
|
|
#include "netsetup.h"
|
|
#include "persist.h"
|
|
|
|
const WCHAR c_szRegKeyNetBiosLinkage[] =
|
|
L"System\\CurrentControlSet\\Services\\NetBios\\Linkage";
|
|
|
|
const WCHAR c_szRegKeyNetBiosParameters[] =
|
|
L"System\\CurrentControlSet\\Services\\NetBIOS\\Parameters";
|
|
|
|
const WCHAR c_szRegValueLanaMap[] = L"LanaMap";
|
|
const WCHAR c_szRegValueMaxLana[] = L"MaxLana";
|
|
|
|
#if DBG
|
|
VOID DbgVerifyBindPathString (PCWSTR pszBindPath);
|
|
#else
|
|
VOID DbgVerifyBindPathString (PCWSTR /*pszBindPath*/) {}
|
|
#endif
|
|
|
|
|
|
typedef vector<const GUID*> VECTOR_OF_GUIDS;
|
|
|
|
struct LANA_BIND_PATH
|
|
{
|
|
VECTOR_OF_GUIDS GuidsOfComponentsOnPath;
|
|
BYTE LanaNumber;
|
|
};
|
|
|
|
VOID
|
|
GetFirstComponentFromBindPath (
|
|
IN PCWSTR pszBindPath,
|
|
OUT PCWSTR* ppszComponentStart,
|
|
OUT DWORD* pcchComponent)
|
|
{
|
|
PCWSTR pszComponentEnd;
|
|
PCWSTR pszComponentStart;
|
|
|
|
Assert (pszBindPath);
|
|
Assert (ppszComponentStart);
|
|
Assert (pcchComponent);
|
|
|
|
*pcchComponent = 0;
|
|
|
|
// The Bind path is of the form \Device\<component>_<component>_<etc.>
|
|
//
|
|
pszComponentEnd = wcschr (pszBindPath, L'_');
|
|
if (!pszComponentEnd)
|
|
{
|
|
// There is no underscore so set the end pointer
|
|
// to the end of the string.
|
|
pszComponentEnd = pszBindPath + wcslen (pszBindPath);
|
|
}
|
|
|
|
for (pszComponentStart = pszComponentEnd;
|
|
pszComponentStart != pszBindPath; pszComponentStart--)
|
|
{
|
|
// Backup from the end until we get to the slash.
|
|
// If we don't find a slash, the loop will stop when
|
|
// we hit the beginning.
|
|
//
|
|
if (L'\\' == *pszComponentStart)
|
|
{
|
|
// We hit the slash. The Component start is one character
|
|
// past that.
|
|
pszComponentStart++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*ppszComponentStart = pszComponentStart;
|
|
*pcchComponent = pszComponentEnd - pszComponentStart;
|
|
}
|
|
|
|
VOID
|
|
CLanaMap::Dump (
|
|
OUT CWideString* pstr) const
|
|
{
|
|
Assert (this);
|
|
Assert (pstr);
|
|
|
|
WCHAR pszBuf[1024];
|
|
pstr->erase();
|
|
|
|
const CLanaEntry* pEntry;
|
|
|
|
for (pEntry = begin(); pEntry != end(); pEntry++)
|
|
{
|
|
swprintf (pszBuf, L"Lana: %3d Export: %d Path: %s\n",
|
|
pEntry->RegLanaEntry.LanaNumber,
|
|
pEntry->RegLanaEntry.Exported, pEntry->pszBindPath);
|
|
|
|
pstr->append (pszBuf);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrLoadLanaMap()
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkey;
|
|
|
|
// The lana map is stored in Netbios's linkage key.
|
|
//
|
|
hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyNetBiosLinkage,
|
|
KEY_READ, &hkey);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
REG_LANA_ENTRY* pRegEntries;
|
|
DWORD cbLanaEntries;
|
|
|
|
// Read in the lana map binary blob.
|
|
hr = HrRegQueryBinaryWithAlloc (hkey, c_szRegValueLanaMap,
|
|
(BYTE**)&pRegEntries, &cbLanaEntries);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD cEntries = cbLanaEntries / sizeof (REG_LANA_ENTRY);
|
|
|
|
PWSTR pmszBindPaths;
|
|
|
|
// Grab the bind paths for NetBios so we can match them
|
|
// up with the lana map.
|
|
hr = HrRegQueryMultiSzWithAlloc (hkey, L"Bind", &pmszBindPaths);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
PCWSTR pszScan;
|
|
DWORD cPaths;
|
|
for (pszScan = pmszBindPaths, cPaths = 0;
|
|
*pszScan;
|
|
pszScan += wcslen(pszScan) + 1)
|
|
{
|
|
++cPaths;
|
|
}
|
|
|
|
m_pszBindPathsBuffer = pmszBindPaths;
|
|
|
|
hr = HrReserveRoomForEntries (cPaths);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD dw = 0;
|
|
CLanaEntry Entry;
|
|
|
|
for (pszScan = pmszBindPaths;
|
|
*pszScan;
|
|
pszScan += wcslen(pszScan) + 1)
|
|
{
|
|
Entry.pszBindPath = pszScan;
|
|
|
|
if (dw < cEntries)
|
|
{
|
|
Entry.RegLanaEntry.LanaNumber =
|
|
pRegEntries[dw].LanaNumber;
|
|
Entry.RegLanaEntry.Exported =
|
|
pRegEntries[dw].Exported;
|
|
}
|
|
else
|
|
{
|
|
// We have more bind paths but no more
|
|
// lana map entries to correlate.
|
|
// Now we assign available lanas.
|
|
//
|
|
BYTE* location = find (m_LanasInUse,
|
|
m_LanasInUse + MAX_LANA, 0);
|
|
if (location != m_LanasInUse + MAX_LANA)
|
|
{
|
|
Entry.RegLanaEntry.LanaNumber =
|
|
location - m_LanasInUse;
|
|
Entry.RegLanaEntry.Exported = 1;
|
|
}
|
|
}
|
|
|
|
// Mark this Lana as taken.
|
|
m_LanasInUse[Entry.RegLanaEntry.LanaNumber] = 1;
|
|
|
|
hr = HrAppendEntry (&Entry);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
dw++;
|
|
}
|
|
}
|
|
|
|
}
|
|
MemFree (pRegEntries);
|
|
}
|
|
|
|
// If lana map or bind is not there, it is okay since we will be
|
|
// recreating the info.
|
|
//
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
else
|
|
{
|
|
// If the linkage has not been created yet, it is okay since it will
|
|
// be creating after the lanamap is written out. This occurs when
|
|
// NetBios is first installed.
|
|
//
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaMap::HrLoadLanaMap");
|
|
return hr;
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
DbgVerifyBindPathString (
|
|
PCWSTR pszBindPath)
|
|
{
|
|
const WCHAR c_szDevice[] = L"\\Device\\";
|
|
Assert (pszBindPath);
|
|
Assert (0 == _wcsnicmp (pszBindPath, c_szDevice, celems(c_szDevice)-1));
|
|
}
|
|
#endif // DBG
|
|
|
|
|
|
BOOL
|
|
FBindPathContainsMultipleInterface (
|
|
IN const CComponentList& Components,
|
|
IN PCWSTR pszBindPath)
|
|
{
|
|
BOOL fContainsMultipleInterface = FALSE;
|
|
PCWSTR pszLastDevice = wcsrchr (pszBindPath, L'{');
|
|
|
|
if (pszLastDevice)
|
|
{
|
|
GUID Guid;
|
|
if (S_OK == IIDFromString ((PWSTR)pszLastDevice, &Guid))
|
|
{
|
|
// If this is a multiple interface, it will not exist
|
|
// as a component.
|
|
//
|
|
CComponent* pComponent;
|
|
|
|
pComponent = Components.
|
|
PFindComponentByInstanceGuid (&Guid);
|
|
|
|
if (!pComponent)
|
|
{
|
|
// This means the path contains a multiple interface.
|
|
fContainsMultipleInterface = TRUE;
|
|
}
|
|
}
|
|
}
|
|
return fContainsMultipleInterface;
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrAppendEntry (
|
|
IN CLanaEntry* pEntry)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert (pEntry);
|
|
Assert (pEntry->pszBindPath && *(pEntry->pszBindPath));
|
|
|
|
DbgVerifyBindPathString (pEntry->pszBindPath);
|
|
|
|
NC_TRY
|
|
{
|
|
push_back (*pEntry);
|
|
hr = S_OK;
|
|
}
|
|
NC_CATCH_ALL
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Update out lanas in use map.
|
|
m_LanasInUse[pEntry->RegLanaEntry.LanaNumber] = 1;
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaMap::HrAppendLanaEntry");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrCreateRegistryMap()
|
|
{
|
|
HRESULT hr;
|
|
|
|
CLanaEntry* pEntry;
|
|
|
|
if (m_RegistryLanaMap.CountOfBytesUsed())
|
|
{
|
|
m_RegistryLanaMap.Clear();
|
|
}
|
|
|
|
hr = m_RegistryLanaMap.HrReserveBytes (
|
|
CountEntries() * sizeof (REG_LANA_ENTRY));
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
for (pEntry = begin(); pEntry != end(); pEntry++)
|
|
{
|
|
hr = m_RegistryLanaMap.HrCopyBytes ((BYTE*)&pEntry->RegLanaEntry,
|
|
sizeof (REG_LANA_ENTRY));
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaEntry::HrCreateRegistryMap");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrReserveRoomForEntries (
|
|
IN UINT cEntries)
|
|
{
|
|
HRESULT hr;
|
|
|
|
NC_TRY
|
|
{
|
|
reserve (cEntries);
|
|
hr = S_OK;
|
|
}
|
|
NC_CATCH_ALL
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaMap::HrReserveRoomForEntries");
|
|
return hr;
|
|
}
|
|
|
|
BYTE
|
|
CLanaMap::GetExportValue (
|
|
IN const CComponentList& Components,
|
|
IN PCWSTR pszBindPath)
|
|
{
|
|
const WCHAR c_szNdisWanNbfIn[] = L"NdisWanNbfIn{";
|
|
|
|
BYTE Exported = 1;
|
|
PCWSTR pszLastDevice;
|
|
|
|
Assert (pszBindPath && *pszBindPath);
|
|
|
|
// Get the last "device" on the bind path.
|
|
// If it matches NbfIn, we don't export.
|
|
//
|
|
|
|
pszLastDevice = wcsrchr (pszBindPath, L'_');
|
|
if (!pszLastDevice)
|
|
{
|
|
pszLastDevice = wcsrchr (pszBindPath, L'\\');
|
|
if (!pszLastDevice)
|
|
{
|
|
pszLastDevice = pszBindPath;
|
|
}
|
|
}
|
|
|
|
if (pszLastDevice != pszBindPath)
|
|
{
|
|
pszLastDevice++;
|
|
}
|
|
|
|
if (0 == _wcsnicmp (pszLastDevice, c_szNdisWanNbfIn,
|
|
wcslen (c_szNdisWanNbfIn)))
|
|
{
|
|
Exported = 0;
|
|
}
|
|
|
|
// If we haven't turned off export, check to see if this bind path
|
|
// contains a multiple interface.
|
|
//
|
|
if (0 != Exported && FBindPathContainsMultipleInterface (Components,
|
|
pszBindPath))
|
|
{
|
|
Exported = 0;
|
|
}
|
|
|
|
return Exported;
|
|
}
|
|
|
|
VOID
|
|
CLanaMap::GetLanaEntry (
|
|
IN const CComponentList& Components,
|
|
IN CLanaEntry* pEntry)
|
|
{
|
|
CLanaEntry* pCurrentEntry;
|
|
BOOL fFound = FALSE;
|
|
|
|
Assert (pEntry->pszBindPath);
|
|
|
|
// Check the map for the entry
|
|
//
|
|
for (pCurrentEntry = begin(); pCurrentEntry != end(); pCurrentEntry++)
|
|
{
|
|
if (0 == _wcsicmp (pEntry->pszBindPath, pCurrentEntry->pszBindPath))
|
|
{
|
|
// Found the entry, set the lana number and figure out
|
|
// if this entry should be exported.
|
|
//
|
|
pEntry->RegLanaEntry.Exported =
|
|
GetExportValue (Components, pEntry->pszBindPath);
|
|
pEntry->RegLanaEntry.LanaNumber =
|
|
pCurrentEntry->RegLanaEntry.LanaNumber;
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
// no match, get next available lana number
|
|
BYTE* location = find (m_LanasInUse, m_LanasInUse + MAX_LANA, 0);
|
|
if (location != m_LanasInUse + MAX_LANA)
|
|
{
|
|
pEntry->RegLanaEntry.Exported =
|
|
GetExportValue (Components, pEntry->pszBindPath);
|
|
pEntry->RegLanaEntry.LanaNumber = location - m_LanasInUse;
|
|
m_LanasInUse[location - m_LanasInUse] = 1;
|
|
}
|
|
else
|
|
{
|
|
// They tell me this is impossible.
|
|
AssertSz (FALSE, "No more available Lanas.");
|
|
pEntry->RegLanaEntry.Exported = 0;
|
|
pEntry->RegLanaEntry.LanaNumber = MAX_LANA + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrWriteLanaMapConfig()
|
|
{
|
|
HKEY hkeyLinkage;
|
|
HRESULT hr;
|
|
|
|
hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyNetBiosLinkage,
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyLinkage, NULL);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
const BYTE* pbBuffer;
|
|
DWORD cbBuffer = m_RegistryLanaMap.CountOfBytesUsed();
|
|
|
|
if (cbBuffer > 0)
|
|
{
|
|
pbBuffer = m_RegistryLanaMap.PbBuffer();
|
|
}
|
|
else
|
|
{
|
|
pbBuffer = NULL;
|
|
}
|
|
|
|
hr = HrRegSetBinary (hkeyLinkage, c_szRegValueLanaMap,
|
|
pbBuffer, cbBuffer);
|
|
RegCloseKey (hkeyLinkage);
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
HKEY hkeyParams;
|
|
hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE,
|
|
c_szRegKeyNetBiosParameters, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hkeyParams, NULL);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrRegSetDword (hkeyParams, c_szRegValueMaxLana,
|
|
GetMaxLana());
|
|
|
|
RegCloseKey (hkeyParams);
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaMap::HrWriteLanaMapConfig");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HrGetNetBiosProviderName (
|
|
IN CComponent* pComponent,
|
|
OUT PWSTR pszName)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert (pComponent);
|
|
Assert (pszName);
|
|
|
|
// The netbios provider name for a component is stored in its
|
|
// <service>\Parameters key.
|
|
//
|
|
HKEY hkeyService;
|
|
hr = pComponent->HrOpenServiceKey (KEY_READ, &hkeyService);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
HKEY hkeyParams;
|
|
hr = HrRegOpenKeyEx (hkeyService, L"Parameters", KEY_READ,
|
|
&hkeyParams);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD cbBuffer = _MAX_PATH;
|
|
hr = HrRegQuerySzBuffer (hkeyParams, L"NbProvider", pszName,
|
|
&cbBuffer);
|
|
|
|
RegCloseKey (hkeyParams);
|
|
}
|
|
RegCloseKey (hkeyService);
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr,
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr,
|
|
"HrGetNetBiosProviderName");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CLanaMap::HrSetLanaNumber (
|
|
IN BYTE OldLanaNumber,
|
|
IN BYTE NewLanaNumber)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (0 == m_LanasInUse[NewLanaNumber])
|
|
{
|
|
CLanaEntry* pEntry;
|
|
|
|
for (pEntry = begin(); pEntry != end(); pEntry++)
|
|
{
|
|
if (OldLanaNumber == pEntry->RegLanaEntry.LanaNumber)
|
|
{
|
|
// free up the lana number this entry had.
|
|
m_LanasInUse[pEntry->RegLanaEntry.LanaNumber] = 0;
|
|
|
|
// Give the entry the new lana number.
|
|
pEntry->RegLanaEntry.LanaNumber = NewLanaNumber;
|
|
|
|
m_LanasInUse[NewLanaNumber] = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pEntry == end())
|
|
{
|
|
hr = HRESULT_FROM_WIN32 (ERROR_OBJECT_NOT_FOUND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The lana is not free. We will swap the lanas used by the
|
|
// two paths.
|
|
//
|
|
|
|
CLanaEntry* pEntry;
|
|
CLanaEntry* pEntryToSet = NULL;
|
|
CLanaEntry* pEntryUsingLana = NULL;
|
|
|
|
for (pEntry = begin(); pEntry != end(); pEntry++)
|
|
{
|
|
if (!pEntryToSet &&
|
|
(OldLanaNumber == pEntry->RegLanaEntry.LanaNumber))
|
|
{
|
|
pEntryToSet = pEntry;
|
|
}
|
|
else if (!pEntryUsingLana &&
|
|
(NewLanaNumber == pEntry->RegLanaEntry.LanaNumber))
|
|
{
|
|
pEntryUsingLana = pEntry;
|
|
}
|
|
|
|
if (pEntryToSet && pEntryUsingLana)
|
|
{
|
|
// Give the entry the new lana number.
|
|
pEntryToSet->RegLanaEntry.LanaNumber = NewLanaNumber;
|
|
|
|
// Give the old lana number to the entry that was using the
|
|
// new lana number.
|
|
pEntryUsingLana->RegLanaEntry.LanaNumber = OldLanaNumber;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pEntryToSet || !pEntryUsingLana)
|
|
{
|
|
hr = HRESULT_FROM_WIN32 (ERROR_OBJECT_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CLanaMap::HrSetLanaNumber");
|
|
|
|
return hr;
|
|
}
|
|
|
|
BYTE
|
|
CLanaMap::GetMaxLana()
|
|
{
|
|
for (BYTE b = MAX_LANA; b; b--)
|
|
{
|
|
if (m_LanasInUse[b]) return b;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CLanaMap::HrWriteLanaConfiguration (
|
|
IN const CComponentList& Components)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Create the registry map that will be stored.
|
|
hr = HrCreateRegistryMap();
|
|
if (S_OK == hr)
|
|
{
|
|
// Write out the map and other lana info.
|
|
hr = HrWriteLanaMapConfig();
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "HrWriteLanaConfiguration");
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
DumpLanaBindPaths (
|
|
IN LANA_BIND_PATH* pBindSet,
|
|
IN DWORD cPaths)
|
|
{
|
|
LANA_BIND_PATH* pPath = pBindSet;
|
|
DWORD dw = 0;
|
|
VECTOR_OF_GUIDS::iterator iter;
|
|
|
|
for (dw = 0; dw < cPaths; dw++)
|
|
{
|
|
TraceTag (ttidNetcfgBase, "Path %d", dw);
|
|
for (iter = pPath->GuidsOfComponentsOnPath.begin();
|
|
iter != pPath->GuidsOfComponentsOnPath.end();
|
|
iter++)
|
|
{
|
|
const GUID* guid = *iter;
|
|
TraceTag (ttidNetcfgBase, " %lX", guid->Data1);
|
|
}
|
|
pPath++;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
UpdateLanaConfigWithAnswerFileInfo (
|
|
IN CLanaMap* pLanaMap,
|
|
IN DWORD cAfPaths,
|
|
IN LANA_BIND_PATH* pOriginalBindSet,
|
|
IN LANA_BIND_PATH* pAnswerFileBindSet)
|
|
{
|
|
DWORD dwAnswerFile;
|
|
DWORD dwPaths;
|
|
DWORD dwComponents;
|
|
DWORD dwNumberOfComponents;
|
|
BOOL fEqual;
|
|
LANA_BIND_PATH* pAfEntry;
|
|
LANA_BIND_PATH* pOEntry;
|
|
|
|
Assert (pLanaMap);
|
|
Assert (pOriginalBindSet);
|
|
Assert (pAnswerFileBindSet);
|
|
|
|
TraceTag (ttidNetcfgBase, "Dumping original bind set");
|
|
DumpLanaBindPaths (pOriginalBindSet, pLanaMap->CountEntries());
|
|
TraceTag (ttidNetcfgBase, "Dumping af bind set");
|
|
DumpLanaBindPaths (pAnswerFileBindSet, cAfPaths);
|
|
|
|
pAfEntry = pAnswerFileBindSet;
|
|
for (dwAnswerFile = 0; dwAnswerFile < cAfPaths; dwAnswerFile++)
|
|
{
|
|
// Do we have a valid path?
|
|
if (!pAfEntry->GuidsOfComponentsOnPath.empty())
|
|
{
|
|
pOEntry = pOriginalBindSet;
|
|
for (dwPaths = 0; dwPaths < pLanaMap->CountEntries(); dwPaths++)
|
|
{
|
|
if (pAfEntry->GuidsOfComponentsOnPath.size() ==
|
|
pOEntry->GuidsOfComponentsOnPath.size())
|
|
{
|
|
dwNumberOfComponents =
|
|
pAfEntry->GuidsOfComponentsOnPath.size();
|
|
|
|
fEqual = TRUE;
|
|
for (dwComponents = 0;
|
|
dwComponents < dwNumberOfComponents;
|
|
dwComponents++)
|
|
{
|
|
if (pAfEntry->GuidsOfComponentsOnPath[dwComponents] !=
|
|
pOEntry->GuidsOfComponentsOnPath[dwComponents])
|
|
{
|
|
fEqual = FALSE;
|
|
}
|
|
}
|
|
|
|
if (fEqual)
|
|
{
|
|
HRESULT hr;
|
|
hr = pLanaMap->HrSetLanaNumber (
|
|
pOEntry->LanaNumber,
|
|
pAfEntry->LanaNumber);
|
|
|
|
|
|
TraceTag (ttidNetcfgBase, "af path %d matches %d",
|
|
dwAnswerFile, dwPaths);
|
|
TraceTag (ttidNetcfgBase, "Changing lana number "
|
|
"from %X to %X", pOEntry->LanaNumber,
|
|
pAfEntry->LanaNumber);
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "Setting lana");
|
|
}
|
|
}
|
|
pOEntry++;
|
|
}
|
|
}
|
|
pAfEntry++;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ConvertAnswerFileComponentsToGuids (
|
|
IN const CComponentList& Components,
|
|
IN PCWSTR mszComponents,
|
|
OUT VECTOR_OF_GUIDS* pvector)
|
|
{
|
|
CComponent* pComponent;
|
|
PCWSTR pszScan;
|
|
const GUID* pguid;
|
|
GUID guidTemp;
|
|
|
|
Assert (mszComponents);
|
|
Assert (pvector);
|
|
|
|
for (pszScan = mszComponents; *pszScan; pszScan += wcslen (pszScan) + 1)
|
|
{
|
|
|
|
TraceTag (ttidNetcfgBase, " Looking for af component %S", pszScan);
|
|
|
|
// Look for the component in our installed components list.
|
|
//
|
|
pComponent = Components.PFindComponentByInfId (pszScan, NULL);
|
|
|
|
if (pComponent)
|
|
{
|
|
pguid = &pComponent->m_InstanceGuid;
|
|
}
|
|
else
|
|
{
|
|
TraceTag (ttidNetcfgBase, " Id did not match installed ids. "
|
|
"Checking af map");
|
|
|
|
// The component wasn't listed in our installed list. The inf
|
|
// id might be something that the answerfile processor has mapped
|
|
// to the component's instance guid. This happens for adapters.
|
|
// e.g. Id is listed as Adapter01 so netsetup uses an alogrithm
|
|
// to determine which adapter it is and then save off its
|
|
// instance guid in a map.
|
|
//
|
|
if (FGetInstanceGuidOfComponentFromAnswerFileMap (
|
|
pszScan, &guidTemp))
|
|
{
|
|
pComponent = Components.PFindComponentByInstanceGuid (
|
|
&guidTemp);
|
|
}
|
|
else
|
|
{
|
|
TraceTag (ttidError, " Component %S not found in answerfile "
|
|
"map", pszScan);
|
|
}
|
|
|
|
// If we found the component, store a reference to its
|
|
// instance guid
|
|
//
|
|
if (pComponent)
|
|
{
|
|
TraceTag (ttidNetcfgBase, " Found component");
|
|
pguid = &pComponent->m_InstanceGuid;
|
|
}
|
|
else
|
|
{
|
|
// We didn't find the component. Store GUID_NULL.
|
|
pguid = &GUID_NULL;
|
|
}
|
|
}
|
|
TraceTag (ttidNetcfgBase, " Using GUID %lX", pguid->Data1);
|
|
|
|
pvector->push_back (pguid);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
HrConvertAnswerFileParamsToLanaBindSet (
|
|
IN INFCONTEXT& ctxLana,
|
|
IN const CComponentList& Components,
|
|
IN DWORD cPaths,
|
|
OUT LANA_BIND_PATH* pBindSet)
|
|
{
|
|
DWORD cchField = _MAX_PATH;
|
|
DWORD cchRequired;
|
|
INT LanaCode;
|
|
PWSTR mszComponents;
|
|
HRESULT hr;
|
|
DWORD dw;
|
|
INFCONTEXT ctx = ctxLana;
|
|
LANA_BIND_PATH* pPath;
|
|
|
|
hr = S_OK;
|
|
mszComponents = (PWSTR)MemAlloc (cchField * sizeof (WCHAR));
|
|
|
|
pPath = pBindSet;
|
|
for (dw = 0; dw < cPaths; dw++)
|
|
{
|
|
if (mszComponents && (S_OK == hr))
|
|
{
|
|
hr = HrSetupGetMultiSzField (ctx, 1, mszComponents, cchField,
|
|
&cchRequired);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
TraceTag (ttidNetcfgBase, "Path %ld", dw);
|
|
ConvertAnswerFileComponentsToGuids (Components,
|
|
mszComponents,
|
|
&(pPath->GuidsOfComponentsOnPath));
|
|
|
|
hr = HrSetupFindNextLine (ctx, &ctx);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrSetupGetIntField (ctx, 1, &LanaCode);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
pPath->LanaNumber = LanaCode & 0xff;
|
|
|
|
TraceTag (ttidNetcfgBase, " Using LanaNumber %X for "
|
|
"path", pPath->LanaNumber);
|
|
}
|
|
else
|
|
{
|
|
TraceTag (ttidNetcfgBase, " Bad lana code");
|
|
// Bad lana number, clear the guids so we won't match
|
|
// this path and use this info.
|
|
//
|
|
pPath->GuidsOfComponentsOnPath.erase(
|
|
pPath->GuidsOfComponentsOnPath.begin(),
|
|
pPath->GuidsOfComponentsOnPath.end());
|
|
}
|
|
}
|
|
|
|
hr = HrSetupFindNextMatchLine (ctx, L"LanaPath", &ctx);
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pPath++;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
|
|
{
|
|
// Reallocate the buffer.
|
|
//
|
|
hr = S_OK;
|
|
MemFree (mszComponents);
|
|
mszComponents = (PWSTR)MemAlloc (cchRequired * sizeof(WCHAR));
|
|
cchField = cchRequired;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
// Check to see if we were really finished.
|
|
if ((dw + 1) < cPaths)
|
|
{
|
|
TraceTag (ttidError, "Answerfile specified %d lana paths "
|
|
"but only %d were found", cPaths, (dw + 1));
|
|
}
|
|
|
|
// This fcn only returns S_OK on success.
|
|
hr = S_OK;
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"HrConvertAnswerFileParamsToLanaBindSet");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HrProcessAnswerFile (
|
|
IN PCWSTR pszAnswerFile,
|
|
IN PCWSTR pszSection,
|
|
IN const CComponentList& Components,
|
|
OUT LANA_BIND_PATH** ppBindSet,
|
|
OUT DWORD* pcPaths)
|
|
{
|
|
HINF hinf;
|
|
PCWSTR pszBindPath;
|
|
WCHAR szBindName[_MAX_PATH];
|
|
HRESULT hr;
|
|
|
|
Assert (pszAnswerFile);
|
|
Assert (pszSection);
|
|
Assert (ppBindSet);
|
|
Assert (pcPaths);
|
|
|
|
*pcPaths = 0;
|
|
*ppBindSet = NULL;
|
|
|
|
hr = HrSetupOpenInfFile (pszAnswerFile, NULL,
|
|
INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL, &hinf);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrSetupGetFirstDword (hinf, pszSection,
|
|
L"NumberOfPaths", pcPaths);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
TraceTag (ttidNetcfgBase, "\n\n");
|
|
TraceTag (ttidNetcfgBase, "%d paths found in answerfile",
|
|
*pcPaths);
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
*ppBindSet = new LANA_BIND_PATH[*pcPaths];
|
|
if (*ppBindSet)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
INFCONTEXT ctx;
|
|
hr = HrSetupFindFirstLine (hinf, pszSection, L"LanaPath", &ctx);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrConvertAnswerFileParamsToLanaBindSet (ctx, Components,
|
|
*pcPaths, *ppBindSet);
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "HrProcessAnswerFile");
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
HrConvertBindingsToLanaBindSet (
|
|
IN const CComponentList& Components,
|
|
IN const CLanaMap& LanaMap,
|
|
OUT LANA_BIND_PATH** ppBindSet)
|
|
{
|
|
|
|
PCWSTR pszBindPath;
|
|
WCHAR szBindName[_MAX_PATH];
|
|
HRESULT hr;
|
|
DWORD cPaths;
|
|
|
|
Assert (ppBindSet);
|
|
|
|
cPaths = LanaMap.CountEntries();
|
|
|
|
TraceTag (ttidNetcfgBase, "%d paths in system", cPaths);
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
*ppBindSet = new LANA_BIND_PATH[cPaths];
|
|
|
|
if (*ppBindSet)
|
|
{
|
|
LANA_BIND_PATH* pBindPath = *ppBindSet;
|
|
CComponent* pComponent;
|
|
PCWSTR pszCompStart;
|
|
PCWSTR pszCompEnd;
|
|
DWORD cchComp;
|
|
|
|
hr = S_OK;
|
|
|
|
const CLanaEntry* pEntry;
|
|
for (pEntry = LanaMap.begin(); pEntry != LanaMap.end(); pEntry++)
|
|
{
|
|
pszBindPath = pEntry->pszBindPath;
|
|
|
|
TraceTag (ttidNetcfgBase, "BindPath %S", pszBindPath);
|
|
|
|
pBindPath->LanaNumber = pEntry->RegLanaEntry.LanaNumber;
|
|
TraceTag (ttidNetcfgBase, "Lana %X", pBindPath->LanaNumber);
|
|
|
|
GetFirstComponentFromBindPath (pszBindPath, &pszCompStart,
|
|
&cchComp);
|
|
|
|
while (*pszCompStart)
|
|
{
|
|
wcsncpy (szBindName, pszCompStart, cchComp);
|
|
szBindName[cchComp] = L'\0';
|
|
|
|
TraceTag (ttidNetcfgBase, " Searching for component with bind name %S",
|
|
szBindName);
|
|
|
|
pComponent = Components.PFindComponentByBindName (NC_INVALID,
|
|
szBindName);
|
|
|
|
if (pComponent)
|
|
{
|
|
TraceTag (ttidNetcfgBase, " Found component. Guid = %lX",
|
|
pComponent->m_InstanceGuid.Data1);
|
|
pBindPath->GuidsOfComponentsOnPath.push_back (&pComponent->m_InstanceGuid);
|
|
}
|
|
else
|
|
{
|
|
if (*pszCompEnd)
|
|
{
|
|
AssertSz (FALSE, " Bind Name not found in component list");
|
|
pBindPath->GuidsOfComponentsOnPath.push_back (&GUID_NULL);
|
|
}
|
|
}
|
|
|
|
pszCompStart = pszCompStart + cchComp;
|
|
|
|
if (*pszCompStart)
|
|
{
|
|
pszCompStart++;
|
|
|
|
pszCompEnd = wcschr (pszCompStart, L'_');
|
|
if (!pszCompEnd)
|
|
{
|
|
// There is no underscore so set the end pointer
|
|
// to the end of the string.
|
|
pszCompEnd = pszBindPath + wcslen (pszBindPath);
|
|
}
|
|
}
|
|
|
|
cchComp = pszCompEnd - pszCompStart;
|
|
}
|
|
pBindPath++;
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "HrConvertBindingsToLanaBindSet");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HrUpdateLanaConfig (
|
|
IN const CComponentList& Components,
|
|
IN PCWSTR pszBindPaths,
|
|
IN UINT cPaths)
|
|
{
|
|
CLanaMap CurrentLanaMap;
|
|
CLanaMap NewLanaMap;
|
|
HRESULT hr;
|
|
|
|
hr = CurrentLanaMap.HrLoadLanaMap();
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = NewLanaMap.HrReserveRoomForEntries (cPaths);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
PCWSTR pszScan;
|
|
CLanaEntry LanaEntry;
|
|
|
|
for (pszScan = pszBindPaths;
|
|
*pszScan;
|
|
pszScan += wcslen (pszScan) + 1)
|
|
{
|
|
LanaEntry.pszBindPath = pszScan;
|
|
CurrentLanaMap.GetLanaEntry (Components, &LanaEntry);
|
|
|
|
hr = NewLanaMap.HrAppendEntry (&LanaEntry);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = NewLanaMap.HrWriteLanaConfiguration (Components);
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "HrUpdateLanaConfig");
|
|
return hr;
|
|
|
|
}
|
|
|
|
EXTERN_C
|
|
VOID
|
|
WINAPI
|
|
UpdateLanaConfigUsingAnswerfile (
|
|
IN PCWSTR pszAnswerFile,
|
|
IN PCWSTR pszSection)
|
|
{
|
|
HRESULT hr;
|
|
CLanaMap LanaMap;
|
|
|
|
// Load the current lanamap information.
|
|
hr = LanaMap.HrLoadLanaMap();
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
TraceTag (ttidNetcfgBase, "Answerfile params %S:%S",
|
|
pszAnswerFile, pszSection);
|
|
|
|
// Load up the current network configuration.
|
|
//
|
|
|
|
CNetConfig NetConfig;
|
|
hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, &NetConfig);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = NetConfig.HrEnsureExternalDataLoadedForAllComponents();
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Convert our current lana bind paths to a lana bind set.
|
|
//
|
|
LANA_BIND_PATH* pBindSet;
|
|
hr = HrConvertBindingsToLanaBindSet (
|
|
NetConfig.Core.Components, LanaMap, &pBindSet);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Convert the answerfile lana bind paths
|
|
// to a lana bind set.
|
|
//
|
|
LANA_BIND_PATH* pAnswerFileBindSet;
|
|
DWORD cAnswerFilePaths;
|
|
|
|
hr = HrProcessAnswerFile (
|
|
pszAnswerFile, pszSection,
|
|
NetConfig.Core.Components, &pAnswerFileBindSet,
|
|
&cAnswerFilePaths);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Now update the config using the answerfile info.
|
|
//
|
|
UpdateLanaConfigWithAnswerFileInfo (
|
|
&LanaMap, cAnswerFilePaths,
|
|
pBindSet, pAnswerFileBindSet);
|
|
|
|
// Write out the information.
|
|
hr = LanaMap.HrWriteLanaConfiguration (
|
|
NetConfig.Core.Components);
|
|
|
|
delete [] pAnswerFileBindSet;
|
|
}
|
|
delete [] pBindSet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "UpdateLanaConfigUsingAnswerfile");
|
|
}
|
|
|