|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: C L A S S I N S T . C P P
//
// Contents: Defines the interface between the binding engine and the
// network class installer.
//
// Notes:
//
// Author: billbe 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "adapter.h"
#include "benchmrk.h"
#include "classinst.h"
#include "filtdev.h"
#include "netcfg.h"
#include "iatl.h"
#include "lockdown.h"
#include "ncatl.h"
#include "ncoc.h"
#include "ncreg.h"
#include "ncsetup.h"
#include "ncui.h"
#include "ncwins.h"
#include "persist.h"
#include "provider.h"
#include "resource.h"
#include "util.h"
// HrRegisterNotificationDll functions
enum ciRegisterDllFunction {CIRDF_REGISTER, CIRDF_UNREGISTER};
// The temporary key used for dumping a component's registry entries. This is used
// during the pruning of inapplicable protocols and filter services from the select
// dialog.
static const WCHAR c_szRegKeyTemp[] = L"System\\CurrentControlSet\\Control\\Network\\FTempKey";
//+--------------------------------------------------------------------------
//
// Function: HrCiRegDeleteComponentNetworkKey
//
// Purpose: This function deletes the component key strInstanceGuid
// (and its subkeys) under the Network\<guidClass> tree.
//
// Arguments:
// Class [in] The class of the component
// pszInstanceGuid [in] The instance guid of the component
//
// Returns: HRESULT. S_OK if successful, an error code otherwise.
//
// Author: billbe 27 Apr 1997
//
// Notes:
//
HRESULT HrCiRegDeleteComponentNetworkKey ( IN NETCLASS Class, IN PCWSTR pszInstanceGuid) { HRESULT hr = S_OK; HKEY hkeyClass = NULL;
PCWSTR pszNetworkSubtreePath = MAP_NETCLASS_TO_NETWORK_SUBTREE[Class];
// Open the proper class key in the Network tree
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, pszNetworkSubtreePath, KEY_WRITE, &hkeyClass);
// Delete the instance key tree
//
if (S_OK == hr) { hr = HrRegDeleteKeyTree(hkeyClass, pszInstanceGuid); RegSafeCloseKey(hkeyClass); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegDeleteComponentKey"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiRegisterNotificationDll
//
// Purpose: Registers or Unregisters a component's notification dll with
// COM
//
// Arguments:
// hkeyInstance [in] The handle to the instance key for the component
// crdf [in] CIRDF_REGISTER if we are registering,
// CIRDF_UNREGISTER if we are unregistering
//
// Returns: HRESULT. S_OK on if dll is successfully registered,
// S_FALSE, if the component has no dll to
// register, error code otherwise
//
// Author: billbe 23 Mar 1997
//
// Notes:
//
HRESULT HrCiRegisterNotificationDll( IN HKEY hkeyInstance, IN ciRegisterDllFunction crdf) { Assert(hkeyInstance);
HKEY hkeyNdi; HRESULT hr;
// Open the ndi key in the component's instance key so we can get the
// Dll path.
hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi); if (S_OK == hr) { // Get the notification dll path
tstring strDllPath; hr = HrRegQueryString (hkeyNdi, L"ComponentDLL", &strDllPath);
if (S_OK == hr) { TraceTag (ttidClassInst, "Attempting to (un)register notification dll '%S'", strDllPath.c_str()); hr = (CIRDF_REGISTER == crdf) ? HrRegisterComObject (strDllPath.c_str()) : HrUnregisterComObject (strDllPath.c_str()); } else { if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // The presence of the value is optional, so return
// S_OK if it was not found
hr = S_OK; } } RegCloseKey (hkeyNdi); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegisterNotificationDll"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiInstallServices
//
// Purpose: Processes any Inf service sections using strInfSection as a
// base name
//
// Arguments:
// hinfFile [in] A handle to the inf file
// pszInfSection [in] The base section name
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 2 Apr 1997
//
// Notes: See SetupInstallServicesFromInfSection in SetupApi for more
// info.
//
HRESULT HrCiInstallServices( IN HINF hinfFile, IN PCWSTR pszInfSection) { Assert (IsValidHandle(hinfFile)); Assert (pszInfSection && *pszInfSection);
BOOL fSuccess; WCHAR szServiceSection[_MAX_PATH];
// append .Services to the section name
//
swprintf (szServiceSection, L"%s.%s", pszInfSection, INFSTR_SUBKEY_SERVICES);
// Process the Services section
fSuccess = SetupInstallServicesFromInfSection (hinfFile, szServiceSection, 0); if (!fSuccess) { // Since the section is optional, we can ignore
// ERROR_SECTION_NOT_FOUND
if (ERROR_SECTION_NOT_FOUND == GetLastError()) { fSuccess = TRUE; } }
// Any errors must be converted
HRESULT hr = S_OK; if (!fSuccess) { hr = HrFromLastWin32Error(); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallServices (%S)", szServiceSection); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiInstallFromInfSection
//
// Purpose: A wrapper function for SetupInstallFromInfSection. This
// function handles setting up the copy files process for
// SetupInstallFromInfSection as well.
//
// Arguments:
// hinfFile [in] A handle to the inf file to install from
// pszInfSectionName [in] The section to install
// hkeyRelative [in] The key that will be used as the section's
// HKR
// hwndParent [in] The HWND to the parent window, used for UI
// dwInstallFlags [in] See SetupInstallFromInfSection for info on
// these flags
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 4 Apr 1997
//
// Notes: See SetupApi documentation for more info on
// SetupInstallFromInfSection and
// SetupInstallFilesFromInfSection
//
HRESULT HrCiInstallFromInfSection( IN HINF hinfFile, IN PCWSTR pszInfSectionName, IN HKEY hkeyRelative, IN HWND hwndParent, IN DWORD dwInstallFlags) { Assert (IsValidHandle (hinfFile)); Assert (pszInfSectionName && *pszInfSectionName);
HRESULT hr = S_OK;
if (dwInstallFlags & SPINST_FILES) { // The next three variables are used for SetupApi's copy files process
PSP_FILE_CALLBACK pfc; PVOID pvCtx; HSPFILEQ hfq;
// If the inf file has a layout entry in its version section
// we need to append its information for proper locations
// of any files we need to copy. If the call fails we can
// still install, it just means the prompt for files will not
// have the correct directory to begin with
(VOID) SetupOpenAppendInfFile (NULL, hinfFile, NULL);
// We need to create our own file queue so we can scan all the
// files to be copied. Scanning before committing our queue will
// prompt the user if the files already exist in the destination
//
hr = HrSetupOpenFileQueue (&hfq); if (S_OK == hr) { BOOL fInGuiModeSetup = FInSystemSetup();
hr = HrSetupInstallFilesFromInfSection (hinfFile, NULL, hfq, pszInfSectionName, NULL, 0);
// Set the default callback context
// If the we are in system setup, we need to make sure the
// callback doesn't display UI
//
if (S_OK == hr) { hr = HrSetupInitDefaultQueueCallbackEx (hwndParent, (fInGuiModeSetup ? (HWND)INVALID_HANDLE_VALUE : NULL), 0, 0, NULL, &pvCtx);
if (S_OK == hr) { // Not doing anything special so use SetupApi default
// handler for file copy.
pfc = SetupDefaultQueueCallback;
// Scan the queue to see if the files are already in the
// destination and if so, prune them out.
DWORD dwScanResult; hr = HrSetupScanFileQueueWithNoCallback (hfq, SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE, hwndParent, &dwScanResult);
// Now commit the queue so any files needing to be
// copied, will be. If the scan result is 1 then there
// is nothing to commit.
//
if ((S_OK == hr) && (1 != dwScanResult)) { hr = HrSetupCommitFileQueue (hwndParent, hfq, pfc, pvCtx); }
// We need to release the default context and close our
// file queue
//
SetupTermDefaultQueueCallback (pvCtx); SetupCloseFileQueue (hfq); } } } }
if ((S_OK == hr) && (dwInstallFlags & ~SPINST_FILES)) { Assert (hkeyRelative);
// Now we run all sections but CopyFiles
hr = HrSetupInstallFromInfSection (hwndParent, hinfFile, pszInfSectionName, (dwInstallFlags & ~SPINST_FILES), hkeyRelative, NULL, 0, NULL, NULL, NULL, NULL); }
TraceHr (ttidError, FAL, hr, HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr, "HrCiInstallFromInfSection"); return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrCiDoCompleteSectionInstall
//
// Purpose: Runs all relevant sections of an inf file using strSection
// as the base section name.
//
// Arguments:
// hinfFile [in] SetupApi handle to an inf file
// hkeyRelative [in] The registry key that will be the HKR
// key during inf processing.
// pszSection [in] Section name to install
// hwndParent [in] The handle to the parent, for
// displaying UI
// fEnumerated [in] TRUE if this component is PnP enumerated
// FALSE otherwise
//
// Returns: HRESULT. S_OK if sucessful, error code otherwise
//
// Author: billbe 15 Apr 1997
//
// Notes:
//
HRESULT HrCiDoCompleteSectionInstall( IN HINF hinfFile, IN HKEY hkeyRelative, IN PCWSTR pszSection, IN HWND hwndParent, IN BOOL fEnumerated) { Assert (IsValidHandle (hinfFile)); Assert (FImplies (!fEnumerated, hkeyRelative));
HRESULT hr = S_OK;
// Only do this if there is a section name to work with
if (pszSection && *pszSection) { // If this is an enumerated device, the service section and
// the copy files section will be processed by the Device Installer
// fcn SetupDiInstallDevice so we can exclude it from the following
// calls. But we do some processing based on registry and log config
// entries so we will pre-run the registry section for enumerated
// devices and exclude the others
//
// Run the section found using hkeyRelative as the HKR
hr = HrCiInstallFromInfSection (hinfFile, pszSection, hkeyRelative, hwndParent, (fEnumerated ? (SPINST_REGISTRY | SPINST_LOGCONFIG) : SPINST_ALL & ~SPINST_REGSVR));
if (!fEnumerated) { // We need to run the Services section and
// check for Winsock dependency if they aren't specified to be
// excluded.
//
// Note: Other sections may be added later. The default is to
// run all sections not listed in dwExcludeSectionFlags
//
if (S_OK == hr) { // run services section if it exists
hr = HrCiInstallServices (hinfFile, pszSection); if (S_OK == hr) { // Bug #383239: Wait till services are installed before
// running the RegisterDlls section
//
hr = HrCiInstallFromInfSection (hinfFile, pszSection, hkeyRelative, hwndParent, SPINST_REGSVR); } }
}
if (S_OK == hr) {
//sb This part can be called for either add or remove. We
//sb are moving only the remove part forward. This should
//sb still be performed for add.
//
// Determine if a .Winsock section exists for the
// section specified in szActualSection
PCWSTR pszSubSection = wcsstr(pszSection, L".Remove");
if(!pszSubSection || wcscmp(pszSubSection, L".Remove")) { hr = HrAddOrRemoveWinsockDependancy (hinfFile, pszSection); }
// These other extensions are undocumented and some have been
// added by external groups. We don't want any of them
// processed for enumerated components.
//
if ((S_OK == hr) && !fEnumerated) { // Process the additional INF extensions (SNMP Agent,
// PrintMonitors, etc.)
//
hr = HrProcessAllINFExtensions (hinfFile, pszSection); } } }
TraceHr (ttidError, FAL, hr, (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr), "HrCiDoCompleteSectionInstall"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiRemoveNonEnumeratedComponent
//
// Purpose: This will run the remove section and delete the network
// instance key for the component if necessary. This
// function is called for partially (i.e. failed install)
// and fully installed components
//
// Arguments:
// hinf [in] The handle to the component's inf file
// hkeyInstance [in] The handle to the component's instance key
// Class [in] The class of the component
// InstanceGuid [in] The instance guid of the component
// pstrRemoveSection [out] Optional pointer to a tstring which receives
// the remove section name.
//
// Returns: HRESULT. S_OK if successful, NETCFG_S_REBOOT if successful
// but a reboot is required, or an error code otherwise
//
// Author: billbe 10 Dec 1996
// Revised 27 Apr 1997
//
// Notes:
//
HRESULT HrCiRemoveNonEnumeratedComponent( IN HINF hinf, IN HKEY hkeyInstance, IN NETCLASS Class, IN const GUID& InstanceGuid, OUT tstring* pstrRemoveSection OPTIONAL) { Assert (IsValidHandle (hinf)); Assert (IsValidHandle (hkeyInstance));
static const WCHAR c_szRemoveSectionSuffix[] = L".Remove";
// We get the remove section name and process all relevant sections
// We also try to unregister any Notify objects available
//
WCHAR szRemoveSection[_MAX_PATH]; DWORD cbBuffer = sizeof (szRemoveSection); HRESULT hr = HrRegQuerySzBuffer (hkeyInstance, REGSTR_VAL_INFSECTION, szRemoveSection, &cbBuffer);
if (S_OK == hr) { wcscat (szRemoveSection, c_szRemoveSectionSuffix); if (pstrRemoveSection) { pstrRemoveSection->assign(szRemoveSection); } hr = HrCiDoCompleteSectionInstall (hinf, hkeyInstance, szRemoveSection, NULL, NULL); } // Whether unregistering the notify object is successful or not,
// we must fully remove the component.
(VOID) HrCiRegisterNotificationDll (hkeyInstance, CIRDF_UNREGISTER);
// Now we need to remove the component key in the Network tree
// We need to do this regardless of any previous errors
// so we don't need the return value.
WCHAR szGuid[c_cchGuidWithTerm]; StringFromGUID2 (InstanceGuid, szGuid, c_cchGuidWithTerm); (VOID) HrCiRegDeleteComponentNetworkKey (Class, szGuid);
// if all went well, set the return value based on whether a reboot
// is required or not or any error from HrRegisterNotificationDll.
//
if (S_FALSE == hr) { // S_FALSE is okay but should not be returned by this fcn.
hr = S_OK; }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiRemoveNonEnumeratedComponent"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiRemoveComponent
//
// Purpose: Called from INetCfg, this will uninstall a network component.
//
// Arguments:
// pComponent [in] The component to uninstall.
// pstrRemoveSection [out] Optional pointer to a tstring which receives
// the remove section name.
//
// Returns: HRESULT. S_OK if successful, NETCFG_S_REBOOT if successful
// but a reboot is required, or an error code otherwise
//
// Author: billbe 10 Dec 1996
// Revised 27 Apr 1997
//
// Notes:
//
HRESULT HrCiRemoveComponent( IN const CComponent* pComponent, OUT tstring* pstrRemoveSection OPTIONAL) { Assert (pComponent);
HINF hinf = NULL; HDEVINFO hdi = NULL; SP_DEVINFO_DATA deid; HKEY hkeyInstance = NULL; HRESULT hr = S_OK;
// If this is an enumerated net class component, then we need to
// create the Device Installer structures for HrSetupDiRemoveDevice
//
if (FIsEnumerated (pComponent->Class())) { if (pComponent->m_dwCharacter & NCF_PHYSICAL) { // The binding engine calls us to remove physical devices
// only when we need to potentially cleanup the information
// we saved away when the class installer removed the device.
// This happens when the class installer is told to remove
// the device (which it does) and then notifies the binding
// engine to remove it from its data structures. The binding
// engine then calls this method to cleanup this info we
// set so that the binding engine could notify components of
// its removal.
//
// We can also be called here when a physical component is
// removed (with the binding engine write lock held by someone)
// and then readded immediately. The new component will get
// the same PnpId as the removed one but the bindng engine still
// has the removed component in its structures. When this
// condition is detected, the binding engine will remove the
// old instance (by calling us here). In this case, if we were
// to open the device info on pComponent->m_pszPnpId, we'd open
// the new instance that was added. We don't want to do this.
// We just want to cleanup any of the information that we set
// for the binding engine when we first removed the device.
//
HKEY hkeyComponent; hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szTempNetcfgStorageForUninstalledEnumeratedComponent, KEY_WRITE, &hkeyComponent);
if (S_OK == hr) { WCHAR szGuid[c_cchGuidWithTerm]; INT cch = StringFromGUID2 (pComponent->m_InstanceGuid, szGuid, c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
(VOID) HrRegDeleteKeyTree (hkeyComponent, szGuid); RegCloseKey (hkeyComponent); } } else { // Create a device info list
hr = HrOpenDeviceInfo (pComponent->Class(), pComponent->m_pszPnpId, &hdi, &deid);
if (S_OK == hr) { // removals must go through device installer
// hook (NetClassInstaller). The function we are
// in can only be called if the caller has the write lock
// so we need to indicate this to the device installer hook
// through our reserved data.
ADAPTER_REMOVE_PARAMS arp = {0}; CiSetReservedField (hdi, &deid, &arp);
// removals must go through device installer
// hook (NetClassInstaller).
hr = HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, &deid);
// clear the reserved field so we don't delete it later
CiClearReservedField (hdi, &deid);
if (S_OK == hr) { hr = FSetupDiCheckIfRestartNeeded (hdi, &deid) ? NETCFG_S_REBOOT : S_OK; #ifdef ENABLETRACE
if (NETCFG_S_REBOOT == hr) { TraceTag (ttidClassInst, "***********************************" "**************************************************");
TraceTag (ttidClassInst, "The component %S needs a reboot " "in order to function", pComponent->m_pszPnpId);
TraceTag (ttidClassInst, "***********************************" "**************************************************"); } #endif //ENABLETRACE
} SetupDiDestroyDeviceInfoList (hdi); } } } else { // For non enumerated components, the instance key is the
// component key
hr = pComponent->HrOpenInstanceKey (KEY_ALL_ACCESS, &hkeyInstance, NULL, NULL);
if (S_OK == hr) { if (NC_NETCLIENT == pComponent->Class ()) { hr = HrCiDeleteNetProviderInfo (hkeyInstance, NULL, NULL); }
if (S_OK == hr) { hr = pComponent->HrOpenInfFile(&hinf);
if( S_OK == hr ) { // Remove the component
hr = HrCiRemoveNonEnumeratedComponent ( hinf, hkeyInstance, pComponent->Class(), pComponent->m_InstanceGuid, pstrRemoveSection); } } }
RegSafeCloseKey (hkeyInstance); }
TraceHr (ttidError, FAL, hr, NETCFG_S_REBOOT == hr, "HrCiRemoveComponent (%S)", pComponent->PszGetPnpIdOrInfId()); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiGetDriverInfo
//
// Purpose: Finds a component's driver information (in the inf file) and
// creates a Device Info Data structure containing that
// information as the structure's selected driver.
// (see Device Installer Api for more info).
//
// Arguments:
// hdi [in] See Device Installer Api documentation for more info.
// pdeid [in, out] See Device Installer Api documentation for
// more info. Should be allocated by caller, but empty.
// guidClass [in] The class guid for the component.
// pszInfId [in] The id of the component as found in its inf.
// pszInfFile [in] Optional. The inf file for the component.
//
// Returns: HRESULT. S_OK if successful, error code otherwise.
//
// Author: billbe 11 Mar 1997
//
// Notes:
//
HRESULT HrCiGetDriverInfo ( IN HDEVINFO hdi, IN OUT PSP_DEVINFO_DATA pdeid, IN const GUID& guidClass, IN PCWSTR pszInfId, IN PCWSTR pszInfFile OPTIONAL) { HRESULT hr;
Assert (IsValidHandle (hdi)); Assert (pdeid); Assert (pszInfId);
// Copy the Id since we may need to change it.
//
WCHAR szId[_MAX_PATH]; wcscpy (szId, pszInfId);
// We cannot generate ids via HrSetupDiCreateDeviceInfo if they contain
// slashes (e.g. Eisa\*pnp0232), so we need to convert any slashes in
// the instance id to ampersands.
//
int iPos = 0; while (szId[iPos]) { if (L'\\' == szId[iPos]) { szId[iPos] = L'&'; } ++iPos; }
// First, create a [temporary] device info. This will be used to
// find the component's Inf file.
hr = HrSetupDiCreateDeviceInfo (hdi, szId, guidClass, NULL, NULL, DICD_GENERATE_ID, pdeid);
if (S_OK == hr) { // In order to find the Inf file, Device Installer Api needs the
// component id which it calls the Hardware id.
//
// We need to include an extra null since this registry value is a
// multi-sz
//
wcsncpy (szId, pszInfId, iPos); szId[iPos + 1] = 0;
hr = HrSetupDiSetDeviceRegistryProperty (hdi, pdeid, SPDRP_HARDWAREID, (const BYTE*)szId, CbOfSzAndTerm (szId) + sizeof(WCHAR));
if (S_OK == hr) { // Get the install params and set the class for compat flag
// This will use the device's class guid as a filter when
// searching through infs, speeding things up. We can also
// let Device Installer Api know that we want to use a single
// inf. if we can't get the params and set it it isn't an error
// since it only slows things down a bit
//
SP_DEVINSTALL_PARAMS deip; hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip); if (S_OK == hr) { deip.FlagsEx |= DI_FLAGSEX_USECLASSFORCOMPAT;
// If we were not given an inf file to use...
// We have a map of known components and their inf files.
// If this component is in the map then we can set the
// driver path in the device info data and
// set the enumerate a single inf flag. This will
// cause the device installer to just look at the specified
// inf file for the driver node.
//
// We only do this if the node doesn't already have a file
// name set.
//
if (!(*deip.DriverPath)) { if (pszInfFile && *pszInfFile) { wcscpy (deip.DriverPath, pszInfFile); } else { FInfFileFromComponentId (pszInfId, deip.DriverPath); } }
if (*deip.DriverPath) {
TraceTag (ttidClassInst, "Class Installer was given %S " "as a filename for %S", deip.DriverPath, pszInfId); deip.Flags |= DI_ENUMSINGLEINF;
if ((0 == _wcsicmp(L"netrasa.inf", deip.DriverPath)) || (0 == _wcsicmp(L"netpsa.inf", deip.DriverPath))) { deip.Flags |= DI_NOFILECOPY; } }
// For non-device classes, we need to allow excluded
// drivers in order to get any driver list returned.
if (!FIsEnumerated (guidClass)) { deip.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS; }
(VOID) HrSetupDiSetDeviceInstallParams (hdi, pdeid, &deip); }
// Now we let Device Installer Api build a driver list based on
// the information we have given so far. This will result in the
// Inf file being found if it exists in the usual Inf directory
//
#ifdef ENABLETRACE
CBenchmark bmrk; bmrk.Start ("SetupDiBuildDriverInfoList"); #endif //ENABLETRACE
hr = HrSetupDiBuildDriverInfoList (hdi, pdeid, SPDIT_COMPATDRIVER); #ifdef ENABLETRACE
bmrk.Stop(); TraceTag (ttidBenchmark, "%s : %s seconds", bmrk.SznDescription(), bmrk.SznBenchmarkSeconds (2)); #endif //ENABLETRACE
if (S_OK == hr) { // HrSetupDiSelectBestCompatDrv finds and selects the best
// driver for the device.
//
SP_DRVINFO_DATA drid; hr = HrSetupDiSelectBestCompatDrv(hdi, pdeid);
if (HRESULT_FROM_SETUPAPI(ERROR_NO_COMPAT_DRIVERS) == hr) { // Make the ERROR_NO_COMPAT_DRIVERS case look like what
// it really means -- the requested component's driver
// info (i.e. inf) could not be found.
//
hr = SPAPI_E_NO_DRIVER_SELECTED; } } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // We couldn't find an inf file which means we cannot
// selected the driver for this component.
//
hr = SPAPI_E_NO_DRIVER_SELECTED; } }
// if anything failed, we should remove the device node we created
if (FAILED(hr)) { (VOID) SetupDiDeleteDeviceInfo (hdi, pdeid); } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetDriverInfo"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiGetClassAndInfFileOfInfId
//
// Purpose: Finds a component's class and inf file.
//
// Arguments:
// pszInfId [in] The Id of the component as found in its Inf.
// pClass [out] The class of the component.
// pszInfFile [out] The filename of the component's inf
// (must be _MAX_PATH long).
//
// Returns: HRESULT. S_OK if successful, error code otherwise.
//
// Author: billbe 16 Mar 1998
//
// Notes:
//
HRESULT HrCiGetClassAndInfFileOfInfId ( IN PCWSTR pszInfId, OUT NETCLASS* pClass, OUT PWSTR pszInfFile) // Must be _MAX_PATH long
{ HRESULT hr; const COMPONENT_INFO* pCompInfo; HDEVINFO hdi;
Assert (pszInfId && *pszInfId); Assert (pClass); Assert (pszInfFile);
hr = S_OK;
// First, try the fast route by seeing if it's in our internal map.
//
pCompInfo = PComponentInfoFromComponentId (pszInfId); if (pCompInfo) { *pClass = NetClassEnumFromGuid (*pCompInfo->pguidClass);
if (FIsValidNetClass (*pClass)) { wcsncpy (pszInfFile, pCompInfo->pszInfFile, _MAX_PATH); pszInfFile [_MAX_PATH - 1] = 0; } else { hr = SPAPI_E_INVALID_CLASS; } } else { // Create a device info list.
//
hr = HrSetupDiCreateDeviceInfoList (NULL, NULL, &hdi); if (S_OK == hr) { SP_DEVINFO_DATA deid;
// Get the driver info for the component and set it as the
// selected driver
//
hr = HrCiGetDriverInfo (hdi, &deid, GUID_NULL, pszInfId, NULL); if (S_OK == hr) { SP_DRVINFO_DATA drid;
// Get the selected driver.
//
hr = HrSetupDiGetSelectedDriver (hdi, &deid, &drid); if (S_OK == hr) { // Set the class output parameter from the dev info data
// structure (HrGetDriverInfo updates this field if a driver
// was found)
//
*pClass = NetClassEnumFromGuid (deid.ClassGuid);
if (!FIsValidNetClass (*pClass)) { hr = SPAPI_E_INVALID_CLASS; } else { PSP_DRVINFO_DETAIL_DATA pdridd;
// Now get the driver's detailed information
//
hr = HrCiGetDriverDetail (hdi, &deid, &drid, &pdridd); if (S_OK == hr) { // Get the inf filename and set the
// output parameter.
//
wcsncpy (pszInfFile, pdridd->InfFileName, _MAX_PATH); pszInfFile[_MAX_PATH - 1] = 0;
MemFree (pdridd); } } } } SetupDiDestroyDeviceInfoList (hdi); } }
if (S_OK != hr) { *pClass = NC_INVALID; *pszInfFile = 0; }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetClassAndInfFileOfInfId"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiGetDriverDetail
//
// Purpose: Creates and fills a PSP_DRVINFO_DETAIL_DATA structure
// with detailed information about the pDevInfoData's
// selected driver
//
// Arguments:
// hdi [in] See Device Installer Api documentation for more info
// pdeid [in] See Device Installer Api documentation for more info
// This value is NULL for non-physical net
// components.
// pdrid [in] See Device Installer Api documentation for more info
// ppdridd [out] See Device Installer Api documentation for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 11 Mar 1997
//
// Notes:
//
HRESULT HrCiGetDriverDetail ( IN HDEVINFO hdi, IN PSP_DEVINFO_DATA pdeid OPTIONAL, OUT PSP_DRVINFO_DATA pdrid, OUT PSP_DRVINFO_DETAIL_DATA* ppdridd) { Assert(IsValidHandle(hdi)); Assert(pdrid); Assert(ppdridd);
// initialize pdrid and set its cbSize field
ZeroMemory (pdrid, sizeof (SP_DRVINFO_DATA)); pdrid->cbSize = sizeof (SP_DRVINFO_DATA);
HRESULT hr = S_OK;
*ppdridd = NULL;
// Get the selected driver for the component
hr = HrSetupDiGetSelectedDriver (hdi, pdeid, pdrid); if (S_OK == hr) { // Get driver detail info
hr = HrSetupDiGetDriverInfoDetail (hdi, pdeid, pdrid, ppdridd); }
// clean up on failure
if (FAILED(hr)) { if (*ppdridd) { MemFree (*ppdridd); *ppdridd = NULL; } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetDriverDetail"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiRegSetComponentInformation
//
// Purpose: Stores component information under the instance key of
// the component.
//
// Arguments:
// hkeyInstance [in] Component's instance registry key.
// pcii [in] Component's information to store in hkeyInstance.
//
// Returns: HRESULT. S_OK if successful, error code otherwise.
//
// Author: billbe 11 Mar 1997
//
// Notes:
//
HRESULT HrCiRegSetComponentInformation( IN HKEY hkeyInstance, IN COMPONENT_INSTALL_INFO* pcii) { Assert(hkeyInstance); Assert(pcii);
HRESULT hr = S_OK;
BOOL fIsEnumerated = FIsEnumerated (pcii->Class);
// Store the characteristics, inf path, and main
// install section for the component
//
hr = HrRegSetDword (hkeyInstance, L"Characteristics", pcii->dwCharacter);
if (FAILED(hr)) { goto exit; }
if (!fIsEnumerated) { hr = HrRegSetSz (hkeyInstance, L"InfPath" /*REGSTR_VAL_INFPATH*/, pcii->pszInfFile);
if (FAILED(hr)) { goto exit; }
hr = HrRegSetSz (hkeyInstance, L"InfSection"/*REGSTR_VAL_INFSECTION*/, pcii->pszSectionName);
if (FAILED(hr)) { goto exit; } }
// For non-enumerated components, store description into the registry.
//
if (!fIsEnumerated) { hr = HrRegSetSz (hkeyInstance, L"Description", pcii->pszDescription);
if (FAILED(hr)) { goto exit; } }
// If this component is already installed, then there is no need to write
// the following information
//
if (FIsEnumerated (pcii->Class) && !pcii->fPreviouslyInstalled && FIsPhysicalAdapter (pcii->Class, pcii->dwCharacter) && (InterfaceTypeUndefined != pcii->BusType)) { hr = HrRegSetSzAsUlong (hkeyInstance, L"BusType", pcii->BusType, c_nBase10);
if (FAILED(hr)) { goto exit; } }
hr = HrRegSetSz (hkeyInstance, L"ComponentId", pcii->pszInfId);
exit:
TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegSetComponentInformation"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiCreateInstanceKey
//
// Purpose: Creates an instance key for the component. For enumerated
// devices, this is
// HKLM\System\CCS\Control\Class\<net guid>\<instance id>
// For non-enumerated components, this is under
// HKLM\System\CCS\Control\Network\<Class Guid>\<Instance Guid>
//
// Arguments:
// pcii [inout] Component install info structure.
// phkeyInstance [out] The component's registry instance key.
//
// Returns: HRESULT
//
// Author: billbe 22 Mar 1997
//
// Notes:
//
HRESULT HrCiCreateInstanceKey( IN COMPONENT_INSTALL_INFO* pcii, OUT HKEY* phkeyInstance) { Assert (pcii); Assert (phkeyInstance); Assert (FImplies (FIsEnumerated (pcii->Class), IsValidHandle (pcii->hdi) && pcii->pdeid));
HRESULT hr = S_OK;
// initialize the HKEY parameter
*phkeyInstance = NULL;
// Create the instance key for this component under the
// Network\<net guid> tree. This will be the component's
// instance key for all but physical net class components. Their
// instance key is created by Device Installer Api and lives under the
// Pnp Net Class driver tree.
// If the object is an enumerated component then we let
// the Device Installer api do the work
//
if (FIsEnumerated (pcii->Class)) {
// We need to create the adapter's driver key under
// the Pnp Net Class Driver tree.
//
hr = HrSetupDiCreateDevRegKey (pcii->hdi, pcii->pdeid, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL, phkeyInstance); } else { // Not a physical net adapter so the component key is
// the instance key
// First, create the instance GUID
hr = CoCreateGuid (&pcii->InstanceGuid);
// Now create the key
if (S_OK == hr) { WCHAR szInstanceKeyPath[_MAX_PATH];
CreateInstanceKeyPath (pcii->Class, pcii->InstanceGuid, szInstanceKeyPath);
hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE, szInstanceKeyPath, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phkeyInstance, NULL); } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiCreateInstanceKey"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiGetPropertiesFromInf
//
// Purpose: Retrieves a set of the component's proerties from the inf
// file.
//
// Arguments:
// hinfFile [in] A handle to the component's inf file
// pcii [inout] The component info structure
// See compinfo.h for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 14 Jun 1997
//
// Notes:
//
HRESULT HrCiGetPropertiesFromInf ( IN HINF hinfFile, IN OUT COMPONENT_INSTALL_INFO* pcii) { Assert (IsValidHandle (hinfFile)); Assert (pcii); Assert (pcii->pszSectionName);
// Find the inf line that contains Characteristics and retrieve it
HRESULT hr = HrSetupGetFirstDword (hinfFile, pcii->pszSectionName, L"Characteristics", &pcii->dwCharacter);
if ((S_OK == hr) && (FIsPhysicalAdapter(pcii->Class, pcii->dwCharacter))) { hr = HrCiGetBusInfoFromInf (hinfFile, pcii); } #ifdef DBG
else if (FAILED(hr)) { TraceTag(ttidError, "Inf contains no Characteristics field"); } #endif // DBG
TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetPropertiesFromInf"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiIsInstalledComponent
//
// Purpose: Checks if the component is already installed
//
//
// Arguments:
// pcici [in] A structure containing the component information
// See compinst.h for definition
// phkey [out] The registry instance key of the adapter
// during inf processing. only set if fcn returns S_OK
//
// Returns: HRESULT - S_OK if the component is already installed
// S_FALSE if the component is not already installed
// A win32 converted error otherwise
//
// Author: billbe 17 Sep 1997
//
// Notes:
//
HRESULT HrCiIsInstalledComponent ( IN COMPONENT_INSTALL_INFO* pcii, OUT HKEY* phkey) { HRESULT hr;
Assert(pcii);
if (phkey) { *phkey = NULL; }
// If this is an enumerated component, we just check for NetCfgInstanceId
// in the instance (driver) key.
//
if (FIsEnumerated (pcii->Class)) { HKEY hkey; hr = HrSetupDiOpenDevRegKey (pcii->hdi, pcii->pdeid, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS, &hkey);
if (S_OK == hr) { WCHAR szGuid[c_cchGuidWithTerm]; DWORD cbGuid = sizeof (szGuid); hr = HrRegQuerySzBuffer (hkey, L"NetCfgInstanceId", szGuid, &cbGuid);
if (S_OK == hr) { IIDFromString (szGuid, &pcii->InstanceGuid); if (phkey) { *phkey = hkey; } } else { RegCloseKey (hkey); hr = S_FALSE; } } else if ((SPAPI_E_KEY_DOES_NOT_EXIST == hr) || (SPAPI_E_DEVINFO_NOT_REGISTERED == hr))
{ TraceTag(ttidClassInst, "Component is not known by Net Config"); hr = S_FALSE; } } else { // For non-enumerated components, we check the netcfg "config blob" to
// determine if this component is isntalled.
CNetConfig NetConfig; hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, &NetConfig);
if (S_OK == hr) { CComponent* pComponent; pComponent = NetConfig.Core.Components. PFindComponentByInfId(pcii->pszInfId, NULL);
if (pComponent) { pcii->InstanceGuid = pComponent->m_InstanceGuid; if (phkey) { hr = pComponent->HrOpenInstanceKey(KEY_ALL_ACCESS, phkey, NULL, NULL); } } else { hr = S_FALSE; } } }
TraceHr (ttidError, FAL, hr, S_FALSE == hr, "HrCiIsInstalledComponent"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiCreateInstanceKeyAndProcessMainInfSection
//
// Purpose: Processes a component's main inf section and
// storing, in the registry, any extra information needed for
// component initialization
//
// Arguments:
// hinf [in] Handle to the component's inf file.
// pcii [inout] Will be filled with information about the
// component.
// phkey [out] Handle to the component's registry instance key.
//
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 15 Nov 1996
//
// Notes:
//
HRESULT HrCiCreateInstanceKeyAndProcessMainInfSection( IN HINF hinf, IN COMPONENT_INSTALL_INFO* pcii, OUT HKEY* phkey) { #if defined(REMOTE_BOOT)
GUID c_guidRemoteBoot; static const WCHAR c_szRemoteBootAdapterGuid[] = L"{54C7D140-09EF-11D1-B25A-F5FE627ED95E}";
DEFINE_GUID(c_guidRemoteBoot, 0x54c7d140, 0x09ef, 0x11d1, 0xb2, 0x5a, 0xf5, 0xfe, 0x62, 0x7e, 0xd9, 0x5e); #endif // defined(REMOTE_BOOT)
Assert (IsValidHandle (hinf)); Assert (pcii); Assert (phkey);
// The properties retrieved here will be written to the registry
// later.
HRESULT hr = HrCiGetPropertiesFromInf (hinf, pcii);
if (S_OK == hr) { BOOL fEnumerated = FIsEnumerated (pcii->Class);
// If this component is enumerated, then we need to know if it
// is a remote boot adapter.
if (fEnumerated) { Assert (IsValidHandle (pcii->hdi)); Assert (pcii->pdeid);
#if defined(REMOTE_BOOT)
// If this adapter is a remote boot adapter, then we have
// to use a pre-determined GUID
//
if (S_OK == HrIsRemoteBootAdapter(pcii->hdi, pcii->pdeid)) { pcai->m_fRemoteBoot = TRUE; pcii->InstanceGuid = c_guidRemoteBoot; } #endif // defined(REMOTE_BOOT)
}
// Is this a fresh install or a reinstall?
hr = HrCiIsInstalledComponent(pcii, phkey);
if (S_FALSE == hr) { hr = S_OK;
// Fresh install
//
if (S_OK == hr) { // For non-physical components, the relative key will
// be the driver instance key which is under the class
// branch of the Network key. Its form is
// <Class GUID>/<instance GUID>.
// For physical components, the key is under
// the Pnp class driver tree. The next call will
// create this key
hr = HrCiCreateInstanceKey(pcii, phkey);
if (fEnumerated) { // If we don't have an instance
// guid (i.e. not remote boot adapter),
// get one
if (GUID_NULL == pcii->InstanceGuid) { hr = CoCreateGuid(&pcii->InstanceGuid); #ifdef ENABLETRACE
WCHAR szGuid[c_cchGuidWithTerm]; StringFromGUID2(pcii->InstanceGuid, szGuid, c_cchGuidWithTerm); TraceTag(ttidClassInst, "NetCfg Instance Guid %S " "generated for %S", szGuid, pcii->pszInfId); #endif // ENABLETRACE
} } } } else if (S_OK == hr) { // This component is being reinstalled
pcii->fPreviouslyInstalled = TRUE; }
if (S_OK == hr) { // Now that the instance key is created, we need to run
// the main inf sections
//
hr = HrCiDoCompleteSectionInstall(hinf, *phkey, pcii->pszSectionName, pcii->hwndParent, fEnumerated);
// On failure of fresh installs, remove components
if (FAILED(hr) && !pcii->fPreviouslyInstalled) { if (!fEnumerated) { HrCiRemoveNonEnumeratedComponent (hinf, *phkey, pcii->Class, pcii->InstanceGuid, NULL); } } } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiCreateInstanceKeyAndProcessMainInfSection"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiDoOemFileCopyIfNeeded
//
// Purpose: Calls HrSetupCopyOemInf if strInfPath is not already in the
// inf directory. This will copy an Oem inf to the inf
// directory with a new name.
//
// Arguments:
// pszInfPath [in] Path to the inf file
// pszNewName [out] The new name of the copied inf file
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 15 May 1997
//
// Notes:
//
HRESULT HrCiDoOemFileCopyIfNeeded( IN PCWSTR pszInfPath, OUT PWSTR pszNewName) { Assert (pszInfPath); Assert (pszNewName);
HRESULT hr = S_OK; WCHAR szInfDir[_MAX_PATH] = {0};
// fill buffer with path to %windir%
GetSystemWindowsDirectory (szInfDir, _MAX_PATH);
// the inf directory is %windir%\inf
//
wcscat (szInfDir, L"\\"); wcscat (szInfDir, L"Inf");
// Extract the directory from the filename
//
PWSTR pszEnd = wcsrchr (pszInfPath, L'\\'); DWORD cch; if (pszEnd) { cch = (DWORD)(pszEnd - pszInfPath); } else { cch = wcslen (pszInfPath); }
// if the inf is not already in the inf directory, copy it there
//
if ((cch != wcslen (szInfDir)) || (0 != _wcsnicmp (pszInfPath, szInfDir, cch))) { WCHAR szDestFilePath[_MAX_PATH]; PWSTR pszDestFilename; hr = HrSetupCopyOemInfBuffer (pszInfPath, NULL, SPOST_PATH, 0, szDestFilePath, _MAX_PATH, &pszDestFilename);
if (S_OK == hr) { wcscpy (pszNewName, pszDestFilename); } } else { // The inf is already in the right directory so just copy the
// current filename component.
if (pszEnd) { wcscpy (pszNewName, pszEnd + 1); } else { wcscpy (pszNewName, pszInfPath); } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiDoOemFileCopyIfNeeded"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiInstallNonEnumeratedComponent
//
// Purpose: This function completes the installation of a non-enumerated
// component
//
// Arguments:
// hinf [in] SetupApi handle to an inf file
// hkey [in] The registry instance key of the adapter
// during inf processing.
// pcii [in] A structure containing the component information
//
// Returns: HRESULT. S_OK if successful, or error code otherwise
//
// Author: billbe 28 Apr 1997
//
// Notes:
//
HRESULT HrCiInstallNonEnumeratedComponent ( IN HINF hinf, IN HKEY hkey, IN COMPONENT_INSTALL_INFO* pcii) { // Register the notification dll for this component,
// if it exists.
HRESULT hr = HrCiRegisterNotificationDll(hkey, CIRDF_REGISTER);
// Device Installer Api handles OEM files for
// enumerated components in InstallDevice
// Since this component is non-enumerated
// we need to handle any oem files
// manually.
//
// Copy the inf file if needed then store
// the new inf name
// Note: if the inf file does not need to
// be copied, the new name will be the
// old name without the directory info.
//
if (S_OK == hr) { WCHAR szNewName[_MAX_PATH];; hr = HrCiDoOemFileCopyIfNeeded (pcii->pszInfFile, szNewName); if (S_OK == hr) { // set the new path value in the registry.
hr = HrRegSetSz (hkey, REGSTR_VAL_INFPATH, szNewName);
if ((S_OK == hr) && (NC_NETCLIENT == pcii->Class)) { // if this is a network client, do appropriate processing.
hr = HrCiAddNetProviderInfo (hinf, pcii->pszSectionName, hkey, pcii->fPreviouslyInstalled); } } }
// On failures of first time installs, remove the component.
//
if (FAILED(hr) && !pcii->fPreviouslyInstalled) { TraceTag (ttidClassInst, "Install canceled. Removing..."); (VOID) HrCiRemoveNonEnumeratedComponent (hinf, hkey, pcii->Class, pcii->InstanceGuid, NULL); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallNonEnumeratedComponent"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiInstallComponentInternal
//
// Purpose: Installs a component
//
// Arguments:
// pcii [in, out] Will be filled with information about the
// component.
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 15 Nov 1996
//
// Notes:
//
HRESULT HrCiInstallComponentInternal ( IN OUT COMPONENT_INSTALL_INFO* pcii) { HRESULT hr = S_OK; HINF hinfInstallFile = NULL; HKEY hkeyInstance = NULL;
TraceTag (ttidClassInst, "Installing %S from %S", pcii->pszInfId, pcii->pszInfFile);
// Open the component's inf file.
hr = HrSetupOpenInfFile (pcii->pszInfFile, NULL, INF_STYLE_WIN4, NULL, &hinfInstallFile);
// Continue only if we have opened the file.
if (S_OK == hr) { // The section we have currently might need to be decorated
// with OS and Platform specific suffixes. The next call
// will return the actual decorated section name or our
// current section name if the decorated one does not exist.
//
// Store the original section name pointer so we can restore
// it after we have finished.
PCWSTR pszOriginalSectionName = pcii->pszSectionName;
// Now we get the actual section name.
//
WCHAR szActualSection[_MAX_PATH]; hr = HrSetupDiGetActualSectionToInstallWithBuffer (hinfInstallFile, pcii->pszSectionName, szActualSection, _MAX_PATH, NULL, NULL);
if (S_OK == hr) { pcii->pszSectionName = szActualSection; hr = HrCiCreateInstanceKeyAndProcessMainInfSection ( hinfInstallFile, pcii, &hkeyInstance);
if (S_OK == hr) { // Set up the registry with the component info.
hr = HrCiRegSetComponentInformation (hkeyInstance, pcii);
if (S_OK == hr) { // We do different things during install based
// on whether PnP knows about the component
// (i.e. enumerated) or not.
if (FIsEnumerated (pcii->Class)) { hr = HrCiInstallEnumeratedComponent ( hinfInstallFile, hkeyInstance, *pcii); } else { hr = HrCiInstallNonEnumeratedComponent ( hinfInstallFile, hkeyInstance, pcii); } } RegSafeCloseKey(hkeyInstance); } // set the section name back
pcii->pszSectionName = pszOriginalSectionName; } SetupCloseInfFile(hinfInstallFile); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallComponentInternal"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiCallClassInstallerToInstallComponent
//
// Purpose: This function invokes the class installer to install an
// enumerated component.
//
// Arguments:
// hdi [in] See Device Installer docs for more info.
// pdeid [in]
//
// Returns: HRESULT. S_OK if successful, or error code otherwise
//
// Author: billbe 28 Apr 1997
//
// Notes: This should only be called while the INetCfg lock is held.
//
HRESULT HrCiCallClassInstallerToInstallComponent(HDEVINFO hdi, PSP_DEVINFO_DATA pdeid) { HRESULT hr;
Assert(IsValidHandle(hdi)); Assert(pdeid);
// We need to register the device before we do any work on it.
hr = HrSetupDiCallClassInstaller (DIF_REGISTERDEVICE, hdi, pdeid);
if (S_OK == hr) { // Check if we can install of this component. i.e. is the inf
// a valid Windows 2000 inf.
hr = HrSetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hdi, pdeid);
if (S_OK == hr) { BOOL fFileCopy = TRUE; SP_DEVINSTALL_PARAMS deip;
// Fu fu fu: SetupApi is ignoring DI_NOFILECOPY so we'll overcome
// their shortcomings and do it ourselves.
//
hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip); if (S_OK == hr) { if (deip.Flags & DI_NOFILECOPY) { fFileCopy = FALSE; } }
if (fFileCopy) { // Install needed files.
hr = HrSetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hdi, pdeid); }
if (S_OK == hr) { // Now that all files have been copied, we need to set the
// no file copy flag. Otherwise, setupapi will try to copy
// files at each dif code. This results in multiple (1 per
// dif code) unsigned driver popups if the driver was
// unsigned.
// We'll only do this if the no copy file flag wasn't already
// set. i.e. if fFileCopy is TRUE.
//
if (fFileCopy) { // An error here isn't bad enough to stop installation.
//
HRESULT hrTemp; hrTemp = HrSetupDiSetDeipFlags (hdi, pdeid, DI_NOFILECOPY, SDDFT_FLAGS, SDFBO_OR);
TraceHr (ttidError, FAL, hrTemp, FALSE, "HrCiCallClassInstallerToInstallComponent: " "HrSetupDiSetDeipFlags"); }
// Device co-installers need to be registered at this point
// so they can do work.
hr = HrSetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS, hdi, pdeid);
if (S_OK == hr) { hr = HrSetupDiCallClassInstaller (DIF_INSTALLINTERFACES, hdi, pdeid);
if (S_OK == hr) { hr = HrSetupDiCallClassInstaller (DIF_INSTALLDEVICE, hdi, pdeid); } } } }
// If we failed for any reason, we need to clean up since
// we initiated this install.
if (FAILED(hr)) { ADAPTER_REMOVE_PARAMS arp; arp.fBadDevInst = TRUE; arp.fNotifyINetCfg = FALSE;
CiSetReservedField (hdi, pdeid, &arp); HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, pdeid); CiClearReservedField (hdi, pdeid);
} }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiCallClassInstallerToInstallComponent"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiInstallComponent
//
// Purpose: This function takes a Network Component's Id and its class
// guid and gathers the information needed by
// HrCiInstallComponent. Since it is called from INetCfg, we
// have the write lock
//
// Arguments:
// Params [in] Component install params. See install.h
// ppComponent [out] A created CComponent representing the installed
// component.
// pdwNewCharacter [out] Optional pointer to a DWORD to receive the
// characteristics of the component.
//
// Returns: HRESULT. S_OK is successful, NETCFG_S_REBOOT if a reboot is
// needed to start the device, or an error code
//
// Author: billbe 16 Mar 1997
//
// Notes:
//
HRESULT HrCiInstallComponent ( IN const COMPONENT_INSTALL_PARAMS& Params, OUT CComponent** ppComponent, OUT DWORD* pdwNewCharacter) { Assert (FIsValidNetClass (Params.Class)); Assert (Params.pszInfId && *Params.pszInfId); Assert (!Params.pComponent);
HRESULT hr = S_OK; HDEVINFO hdi = NULL; SP_DEVINFO_DATA deid; const GUID* pguidClass = MAP_NETCLASS_TO_GUID[Params.Class];
if (ppComponent) { *ppComponent = NULL; } if (pdwNewCharacter) { *pdwNewCharacter = 0; }
// If we're about to install the component, it better not be in
// lockdown.
//
Assert (!FIsComponentLockedDown (Params.pszInfId));
// First create a device info set
hr = HrSetupDiCreateDeviceInfoList (pguidClass, NULL, &hdi);
if (S_OK == hr) { // This will create an node in the enum tree for this component.
// If it is enumerated, we will register it which will make
// it persist. If non-enumerated, we will not register it and
// the node will be deleted in the call to SetDiDestroyDeviceInfoList.
//
hr = HrCiGetDriverInfo (hdi, &deid, *pguidClass, Params.pszInfId, Params.pszInfFile);
// Get the driver info for the component
if (S_OK == hr) { BASIC_COMPONENT_DATA Data = {0}; Data.Class = Params.Class; Data.pszInfId = Params.pszInfId;
if (FIsEnumerated (Params.Class)) { // If the component is enumerated, we will need a place to
// store its pnp id.
WCHAR szPnpId[MAX_DEVICE_ID_LEN]; ADAPTER_OUT_PARAMS AdapterOutParams;
ZeroMemory (&AdapterOutParams, sizeof(AdapterOutParams));
// Net class components have to go through the device
// installer hook (aka NetClassInstaller)
//
if (FInSystemSetup()) { // if we are in GUI mode we need to make the
// device install quiet and always copy from
// the source location even if the files are
// already present. We also need to set
// the in system setup flag. This is what
// syssetup would do if it initiated the install
// so INetCfg initiated installs must do the same.
//
// We should also set the parent hwnd.
//
SP_DEVINSTALL_PARAMS deip; HRESULT hrTemp = HrSetupDiGetDeviceInstallParams ( hdi, &deid, &deip);
if (S_OK == hr) { deip.hwndParent = Params.hwndParent; deip.Flags |= DI_QUIETINSTALL | DI_FORCECOPY; deip.FlagsEx |= DI_FLAGSEX_IN_SYSTEM_SETUP;
hrTemp = HrSetupDiSetDeviceInstallParams ( hdi, &deid, &deip); }
TraceHr (ttidError, FAL, hrTemp, FALSE, "Error " "getting and setting device params."); }
CiSetReservedField (hdi, &deid, &AdapterOutParams);
// Officially call the class installer to install
// this device
//
hr = HrCiCallClassInstallerToInstallComponent (hdi, &deid);
CiClearReservedField (hdi, &deid);
Data.dwCharacter = AdapterOutParams.dwCharacter; Data.InstanceGuid = AdapterOutParams.InstanceGuid;
if (S_OK == hr) { hr = HrSetupDiGetDeviceInstanceId (hdi, &deid, szPnpId, MAX_DEVICE_ID_LEN, NULL);
if (S_OK == hr) { Data.pszPnpId = szPnpId; } } } else // Non-net class components
{ COMPONENT_INSTALL_INFO cii; PSP_DRVINFO_DETAIL_DATA pdridd = NULL; SP_DRVINFO_DATA drid;
// Now get the driver's detailed information
hr = HrCiGetDriverDetail (hdi, &deid, &drid, &pdridd);
if (S_OK == hr) { ZeroMemory (&cii, sizeof(cii)); cii.Class = Params.Class; cii.pszInfId = Params.pszInfId; cii.pszInfFile = pdridd->InfFileName; cii.hwndParent = Params.hwndParent; cii.pszDescription = drid.Description; cii.pszSectionName = pdridd->SectionName;
HINF hinf; hr = HrSetupOpenInfFile (pdridd->InfFileName, NULL, INF_STYLE_WIN4, NULL, &hinf);
if (S_OK == hr) { // Make sure this is an NT5 inf network inf
//
hr = HrSetupIsValidNt5Inf (hinf); SetupCloseInfFile (hinf); }
if (S_OK == hr) { hr = HrCiInstallComponentInternal (&cii); if (S_OK == hr) { Data.InstanceGuid = cii.InstanceGuid; Data.dwCharacter = cii.dwCharacter; } } MemFree (pdridd); } }
if ((S_OK == hr) && ppComponent) // !previously installed
{ CComponent* pComponent;
hr = CComponent::HrCreateInstance ( &Data, CCI_ENSURE_EXTERNAL_DATA_LOADED, Params.pOboToken, &pComponent);
if (S_OK == hr) { *ppComponent = pComponent; } }
if ((S_OK == hr) && pdwNewCharacter) { *pdwNewCharacter = Data.dwCharacter; } }
SetupDiDestroyDeviceInfoList(hdi); }
#ifdef ENABLETRACE
if (S_OK == hr) { TraceTag(ttidClassInst, "Component now installed!"); } #endif //ENABLETRACE
TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallComponent (%S)", Params.pszInfId); return hr; }
//+--------------------------------------------------------------------------
//
// Function: SetBadDriverFlagIfNeededInList
//
// Purpose: Enumerates a driver list setting the DNF_BAD_DRIVER flag
// in every node that has a DNF_EXCLUDEFROMLIST flag.
//
// Arguments:
// hdi [in] See Device Installer Api documentaion for details
//
// Returns: HRESULT. S_OK
//
// Author: billbe 24 Nov 1998
//
// Notes: SetupDi forces us to use the DNF_BAD_DRIVER flag for non-netdevice
// classes if we want to exclude them from the select device dialog.
// This means to non-netclass components that
// DNF_BAD_DRIVER = DNF_EXCLUDEFROMLIST.
//
VOID SetBadDriverFlagIfNeededInList(HDEVINFO hdi) { Assert(IsValidHandle(hdi));
HRESULT hr = S_OK; SP_DRVINSTALL_PARAMS drip; SP_DRVINFO_DATA drid; DWORD dwIndex = 0;
// Enumerate each driver in hdi
while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL, SPDIT_CLASSDRIVER, dwIndex++, &drid))) { hr = HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
if (S_OK == hr) { // If the driver already has the bad driver flag set,
// go on to the next one.
if (drip.Flags & DNF_BAD_DRIVER) { continue; }
// If the driver has the exclude flag set, then set the
// bad driver flag.
if (drip.Flags & DNF_EXCLUDEFROMLIST) { drip.Flags |= DNF_BAD_DRIVER; (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL, &drid, &drip); } } }
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; }
TraceHr (ttidError, FAL, hr, FALSE, "SetBadDriverFlagIfNeededInList"); }
//+--------------------------------------------------------------------------
//
// Function: HrCiExcludeNonNetClassDriverFromSelectUsingInfId
//
// Purpose: Locates a driver in a driver list and sets its exclude from
// select flag.
//
// Arguments:
// hdi [in] See Device Installer Api documentaion for details
// pszInfId [in] The INF id of the component to exclude
//
// Returns: HRESULT. S_OK
//
// Author: billbe 29 Oct 1998
//
// Notes:
//
HRESULT HrCiExcludeNonNetClassDriverFromSelectUsingInfId( IN HDEVINFO hdi, IN PCWSTR pszInfId) { Assert(IsValidHandle(hdi)); Assert(pszInfId);
HRESULT hr = S_OK; SP_DRVINSTALL_PARAMS drip; SP_DRVINFO_DATA drid; PSP_DRVINFO_DETAIL_DATA pdridd; DWORD dwIndex = 0;
// Enumerate each driver in hdi
while (S_OK == (hr = HrSetupDiEnumDriverInfo (hdi, NULL, SPDIT_CLASSDRIVER, dwIndex++, &drid))) { (VOID) HrSetupDiGetDriverInstallParams (hdi, NULL, &drid, &drip);
// If the driver is already excluded for some other reason
// don't bother trying to determine if it should be excluded.
// Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
// non-device drivers rather than using DNF_EXCLUDEFROMLIST.
if (drip.Flags & DNF_BAD_DRIVER) { continue; }
// Get driver detail info
hr = HrSetupDiGetDriverInfoDetail (hdi, NULL, &drid, &pdridd);
if (S_OK == hr) { // If the IDs match, exclude it from the dialog
//
if (0 == lstrcmpiW (pdridd->HardwareID, pszInfId)) { // Non-device drivers can't use DNF_EXCLUDEFROMLIST
// and must use DNF_BAD_DRIVER.
drip.Flags |= DNF_BAD_DRIVER; (VOID) HrSetupDiSetDriverInstallParams (hdi, NULL, &drid, &drip); } MemFree (pdridd); } }
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiExcludeNonNetClassDriverFromSelectUsingInfId"); return hr; }
//+---------------------------------------------------------------------------
//
// Function: ExcludeLockedDownComponents
//
// Purpose: A callback function compatible with EnumLockedDownComponents
// that is used to exclude locked down components from
// selection. Called from HrCiPrepareSelectDeviceDialog.
// This call back is called for each locked down component.
//
// Arguments:
// pszInfId [in] the INF ID to exclude.
// pvCallerData [in] the HDEVINFO cast to PVOID
//
// Returns: nothing
//
// Author: shaunco 24 May 1999
//
// Notes: The callback interface was chosen so that the class installer
// is not burdended with the details of how/where the locked
// down components are implemented.
//
VOID CALLBACK ExcludeLockedDownComponents ( IN PCWSTR pszInfId, IN PVOID pvCallerData) { Assert (pszInfId && *pszInfId); Assert (pvCallerData);
HDEVINFO hdi = (HDEVINFO)pvCallerData;
HrCiExcludeNonNetClassDriverFromSelectUsingInfId (hdi, pszInfId); }
//+--------------------------------------------------------------------------
//
// Function: HrCiBuildExcludedDriverList
//
// Purpose: Non-Net class components can only be installed once
// So we need to iterate through the installed
// components, find their matching driver node in
// a Device Installer Api built driver list for the class,
// and set their exclude from select flag. This list
// will then be given to SetupDiSelectDevice which
// will not display the nodes with the exclude flag set.
//
// Arguments:
// hdi [in] See Device Installer Api documentaion for details
// guidClass [in] The class of components to build a driver list for
// pNetCfg [out] The current network configuration (i.e. what is
// installed).
//
// Returns: HRESULT. S_OK
//
// Author: billbe 10 Dec 1996
//
// Notes: Device Installer Api builds the driver list by rummaging
// through the inf directory and finding the components
// that are in files with the same class guid as the
// HDEVINFO. This is the same processing done
// in SetupDiSelectDevice, but the process is
// not repeated twice because we will give the
// list we built here to SetupDiSelectDevice.
//
HRESULT HrCiBuildExcludedDriverList( IN HDEVINFO hdi, IN NETCLASS Class, IN CNetConfig* pNetConfig) { HRESULT hr;
Assert(IsValidHandle(hdi)); Assert(pNetConfig);
// This might take some time. We are doing the same work as
// SetupDiSelectDevice would do. When we are done, we will
// hand the driver list to SetupDiSelectDevice so it won't
// need to rummage through the inf directory
//
CWaitCursor wc;
// For non-device classes, we need to allow excluded drivers
// in order to get a list returned.
hr = HrSetupDiSetDeipFlags(hdi, NULL, DI_FLAGSEX_ALLOWEXCLUDEDDRVS, SDDFT_FLAGSEX, SDFBO_OR);
if (S_OK == hr) { #ifdef ENABLETRACE
CBenchmark bmrk; bmrk.Start("SetupDiBuildDriverInfoList"); #endif //ENABLETRACE
hr = HrSetupDiBuildDriverInfoList(hdi, NULL, SPDIT_CLASSDRIVER);
#ifdef ENABLETRACE
bmrk.Stop(); TraceTag(ttidBenchmark, "%s : %s seconds", bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2)); #endif //ENABLETRACE
}
// Go through the network configuration and hide already installed
// components. Note: We only do this the first time. We show installed
// components if the user selects Have Disk on the dialog.
CComponent* pComponent; CComponentList::const_iterator iter;
for (iter = pNetConfig->Core.Components.begin(); iter != pNetConfig->Core.Components.end(); iter++) { pComponent = *iter; Assert (pComponent);
if (Class == pComponent->Class()) { // Hide the driver
hr = HrCiExcludeNonNetClassDriverFromSelectUsingInfId( hdi, pComponent->m_pszInfId); } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiBuildExcludedDriverList"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiSelectComponent
//
// Purpose: This function displays the Select Device dialog for the
// class of components specified by guidClass. Once the
// component has been selected, it is installed.. Since
// this fcn is called from INetCfg, we have the write lock.
//
// Arguments:
// Class [in] The class of components to display in the
// Select Device dialog
// hwndParent [in] The HWND of the parent window, used to display
// the UI
// pcfi [in] A structure used to determine what
// components should be filtered out of
// the select dialog (defined in netcfg.h)
// ppParams [out] Params used to install the component.
//
// Returns: HRESULT. S_OK if successful, S_FALSE if the component
// selected is being reinstalled instead of fresh
// installed, an error code otherwise
//
// Author: billbe 11 Nov 1996
//
// Notes: Filtering is only performed when selecting protocols,
// services, and clients.
//
HRESULT HrCiSelectComponent( IN NETCLASS Class, IN HWND hwndParent, IN const CI_FILTER_INFO* pcfi, OUT COMPONENT_INSTALL_PARAMS** ppParams) { Assert (ppParams); Assert (!FIsEnumerated (Class));
HRESULT hr; HDEVINFO hdi;
// We need to create a DeviceInfoSet item to use the SelectDevice dialog.
hr = HrSetupDiCreateDeviceInfoList( MAP_NETCLASS_TO_GUID[Class], hwndParent, &hdi);
if (S_OK == hr) { // call the class installer to bring up the select device dialog
// for enumerated components. This will notify any coinstallers
//
// This will be a map of component ids to instance guids
// for all installed components of Class.
CNetConfig NetConfig; hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, &NetConfig); if (S_OK == hr) { hr = HrCiBuildExcludedDriverList (hdi, Class, &NetConfig); }
if (S_OK == hr) { // Store the filter info in the hdi
CiSetReservedField(hdi, NULL, pcfi);
// We want the Have disk button, but if the call fails we can
// still continue
(VOID) HrSetupDiSetDeipFlags(hdi, NULL, DI_SHOWOEM, SDDFT_FLAGS, SDFBO_OR);
// Bring up the dialog
hr = HrSetupDiCallClassInstaller(DIF_SELECTDEVICE, hdi, NULL);
if (S_OK == hr) { SP_DRVINFO_DATA drid; PSP_DRVINFO_DETAIL_DATA pdridd;
// Now get the driver's detailed information
hr = HrCiGetDriverDetail (hdi, NULL, &drid, &pdridd);
if (S_OK == hr) { DWORD cbInfId = CbOfSzAndTerm(pdridd->HardwareID); DWORD cbInfFile = CbOfSzAndTerm(pdridd->InfFileName);
// Create a component install params structure so we
// can install the component.
hr = E_OUTOFMEMORY; *ppParams = new (extrabytes, cbInfId + cbInfFile) COMPONENT_INSTALL_PARAMS;
if (*ppParams) { ZeroMemory (*ppParams, sizeof (COMPONENT_INSTALL_PARAMS));
(*ppParams)->Class = Class; (*ppParams)->hwndParent = hwndParent; (*ppParams)->pszInfId = (PCWSTR)(*ppParams + 1); wcscpy ((PWSTR)(*ppParams)->pszInfId, pdridd->HardwareID);
(*ppParams)->pszInfFile = (PCWSTR)((BYTE*)(*ppParams)->pszInfId + cbInfId);
wcscpy ((PWSTR)(*ppParams)->pszInfFile, pdridd->InfFileName);
hr = S_OK; } MemFree (pdridd); } }
// Clear the field so we don't try to destroy it later
// via DIF_DESTROYPRIVATEDATA
CiClearReservedField(hdi, NULL); } SetupDiDestroyDeviceInfoList(hdi); }
TraceHr (ttidError, FAL, hr, HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr, "HrCiSelectComponent"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiHideIrrelevantRasProtocols
//
// Purpose: Hides protocols from the SelectDevice dialog that RAS does
// not interact with.
//
// Arguments:
// hdi [in] Contains a list of available drivers.
// See Device Installer Api documentation for
// more info
// eFilter [in] Either FC_RASSRV or FC_RASCLI.
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 18 May 1998
//
// Notes:
//
HRESULT HrCiHideIrrelevantRasProtocols ( IN HDEVINFO hdi, IN CI_FILTER_COMPONENT eFilter) { DWORD dwIndex = 0; SP_DRVINFO_DATA drid; SP_DRVINSTALL_PARAMS drip; PSP_DRVINFO_DETAIL_DATA pdridd; HRESULT hr;
extern const WCHAR c_szInfId_MS_AppleTalk[]; extern const WCHAR c_szInfId_MS_NetMon[]; extern const WCHAR c_szInfId_MS_NWIPX[]; extern const WCHAR c_szInfId_MS_TCPIP[];
static const WCHAR* const c_aszServerProtocols[] = { c_szInfId_MS_AppleTalk, c_szInfId_MS_NetMon, c_szInfId_MS_NWIPX, c_szInfId_MS_TCPIP };
static const WCHAR* const c_aszClientProtocols[] = { c_szInfId_MS_NetMon, c_szInfId_MS_NWIPX, c_szInfId_MS_TCPIP };
Assert ((FC_RASSRV == eFilter) || (FC_RASCLI == eFilter));
const WCHAR* const* aszProtocols; DWORD cProtocols;
// What we show as available protocols to install differs between
// ras server and ras client (aka Incoming connectoid and Dial-up).
//
if (FC_RASSRV == eFilter) { aszProtocols = c_aszServerProtocols; cProtocols = celems(c_aszServerProtocols);
} else { aszProtocols = c_aszClientProtocols; cProtocols = celems(c_aszClientProtocols); }
// Enumerate each driver in hdi
while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL, SPDIT_CLASSDRIVER, dwIndex++, &drid))) { (VOID) HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
// If the driver is already excluded for some other reason
// don't bother trying to determine if it should be excluded
// Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
// non-device drivers rather than using DNF_EXCLUDEFROMLIST.
if (drip.Flags & DNF_BAD_DRIVER) { continue; }
// Get driver detail info
hr = HrSetupDiGetDriverInfoDetail(hdi, NULL, &drid, &pdridd);
if (S_OK == hr) { // go through the list of relevant protocols to find which
// ones can be shown
//
// Assume we are going to hide this protocol
BOOL fHideProtocol = TRUE; for (DWORD i = 0; i < cProtocols; i++) { // If the protocol is on the guest list, we won't boot
// it out
//
if (0 == _wcsicmp(aszProtocols[i], pdridd->HardwareID)) { fHideProtocol = FALSE; } }
if (fHideProtocol) { // exclude from select
// Note that setupdi forces us to use DNF_BAD_DRIVER to
// exclude non-device drivers rather than using
// DNF_EXCLUDEFROMLIST.
drip.Flags |= DNF_BAD_DRIVER; (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL, &drid, &drip); } MemFree (pdridd); } }
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiHideIrrelevantRasProtocols"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiHideIrrelevantDrivers
//
// Purpose: Enumerates a driver list, opening each driver file and
// processing its registry entries into a temporary key.
// The lower range of each driver is then examined for
// a match with pszUpperRange. If no match is
// found, the driver's DNF_BAD_DRIVER flag is set
// which will prevent it from being shown in the
// Select Device Dialog
//
// Arguments:
// hdi [in] Contains a list of available drivers.
// See Device Installer Api documentation for
// more info
// pszUpperRange [in] The upper range will be used to hide irrelevant
// drivers.
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 7 May 1998
//
// Notes:
//
HRESULT HrCiHideIrrelevantDrivers( IN HDEVINFO hdi, IN PCWSTR pszUpperRange) { Assert(IsValidHandle(hdi)); Assert(pszUpperRange);
// Create a temporary key so we can process each protocol's
// registry entries in an effort to get its supported
// lower range of interfaces
HKEY hkeyTemp; HRESULT hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyTemp, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyTemp, NULL);
if (S_OK == hr) { DWORD dwIndex = 0; SP_DRVINFO_DATA drid; SP_DRVINSTALL_PARAMS drip; HKEY hkeyInterfaces;
// Enumerate each driver in hdi
while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL, SPDIT_CLASSDRIVER, dwIndex++, &drid))) { (VOID) HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
// If the driver is already excluded for some other reason
// don't bother trying to determine if it should be exluded.
// Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
// non-device drivers rather than using DNF_EXCLUDEFROMLIST.
if (drip.Flags & DNF_BAD_DRIVER) { continue; }
// Get driver detail info
PSP_DRVINFO_DETAIL_DATA pdridd = NULL; hr = HrSetupDiGetDriverInfoDetail(hdi, NULL, &drid, &pdridd);
if (S_OK == hr) { HINF hinf = NULL; // Open the driver inf
hr = HrSetupOpenInfFile(pdridd->InfFileName, NULL, INF_STYLE_WIN4, NULL, &hinf);
WCHAR szActual[_MAX_PATH]; if (S_OK == hr) { // Get the actual install section name (i.e. with
// os/platform extension if it exists)
hr = HrSetupDiGetActualSectionToInstallWithBuffer (hinf, pdridd->SectionName, szActual, _MAX_PATH, NULL, NULL);
if (S_OK == hr) { // Run the registry sections into the temporary key
hr = HrCiInstallFromInfSection(hinf, szActual, hkeyTemp, NULL, SPINST_REGISTRY); } }
if (S_OK == hr) { // Open the interfaces key of the driver
hr = HrRegOpenKeyEx(hkeyTemp, L"Ndi\\Interfaces", KEY_ALL_ACCESS, &hkeyInterfaces);
if (S_OK == hr) { PWSTR pszLowerRange = NULL;
// Read the lower interfaces value.
//
hr = HrRegQuerySzWithAlloc (hkeyInterfaces, L"LowerRange", &pszLowerRange);
// If we succeeded in reading the list and
// there is no match with one of the upper
// interfaces...
if ((S_OK == hr) && !FSubstringMatch (pszUpperRange, pszLowerRange, NULL, NULL)) { // exclude from select
drip.Flags |= DNF_BAD_DRIVER; (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL, &drid, &drip); }
// Clear lower interface list for next component
MemFree(pszLowerRange);
RegDeleteValue (hkeyInterfaces, L"LowerRange"); RegCloseKey(hkeyInterfaces); } } SetupCloseInfFileSafe(hinf); MemFree (pdridd); } }
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; }
RegCloseKey(hkeyTemp); HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyTemp); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiHideIrrelevantDrivers"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiHideIrrelevantFilterServices
//
// Purpose: Enumerates a driver list, opening each driver file and
// processing its registry entries into a temporary key.
// Only filter services are filtered here. If the component is
// a filter service (characteristics|NCF_FILTER)
// the FilterMediaTypes and the LowerExclude attributes are examined
// to see if the filter service can bind to the adapter. The filter
// services which cannot bind to the adapter are culled from
// the select dialog
//
// Arguments:
// hdi [in] Contains a list of available drivers.
// See Device Installer Api documentation for
// more info
// pAdapter [in] Pointer to a CComponent object representing the
// adapter for which filter services are to be hidden.
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: sumeetb October 17, 2001
//
// Notes:
//
HRESULT HrCiHideIrrelevantFilterServices( IN HDEVINFO hdi, IN const CComponent * const pAdapter) { Assert(IsValidHandle(hdi)); Assert(pAdapter);
// Create a temporary key so we can process each filter's
// registry entries in an effort to get its FilterMediaTypes and
// LowerExclude attributes
HKEY hkeyTemp; HRESULT hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyTemp, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyTemp, NULL);
if (S_OK == hr) { DWORD dwIndex = 0; SP_DRVINFO_DATA drid; SP_DRVINSTALL_PARAMS drip; HKEY hkeyInterfaces;
// Enumerate each driver in hdi
while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL, SPDIT_CLASSDRIVER, dwIndex++, &drid))) { BOOL fCanBind = TRUE;
(VOID) HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
// If the driver is already excluded for some other reason
// don't bother trying to determine if it should be excluded.
// Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
// non-device drivers rather than using DNF_EXCLUDEFROMLIST.
if (drip.Flags & DNF_BAD_DRIVER) { continue; }
// Get driver detail info
PSP_DRVINFO_DETAIL_DATA pdridd = NULL; hr = HrSetupDiGetDriverInfoDetail(hdi, NULL, &drid, &pdridd);
if (S_OK == hr) { HINF hinf = NULL; // Open the driver inf
hr = HrSetupOpenInfFile(pdridd->InfFileName, NULL, INF_STYLE_WIN4, NULL, &hinf);
if (S_OK == hr) { WCHAR szActual[_MAX_PATH]; // Get the actual install section name (i.e. with
// os/platform extension if it exists)
hr = HrSetupDiGetActualSectionToInstallWithBuffer (hinf, pdridd->SectionName, szActual, _MAX_PATH, NULL, NULL);
if (S_OK == hr) { DWORD dwCharacteristics = 0;
hr = HrSetupGetFirstDword (hinf, szActual, L"Characteristics", &dwCharacteristics); if (S_OK == hr ) { if (dwCharacteristics & NCF_FILTER) { // it is a filter.
// Run the registry sections into the temporary key
hr = HrCiInstallFromInfSection(hinf, szActual, hkeyTemp, NULL, SPINST_REGISTRY); if (S_OK == hr) { hr = HrRegOpenKeyEx(hkeyTemp, L"Ndi\\Interfaces", KEY_ALL_ACCESS, &hkeyInterfaces); if (S_OK == hr) { // check filter attributes - FilterMediaTypes and
// LowerExclude to see if the filter can bind to
// the adapter
PWSTR pszFilterMediaTypes = NULL; PWSTR pszLowerExclude = NULL;
(VOID) HrRegQuerySzWithAlloc (hkeyInterfaces, L"FilterMediaTypes", &pszFilterMediaTypes); (VOID) HrRegQuerySzWithAlloc (hkeyInterfaces, L"LowerExclude", &pszLowerExclude);
fCanBind = pAdapter->FCanDirectlyBindToFilter( pszFilterMediaTypes, pszLowerExclude);
MemFree(pszFilterMediaTypes); MemFree(pszLowerExclude);
// clean up the relevant keys from the
// registry for the filter
RegDeleteValue (hkeyInterfaces, L"FilterMediaTypes"); RegDeleteValue (hkeyInterfaces, L"LowerExclude"); RegCloseKey(hkeyInterfaces); } // end open Interface key
} // end install from inf section
} // end if filter
} // end get Characteristics
} // end get actual install section.
SetupCloseInfFileSafe(hinf); } // end open inf file
if (!fCanBind) { drip.Flags |= DNF_BAD_DRIVER; (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL, &drid, &drip); } MemFree (pdridd); } // end get driver detail
} // end while
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; } RegCloseKey(hkeyTemp); HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyTemp); } // end create temp key
TraceHr (ttidError, FAL, hr, FALSE, "HrCiHideIrrelevantFilterServices"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiSetSelectDeviceDialogStrings
//
// Purpose: This function sets the strings displayed in the Select Device
// dialog based on the class of devices being selected.
//
// Arguments:
// hdi [in] See Device Installer Api
// pdeid [in]
// guidClass [in] The class of device being selected
//
// Returns: HRESULT. S_OK if successful, an error code otherwise
//
// Author: billbe 11 Nov 1996
//
// Notes:
//
HRESULT HrCiSetSelectDeviceDialogStrings( IN HDEVINFO hdi, IN PSP_DEVINFO_DATA pdeid, IN const GUID& guidClass) { Assert(IsValidHandle(hdi));
SP_SELECTDEVICE_PARAMS sdep;
// The strings used in the dialog are specified through the
// SP_SELECTDEVICE_PARAMS structure
//
HRESULT hr = HrSetupDiGetFixedSizeClassInstallParams(hdi, pdeid, (PSP_CLASSINSTALL_HEADER)&sdep, sizeof(sdep));
if (FAILED(hr)) { // If the error is ERROR_NO_CLASSINSTALL_PARAMS then this function
// didn't really fail since it is possible
if (SPAPI_E_NO_CLASSINSTALL_PARAMS == hr) { hr = S_OK; } } else if (DIF_SELECTDEVICE != sdep.ClassInstallHeader.InstallFunction) { TraceTag(ttidClassInst, "Incorrect function in Class Install Header " "Expected DIF_SELECTDEVICE, got %lX", sdep.ClassInstallHeader.InstallFunction); }
BOOL fHaveDiskShown = FALSE; if (S_OK == hr) { // Get the install params and check if the DI_SHOWOEM flag is set
// if so, the Have Disk button will be shown
//
SP_DEVINSTALL_PARAMS deip; // If the call fails we can still go on unfazed.
(VOID) HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip); if (deip.Flags & DI_SHOWOEM) { fHaveDiskShown = TRUE; }
// Now we set the strings based on the type of component we are
// selecting
if (GUID_DEVCLASS_NETCLIENT == guidClass) { wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICECLIENTTITLE));
wcscpy (sdep.ListLabel, SzLoadIds (IDS_SELECTDEVICECLIENTLISTLABEL));
wcscpy (sdep.Instructions, SzLoadIds (IDS_SELECTDEVICECLIENTINSTRUCTIONS));
} else if (GUID_DEVCLASS_NETSERVICE == guidClass) { wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICESERVICETITLE));
wcscpy (sdep.ListLabel, SzLoadIds (IDS_SELECTDEVICESERVICELISTLABEL));
wcscpy (sdep.Instructions, SzLoadIds (IDS_SELECTDEVICESERVICEINSTRUCTIONS));
} else if (GUID_DEVCLASS_NETTRANS == guidClass) { wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEPROTOCOLTITLE));
wcscpy (sdep.ListLabel, SzLoadIds (IDS_SELECTDEVICEPROTOCOLLISTLABEL));
wcscpy (sdep.Instructions, SzLoadIds (IDS_SELECTDEVICEPROTOCOLINSTRUCTIONS)); } else if (GUID_DEVCLASS_NET == guidClass) { wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEADAPTERTITLE));
wcscpy (sdep.SubTitle, SzLoadIds (IDS_SELECTDEVICEADAPTERSUBTITLE));
wcscpy (sdep.ListLabel, SzLoadIds (IDS_SELECTDEVICEADAPTERLISTLABEL));
wcscpy (sdep.Instructions, SzLoadIds (IDS_SELECTDEVICEADAPTERINSTRUCTIONS)); } else if (GUID_DEVCLASS_INFRARED == guidClass) { wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEINFRAREDTITLE));
wcscpy (sdep.SubTitle, SzLoadIds (IDS_SELECTDEVICEINFRAREDSUBTITLE));
wcscpy (sdep.ListLabel, SzLoadIds (IDS_SELECTDEVICEINFRAREDLISTLABEL));
wcscpy (sdep.Instructions, SzLoadIds (IDS_SELECTDEVICEINFRAREDINSTRUCTIONS)); } else { // We should never get here
AssertSz(FALSE, "Invalid Class"); }
// If the Have Disk button is shown, we need to add instructions for
// it
if (fHaveDiskShown) { wcscat (sdep.Instructions, SzLoadIds (IDS_HAVEDISK_INSTRUCTIONS)); }
sdep.ClassInstallHeader.InstallFunction = DIF_SELECTDEVICE;
// Now we update the parameters.
hr = HrSetupDiSetClassInstallParams (hdi, pdeid, (PSP_CLASSINSTALL_HEADER)&sdep, sizeof(SP_SELECTDEVICE_PARAMS)); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiSetSelectDeviceDialogStrings"); return hr; }
//+--------------------------------------------------------------------------
//
// Function: HrCiPrepareSelectDeviceDialog
//
// Purpose: Sets the strings that will appear in the Select Device
// dialog based on class type. Also, filters out components
// based on filtering criteria (note: only for non-net
// class components
//
// Arguments:
// hdi [in] See Device Installer Api documentation for more info
// pdeid [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 Jun 1997
//
// Notes:
//
HRESULT HrCiPrepareSelectDeviceDialog( IN HDEVINFO hdi, IN PSP_DEVINFO_DATA pdeid) { Assert(IsValidHandle(hdi));
GUID guidClass; CI_FILTER_INFO* pcfi; HRESULT hr = S_OK; static const WCHAR c_szNetwareInfId[] = L"MS_NwClient"; static const WCHAR c_szQosInfId[] = L"MS_PSched";
if (pdeid) { // Get the class guid from the specified device element
guidClass = pdeid->ClassGuid; } else { // otherwise, get it from the hdi
hr = HrSetupDiGetDeviceInfoListClass (hdi, &guidClass); }
if ((S_OK == hr) && !FIsEnumerated (guidClass)) { // This might take some time. We are doing the same work as
// SetupDiSelectDevice would do. When we are done, we will
// hand the driver list to SetupDiSelectDevice so it won't
// need to rummage through the inf directory
//
CWaitCursor wc;
// For non-device classes, we need to allow excluded drivers
// in order to get a list returned.
hr = HrSetupDiSetDeipFlags(hdi, NULL, DI_FLAGSEX_ALLOWEXCLUDEDDRVS, SDDFT_FLAGSEX, SDFBO_OR);
if (S_OK == hr) { #ifdef ENABLETRACE
CBenchmark bmrk; bmrk.Start("SetupDiBuildDriverInfoList"); #endif //ENABLETRACE
// If we have already built a driver list, this will return
// immediately.
//
hr = HrSetupDiBuildDriverInfoList(hdi, NULL, SPDIT_CLASSDRIVER);
#ifdef ENABLETRACE
bmrk.Stop(); TraceTag(ttidBenchmark, "%s : %s seconds", bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2)); #endif //ENABLETRACE
}
if (S_OK == hr) { // Go through every driver node and set DNF_BAD_DRIVER
// if DNF_EXCLUDEFROMLIST is set. Note: SetupDi forces us
// to do this for non netclass driver lists.
SetBadDriverFlagIfNeededInList(hdi);
// Exclude components that are in lockdown.
//
EnumLockedDownComponents (ExcludeLockedDownComponents, hdi);
SP_DEVINSTALL_PARAMS deip; hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
if (S_OK == hr) { pcfi = (CI_FILTER_INFO*)deip.ClassInstallReserved;
// if filter info was present and we are selecting protocols...
if (pcfi) { if (GUID_DEVCLASS_NETTRANS == guidClass) { // If the filter is for lan or atm and pvReserved is
// not null...
if (((FC_LAN == pcfi->eFilter) || (FC_ATM == pcfi->eFilter)) && pcfi->pvReserved) { // Hide any drivers that can't bind to pvReserved
hr = HrCiHideIrrelevantDrivers(hdi, (PCWSTR)((CComponent *)pcfi->pvReserved)->Ext.PszUpperRange());
} else if ((FC_RASSRV == pcfi->eFilter) || (FC_RASCLI == pcfi->eFilter)) { // Hide from the select dialog any protocols RAS does
// not support
hr = HrCiHideIrrelevantRasProtocols (hdi, pcfi->eFilter); } } else if ((GUID_DEVCLASS_NETCLIENT == guidClass) && (FC_ATM == pcfi->eFilter)) { // ATM adapters don't bind to Netware Client so
// we need to try to hide it from the dialog
(VOID) HrCiExcludeNonNetClassDriverFromSelectUsingInfId( hdi, c_szNetwareInfId); } else if ((GUID_DEVCLASS_NETSERVICE == guidClass) && (pcfi->pvReserved)) { // Hide any filters that can't bind to this adapter
hr = HrCiHideIrrelevantFilterServices(hdi, (CComponent *)pcfi->pvReserved); } } } } }
if (S_OK == hr) {
// Set the strings for the Select Device dialog.
// This is done by changing the parameters in the DeviceInfoSet.
// The next call will create this InfoSet
// If the call fails, we can still go on, we'll just have
// slightly odd descriptions in the dialog. This is done after
// the section above because strings change based on the existence
// of the Have Disk button
(VOID) HrCiSetSelectDeviceDialogStrings(hdi, pdeid, guidClass);
// Now we need to indicate that we created a class install params
// header in the structures and set the select device dialog strings
// in it. If the call fails, we can still proceed though the
// dialog will appear a bit strange
(VOID) HrSetupDiSetDeipFlags(hdi, pdeid, DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS, SDDFT_FLAGS, SDFBO_OR); }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiPrepareSelectDeviceDialog"); return hr; }
HRESULT HrCiInstallFilterDevice ( IN HDEVINFO hdi, IN PCWSTR pszInfId, IN CComponent* pAdapter, IN CComponent* pFilter, IN CFilterDevice** ppFilterDevice) { HRESULT hr; SP_DEVINFO_DATA deid;
Assert (hdi); Assert (pszInfId && *pszInfId); Assert (pAdapter); Assert (FIsEnumerated(pAdapter->Class())); Assert (pFilter); Assert (pFilter->FIsFilter()); Assert (NC_NETSERVICE == pFilter->Class()); Assert (ppFilterDevice);
*ppFilterDevice = NULL;
// Initialize the devinfo data corresponding to the driver the
// caller wants us to install.
//
hr = HrCiGetDriverInfo (hdi, &deid, *MAP_NETCLASS_TO_GUID[NC_NET], pszInfId, NULL);
if (S_OK == hr) { ADAPTER_OUT_PARAMS AdapterOutParams;
ZeroMemory (&AdapterOutParams, sizeof(AdapterOutParams));
CiSetReservedField (hdi, &deid, &AdapterOutParams);
// Perform the installation.
//
hr = HrCiCallClassInstallerToInstallComponent (hdi, &deid);
CiClearReservedField (hdi, &deid);
if (S_OK == hr) { WCHAR szInstanceGuid[c_cchGuidWithTerm]; INT cch; HKEY hkeyInstance;
// Convert the instance guid to a string.
//
cch = StringFromGUID2 ( AdapterOutParams.InstanceGuid, szInstanceGuid, c_cchGuidWithTerm); Assert (c_cchGuidWithTerm == cch);
// Open the instance key of the newly installed device
// so we can write the instance guid and the back pointer
// to the filter.
//
hr = HrSetupDiOpenDevRegKey (hdi, &deid, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_WRITE, &hkeyInstance);
if (S_OK == hr) { // Write the instance guid.
//
hr = HrRegSetSz (hkeyInstance, L"NetCfgInstanceId", szInstanceGuid);
// Write the inf id of the parent filter.
//
hr = HrRegSetSz (hkeyInstance, L"FilterInfId", pFilter->m_pszInfId);
RegCloseKey (hkeyInstance); }
// Set the friendly name to include the adapter being
// filtered.
//
if (S_OK == hr) { PWSTR pszFilterDesc;
hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc ( hdi, &deid, SPDRP_DEVICEDESC, NULL, (BYTE**)&pszFilterDesc);
if (S_OK == hr) { #define SZ_NAME_SEP L" - "
PWSTR pszName; ULONG cb;
// sizeof(SZ_NAME_SEP) includes the NULL-terminator
// so that will automatically add room for the
// NULL-terminator we need to allocate for pszName.
//
cb = CbOfSzSafe (pAdapter->Ext.PszDescription()) + sizeof(SZ_NAME_SEP) + CbOfSzSafe (pszFilterDesc);
pszName = (PWSTR)MemAlloc (cb); if (pszName) { wcscpy (pszName, pAdapter->Ext.PszDescription()); wcscat (pszName, SZ_NAME_SEP); wcscat (pszName, pszFilterDesc);
Assert (cb == CbOfSzAndTerm(pszName));
hr = HrSetupDiSetDeviceRegistryProperty ( hdi, &deid, SPDRP_FRIENDLYNAME, (const BYTE*)pszName, cb);
MemFree (pszName); }
MemFree (pszFilterDesc); }
// If the above fails, its not a big deal.
//
hr = S_OK; }
if (S_OK == hr) { hr = CFilterDevice::HrCreateInstance ( pAdapter, pFilter, &deid, szInstanceGuid, ppFilterDevice); } } }
TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallFilterDevice"); return hr; }
HRESULT HrCiRemoveFilterDevice ( IN HDEVINFO hdi, IN SP_DEVINFO_DATA* pdeid) { HRESULT hr; ADAPTER_REMOVE_PARAMS arp = {0};
Assert (hdi); Assert (pdeid);
CiSetReservedField (hdi, pdeid, &arp);
hr = HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, pdeid);
CiClearReservedField (hdi, pdeid);
TraceHr (ttidError, FAL, hr, FALSE, "HrCiRemoveFilterDevice"); return hr; }
|