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.
 
 
 
 
 
 

1039 lines
32 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: R E G B I N D . C P P
//
// Contents: This module is responsible for writing bindings to the
// registry so that they may be consumed by NDIS and TDI.
//
// Notes:
//
// Author: shaunco 1 Feb 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "filtdevs.h"
#include "lanamap.h"
#include "netcfg.h"
#include "ncreg.h"
#include "ndispnp.h"
HRESULT
HrRegSetMultiSzAndLogDifference (
IN HKEY hkey,
IN PCWSTR pszValueName,
IN PCWSTR pmszValue,
IN const CComponent* pComponent
)
{
// Only log the difference if we're operating under the appropriate
// diagnostic context.
//
if (g_pDiagCtx->Flags() & DF_REPAIR_REGISTRY_BINDINGS)
{
HRESULT hr;
DWORD cbCurrent;
PWSTR pmszCurrent = (PWSTR)g_pDiagCtx->GetScratchBuffer(&cbCurrent);
// Read the current value into the diagnostic context's scratch
// buffer.
//
hr = HrRegQueryTypeSzBuffer (hkey, pszValueName, REG_MULTI_SZ,
pmszCurrent, &cbCurrent);
// Grow the scratch buffer and retry if the value is bigger than
// than will fit.
//
if ((HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr) ||
((NULL == pmszCurrent) && (S_OK == hr)))
{
pmszCurrent = (PWSTR)g_pDiagCtx->GrowScratchBuffer(&cbCurrent);
if (pmszCurrent)
{
hr = HrRegQueryTypeSzBuffer (hkey, pszValueName, REG_MULTI_SZ,
pmszCurrent, &cbCurrent);
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (S_OK == hr)
{
DWORD cbValue = CbOfMultiSzAndTermSafe(pmszValue);
// Compare the values and log if they are different.
//
if ((cbValue != cbCurrent) ||
(memcmp(pmszValue, pmszCurrent, cbCurrent)))
{
FILE *LogFile = g_pDiagCtx->LogFile();
fprintf(LogFile,
"reset Linkage\\%S for %S. bad value was:\n",
pszValueName, pComponent->PszGetPnpIdOrInfId());
fprintf(LogFile, " REG_MULTI_SZ =\n");
if (*pmszCurrent)
{
while (*pmszCurrent)
{
fprintf(LogFile, " %S\n", pmszCurrent);
pmszCurrent += wcslen(pmszCurrent) + 1;
}
}
else
{
fprintf(LogFile, " <empty>\n");
}
fprintf(LogFile, "\n");
}
else
{
// The value is correct. No need to write it.
//
return S_OK;
}
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
fprintf(g_pDiagCtx->LogFile(),
"added Linkage\\%S for %S\n",
pszValueName, pComponent->PszGetPnpIdOrInfId());
}
}
// N.B. success or failure of the diagnostic portion of this routine
// (above) should NOT affect the return value of this routine.
//
return HrRegSetMultiSz (hkey, pszValueName, pmszValue);
}
HRESULT
HrCreateLinkageKey (
IN const CComponent* pComponent,
IN CFilterDevice* pDevice,
IN HDEVINFO hdi,
OUT HKEY* phKey)
{
HRESULT hr = E_UNEXPECTED;
HKEY hkeyParent = NULL;
CONST REGSAM samDesired = KEY_READ | KEY_WRITE;
Assert (pComponent || pDevice);
Assert (!(pComponent && pDevice));
Assert (FIff(pDevice, hdi));
Assert (phKey);
if (pComponent)
{
// Open the parent of the linkage key. This is the instance key if
// the component is enumerated or does not have a service.
//
if (FIsEnumerated (pComponent->Class()) || !pComponent->FHasService())
{
hr = pComponent->HrOpenInstanceKey (samDesired,
&hkeyParent,
NULL, NULL);
if ((S_OK == hr) && FIsEnumerated (pComponent->Class()))
{
// Write out the netcfg instance id. Connections will use
// this to determine if the device is known by net config
// and will create the <instance guid> key under network
// to store its connection info. We only need to do this
// for enumerated components.
//
hr = HrRegSetGuidAsSz (hkeyParent, L"NetCfgInstanceId",
pComponent->m_InstanceGuid);
}
}
else
{
hr = pComponent->HrOpenServiceKey (samDesired, &hkeyParent);
}
}
else
{
Assert (pDevice);
Assert (hdi);
hr = HrSetupDiOpenDevRegKey (
hdi,
&pDevice->m_deid,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
samDesired,
&hkeyParent);
}
if (S_OK == hr)
{
Assert (hkeyParent);
hr = HrRegCreateKeyEx (
hkeyParent,
L"Linkage",
REG_OPTION_NON_VOLATILE,
samDesired,
NULL,
phKey,
NULL);
RegCloseKey (hkeyParent);
}
TraceHr (ttidError, FAL, hr,
(SPAPI_E_NO_SUCH_DEVINST == hr),
"HrCreateLinkageKey");
return hr;
}
HRESULT
HrWriteLinkageValues (
IN const CComponent* pComponent,
IN PCWSTR pmszBind,
IN PCWSTR pmszExport,
IN PCWSTR pmszRoute)
{
HRESULT hr;
HKEY hkeyLinkage;
PCWSTR pmsz;
Assert (pmszBind);
Assert (pmszExport);
Assert (pmszRoute);
g_pDiagCtx->Printf (ttidBeDiag, " %S (%S)\n",
pComponent->Ext.PszBindName(),
pComponent->PszGetPnpIdOrInfId());
if (FIsEnumerated (pComponent->Class()))
{
g_pDiagCtx->Printf (ttidBeDiag, " UpperBind:\n");
}
else
{
g_pDiagCtx->Printf (ttidBeDiag, " Bind:\n");
}
pmsz = pmszBind;
while (*pmsz)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pmsz);
pmsz += wcslen (pmsz) + 1;
}
g_pDiagCtx->Printf (ttidBeDiag, " Export:\n");
pmsz = pmszExport;
while (*pmsz)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pmsz);
pmsz += wcslen (pmsz) + 1;
}
g_pDiagCtx->Printf (ttidBeDiag, "\n");
hr = HrCreateLinkageKey (pComponent, NULL, NULL, &hkeyLinkage);
if (S_OK == hr)
{
// For enumerated components, write RootDevice, UpperBind, and Export.
// For non-enumerated components, write Bind and Export.
//
if (FIsEnumerated (pComponent->Class()))
{
// Create the root device multi-sz from the bindname.
//
WCHAR mszRootDevice [_MAX_PATH];
wcscpy (mszRootDevice, pComponent->Ext.PszBindName());
mszRootDevice [wcslen(mszRootDevice) + 1] = 0;
hr = HrRegSetMultiSzAndLogDifference (
hkeyLinkage, L"RootDevice", mszRootDevice, pComponent);
if (S_OK == hr)
{
hr = HrRegSetMultiSzAndLogDifference (
hkeyLinkage, L"UpperBind", pmszBind, pComponent);
}
}
else
{
hr = HrRegSetMultiSzAndLogDifference (
hkeyLinkage, L"Bind", pmszBind, pComponent);
if (S_OK == hr)
{
hr = HrRegSetMultiSzAndLogDifference (
hkeyLinkage, L"Route", pmszRoute, pComponent);
}
}
if ((S_OK == hr) && *pmszExport)
{
hr = HrRegSetMultiSzAndLogDifference (
hkeyLinkage, L"Export", pmszExport, pComponent);
}
RegCloseKey (hkeyLinkage);
}
TraceHr (ttidError, FAL, hr,
(SPAPI_E_NO_SUCH_DEVINST == hr),
"HrWriteLinkageValues");
return hr;
}
HRESULT
HrWriteFilterDeviceLinkage (
IN CFilterDevice* pDevice,
IN HDEVINFO hdi,
IN PCWSTR pmszExport,
IN PCWSTR pmszRootDevice,
IN PCWSTR pmszUpperBind)
{
HRESULT hr;
HKEY hkeyLinkage;
PCWSTR pmsz;
g_pDiagCtx->Printf (ttidBeDiag, " %S filter over %S adapter\n",
pDevice->m_pFilter->m_pszInfId,
pDevice->m_pAdapter->m_pszPnpId);
g_pDiagCtx->Printf (ttidBeDiag, " Export:\n");
pmsz = pmszExport;
while (*pmsz)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pmsz);
pmsz += wcslen (pmsz) + 1;
}
g_pDiagCtx->Printf (ttidBeDiag, " RootDevice:\n");
pmsz = pmszRootDevice;
while (*pmsz)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pmsz);
pmsz += wcslen (pmsz) + 1;
}
g_pDiagCtx->Printf (ttidBeDiag, " UpperBind:\n");
pmsz = pmszUpperBind;
while (*pmsz)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S\n", pmsz);
pmsz += wcslen (pmsz) + 1;
}
g_pDiagCtx->Printf (ttidBeDiag, "\n");
hr = HrCreateLinkageKey (NULL, pDevice, hdi, &hkeyLinkage);
if (S_OK == hr)
{
hr = HrRegSetMultiSz (hkeyLinkage, L"Export", pmszExport);
if (S_OK == hr)
{
hr = HrRegSetMultiSz (hkeyLinkage, L"RootDevice", pmszRootDevice);
}
if (S_OK == hr)
{
hr = HrRegSetMultiSz (hkeyLinkage, L"UpperBind", pmszUpperBind);
}
// Delete values used by the previous binding engine that are
// not needed any longer.
//
RegDeleteValue (hkeyLinkage, L"BindPath");
RegDeleteValue (hkeyLinkage, L"Bind");
RegDeleteValue (hkeyLinkage, L"Route");
RegDeleteKey (hkeyLinkage, L"Disabled");
RegCloseKey (hkeyLinkage);
}
// Now write to the standard filter parameter registry layout under
// the filter's service key.
//
if (pDevice->m_pFilter->Ext.PszService())
{
HKEY hkeyAdapterParams;
WCHAR szRegPath [_MAX_PATH];
Assert (pDevice->m_pFilter->Ext.PszService());
Assert (pDevice->m_pAdapter->Ext.PszBindName());
wsprintfW (
szRegPath,
L"System\\CurrentControlSet\\Services\\%s\\Parameters\\Adapters\\%s",
pDevice->m_pFilter->Ext.PszService(),
pDevice->m_pAdapter->Ext.PszBindName());
hr = HrRegCreateKeyEx (
HKEY_LOCAL_MACHINE,
szRegPath,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkeyAdapterParams,
NULL);
if (S_OK == hr)
{
// UpperBindings is a REG_SZ, not a REG_MULTI_SZ.
//
hr = HrRegSetSz (hkeyAdapterParams, L"UpperBindings", pmszExport);
RegCloseKey (hkeyAdapterParams);
}
}
TraceHr (ttidError, FAL, hr, FALSE, "HrWriteFilterDeviceLinkage");
return hr;
}
HRESULT
HrWriteFilteredAdapterUpperBind (
IN const CComponent* pAdapter,
IN PCWSTR pmszUpperBind)
{
HRESULT hr;
HKEY hkeyLinkage;
hr = HrCreateLinkageKey (pAdapter, NULL, NULL, &hkeyLinkage);
if (S_OK == hr)
{
hr = HrRegSetMultiSz (hkeyLinkage, L"UpperBind", pmszUpperBind);
RegCloseKey (hkeyLinkage);
}
TraceHr (ttidError, FAL, hr, FALSE, "HrWriteFilteredAdapterUpperBind");
return hr;
}
HRESULT
CRegistryBindingsContext::HrPrepare (
IN CNetConfig* pNetConfig)
{
HRESULT hr;
Assert (pNetConfig);
m_pNetConfig = pNetConfig;
hr = m_BindValue.HrReserveBytes (4096);
if (S_OK != hr)
{
return hr;
}
hr = m_ExportValue.HrReserveBytes (4096);
if (S_OK != hr)
{
return hr;
}
hr = m_RouteValue.HrReserveBytes (4096);
if (S_OK != hr)
{
return hr;
}
// Ensure all of the external data for all components is loaded.
//
hr = m_pNetConfig->HrEnsureExternalDataLoadedForAllComponents ();
if (S_OK != hr)
{
return hr;
}
// Ensure all of the notify objects have been initialized.
//
hr = m_pNetConfig->Notify.HrEnsureNotifyObjectsInitialized ();
if (S_OK != hr)
{
return hr;
}
return S_OK;
}
HRESULT
CRegistryBindingsContext::HrDeleteBindingsForComponent (
IN const CComponent* pComponent)
{
return HrWriteLinkageValues (pComponent, L"", L"", L"");
}
HRESULT
CRegistryBindingsContext::HrGetAdapterUpperBindValue (
IN const CComponent* pAdapter)
{
HRESULT hr;
const CBindPath* pBindPath;
m_BindValue.Clear();
// Get the upper bindings of the component. This returns a bindset
// with binpaths only 2 levels deep. That is, the bindpaths begin
// with the components one level above pComponent.
//
hr = m_pNetConfig->Core.HrGetComponentUpperBindings (
pAdapter,
GBF_PRUNE_DISABLED_BINDINGS,
&m_BindSet);
if (S_OK == hr)
{
for (pBindPath = m_BindSet.begin();
pBindPath != m_BindSet.end();
pBindPath++)
{
// Don't put filters in the UpperBind of an adapter.
//
if (pBindPath->POwner()->FIsFilter())
{
continue;
}
hr = m_BindValue.HrCopyString (
pBindPath->POwner()->Ext.PszBindName());
if (S_OK != hr)
{
break;
}
}
hr = m_BindValue.HrCopyString (L"");
}
TraceHr (ttidError, FAL, hr, FALSE,
"CRegistryBindingsContext::HrGetAdapterUpperBindValue");
return hr;
}
HRESULT
CRegistryBindingsContext::HrWriteBindingsForComponent (
IN const CComponent* pComponent)
{
HRESULT hr;
const CBindPath* pBindPath;
CBindPath::const_iterator iter;
const CComponent* pUpper;
const CComponent* pLower;
WCHAR szBind [_MAX_BIND_LENGTH];
WCHAR szExport [_MAX_BIND_LENGTH];
WCHAR szRoute [_MAX_BIND_LENGTH];
PWCHAR pchBind;
PWCHAR pchExport;
Assert (pComponent);
pComponent->Ext.DbgVerifyExternalDataLoaded ();
// If the component is not bindable, we have nothing to do.
//
if (!pComponent->FIsBindable())
{
return S_OK;
}
m_BindValue.Clear ();
m_ExportValue.Clear ();
m_RouteValue.Clear ();
wcscpy (szExport, L"\\Device\\");
wcscat (szExport, pComponent->Ext.PszBindName());
hr = m_ExportValue.HrCopyString (szExport);
Assert (S_OK == hr);
hr = m_ExportValue.HrCopyString (L"");
Assert (S_OK == hr);
if (FIsEnumerated (pComponent->Class()))
{
// UpperBind
//
hr = HrGetAdapterUpperBindValue (pComponent);
}
else
{
// Bind, Export
//
hr = m_pNetConfig->Core.HrGetComponentBindings (
pComponent,
GBF_PRUNE_DISABLED_BINDINGS,
&m_BindSet);
if ((S_OK == hr) && (m_BindSet.CountBindPaths() > 0))
{
// Since the component has bindings, it's export value will be
// different from the default one we initialized with above.
//
m_ExportValue.Clear ();
for (pBindPath = m_BindSet.begin();
pBindPath != m_BindSet.end();
pBindPath++)
{
Assert (pBindPath->CountComponents() > 1);
wcscpy (szBind, L"\\Device\\");
wcscpy (szExport, L"\\Device\\");
*szRoute = 0;
for (iter = pBindPath->begin();
iter != pBindPath->end();
iter++)
{
pUpper = *iter;
Assert (pUpper);
// For the bind value, skip the first component in each
// path because it is the component we are writing the
// bindings for.
//
if (iter != pBindPath->begin())
{
Assert (wcslen(szBind) + 1 +
wcslen(pUpper->Ext.PszBindName())
< celems(szBind));
// If this isn't the first component to come after
// \Device\, add underscores to seperate the
// components.
//
if (iter != (pBindPath->begin() + 1))
{
wcscat (szBind, L"_");
wcscat (szRoute, L" ");
}
wcscat (szBind, pUpper->Ext.PszBindName());
wcscat (szRoute, L"\"");
wcscat (szRoute, pUpper->Ext.PszBindName());
wcscat (szRoute, L"\"");
}
Assert (wcslen(szExport) + 1 +
wcslen(pUpper->Ext.PszBindName())
< celems(szExport));
// If this isn't the first component to come after
// \Device\, add underscores to seperate the
// components.
//
if (iter != pBindPath->begin())
{
wcscat (szExport, L"_");
}
wcscat (szExport, pUpper->Ext.PszBindName());
// If the next component in the bindpath is the last
// component, it is an adapter (by convention). Check
// to see if there are multiple interfaces to be expanded
// for the current component over this adapter.
//
if ((iter + 1) == (pBindPath->end() - 1))
{
DWORD cInterfaces;
GUID* pguidInterfaceIds;
pLower = *(iter + 1);
hr = pUpper->Notify.HrGetInterfaceIdsForAdapter (
m_pNetConfig->Notify.PINetCfg(),
pLower,
&cInterfaces,
&pguidInterfaceIds);
if (FAILED(hr))
{
break;
}
if (cInterfaces)
{
Assert (pguidInterfaceIds);
if (iter != pBindPath->begin())
{
wcscat (szBind, L"_");
pchBind = szBind + wcslen(szBind);
Assert (wcslen(szBind) +
c_cchGuidWithTerm < celems(szBind));
}
else
{
// The first component in the bindpath is
// one that has multiple interfaces over the
// adapter. The bind value should be as
// normal, the export value will have the
// expand interfaces.
//
Assert (wcslen(szBind) +
wcslen(pLower->Ext.PszBindName())
< celems(szBind));
wcscat (szBind, pLower->Ext.PszBindName());
hr = m_BindValue.HrCopyString (szBind);
if (S_OK != hr)
{
break;
}
}
wcscat (szExport, L"_");
pchExport = szExport + wcslen(szExport);
Assert (wcslen(szExport) +
c_cchGuidWithTerm < celems(szExport));
for (UINT i = 0; i < cInterfaces; i++)
{
if (iter != pBindPath->begin())
{
StringFromGUID2 (
pguidInterfaceIds[i],
pchBind, c_cchGuidWithTerm);
hr = m_BindValue.HrCopyString (szBind);
if (S_OK != hr)
{
break;
}
}
StringFromGUID2 (
pguidInterfaceIds[i],
pchExport, c_cchGuidWithTerm);
hr = m_ExportValue.HrCopyString (szExport);
if (S_OK != hr)
{
break;
}
}
CoTaskMemFree (pguidInterfaceIds);
if (iter != pBindPath->begin())
{
wcscat (szRoute, L" ");
}
wcscat (szRoute, L"\"");
wcscat (szRoute, pLower->Ext.PszBindName());
wcscat (szRoute, L"\"");
hr = m_RouteValue.HrCopyString (szRoute);
if (S_OK != hr)
{
break;
}
// We only allow one component in a bindpath
// to support mutliple interfaces and it always
// comes at the end of the bindpath. Therefore,
// after expanding them, we are done with the
// bindpath and proceed to the next. (Hence, the
// 'break').
//
break;
}
}
}
// If we exited the loop because we traversed the entire
// bindpath (as opposed to expanding multiple interfaces,
// where we would have stopped short), then add the bind
// and export strings for this bindpath to the buffer and
// proceed to the next bindpath.
//
if (iter == pBindPath->end())
{
hr = m_BindValue.HrCopyString (szBind);
if (S_OK != hr)
{
break;
}
hr = m_ExportValue.HrCopyString (szExport);
if (S_OK != hr)
{
break;
}
hr = m_RouteValue.HrCopyString (szRoute);
if (S_OK != hr)
{
break;
}
}
}
// The bind and export values are multi-sz, so make sure they
// are double null-terminiated.
//
hr = m_BindValue.HrCopyString (L"");
if (S_OK == hr)
{
hr = m_ExportValue.HrCopyString (L"");
}
if (S_OK == hr)
{
hr = m_RouteValue.HrCopyString (L"");
}
}
// Special case: NCF_DONTEXPOSELOWER
//
if ((S_OK == hr) &&
((pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER) ||
(0 == wcscmp(L"ms_nwspx", pComponent->m_pszInfId))))
{
wcscpy (szExport, L"\\Device\\");
wcscat (szExport, pComponent->Ext.PszBindName());
m_ExportValue.Clear ();
hr = m_ExportValue.HrCopyString (szExport);
Assert (S_OK == hr);
hr = m_ExportValue.HrCopyString (L"");
Assert (S_OK == hr);
}
// End Special case
}
if (S_OK == hr)
{
// Need to write out lanamap before writing new bindings since
// we need the old binding information to persist lana numbers.
//
if (0 == wcscmp (pComponent->m_pszInfId, L"ms_netbios"))
{
(VOID) HrUpdateLanaConfig (
m_pNetConfig->Core.Components,
(PCWSTR)m_BindValue.PbBuffer(),
m_BindSet.CountBindPaths());
}
hr = HrWriteLinkageValues (
pComponent,
(PCWSTR)m_BindValue.PbBuffer(),
(PCWSTR)m_ExportValue.PbBuffer(),
(PCWSTR)m_RouteValue.PbBuffer());
if(S_OK == hr)
{
// mbend June 20, 2000
// RAID 23275: Default gateway isn't respecting the adapter order specified under connections->advanced->properties
// Notify NDIS when the binding list for a component changes.
//
UNICODE_STRING LowerComponent;
UNICODE_STRING UpperComponent;
UNICODE_STRING BindList;
BOOL bOk = TRUE;
if (FIsEnumerated(pComponent->Class()))
{
RtlInitUnicodeString(&BindList, NULL);
RtlInitUnicodeString(&LowerComponent, NULL);
RtlInitUnicodeString(&UpperComponent, pComponent->Ext.PszBindName());
bOk = NdisHandlePnPEvent(
NDIS,
BIND_LIST,
&LowerComponent,
&UpperComponent,
&BindList,
const_cast<PBYTE>(m_BindValue.PbBuffer()),
m_BindValue.CountOfBytesUsed());
}
else
{
RtlInitUnicodeString(&BindList, NULL);
RtlInitUnicodeString(&LowerComponent, NULL);
RtlInitUnicodeString(&UpperComponent, pComponent->Ext.PszBindName());
TraceTag(ttidBeDiag, "BindName (TDI Client): %S", pComponent->Ext.PszBindName());
bOk = NdisHandlePnPEvent(
TDI,
RECONFIGURE,
&LowerComponent,
&UpperComponent,
&BindList,
const_cast<PBYTE>(m_BindValue.PbBuffer()),
m_BindValue.CountOfBytesUsed());
}
if(!bOk)
{
// hr = HrFromLastWin32Error();
}
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CRegistryBindingsContext::HrWriteBindingsForComponent");
return hr;
}
HRESULT
CRegistryBindingsContext::HrWriteBindingsForFilterDevices (
IN CFilterDevices* pFilterDevices)
{
HRESULT hr;
CFilterDevices::iterator iter;
CFilterDevices::iterator next;
CFilterDevice* pDevice;
CFilterDevice* pNextDevice;
CFilterDevice* pPrevDevice;
PCWSTR pmszRootDevice;
PCWSTR pmszUpperBind;
#define SZ_DEVICE_LEN 8 // characters in L"\\Device\\"
WCHAR mszExport [SZ_DEVICE_LEN + c_cchGuidWithTerm + 1];
WCHAR* const pchExportGuid = mszExport + SZ_DEVICE_LEN;
// Pre-fill the beginning of the Export string.
// Set the terminating NULL for the mutli-sz too.
//
wcscpy (mszExport, L"\\Device\\");
Assert (SZ_DEVICE_LEN == wcslen(mszExport));
mszExport[celems(mszExport) - 1] = 0;
hr = S_OK;
// Sort the filter devices by pAdapter and then by
// pFilter->m_dwFilterClassOrdinal. We will then iterate all filter
// devices to write the bindings. Because of the sort, we'll iterate
// all filter devices for a given adapter in class order from smallest
// to largest. (Smaller class ordinals have affinity for the protocol.)
//
pFilterDevices->SortForWritingBindings ();
pPrevDevice = NULL;
for (iter = pFilterDevices->begin();
iter != pFilterDevices->end();
iter++)
{
pDevice = *iter;
Assert (pDevice);
// Generate the rest of the Export string.
// \Device\{GUID}
//
Assert ((c_cchGuidWithTerm - 1) == wcslen(pDevice->m_szInstanceGuid));
wcscpy (pchExportGuid, pDevice->m_szInstanceGuid);
// If this device's adapter is different than the previous device's
// adapter, we are dealing with the top of a new chain. We need
// to initialize RootDevice which will be the multi-sz of all
// bindnames in the chain including the adapter.
//
if (!pPrevDevice ||
(pDevice->m_pAdapter != pPrevDevice->m_pAdapter))
{
// Compute RootDevice.
// We'll use m_ExportValue as the buffer.
//
m_ExportValue.Clear();
m_ExportValue.HrCopyString (pDevice->m_szInstanceGuid);
for (next = iter + 1;
next != pFilterDevices->end();
next++)
{
pNextDevice = *next;
Assert (pNextDevice);
// We're done when we reach the next filter chain.
//
if (pNextDevice->m_pAdapter != pDevice->m_pAdapter)
{
break;
}
m_ExportValue.HrCopyString (pNextDevice->m_szInstanceGuid);
}
m_ExportValue.HrCopyString (pDevice->m_pAdapter->Ext.PszBindName());
m_ExportValue.HrCopyString (L"");
pmszRootDevice = (PCWSTR)m_ExportValue.PbBuffer();
Assert (*pmszRootDevice);
// Compute UpperBind.
// We'll use m_BindValue as the buffer.
//
hr = HrGetAdapterUpperBindValue (pDevice->m_pAdapter);
}
// We're continuing in the filter chain and this device is not
// the topmost. (not closest to the protocol).
//
else
{
// Since RootDevice was built up for the top device in the chain,
// each successive device just needs to skip past the next
// string in the mutli-sz.
//
Assert (*pmszRootDevice);
pmszRootDevice += wcslen(pmszRootDevice) + 1;
// UpperBind is the previous device's filter's bind name.
//
m_BindValue.Clear();
m_BindValue.HrCopyString (pPrevDevice->m_pFilter->Ext.PszBindName());
m_BindValue.HrCopyString (L"");
}
pmszUpperBind = (PCWSTR)m_BindValue.PbBuffer();
// We now have:
// Export in mszExport
// RootDevice at pmszRootDevice (in m_ExportValue)
// UpperBind at pmszUpperBind (in m_BindValue)
//
hr = HrWriteFilterDeviceLinkage (
pDevice, pFilterDevices->m_hdi,
mszExport, pmszRootDevice, pmszUpperBind);
// If this is the last device in the chain, we need to write
// the UpperBind of the adapter to be this filter device.
//
next = iter + 1;
if ((next == pFilterDevices->end()) ||
(*next)->m_pAdapter != pDevice->m_pAdapter)
{
// UpperBind is this last device's filter's bind name.
//
m_BindValue.Clear();
m_BindValue.HrCopyString (pDevice->m_pFilter->Ext.PszBindName());
m_BindValue.HrCopyString (L"");
pmszUpperBind = (PCWSTR)m_BindValue.PbBuffer();
hr = HrWriteFilteredAdapterUpperBind (
pDevice->m_pAdapter,
pmszUpperBind);
}
// Remember the previous device so that when we go to the next
// device, we'll know we're dealing with a different chain if
// the next device's adapter is different than this one.
//
pPrevDevice = pDevice;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CRegistryBindingsContext::HrWriteBindingsForFilterDevices");
return hr;
}