867 lines
24 KiB
C++
867 lines
24 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1999.
|
||
|
//
|
||
|
// File: F I L T D E V S . C P P
|
||
|
//
|
||
|
// Contents: Implements the basic datatype for a collection of filter
|
||
|
// devices.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: shaunco 15 Jan 1999
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.h>
|
||
|
#pragma hdrstop
|
||
|
#include "classinst.h"
|
||
|
#include "filtdevs.h"
|
||
|
#include "nceh.h"
|
||
|
#include "ncreg.h"
|
||
|
#include "ncstl.h"
|
||
|
#include "ncsetup.h"
|
||
|
|
||
|
|
||
|
CFilterDevices::CFilterDevices (
|
||
|
IN CNetConfigCore* pCore)
|
||
|
{
|
||
|
Assert (pCore);
|
||
|
|
||
|
ZeroMemory (this, sizeof(*this));
|
||
|
|
||
|
m_pCore = pCore;
|
||
|
}
|
||
|
|
||
|
CFilterDevices::~CFilterDevices ()
|
||
|
{
|
||
|
// Free had better have been called before this.
|
||
|
//
|
||
|
Assert (this);
|
||
|
Assert (!m_hdi);
|
||
|
Assert (!m_pmszFilterClasses);
|
||
|
Assert (empty());
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CFilterDevices::HrInsertFilterDevice (
|
||
|
IN CFilterDevice* pDevice)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (pDevice);
|
||
|
|
||
|
// Assert there is not already a device in the list with the
|
||
|
// same instance guid.
|
||
|
//
|
||
|
Assert (!PFindFilterDeviceByInstanceGuid (pDevice->m_szInstanceGuid));
|
||
|
|
||
|
// Assert there is not already a device in the list with the
|
||
|
// same parent filter AND the same filtered adapter.
|
||
|
//
|
||
|
Assert (!PFindFilterDeviceByAdapterAndFilter (
|
||
|
pDevice->m_pAdapter,
|
||
|
pDevice->m_pFilter));
|
||
|
|
||
|
NC_TRY
|
||
|
{
|
||
|
push_back (pDevice);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
NC_CATCH_ALL
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "CFilterDevices::HrInsertFilterDevice");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CFilterDevices::HrPrepare ()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
HKEY hkeyNetwork;
|
||
|
|
||
|
// Reserve room for 8 different filters in our internal member.
|
||
|
// We use this component list at various times as "scratch space" when
|
||
|
// figuring out which filters are enabled for an adapter.
|
||
|
//
|
||
|
hr = m_Filters.HrReserveRoomForComponents (8);
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
goto finished;
|
||
|
}
|
||
|
|
||
|
hr = m_BindPathsToRebind.HrReserveRoomForBindPaths (8);
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
goto finished;
|
||
|
}
|
||
|
|
||
|
// Load the FilterClasses multi-sz.
|
||
|
//
|
||
|
|
||
|
hr = HrOpenNetworkKey (KEY_READ, &hkeyNetwork);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrRegQueryMultiSzWithAlloc (
|
||
|
hkeyNetwork,
|
||
|
L"FilterClasses",
|
||
|
&m_pmszFilterClasses);
|
||
|
|
||
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
||
|
{
|
||
|
Assert (!m_pmszFilterClasses);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hkeyNetwork);
|
||
|
}
|
||
|
|
||
|
finished:
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "CFilterDevices::HrPrepare");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CFilterDevice*
|
||
|
CFilterDevices::PFindFilterDeviceByAdapterAndFilter (
|
||
|
IN const CComponent* pAdapter,
|
||
|
IN const CComponent* pFilter) const
|
||
|
{
|
||
|
const_iterator iter;
|
||
|
CFilterDevice* pDevice;
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (pAdapter);
|
||
|
Assert (pFilter);
|
||
|
Assert (FIsEnumerated(pAdapter->Class()));
|
||
|
Assert (NC_NETSERVICE == pFilter->Class());
|
||
|
Assert (pFilter->FIsFilter());
|
||
|
|
||
|
for (iter = begin(); iter != end(); iter++)
|
||
|
{
|
||
|
pDevice = *iter;
|
||
|
Assert (pDevice);
|
||
|
|
||
|
if ((pAdapter == pDevice->m_pAdapter) &&
|
||
|
(pFilter == pDevice->m_pFilter))
|
||
|
{
|
||
|
return pDevice;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CFilterDevices::MapFilterClassToOrdinal (
|
||
|
IN PCWSTR pszFilterClass)
|
||
|
{
|
||
|
DWORD Ordinal;
|
||
|
DWORD dwIndex;
|
||
|
DWORD cStrings;
|
||
|
|
||
|
Assert (pszFilterClass);
|
||
|
#if DBG
|
||
|
Ordinal = 0;
|
||
|
#endif
|
||
|
|
||
|
// If the class is found in the list, return its position.
|
||
|
//
|
||
|
if (FGetSzPositionInMultiSzSafe (
|
||
|
pszFilterClass,
|
||
|
m_pmszFilterClasses,
|
||
|
&dwIndex,
|
||
|
NULL,
|
||
|
&cStrings))
|
||
|
{
|
||
|
Ordinal = dwIndex + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
PWSTR pmszNew;
|
||
|
BOOL fChanged;
|
||
|
|
||
|
// We're adding another string, so compute the new ordinal value
|
||
|
// for return.
|
||
|
//
|
||
|
Ordinal = cStrings + 1;
|
||
|
|
||
|
// String was not found, so we append it at the end.
|
||
|
// It is important to insert at the end so we don't have to
|
||
|
// change the ordinals of any existing filters that already
|
||
|
// had their ordinal computed.
|
||
|
//
|
||
|
hr = HrAddSzToMultiSz (pszFilterClass, m_pmszFilterClasses,
|
||
|
STRING_FLAG_ENSURE_AT_END, 0, &pmszNew, &fChanged);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
HKEY hkeyNetwork;
|
||
|
|
||
|
// It better have changed because we didn't find the string
|
||
|
// above.
|
||
|
//
|
||
|
Assert (fChanged);
|
||
|
|
||
|
// Out with the old. In with the new.
|
||
|
//
|
||
|
MemFree (m_pmszFilterClasses);
|
||
|
m_pmszFilterClasses = pmszNew;
|
||
|
|
||
|
// Save it back to the registry.
|
||
|
//
|
||
|
hr = HrOpenNetworkKey (KEY_WRITE, &hkeyNetwork);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrRegSetMultiSz (
|
||
|
hkeyNetwork,
|
||
|
L"FilterClasses",
|
||
|
m_pmszFilterClasses);
|
||
|
|
||
|
Assert (S_OK == hr);
|
||
|
|
||
|
RegCloseKey (hkeyNetwork);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// By definition, Ordinal is 1-based. This is so that when stored
|
||
|
// in CComponent, we know we have to load the filter class and get
|
||
|
// its ordinal if CComponent::FilterClassOrdinal is zero. i.e. zero
|
||
|
// is a sentinel value that means we need to do work and when non-zero
|
||
|
// means we don't have to do that work again.
|
||
|
//
|
||
|
Assert (Ordinal != 0);
|
||
|
return Ordinal;
|
||
|
}
|
||
|
|
||
|
CFilterDevice*
|
||
|
CFilterDevices::PFindFilterDeviceByInstanceGuid (
|
||
|
IN PCWSTR pszInstanceGuid) const
|
||
|
{
|
||
|
const_iterator iter;
|
||
|
CFilterDevice* pDevice;
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (pszInstanceGuid && *pszInstanceGuid);
|
||
|
|
||
|
for (iter = begin(); iter != end(); iter++)
|
||
|
{
|
||
|
pDevice = *iter;
|
||
|
Assert (pDevice);
|
||
|
|
||
|
if (0 == wcscmp(pszInstanceGuid, pDevice->m_szInstanceGuid))
|
||
|
{
|
||
|
return pDevice;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CFilterDevices::HrLoadFilterDevice (
|
||
|
IN SP_DEVINFO_DATA* pdeid,
|
||
|
IN HKEY hkeyInstance,
|
||
|
IN PCWSTR pszFilterInfId,
|
||
|
OUT BOOL* pfRemove)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
CComponent* pAdapter;
|
||
|
CComponent* pFilter;
|
||
|
WCHAR szInstanceGuid [c_cchGuidWithTerm];
|
||
|
DWORD cbBuffer;
|
||
|
|
||
|
Assert (pszFilterInfId && *pszFilterInfId);
|
||
|
Assert (pfRemove);
|
||
|
|
||
|
*pfRemove = FALSE;
|
||
|
|
||
|
// Initialize these to NULL. If we don't find them below, they will
|
||
|
// remain NULL and this will tell us something.
|
||
|
//
|
||
|
pAdapter = NULL;
|
||
|
pFilter = NULL;
|
||
|
|
||
|
cbBuffer = sizeof(szInstanceGuid);
|
||
|
hr = HrRegQuerySzBuffer (
|
||
|
hkeyInstance,
|
||
|
L"NetCfgInstanceId",
|
||
|
szInstanceGuid, &cbBuffer);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
HKEY hkeyLinkage;
|
||
|
|
||
|
// Read the RootDevice registry value for this filter device. The
|
||
|
// last entry in that multi-sz will be the bindname of the adapter
|
||
|
// being filtered.
|
||
|
//
|
||
|
hr = HrRegOpenKeyEx (
|
||
|
hkeyInstance,
|
||
|
L"Linkage",
|
||
|
KEY_READ,
|
||
|
&hkeyLinkage);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
PWSTR pmszRootDevice;
|
||
|
|
||
|
hr = HrRegQueryMultiSzWithAlloc (
|
||
|
hkeyLinkage,
|
||
|
L"RootDevice",
|
||
|
&pmszRootDevice);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
PCWSTR pszScan;
|
||
|
PCWSTR pszLastDevice = NULL;
|
||
|
|
||
|
// Scan to the last string in the multi-sz and note it.
|
||
|
//
|
||
|
for (pszScan = pmszRootDevice;
|
||
|
*pszScan;
|
||
|
pszScan += wcslen(pszScan) + 1)
|
||
|
{
|
||
|
pszLastDevice = pszScan;
|
||
|
}
|
||
|
|
||
|
// The last string in the multi-sz is the bindname of the
|
||
|
// adapter being filtered.
|
||
|
//
|
||
|
if (pszLastDevice)
|
||
|
{
|
||
|
pAdapter = m_pCore->Components.PFindComponentByBindName (
|
||
|
NC_NET, pszLastDevice);
|
||
|
if (!pAdapter)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MemFree (pmszRootDevice);
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hkeyLinkage);
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Should have the adapter if no error.
|
||
|
//
|
||
|
Assert (pAdapter);
|
||
|
|
||
|
// Get the enabled filters for the adapter.
|
||
|
//
|
||
|
hr = m_pCore->HrGetFiltersEnabledForAdapter (pAdapter, &m_Filters);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Use pszFilterInfId to find the parent filter component for
|
||
|
// this filter device. If it is not found, it probably means
|
||
|
// the entire filter is in the process of being removed.
|
||
|
// (Or the registry was messed with.)
|
||
|
//
|
||
|
pFilter = m_pCore->Components.PFindComponentByInfId (
|
||
|
pszFilterInfId, NULL);
|
||
|
|
||
|
// If the filter corresponding to this device is still
|
||
|
// installed and is enabled over the adapter, then we'll
|
||
|
// insert the device into our list. Otherwise, we're going
|
||
|
// to remove it.
|
||
|
//
|
||
|
if (pFilter && m_Filters.FComponentInList (pFilter))
|
||
|
{
|
||
|
CFilterDevice* pFilterDevice;
|
||
|
|
||
|
// Create an instance of the filter device class to
|
||
|
// represent this filter device.
|
||
|
//
|
||
|
hr = CFilterDevice::HrCreateInstance (
|
||
|
pAdapter,
|
||
|
pFilter,
|
||
|
pdeid,
|
||
|
szInstanceGuid,
|
||
|
&pFilterDevice);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Add the filter device to our list of filter devices.
|
||
|
//
|
||
|
hr = HrInsertFilterDevice (pFilterDevice);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
delete pFilterDevice;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pfRemove = TRUE;
|
||
|
|
||
|
Assert (pszFilterInfId && *pszFilterInfId);
|
||
|
Assert (pAdapter);
|
||
|
|
||
|
g_pDiagCtx->Printf (ttidBeDiag,
|
||
|
" Removing filter device for %S over %S adapter\n",
|
||
|
pszFilterInfId,
|
||
|
pAdapter->m_pszPnpId);
|
||
|
|
||
|
// Since we will be removing a filter device from the
|
||
|
// chain, we need to rebind the protocols above the
|
||
|
// adapter we are removing the filter device for.
|
||
|
//
|
||
|
// So, get the upper bindings of the adapter (bindpaths
|
||
|
// are only 2 levels deep) and add them to the bind set
|
||
|
// that we will rebind later on.
|
||
|
//
|
||
|
hr = m_pCore->HrGetComponentUpperBindings (
|
||
|
pAdapter,
|
||
|
GBF_ADD_TO_BINDSET | GBF_PRUNE_DISABLED_BINDINGS,
|
||
|
&m_BindPathsToRebind);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr,
|
||
|
"CFilterDevices::HrLoadFilterDevice");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterDevices::LoadAndRemoveFilterDevicesIfNeeded ()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
SP_DEVINFO_DATA deid;
|
||
|
DWORD dwIndex;
|
||
|
DWORD cbBuffer;
|
||
|
WCHAR szFilterInfId [_MAX_PATH];
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (m_pCore);
|
||
|
Assert (!m_hdi);
|
||
|
Assert (empty());
|
||
|
|
||
|
// Filter devices can only be of net class.
|
||
|
//
|
||
|
hr = HrSetupDiGetClassDevs (&GUID_DEVCLASS_NET, NULL, NULL,
|
||
|
DIGCF_PROFILE, &m_hdi);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Assert (m_hdi);
|
||
|
|
||
|
// Enumerate all net class devices from setupapi.
|
||
|
//
|
||
|
for (dwIndex = 0; S_OK == hr; dwIndex++)
|
||
|
{
|
||
|
hr = HrSetupDiEnumDeviceInfo (m_hdi, dwIndex, &deid);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
HKEY hkeyInstance;
|
||
|
|
||
|
hr = HrSetupDiOpenDevRegKey (
|
||
|
m_hdi, &deid,
|
||
|
DICS_FLAG_GLOBAL, 0, DIREG_DRV,
|
||
|
KEY_READ, &hkeyInstance);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// If the device has a "FilterInfId" value under its
|
||
|
// instance key, its one of ours.
|
||
|
//
|
||
|
cbBuffer = sizeof(szFilterInfId);
|
||
|
hr = HrRegQuerySzBuffer (
|
||
|
hkeyInstance,
|
||
|
L"FilterInfId",
|
||
|
szFilterInfId,
|
||
|
&cbBuffer);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
BOOL fRemove;
|
||
|
|
||
|
// Load the rest of the filter device, and add it to
|
||
|
// our list. If this fails for any reason, remove the
|
||
|
// filter device because its of no use to us anymore.
|
||
|
//
|
||
|
hr = HrLoadFilterDevice (
|
||
|
&deid,
|
||
|
hkeyInstance,
|
||
|
szFilterInfId,
|
||
|
&fRemove);
|
||
|
|
||
|
if ((S_OK != hr) || fRemove)
|
||
|
{
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf (ttidBeDiag,
|
||
|
" Removing filter device for %S\n",
|
||
|
szFilterInfId);
|
||
|
}
|
||
|
|
||
|
(VOID) HrCiRemoveFilterDevice (m_hdi, &deid);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
||
|
//{
|
||
|
// Not a filter device. Skip it.
|
||
|
//}
|
||
|
|
||
|
RegCloseKey (hkeyInstance);
|
||
|
}
|
||
|
|
||
|
// Allow the loop to continue;
|
||
|
//
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
g_pDiagCtx->Printf (ttidBeDiag, " Loaded %d filter devices\n", size());
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterDevices::InstallFilterDevicesIfNeeded ()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
CComponentList::iterator iterAdapter;
|
||
|
CComponentList::iterator iterFilter;
|
||
|
CComponent* pAdapter;
|
||
|
CComponent* pFilter;
|
||
|
HKEY hkeyInstance;
|
||
|
HKEY hkeyNdi;
|
||
|
DWORD cbBuffer;
|
||
|
BOOL fAddDevice;
|
||
|
BOOL fAddedDeviceForAdapter;
|
||
|
WCHAR szFilterDeviceInfId [_MAX_PATH];
|
||
|
WCHAR szFilterClass [_MAX_PATH];
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (m_pCore);
|
||
|
|
||
|
// If, for some reason, we couldn't get m_hdi up in
|
||
|
// RemoveFilterDevicesIfNeeded, we can't proceed.
|
||
|
//
|
||
|
if (!m_hdi)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// For all adapters (because filters possibly bind to any adapter)
|
||
|
// we get the filters enabled for each. For each on of these filters
|
||
|
// that don't already have an associated filter device for the adapter,
|
||
|
// we create a new one and associated it.
|
||
|
//
|
||
|
for (iterAdapter = m_pCore->Components.begin();
|
||
|
iterAdapter != m_pCore->Components.end();
|
||
|
iterAdapter++)
|
||
|
{
|
||
|
pAdapter = *iterAdapter;
|
||
|
Assert (pAdapter);
|
||
|
|
||
|
// Skip components that are not network adapters.
|
||
|
//
|
||
|
if (NC_NET != pAdapter->Class())
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
hr = m_pCore->HrGetFiltersEnabledForAdapter (pAdapter, &m_Filters);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
// More than likely, we are out of memory.
|
||
|
//
|
||
|
TraceHr (ttidError, FAL, hr, FALSE,
|
||
|
"HrGetFiltersEnabledForAdapter failed in "
|
||
|
"InstallFilterDevicesIfNeeded. Adapter=%S",
|
||
|
pAdapter->m_pszPnpId);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// We haven't yet added any devices for this adapter.
|
||
|
//
|
||
|
fAddedDeviceForAdapter = FALSE;
|
||
|
|
||
|
// For each of the filters enabled for this adapter, install
|
||
|
// a filter device if needed and make sure the filter has its
|
||
|
// ordinal position with respect other filters read from the
|
||
|
// registry. We need m_dwFilterClassOrdinal to be valid (non-zero)
|
||
|
// before we sort the filter devices when writing their bindings.
|
||
|
//
|
||
|
for (iterFilter = m_Filters.begin();
|
||
|
iterFilter != m_Filters.end();
|
||
|
iterFilter++)
|
||
|
{
|
||
|
pFilter = *iterFilter;
|
||
|
Assert (pFilter);
|
||
|
|
||
|
// If there isn't a filter device for the current adapter
|
||
|
// and filter, we need to install one.
|
||
|
//
|
||
|
fAddDevice = !PFindFilterDeviceByAdapterAndFilter (
|
||
|
pAdapter, pFilter);
|
||
|
|
||
|
// If we don't need to add a filter device and we already
|
||
|
// have the ordinal position of the filter, we can continue with
|
||
|
// the next filter for this adapter.
|
||
|
//
|
||
|
if (!fAddDevice && (0 != pFilter->m_dwFilterClassOrdinal))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
*szFilterDeviceInfId = 0;
|
||
|
|
||
|
// Open the instance key of the filter so we can read
|
||
|
// a few values.
|
||
|
//
|
||
|
hr = pFilter->HrOpenInstanceKey (KEY_READ, &hkeyInstance,
|
||
|
NULL, NULL);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Open the Ndi key.
|
||
|
//
|
||
|
hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi",
|
||
|
KEY_READ, &hkeyNdi);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
if (0 == pFilter->m_dwFilterClassOrdinal)
|
||
|
{
|
||
|
// Read the filter class and convert it to an
|
||
|
// ordinal based on its position in the
|
||
|
// filter classes list.
|
||
|
//
|
||
|
cbBuffer = sizeof(szFilterClass);
|
||
|
|
||
|
hr = HrRegQuerySzBuffer (hkeyNdi,
|
||
|
L"FilterClass",
|
||
|
szFilterClass,
|
||
|
&cbBuffer);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
pFilter->m_dwFilterClassOrdinal =
|
||
|
MapFilterClassToOrdinal (szFilterClass);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fAddDevice)
|
||
|
{
|
||
|
// Read the ind id of the filter device.
|
||
|
//
|
||
|
cbBuffer = sizeof(szFilterDeviceInfId);
|
||
|
|
||
|
hr = HrRegQuerySzBuffer (
|
||
|
hkeyNdi, L"FilterDeviceInfId",
|
||
|
szFilterDeviceInfId, &cbBuffer);
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hkeyNdi);
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hkeyInstance);
|
||
|
}
|
||
|
|
||
|
if ((S_OK == hr) && fAddDevice)
|
||
|
{
|
||
|
CFilterDevice* pFilterDevice;
|
||
|
|
||
|
Assert (*szFilterDeviceInfId);
|
||
|
|
||
|
g_pDiagCtx->Printf (ttidBeDiag,
|
||
|
" Installing filter device for %S over %S adapter\n",
|
||
|
pFilter->m_pszInfId,
|
||
|
pAdapter->m_pszPnpId);
|
||
|
|
||
|
|
||
|
hr = HrCiInstallFilterDevice (m_hdi,
|
||
|
szFilterDeviceInfId,
|
||
|
pAdapter,
|
||
|
pFilter,
|
||
|
&pFilterDevice);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrInsertFilterDevice (pFilterDevice);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
fAddedDeviceForAdapter = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete pFilterDevice;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we added at least one filter device in the chain for this
|
||
|
// adapter, we'll need to unbind the adapter from whatever it is
|
||
|
// currently bound to before we start the filter device.
|
||
|
//
|
||
|
if (fAddedDeviceForAdapter)
|
||
|
{
|
||
|
// So, get the upper bindings of the adapter (bindpaths
|
||
|
// are only 2 levels deep) and add them to the bind set
|
||
|
// that we will rebind later on.
|
||
|
//
|
||
|
hr = m_pCore->HrGetComponentUpperBindings (
|
||
|
pAdapter,
|
||
|
GBF_ADD_TO_BINDSET | GBF_PRUNE_DISABLED_BINDINGS,
|
||
|
&m_BindPathsToRebind);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
INT
|
||
|
__cdecl
|
||
|
CompareFilterDevices (
|
||
|
const VOID* pv1,
|
||
|
const VOID* pv2)
|
||
|
{
|
||
|
CFilterDevice* pDevice1 = *((CFilterDevice**)pv1);
|
||
|
CFilterDevice* pDevice2 = *((CFilterDevice**)pv2);
|
||
|
|
||
|
if (pDevice1->m_pAdapter == pDevice2->m_pAdapter)
|
||
|
{
|
||
|
Assert (pDevice1->m_pFilter != pDevice2->m_pFilter);
|
||
|
|
||
|
if (pDevice1->m_pFilter->m_dwFilterClassOrdinal ==
|
||
|
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
|
||
|
{
|
||
|
AssertSz (0, "We have two filters of the same class installed.");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return (pDevice1->m_pFilter->m_dwFilterClassOrdinal <
|
||
|
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
|
||
|
? -1 : 1;
|
||
|
}
|
||
|
|
||
|
return (pDevice1->m_pAdapter < pDevice2->m_pAdapter) ? -1 : 1;
|
||
|
|
||
|
/*
|
||
|
if (pDevice1->m_pFilter == pDevice2->m_pFilter)
|
||
|
{
|
||
|
Assert (pDevice1->m_pAdapter != pDevice2->m_pAdapter);
|
||
|
|
||
|
return (pDevice1->m_pAdapter < pDevice2->m_pAdapter) ? -1 : 1;
|
||
|
}
|
||
|
|
||
|
if (pDevice1->m_pFilter->m_dwFilterClassOrdinal ==
|
||
|
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
|
||
|
{
|
||
|
AssertSz (0, "We have two filters of the same class installed.");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return (pDevice1->m_pFilter->m_dwFilterClassOrdinal <
|
||
|
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
|
||
|
? -1 : 1;
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterDevices::SortForWritingBindings ()
|
||
|
{
|
||
|
Assert (this);
|
||
|
|
||
|
// If we're empty, there is nothing to do.
|
||
|
//
|
||
|
if (empty())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
qsort (begin(), size(), sizeof(CFilterDevice*), CompareFilterDevices);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterDevices::StartFilterDevices ()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
CFilterDevices::reverse_iterator iter;
|
||
|
CFilterDevice* pDevice;
|
||
|
|
||
|
Assert (this);
|
||
|
Assert (m_pCore);
|
||
|
|
||
|
// If we're empty, there is nothing to do.
|
||
|
//
|
||
|
if (empty())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If we're not empty, we must have had m_hdi to insert something.
|
||
|
//
|
||
|
Assert (m_hdi);
|
||
|
|
||
|
for (iter = rbegin(); iter != rend(); iter++)
|
||
|
{
|
||
|
pDevice = *iter;
|
||
|
Assert (pDevice);
|
||
|
|
||
|
g_pDiagCtx->Printf (ttidBeDiag, " %S filter over %S adapter\n",
|
||
|
pDevice->m_pFilter->m_pszInfId,
|
||
|
pDevice->m_pAdapter->m_pszPnpId);
|
||
|
|
||
|
hr = HrSetupDiSendPropertyChangeNotification (
|
||
|
m_hdi,
|
||
|
&pDevice->m_deid,
|
||
|
DICS_START,
|
||
|
DICS_FLAG_CONFIGSPECIFIC,
|
||
|
0);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf (ttidBeDiag, " Failed to start filter device for "
|
||
|
"%S over %S adapter\n",
|
||
|
pDevice->m_pFilter->m_pszInfId,
|
||
|
pDevice->m_pAdapter->m_pszPnpId);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterDevices::Free ()
|
||
|
{
|
||
|
Assert (this);
|
||
|
|
||
|
MemFree (m_pmszFilterClasses);
|
||
|
m_pmszFilterClasses = NULL;
|
||
|
|
||
|
SetupDiDestroyDeviceInfoListSafe (m_hdi);
|
||
|
m_hdi = NULL;
|
||
|
|
||
|
FreeCollectionAndItem (*this);
|
||
|
|
||
|
// Do NOT free m_BindPathsToRebind. This is used even after ApplyChanges
|
||
|
// calls Free.
|
||
|
//
|
||
|
}
|
||
|
|