|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: I N S T A L L . C P P
//
// Contents: Implements actions related to installing components.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "classinst.h"
#include "lockdown.h"
#include "netcfg.h"
#include "obotoken.h"
#include "util.h"
#if DBG
VOID DbgVerifyComponentInstallParams ( IN const COMPONENT_INSTALL_PARAMS& Params) { if (!Params.pComponent) { Assert (FIsValidNetClass (Params.Class)); Assert (Params.pszInfId && *Params.pszInfId); Assert (FOboTokenValidForClass (Params.pOboToken, Params.Class)); } }
#else
#define DbgVerifyComponentInstallParams NOP_FUNCTION
#endif
VOID CModifyContext::InstallAndAddAndNotifyComponent( IN const COMPONENT_INSTALL_PARAMS& Params, OUT CComponent** ppComponent) { CNetConfig* pNetConfig; CComponent* pComponent; UINT cPreviousAddedBindPaths;
Assert (this); Assert (S_OK == m_hr); DbgVerifyComponentInstallParams (Params); Assert (ppComponent);
pNetConfig = PNetConfig();
// Call the class installer to do the grunt work of finding the
// INF, processing it, creating the instance key, etc. If this
// all succeeds, we are returned an allocated CComponent.
//
//$REVIEW: Think about having HrCiInstallComponent return the
// list of required components. This will keep us from having to
// reopen the instance key and ndi key.
//
if (!Params.pComponent) {
// error test only
//if (0 == _wcsicmp(L"ms_nwipx", Params.pszInfId))
//{
// TraceTag (ttidBeDiag, "Simulating failure for: %S", Params.pszInfId);
// m_hr = E_FAIL;
// return;
//}
m_hr = HrCiInstallComponent (Params, &pComponent, NULL); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } } else { pComponent = Params.pComponent; } Assert (pComponent);
// Install all of the components required by this component.
//
// THIS MAY CAUSE RECURSION
//
InstallOrRemoveRequiredComponents (pComponent, IOR_INSTALL); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; }
// If this is an enumerated component, and it has the same PnpId as
// a component already in our core, we will remove the existing component.
// This can happen if an adapter is removed and reinstalled and the
// binding engine could not be notified of both because the write
// lock was held at the time of remove.
//
if (FIsEnumerated(pComponent->Class())) { CComponent* pDup;
while (NULL != (pDup = pNetConfig->Core.Components.PFindComponentByPnpId ( pComponent->m_pszPnpId))) { TraceTag (ttidBeDiag, "Removing duplicate PnpId: %S", pComponent->m_pszPnpId);
pDup->Refs.RemoveAllReferences(); (VOID) HrRemoveComponentIfNotReferenced (pDup, NULL, NULL); } }
// We only insert the component and its stack table entries into our
// list after all of its required components have been installed.
// This is just the concept of "don't consider a component installed
// until all of its requirements are also installed".
// i.e. Atomicity of component installation.
//
m_hr = pNetConfig->Core.HrAddComponentToCore (pComponent, INS_SORTED); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; }
// Notify the component's notify object it is being installed.
// This also sends global notifications to other notify objects
// who may be interested.
//
// THIS MAY CAUSE RECURSION
//
m_hr = pNetConfig->Notify.ComponentAdded (pComponent, Params.pnip); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; }
// Note the number of bindpaths currently in m_AddedBindPaths.
// We need this so that when we add to the set, we only notify
// for the ones we add.
//
cPreviousAddedBindPaths = m_AddedBindPaths.CountBindPaths ();
// Get the bindpaths that involve the component we are adding.
// Add these to the added bindpaths we are keeping track of.
//
m_hr = pNetConfig->Core.HrGetBindingsInvolvingComponent ( pComponent, GBF_ADD_TO_BINDSET | GBF_ONLY_WHICH_CONTAIN_COMPONENT, &m_AddedBindPaths); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; }
// Query and notify for these added bindpaths.
//
// THIS MAY CAUSE RECURSION
//
if (m_AddedBindPaths.CountBindPaths() > cPreviousAddedBindPaths) { m_hr = pNetConfig->Notify.QueryAndNotifyForAddedBindPaths ( &m_AddedBindPaths, cPreviousAddedBindPaths); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } }
// Install any components as a convenience to the user
// depending on the component we just installed component.
//
// THIS MAY CAUSE RECURSION
//
InstallConvenienceComponentsForUser (pComponent); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; }
// Assign the output pointer.
//
Assert (S_OK == m_hr); Assert (pComponent); *ppComponent = pComponent; }
//+---------------------------------------------------------------------------
// Install components on behalf of the user
//
// Assumptions:
//
VOID CModifyContext::InstallConvenienceComponentsForUser ( IN const CComponent* pComponent) { COMPONENT_INSTALL_PARAMS Params; OBO_TOKEN UserOboToken; CComponent* pNewComponent;
Assert (this); Assert (S_OK == m_hr); Assert (pComponent);
ZeroMemory (&UserOboToken, sizeof(UserOboToken)); UserOboToken.Type = OBO_USER;
// If the component is an ATM adapter, make sure ATMUNI and ATMLANE are
// installed.
//
if (FSubstringMatch (L"ndisatm", pComponent->Ext.PszUpperRange(), NULL, NULL)) { ZeroMemory (&Params, sizeof(Params)); Params.pOboToken = &UserOboToken; Params.Class = NC_NETTRANS;
Params.pszInfId = L"ms_atmuni"; HrInstallNewOrReferenceExistingComponent (Params, &pNewComponent);
Params.pszInfId = L"ms_atmlane"; HrInstallNewOrReferenceExistingComponent (Params, &pNewComponent); } }
HRESULT CModifyContext::HrInstallNewOrReferenceExistingComponent ( IN const COMPONENT_INSTALL_PARAMS& Params, OUT CComponent** ppComponent) { HRESULT hr; BOOL fInstallNew; CNetConfig* pNetConfig; CComponent* pComponent;
Assert (this); Assert (S_OK == m_hr); DbgVerifyComponentInstallParams (Params); Assert (ppComponent);
// Initialize the output parameter.
//
*ppComponent = NULL;
// Assume, for now, that we will be installing a new component.
//
hr = S_OK; fInstallNew = TRUE; pNetConfig = PNetConfig(); pComponent = NULL;
// If the user wishes to add a reference if the component is already
// installed...
//
if (Params.pOboToken) { // ...then look to see if the component is installed...
//
pComponent = pNetConfig->Core.Components. PFindComponentByInfId (Params.pszInfId, NULL);
// ...if it is, we won't be installing a new one.
//
if (pComponent) { fInstallNew = FALSE;
if (pComponent->m_dwCharacter & NCF_SINGLE_INSTANCE) { *ppComponent = NULL; return HRESULT_FROM_SETUPAPI(ERROR_DEVINST_ALREADY_EXISTS); }
// If the existing component is already referenced by
// the specified obo token, we can return.
//
if (pComponent->Refs.FIsReferencedByOboToken (Params.pOboToken)) { *ppComponent = pComponent; return S_OK; } }
// ...otherwise, (it is not in the current core) but if it IS
// in the core we started with, it means someone had previously
// removed it during this modify context and now wants to add it
// back. This is tricky and should probably be implemented later.
// For now, return an error and throw up an assert so we can see
// who needs to do this.
//
else if (m_CoreStartedWith.Components. PFindComponentByInfId (Params.pszInfId, NULL)) { AssertSz (FALSE, "Whoa. Someone is trying to install a " "component that was previously removed during this same " "modify context. We need to decide if we can support this."); return E_UNEXPECTED; } }
// If we've decided to install a new component, (which can happen
// if an obo token was not specified OR if an obo token was specified
// but the component was not already present) then do the work.
//
if (fInstallNew) { // If the component to be installed is locked down, bail out.
// Note we don't put the modify context into error if this situation
// occurs.
// Note too that we only do this if Params.pComponent is not present
// which would indicate the class installer calling us to install an
// enumerated component.
//
if (!Params.pComponent) { if (FIsComponentLockedDown (Params.pszInfId)) { TraceTag (ttidBeDiag, "%S is locked down and cannot be installed " "until the next reboot.", Params.pszInfId);
return NETCFG_E_NEED_REBOOT; } }
// Make sure the modify context is setup and keep track of our
// recursion depth.
//
PushRecursionDepth (); Assert (S_OK == m_hr);
InstallAndAddAndNotifyComponent (Params, ppComponent);
hr = HrPopRecursionDepth ();
// If the component to be installed was not found, the return code
// will be SPAPI_E_NO_DRIVER_SELECTED. We want to return this to the
// caller, but we don't need the context to remain with this error.
// This will allow subsequent calls to install other componetns to
// proceed.
//
if (SPAPI_E_NO_DRIVER_SELECTED == m_hr) { m_hr = S_OK; Assert (SPAPI_E_NO_DRIVER_SELECTED == hr); } } else { // Referencing pComponent on behalf of the obo token.
//
Assert (pComponent); Assert (Params.pOboToken);
// Make sure the modify context is setup and keep track of our
// recursion depth.
//
PushRecursionDepth (); Assert (S_OK == m_hr);
m_hr = pComponent->Refs.HrAddReferenceByOboToken (Params.pOboToken);
if (S_OK == m_hr) { *ppComponent = pComponent; }
hr = HrPopRecursionDepth (); }
// If we are returning success, we'd better have our ouput parameter set.
//
Assert (FImplies(SUCCEEDED(hr), *ppComponent)); return hr; }
|