//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include "comp.h" #include "icomp.h" #include "ncreg.h" #include "ncsetup.h" #include "ncstring.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::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())) { fCanBind = TRUE; // If the filter has the FilterMediaTypes value specified, // then we can bind only if we have a match with the adapters // lower range. // if (Ext.PszFilterMediaTypes()) { fCanBind = FSubstringMatch (Ext.PszFilterMediaTypes(), pLower->Ext.PszLowerRange(), NULL, NULL); } // If we (the filter) have a list of lower interface to exclude, // then we can bind only if we don't have a match. // if (fCanBind && Ext.PszLowerExclude()) { fCanBind = !FSubstringMatch (Ext.PszLowerExclude(), pLower->Ext.PszUpperRange(), NULL, NULL); } // 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 = 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; }