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.
517 lines
14 KiB
517 lines
14 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1999.
|
|
//
|
|
// File: C O M P . C P P
|
|
//
|
|
// Contents: The module implements the operations that are valid on
|
|
// network component datatypes.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: shaunco 15 Jan 1999
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.h>
|
|
#pragma hdrstop
|
|
#include "comp.h"
|
|
#include "icomp.h"
|
|
#include "ncreg.h"
|
|
#include "ncsetup.h"
|
|
#include "ncstring.h"
|
|
#include "ncmem.h"
|
|
#include "util.h"
|
|
|
|
// NULL entries means we don't use the network subtree for that class.
|
|
//
|
|
const PCWSTR MAP_NETCLASS_TO_NETWORK_SUBTREE[] =
|
|
{
|
|
L"System\\CurrentControlSet\\Control\\Network\\{4d36e972-e325-11ce-bfc1-08002be10318}",
|
|
L"System\\CurrentControlSet\\Control\\Network\\{6BDD1FC5-810F-11D0-BEC7-08002BE2092F}",
|
|
L"System\\CurrentControlSet\\Control\\Network\\{4d36e975-e325-11ce-bfc1-08002be10318}",
|
|
L"System\\CurrentControlSet\\Control\\Network\\{4d36e973-e325-11ce-bfc1-08002be10318}",
|
|
L"System\\CurrentControlSet\\Control\\Network\\{4d36e974-e325-11ce-bfc1-08002be10318}",
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
// map of NETCLASS enum to GUIDs for class
|
|
//
|
|
const GUID* MAP_NETCLASS_TO_GUID[] =
|
|
{
|
|
&GUID_DEVCLASS_NET,
|
|
&GUID_DEVCLASS_INFRARED,
|
|
&GUID_DEVCLASS_NETTRANS,
|
|
&GUID_DEVCLASS_NETCLIENT,
|
|
&GUID_DEVCLASS_NETSERVICE,
|
|
&GUID_DEVCLASS_UNKNOWN,
|
|
&GUID_DEVCLASS_UNKNOWN
|
|
};
|
|
|
|
const WCHAR c_szTempNetcfgStorageForUninstalledEnumeratedComponent[] =
|
|
L"System\\CurrentControlSet\\Control\\Network\\Uninstalled\\";
|
|
|
|
//static
|
|
HRESULT
|
|
CComponent::HrCreateInstance (
|
|
IN const BASIC_COMPONENT_DATA* pData,
|
|
IN DWORD dwFlags,
|
|
IN const OBO_TOKEN* pOboToken, OPTIONAL
|
|
OUT CComponent** ppComponent)
|
|
{
|
|
ULONG cbInfId;
|
|
ULONG cbPnpId;
|
|
|
|
Assert (pData);
|
|
Assert (pData->pszInfId && *pData->pszInfId);
|
|
Assert (FIsValidNetClass(pData->Class));
|
|
Assert (FImplies(FIsEnumerated(pData->Class),
|
|
pData->pszPnpId && *pData->pszPnpId));
|
|
Assert (FImplies(pData->pszPnpId, *pData->pszPnpId));
|
|
Assert (FImplies(pData->dwDeipFlags, FIsEnumerated(pData->Class)));
|
|
Assert ((CCI_DEFAULT == dwFlags) ||
|
|
(CCI_ENSURE_EXTERNAL_DATA_LOADED == dwFlags));
|
|
Assert (GUID_NULL != pData->InstanceGuid);
|
|
|
|
cbInfId = CbOfSzAndTerm (pData->pszInfId);
|
|
cbPnpId = CbOfSzAndTermSafe (pData->pszPnpId);
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CComponent* pComponent = new(extrabytes, cbInfId + cbPnpId) CComponent;
|
|
if (pComponent)
|
|
{
|
|
hr = S_OK;
|
|
ZeroMemory (pComponent, sizeof(CComponent));
|
|
|
|
pComponent->m_InstanceGuid = pData->InstanceGuid;
|
|
pComponent->m_Class = pData->Class;
|
|
pComponent->m_dwCharacter = pData->dwCharacter;
|
|
pComponent->m_dwDeipFlags = pData->dwDeipFlags;
|
|
|
|
pComponent->m_pszInfId = (PCWSTR)(pComponent + 1);
|
|
wcscpy ((PWSTR)pComponent->m_pszInfId, pData->pszInfId);
|
|
_wcslwr ((PWSTR)pComponent->m_pszInfId);
|
|
|
|
AddOrRemoveDontExposeLowerCharacteristicIfNeeded (pComponent);
|
|
|
|
if (cbPnpId)
|
|
{
|
|
pComponent->m_pszPnpId = (PCWSTR)((BYTE*)pComponent->m_pszInfId
|
|
+ cbInfId);
|
|
wcscpy ((PWSTR)pComponent->m_pszPnpId, pData->pszPnpId);
|
|
}
|
|
|
|
if (dwFlags & CCI_ENSURE_EXTERNAL_DATA_LOADED)
|
|
{
|
|
// Let's ensure we can successfully read all of the external
|
|
// data that the component's INF dumped under the instance
|
|
// key. Failure here means the INF wasn't proper in some
|
|
// way required for us to consider this a valid component.
|
|
//
|
|
hr = pComponent->Ext.HrEnsureExternalDataLoaded ();
|
|
}
|
|
|
|
if ((S_OK == hr) && pOboToken)
|
|
{
|
|
// Add a reference by the obo token if we were given one.
|
|
//
|
|
hr = pComponent->Refs.HrAddReferenceByOboToken (pOboToken);
|
|
}
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
delete pComponent;
|
|
pComponent = NULL;
|
|
}
|
|
}
|
|
|
|
*ppComponent = pComponent;
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CComponent::HrCreateAndInitializeInstance");
|
|
return hr;
|
|
}
|
|
|
|
CComponent::~CComponent()
|
|
{
|
|
// If we have a cached INetCfgComponent interface, we need to tell it
|
|
// that we (as the component it represents) no longer exist. Then we
|
|
// need to release the interface, of course.
|
|
//
|
|
ReleaseINetCfgComponentInterface ();
|
|
if(m_hinf)
|
|
{
|
|
SetupCloseInfFile (m_hinf);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CComponent::ReleaseINetCfgComponentInterface ()
|
|
{
|
|
Assert (this);
|
|
|
|
if (m_pIComp)
|
|
{
|
|
Assert (this == m_pIComp->m_pComponent);
|
|
m_pIComp->m_pComponent = NULL;
|
|
ReleaseObj (m_pIComp->GetUnknown());
|
|
m_pIComp = NULL;
|
|
}
|
|
}
|
|
|
|
INetCfgComponent*
|
|
CComponent::GetINetCfgComponentInterface () const
|
|
{
|
|
Assert (this);
|
|
Assert (m_pIComp);
|
|
return m_pIComp;
|
|
}
|
|
|
|
BOOL
|
|
CComponent::FCanDirectlyBindToFilter (
|
|
IN const WCHAR* const pszFilterMediaTypes,
|
|
IN const WCHAR* const pszLowerExclude) const
|
|
{
|
|
BOOL fCanBind = TRUE;
|
|
|
|
// if pszFilterMediaType is not null, then it must have a substring
|
|
// match with the adapters LowerRange.
|
|
|
|
if (pszFilterMediaTypes)
|
|
{
|
|
fCanBind = FSubstringMatch (pszFilterMediaTypes, Ext.PszLowerRange(),
|
|
NULL, NULL);
|
|
}
|
|
|
|
// if the LowerExclude is not null, it must not have a substring match with
|
|
// the upper range of the adapter.
|
|
|
|
if (fCanBind && pszLowerExclude)
|
|
{
|
|
fCanBind = !FSubstringMatch (pszLowerExclude, Ext.PszUpperRange(),
|
|
NULL, NULL);
|
|
}
|
|
|
|
return fCanBind;
|
|
}
|
|
|
|
BOOL
|
|
CComponent::FCanDirectlyBindTo (
|
|
IN const CComponent* pLower,
|
|
OUT const WCHAR** ppStart,
|
|
OUT ULONG* pcch) const
|
|
{
|
|
BOOL fCanBind;
|
|
|
|
// If this component is a filter and the lower is an adapter,
|
|
// they can bind (by definition) unless the adapter has an upper range
|
|
// that is excluded by the filter.
|
|
//
|
|
if (FIsFilter() && FIsEnumerated(pLower->Class()))
|
|
{
|
|
// See if the filter's attributes - FilterMediaTypes and LowerExclude
|
|
// allow it to bind to the adapter.
|
|
//
|
|
fCanBind = pLower->FCanDirectlyBindToFilter(Ext.PszFilterMediaTypes(),
|
|
Ext.PszLowerExclude());
|
|
|
|
// If the filter can bind to the adapter, and the caller wants
|
|
// the interface name, it will be the first interface the adapter
|
|
// supports.
|
|
//
|
|
if (fCanBind && ppStart && pcch)
|
|
{
|
|
PCWSTR pStart;
|
|
PCWSTR pEnd;
|
|
|
|
pStart = pLower->Ext.PszUpperRange();
|
|
Assert (pStart);
|
|
|
|
while (*pStart && (*pStart == L' ' || *pStart == L','))
|
|
{
|
|
pStart++;
|
|
}
|
|
|
|
pEnd = pStart;
|
|
while (*pEnd && *pEnd != L' ' && *pEnd != L',')
|
|
{
|
|
pEnd++;
|
|
}
|
|
|
|
*ppStart = pStart;
|
|
*pcch = (ULONG)(pEnd - pStart);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fCanBind = FSubstringMatch (
|
|
Ext.PszLowerRange(),
|
|
pLower->Ext.PszUpperRange(), ppStart, pcch);
|
|
}
|
|
|
|
return fCanBind;
|
|
}
|
|
|
|
BOOL
|
|
CComponent::FIsBindable () const
|
|
{
|
|
return (0 != _wcsicmp(L"nolower", Ext.PszLowerRange())) ||
|
|
(0 != _wcsicmp(L"noupper", Ext.PszUpperRange()));
|
|
}
|
|
|
|
BOOL
|
|
CComponent::FIsWanAdapter () const
|
|
{
|
|
Assert (this);
|
|
|
|
return (NC_NET == Class()) &&
|
|
FSubstringMatch (Ext.PszLowerRange(), L"wan", NULL, NULL);
|
|
}
|
|
|
|
HRESULT
|
|
CComponent::HrGetINetCfgComponentInterface (
|
|
IN CImplINetCfg* pINetCfg,
|
|
OUT INetCfgComponent** ppIComp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert (this);
|
|
Assert (pINetCfg);
|
|
Assert (ppIComp);
|
|
|
|
// Caller's are responsible for ensuring that if an interface is about
|
|
// to be handed out, and the external data has been loaded, that the
|
|
// data has been loaded successfully. If we handed out an interface
|
|
// and the data was NOT loaded successfully, it just means we are doomed
|
|
// to fail later when the client of the interface calls a method that
|
|
// requires that data.
|
|
//
|
|
Assert (Ext.FLoadedOkayIfLoadedAtAll());
|
|
|
|
// If we don't yet have the cached INetCfgComponent for ourself,
|
|
// create it and hang onto a reference.
|
|
//
|
|
if (!m_pIComp)
|
|
{
|
|
hr = CImplINetCfgComponent::HrCreateInstance (
|
|
pINetCfg, this, &m_pIComp);
|
|
}
|
|
|
|
// AddRef and return a copy for the caller.
|
|
//
|
|
if (S_OK == hr)
|
|
{
|
|
AddRefObj (m_pIComp->GetUnknown());
|
|
*ppIComp = m_pIComp;
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CComponent::HrGetINetCfgComponentInterface");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CComponent::HrOpenDeviceInfo (
|
|
OUT HDEVINFO* phdiOut,
|
|
OUT SP_DEVINFO_DATA* pdeidOut) const
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert (this);
|
|
Assert (phdiOut);
|
|
Assert (pdeidOut);
|
|
|
|
hr = ::HrOpenDeviceInfo (
|
|
Class(),
|
|
m_pszPnpId,
|
|
phdiOut,
|
|
pdeidOut);
|
|
|
|
TraceHr (ttidError, FAL, hr, SPAPI_E_NO_SUCH_DEVINST == hr,
|
|
"CComponent::HrOpenDeviceInfo (%S)", m_pszPnpId);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CComponent::HrOpenInstanceKey (
|
|
IN REGSAM samDesired,
|
|
OUT HKEY* phkey,
|
|
OUT HDEVINFO* phdiOut OPTIONAL,
|
|
OUT SP_DEVINFO_DATA* pdeidOut OPTIONAL) const
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert (this);
|
|
Assert (phkey);
|
|
|
|
hr = HrOpenComponentInstanceKey (
|
|
Class(),
|
|
m_InstanceGuid,
|
|
m_pszPnpId,
|
|
samDesired,
|
|
phkey,
|
|
phdiOut,
|
|
pdeidOut);
|
|
|
|
TraceHr (ttidError, FAL, hr,
|
|
(SPAPI_E_NO_SUCH_DEVINST == hr),
|
|
"CComponent::HrOpenInstanceKey (%S)", PszGetPnpIdOrInfId());
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CComponent::HrOpenServiceKey (
|
|
IN REGSAM samDesired,
|
|
OUT HKEY* phkey) const
|
|
{
|
|
HRESULT hr;
|
|
WCHAR szServiceSubkey [_MAX_PATH];
|
|
|
|
Assert (this);
|
|
Assert (phkey);
|
|
Assert (FHasService());
|
|
|
|
*phkey = NULL;
|
|
|
|
wcscpy (szServiceSubkey, REGSTR_PATH_SERVICES);
|
|
wcscat (szServiceSubkey, L"\\");
|
|
wcscat (szServiceSubkey, Ext.PszService());
|
|
|
|
hr = HrRegOpenKeyEx (
|
|
HKEY_LOCAL_MACHINE,
|
|
szServiceSubkey,
|
|
samDesired,
|
|
phkey);
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CComponent::HrOpenServiceKey (%S)", Ext.PszService());
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CComponent::HrStartOrStopEnumeratedComponent (
|
|
IN DWORD dwFlag /* DICS_START or DICS_STOP */) const
|
|
{
|
|
HRESULT hr;
|
|
HDEVINFO hdi;
|
|
SP_DEVINFO_DATA deid;
|
|
|
|
Assert (this);
|
|
Assert (FIsEnumerated(Class()));
|
|
Assert ((DICS_START == dwFlag) || (DICS_STOP == dwFlag));
|
|
|
|
hr = HrOpenDeviceInfo (&hdi, &deid);
|
|
if (S_OK == hr)
|
|
{
|
|
if (m_dwDeipFlags)
|
|
{
|
|
TraceTag (ttidBeDiag,
|
|
"Using SP_DEVINSTALL_PARAMS.Flags = 0x%08x for %S",
|
|
m_dwDeipFlags,
|
|
m_pszPnpId);
|
|
|
|
(VOID) HrSetupDiSetDeipFlags (
|
|
hdi, &deid,
|
|
m_dwDeipFlags, SDDFT_FLAGS, SDFBO_OR);
|
|
}
|
|
|
|
// $HACK SetupDi does not honor the DI_DONOTCALLCONFIGMG flag
|
|
// so we can't call it if it is set. If we don't start the device
|
|
// we will return NETCFG_S_REBOOT.
|
|
//
|
|
hr = NETCFG_S_REBOOT;
|
|
if (!(DI_DONOTCALLCONFIGMG & m_dwDeipFlags))
|
|
{
|
|
hr = HrSetupDiSendPropertyChangeNotification (
|
|
hdi, &deid,
|
|
dwFlag,
|
|
DICS_FLAG_CONFIGSPECIFIC,
|
|
0);
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList (hdi);
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CComponent::HrStartOrStopEnumeratedComponent (%S)", m_pszPnpId);
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// A convenience method to get the handle to the components inf file.
|
|
// If the file has been opened previously, the cached handle is returned.
|
|
// Otherwise, the file is opened and the handle is returned.
|
|
|
|
HRESULT
|
|
CComponent::HrOpenInfFile(
|
|
OUT HINF* phinf) const
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hkeyInstance = NULL;
|
|
WCHAR szInfPath[_MAX_PATH];
|
|
DWORD cbPath = sizeof (szInfPath);
|
|
|
|
Assert(phinf);
|
|
*phinf = NULL;
|
|
|
|
if (NULL == m_hinf)
|
|
{
|
|
hr = HrOpenInstanceKey (KEY_READ, &hkeyInstance, NULL, NULL);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrRegQuerySzBuffer (hkeyInstance, L"InfPath", szInfPath, &cbPath);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// open the component's inf file
|
|
hr = HrSetupOpenInfFile (szInfPath, NULL, INF_STYLE_WIN4,
|
|
NULL, &m_hinf);
|
|
}
|
|
RegSafeCloseKey (hkeyInstance);
|
|
}
|
|
}
|
|
*phinf = m_hinf;
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CComponent::HrOpenInfFile (%S)", PszGetPnpIdOrInfId());
|
|
|
|
return hr;
|
|
}
|
|
|
|
NETCLASS
|
|
NetClassEnumFromGuid (
|
|
const GUID& guidClass)
|
|
{
|
|
NETCLASS Class;
|
|
|
|
if (GUID_DEVCLASS_NET == guidClass)
|
|
{
|
|
Class = NC_NET;
|
|
}
|
|
else if (GUID_DEVCLASS_INFRARED == guidClass)
|
|
{
|
|
Class = NC_INFRARED;
|
|
}
|
|
else if (GUID_DEVCLASS_NETTRANS == guidClass)
|
|
{
|
|
Class = NC_NETTRANS;
|
|
}
|
|
else if (GUID_DEVCLASS_NETCLIENT == guidClass)
|
|
{
|
|
Class = NC_NETCLIENT;
|
|
}
|
|
else if (GUID_DEVCLASS_NETSERVICE == guidClass)
|
|
{
|
|
Class = NC_NETSERVICE;
|
|
}
|
|
else
|
|
{
|
|
Class = NC_INVALID;
|
|
}
|
|
|
|
return Class;
|
|
}
|
|
|