windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/dihook.cpp
2020-09-26 16:20:57 +08:00

1163 lines
36 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: D I H O O K. C P P
//
// Contents: Class installer functions called via the device installer.
//
// Notes:
//
// Author: billbe 25 Nov 1996
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "adapter.h"
#include "benchmrk.h"
#include "classinst.h"
#include "compdefs.h"
#include "iatl.h"
#include "isdnhook.h"
#include "ncatl.h"
#include "ncreg.h"
#include "nceh.h"
#include "netsetup.h"
#include "resource.h"
#include "util.h"
#include "netconp.h"
EXTERN_C const CLSID CLSID_InstallQueue;
const DWORD c_cmsWaitForINetCfgWrite = 2000;
inline
BOOL
FIsValidErrorFromINetCfgForDiHook (
IN HRESULT hr)
{
return (NETCFG_E_NO_WRITE_LOCK == hr) ||
(NETCFG_E_NEED_REBOOT == hr);
}
inline
BOOL
FIsHandledByClassInstaller(
IN const GUID& guidClass)
{
return FIsEnumerated(guidClass) ||
(GUID_DEVCLASS_NETTRANS == guidClass) ||
(GUID_DEVCLASS_NETCLIENT == guidClass) ||
(GUID_DEVCLASS_NETSERVICE == guidClass);
}
//+--------------------------------------------------------------------------
//
// Function: HrDiAddComponentToINetCfg
//
// Purpose: This function adds or updates a device In InetCfg.
//
// Arguments:
// pinc [in] INetCfg interface
// pinci [in] INetCfgInstaller interface
// guidClass [in] The class guid of the component
// pszwPnpid [in] The pnp instance id of the device
// eType [in] The install type (NCI_INSTALL or NCI_UPDATE)
// pszInstanceGuid [in] The netcfg instance guid of the component
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 29 Jul 1997
//
// Notes:
//
EXTERN_C
HRESULT
WINAPI
HrDiAddComponentToINetCfg(
IN INetCfg* pINetCfg,
IN INetCfgInternalSetup* pInternalSetup,
IN const NIQ_INFO* pInfo)
{
Assert (pINetCfg);
Assert (pInternalSetup);
Assert (pInfo);
Assert (pInfo->pszPnpId && *(pInfo->pszPnpId));
Assert (NCI_REMOVE != pInfo->eType);
HRESULT hr = S_OK;
NC_TRY
{
CComponent* pComponent;
BASIC_COMPONENT_DATA Data;
ZeroMemory (&Data, sizeof(Data));
Data.InstanceGuid = pInfo->InstanceGuid;
Data.Class = NetClassEnumFromGuid (pInfo->ClassGuid);
Data.pszPnpId = pInfo->pszPnpId;
Data.pszInfId = pInfo->pszInfId;
Data.dwCharacter = pInfo->dwCharacter;
Data.dwDeipFlags = pInfo->dwDeipFlags;
hr = CComponent::HrCreateInstance (
&Data,
CCI_ENSURE_EXTERNAL_DATA_LOADED,
NULL,
&pComponent);
if (S_OK == hr)
{
hr = pInternalSetup->EnumeratedComponentInstalled (pComponent);
}
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
TraceHr (ttidError, FAL, hr, NETCFG_S_REBOOT == hr,
"HrDiAddComponentToINetCfg");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrDiNotifyINetCfgOfInstallation
//
// Purpose: This function notifies INetCfg that a net class component
// has been installed or updated.
//
// Arguments:
// hdi [in] See Device Installer Api for more info
// pdeid [in] See Device Installer Api for more info
// pszwPnpid [in] The pnp instance id of the device
// pszInstanceGuid [in] The netcfg instance guid of the device
// eType [in] NCI_INSTALL if the component was installed
// NCI_UPDATE, if it was updated
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 29 Jul 1997
//
// Notes:
//
HRESULT
HrDiNotifyINetCfgOfInstallation (
IN const NIQ_INFO* pInfo)
{
Assert(pInfo);
Assert((NCI_INSTALL == pInfo->eType) || (NCI_UPDATE == pInfo->eType));
static const WCHAR c_szInstaller[] = L"INetCfg Installer Interface";
INetCfg* pinc;
BOOL fInitCom = TRUE;
BOOL fReboot = FALSE;
#ifdef ENABLETRACE
CBenchmark bmrk2;
bmrk2.Start ("Notifying INetCfg of installation");
#endif //ENABLETRACE
TraceTag(ttidClassInst, "Attempting to notify INetCfg.");
HRESULT hr = HrCreateAndInitializeINetCfg(&fInitCom, &pinc, TRUE,
c_cmsWaitForINetCfgWrite,
c_szInstaller, NULL);
if (S_OK == hr)
{
// Get the INetCfgInternalSetup interface.
INetCfgInternalSetup* pInternalSetup;
hr = pinc->QueryInterface (IID_INetCfgInternalSetup,
(VOID**)&pInternalSetup);
if (S_OK == hr)
{
if (NCI_INSTALL == pInfo->eType)
{
hr = HrDiAddComponentToINetCfg(pinc, pInternalSetup, pInfo);
}
else // NCI_UPDATE
{
hr = pInternalSetup->EnumeratedComponentUpdated (
pInfo->pszPnpId);
}
if (NETCFG_S_REBOOT == hr)
{
fReboot = TRUE;
hr = S_OK;
}
ReleaseObj(pInternalSetup);
}
// Whether we succeeded or not, we are done and it's
// time to clean up. If there was a previous error
// we want to preserve that error code so we assign
// Uninitialize's result to a temporary then assign
// it to hr if there was no previous error.
//
HRESULT hrT = HrUninitializeAndReleaseINetCfg (fInitCom, pinc, TRUE);
hr = (S_OK == hr) ? hrT : hr;
}
if ((S_OK == hr) && fReboot)
{
TraceTag(ttidClassInst, "INetCfg returned NETCFG_S_REBOOT");
hr = NETCFG_S_REBOOT;
}
#ifdef ENABLETRACE
bmrk2.Stop();
TraceTag(ttidBenchmark, "%s : %s seconds",
bmrk2.SznDescription(), bmrk2.SznBenchmarkSeconds(2));
#endif //ENABLETRACE
TraceHr (ttidError, FAL, hr,
NETCFG_S_REBOOT == hr || FIsValidErrorFromINetCfgForDiHook (hr),
"HrDiNotifyINetCfgOfInstallation");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: InsertItemIntoInstallQueue
//
// Purpose: This function uses the InstallQueue object to insert a
// workitem to be processed at a later time. The workitem:
// a device that was installed, removed, or updated and
// INetCfg needs to be notified.
//
// Arguments:
// pguid [in] The class guid of the device
// pszwDeviceId [in] The Id of the device (PnP instance Id if the device
// was added or updated, its netcfg instance guid if
// it was removed
//
// Returns: hresult. S_OK if successful, an error code otherwise.
//
// Author: billbe 8 Sep 1998
//
// Notes:
//
HRESULT
HrInsertItemIntoInstallQueue (
IN const NIQ_INFO* pInfo)
{
// Initialize COM
BOOL fInitCom = TRUE;
HRESULT hr = CoInitializeEx (NULL, COINIT_MULTITHREADED |
COINIT_DISABLE_OLE1DDE);
// We may have changed mode but that's okay
if (RPC_E_CHANGED_MODE == hr)
{
hr = S_OK;
fInitCom = FALSE;
}
if (SUCCEEDED(hr))
{
// Create the Install Queue object and get the
// INetInstallQueue interface
//
INetInstallQueue* pniq;
hr = HrCreateInstance(
CLSID_InstallQueue,
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
&pniq);
TraceHr (ttidError, FAL, hr, FALSE, "HrCreateInstance");
if (S_OK == hr)
{
TraceTag (ttidClassInst, "Adding item %S to queue.",
pInfo->pszPnpId);
// Add the device info and the install type to the queue
hr = pniq->AddItem (pInfo);
pniq->Release();
}
if (fInitCom)
{
CoUninitialize();
}
}
TraceHr (ttidError, FAL, hr, FALSE, "InsertItemIntoInstallQueue");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrDiInstallNetAdapter
//
// Purpose: This function preinstalls the NetAdapter, notifies the
// COM interfaces through CINetCfgClass that the
// component was added. Then it finalizes the install
// by applying all changes to INetCfg.
// Arguments:
// hdi [in] See Device Installer Api for more info
// pdeid [in] See Device Installer Api for more info
// hwndParent [in] The handle to the parent window, used for UI
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 24 Apr 1997
//
// Notes:
//
HRESULT
HrDiInstallNetAdapter(
IN COMPONENT_INSTALL_INFO* pcii)
{
HRESULT hr = S_OK;
ADAPTER_OUT_PARAMS* pAdapterOutParams = NULL;
SP_DEVINSTALL_PARAMS deip;
BOOL fNotifyINetCfg = TRUE;
// If we were called from INetCfg, we have to store the results of the
// install in the out params structure placed in the reserved field.
//
(VOID) HrSetupDiGetDeviceInstallParams (pcii->hdi, pcii->pdeid, &deip);
if (deip.ClassInstallReserved)
{
pAdapterOutParams = (ADAPTER_OUT_PARAMS*)deip.ClassInstallReserved;
fNotifyINetCfg = FALSE;
}
PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
SP_DRVINFO_DATA drid;
hr = HrCiGetDriverDetail (pcii->hdi, pcii->pdeid, &drid, &pdridd);
if (S_OK == hr)
{
pcii->pszInfFile = pdridd->InfFileName;
pcii->pszSectionName = pdridd->SectionName;
pcii->pszInfId = pdridd->HardwareID;
pcii->pszDescription = drid.Description;
}
else if (SPAPI_E_NO_DRIVER_SELECTED == hr)
{
// If we are in GUI mode and the device was previously installed,
// then this device should be removed since its inf file could not
// be found.
//
if (FInSystemSetup() &&
(S_OK == HrCiIsInstalledComponent (pcii, NULL)))
{
// This dev node was is being reinstalled but has no driver
// info. In this case, we are going to remove the devnode.
TraceTag (ttidClassInst, "We are in GUI mode and were told to "
"install a device that has no driver. We will remove "
"device instead.");
// We need to set the reserved field in the pdeid so that the
// remove code will know that this is a bad instance that
// should be removed regardless of the NCF_NOT_USER_REMOVABLE
// characteristic.
//
ADAPTER_REMOVE_PARAMS arp;
arp.fBadDevInst = TRUE;
arp.fNotifyINetCfg = fNotifyINetCfg;
CiSetReservedField (pcii->hdi, pcii->pdeid, &arp);
(VOID) HrSetupDiCallClassInstaller (DIF_REMOVE,
pcii->hdi, pcii->pdeid);
CiClearReservedField (pcii->hdi, pcii->pdeid);
}
}
if (S_OK == hr)
{
TraceTag (ttidClassInst, "Calling HrCiInstallComponentInternal");
#ifdef ENABLETRACE
CBenchmark bmrk1;
bmrk1.Start ("HrCiInstallComponentInternal");
#endif //ENABLETRACE
// Install (or reinstall) the component
hr = HrCiInstallComponentInternal (pcii);
#ifdef ENABLETRACE
bmrk1.Stop();
TraceTag (ttidBenchmark, "%s : %s seconds",
bmrk1.SznDescription(), bmrk1.SznBenchmarkSeconds (2));
#endif //ENABLETRACE
// if we have succeeded so far and we have to notify INetcfg.
// We also have to update the NT4 legacy registry for adapters.
// Note that this is not done for filter devices.
if (S_OK == hr)
{
if (fNotifyINetCfg && !FIsFilterDevice (pcii->hdi, pcii->pdeid))
{
NIQ_INFO Info;
ZeroMemory(&Info, sizeof (Info));
Info.eType = pcii->fPreviouslyInstalled ?
NCI_UPDATE : NCI_INSTALL;
Info.ClassGuid = pcii->pdeid->ClassGuid;
Info.InstanceGuid = pcii->InstanceGuid;
Info.dwCharacter = pcii->dwCharacter;
Info.dwDeipFlags = deip.Flags;
Info.pszInfId = pcii->pszInfId;
Info.pszPnpId = pcii->pszPnpId;
hr = HrDiNotifyINetCfgOfInstallation (&Info);
if (FIsValidErrorFromINetCfgForDiHook (hr))
{
WCHAR szGuid[c_cchGuidWithTerm];
INT cch = StringFromGUID2 (pcii->InstanceGuid, szGuid,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
// use queue
hr = HrInsertItemIntoInstallQueue (&Info);
}
else if (NETCFG_S_REBOOT == hr)
{
(VOID) HrSetupDiSetDeipFlags (pcii->hdi, pcii->pdeid,
DI_NEEDREBOOT, SDDFT_FLAGS, SDFBO_OR);
hr = S_OK;
}
}
else // !fNotifyINetCfg or is a filter device.
{
// Since we installed this enumerated device from INetCfg
// we need to set the out params so they can be retrieved
// when DIF_INSTALLDEVICE has finished.
//
if (pAdapterOutParams)
{
Assert (!pcii->fPreviouslyInstalled);
pAdapterOutParams->dwCharacter = pcii->dwCharacter;
pAdapterOutParams->InstanceGuid = pcii->InstanceGuid;
}
}
// Write out the NT4 legacy registry info for app. compatibility.
// Note, we only do this for physical net devices.
if ((NCF_PHYSICAL & pcii->dwCharacter) &&
(GUID_DEVCLASS_NET == pcii->pdeid->ClassGuid))
{
AddOrRemoveLegacyNt4AdapterKey (pcii->hdi, pcii->pdeid,
&pcii->InstanceGuid, pcii->pszDescription,
LEGACY_NT4_KEY_ADD);
}
}
MemFree (pdridd);
}
// All success codes should be mapped to S_OK since they have no meaning
// along this code path.
if (SUCCEEDED(hr))
{
hr = S_OK;
}
TraceHr (ttidError, FAL, hr, FALSE, "HrDiInstallNetAdapter");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrDiNotifyINetCfgOfRemoval
//
// Purpose: This function notifies INetCfg that a net class component has
// been removed
//
// Arguments:
// hdi [in] See Device Installer api for more info
// pdeid [in]
// szInstanceGuid [in] The instance guid of the component
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 29 Jul 1997
//
// Notes:
//
HRESULT
HrDiNotifyINetCfgOfRemoval (
IN PCWSTR pszPnpId)
{
static const WCHAR c_szUninstaller[] = L"INetCfg UnInstaller Interface";
INetCfg* pINetCfg;
BOOL fInitCom = TRUE;
HRESULT hr = HrCreateAndInitializeINetCfg(&fInitCom, &pINetCfg, TRUE,
c_cmsWaitForINetCfgWrite, c_szUninstaller, NULL);
if (SUCCEEDED(hr))
{
BOOL fNeedReboot = FALSE;
// Get the INetCfgInternalSetup interface.
INetCfgInternalSetup* pInternalSetup;
hr = pINetCfg->QueryInterface (IID_INetCfgInternalSetup,
(VOID**)&pInternalSetup);
if (SUCCEEDED(hr))
{
hr = pInternalSetup->EnumeratedComponentRemoved (pszPnpId);
if (NETCFG_S_REBOOT == hr)
{
fNeedReboot = TRUE;
}
}
// Whether we succeeded or not, we are done and it's
// time to clean up. If there was a previous error
// we want to preserve that error code so we assign
// Uninitialize's result to a temporary then assign
// it to hr if there was no previous error.
//
HRESULT hrT = HrUninitializeAndReleaseINetCfg (TRUE, pINetCfg, TRUE);
// If everything was successful then set the return value to be
// the return of HrUninitializeAndReleaseINetCfg
hr = SUCCEEDED(hr) ? hrT : hr;
if (SUCCEEDED(hr) && fNeedReboot)
{
hr = NETCFG_S_REBOOT;
}
}
TraceHr (ttidError, FAL, hr,
NETCFG_S_REBOOT == hr || FIsValidErrorFromINetCfgForDiHook (hr),
"HrNcNotifyINetCfgOfRemoval");
return hr;
}
VOID
StoreInfoForINetCfg (
IN HKEY hkeyInstance)
{
HKEY hkeyInterfaceStore = NULL;
HKEY hkeyNdiStore = NULL;
WCHAR szGuid[c_cchGuidWithTerm];
DWORD cbGuid = sizeof (szGuid);
WCHAR szNdiPath[_MAX_PATH];
HRESULT hr = HrRegQuerySzBuffer (hkeyInstance, L"NetCfgInstanceId", szGuid,
&cbGuid);
if (S_OK == hr)
{
wcscpy (szNdiPath,
c_szTempNetcfgStorageForUninstalledEnumeratedComponent);
wcscat (szNdiPath, szGuid);
wcscat (szNdiPath, L"\\Ndi");
hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE, szNdiPath,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hkeyNdiStore, NULL);
if (S_OK == hr)
{
hr = HrRegCreateKeyEx (hkeyNdiStore, L"Interfaces",
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hkeyInterfaceStore, NULL);
}
}
if (S_OK == hr)
{
HKEY hkeyNdi;
hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
if (S_OK == hr)
{
PWSTR pszRequiredList;
hr = HrRegQuerySzWithAlloc (hkeyNdi, L"RequiredAll",
&pszRequiredList);
if (S_OK == hr)
{
hr = HrRegSetSz (hkeyNdiStore, L"RequiredAll",
pszRequiredList);
MemFree (pszRequiredList);
}
if (HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_OK;
}
TraceHr (ttidError, FAL, hr, FALSE, "Writing RequiredAll key "
"for INetCfg removal notify");
RegCloseKey (hkeyNdi);
}
HKEY hkeyInterfaces;
hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi\\Interfaces", KEY_READ,
&hkeyInterfaces);
if (S_OK == hr)
{
PWSTR pszUpper;
PWSTR pszLower;
hr = HrRegQuerySzWithAlloc (hkeyInterfaces, L"UpperRange",
&pszUpper);
if (S_OK == hr)
{
(VOID) HrRegSetSz (hkeyInterfaceStore, L"UpperRange",
pszUpper);
MemFree ((VOID*) pszUpper);
}
hr = HrRegQuerySzWithAlloc (hkeyInterfaces, L"LowerRange",
&pszLower);
if (S_OK == hr)
{
(VOID) HrRegSetSz (hkeyInterfaceStore, L"LowerRange",
pszLower);
MemFree ((VOID*) pszLower);
}
RegCloseKey (hkeyInterfaces);
}
}
RegSafeCloseKey (hkeyInterfaceStore);
RegSafeCloseKey (hkeyNdiStore);
}
//+--------------------------------------------------------------------------
//
// Function: HrDiRemoveNetAdapter
//
// Purpose: This function removes a net adapter, notifies the
// COM interfaces through CINetCfgClass that the
// component was removed. Then it finalizes the remove
// by applying all changes to INetCfg.
// Arguments:
// hdi [in] See Device Installer Api for more info
// pdeid [in] See Device Installer Api for more info
// pszPnPId [in] The pnp instance id of the adapter
// hwndParent [in] The handle to the parent window, used for UI
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 24 Apr 1997
//
// Notes:
//
HRESULT
HrDiRemoveNetAdapter (HDEVINFO hdi, PSP_DEVINFO_DATA pdeid,
PWSTR pszPnpId, HWND hwndParent)
{
BOOL fAllowRemove = TRUE;
SP_DEVINSTALL_PARAMS deip;
BOOL fNotifyINetCfg = TRUE;
BOOL fBadDevInst = FALSE;
HRESULT hr = S_OK;
// Check for the existence of a CComponentInfo and retrieve the
// value of the write lock flag
//
(VOID) HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
if (deip.ClassInstallReserved)
{
ADAPTER_REMOVE_PARAMS* parp = reinterpret_cast<ADAPTER_REMOVE_PARAMS*>
(deip.ClassInstallReserved);
fNotifyINetCfg = parp->fNotifyINetCfg;
fBadDevInst = parp->fBadDevInst;
}
if (fNotifyINetCfg)
{
// The component is not being removed programmatically (we can tell
// this because we wouldn't have to notify INetCfg if it was
// being removed through INetCfg). Because of this. we have to
// make sure the user is allowed to do this by checking the
// component's characteristics
//
HKEY hkey;
hr = HrSetupDiOpenDevRegKey (hdi, pdeid, DICS_FLAG_GLOBAL, 0,
DIREG_DRV, KEY_READ, &hkey);
if (S_OK == hr)
{
// If we are removing a bad device instance, don't bother
// checking if we are allowed to. We need to get rid of it.
//
if (!fBadDevInst)
{
DWORD dwCharacter;
hr = HrRegQueryDword (hkey, L"Characteristics", &dwCharacter);
if (S_OK == hr)
{
// Is the not removable characteristic present?
fAllowRemove = !(dwCharacter & NCF_NOT_USER_REMOVABLE);
}
}
if (fAllowRemove)
{
StoreInfoForINetCfg (hkey);
// We need to remove this adapter from the old NT4 registry
// location.
//
if (GUID_DEVCLASS_NET == pdeid->ClassGuid)
{
AddOrRemoveLegacyNt4AdapterKey (hdi, pdeid, NULL, NULL,
LEGACY_NT4_KEY_REMOVE);
}
}
else
{
hr = HRESULT_FROM_WIN32 (ERROR_ACCESS_DENIED);
TraceTag (ttidClassInst, "User is trying to remove a "
"non user-removable device.");
}
RegCloseKey (hkey);
}
else if (SPAPI_E_KEY_DOES_NOT_EXIST == hr)
{
hr = S_OK;
}
}
if ((S_OK == hr) && fAllowRemove)
{
// Remove the device
//
// Open the device's device parameters key
//
HKEY hkeyDevice;
hr = HrSetupDiOpenDevRegKey (hdi, pdeid, DICS_FLAG_GLOBAL,
0, DIREG_DEV, KEY_READ, &hkeyDevice);
if (S_OK == hr)
{
// Delete this adapter's index number from the in-use list
// so it can be reused.
//
// First retrieve the index
//
DWORD dwInstanceIndex;
hr = HrRegQueryDword (hkeyDevice, L"InstanceIndex",
&dwInstanceIndex);
if (S_OK == hr)
{
// Get the description for the adapter so we can
// access the index list of that description
//
PWSTR pszDescription;
hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc (hdi, pdeid,
SPDRP_DEVICEDESC, NULL,
(BYTE**)&pszDescription);
if (S_OK == hr)
{
// Delete the index
(VOID) HrCiUpdateDescriptionIndexList (
NetClassEnumFromGuid(pdeid->ClassGuid),
pszDescription, DM_DELETE,
&dwInstanceIndex);
MemFree (pszDescription);
}
}
RegCloseKey (hkeyDevice);
}
// Note: Yes we can walk over the last hr result.
// We can still go on even if we failed to remove the index
// from the in-use list.
// remove the adapter
#ifdef ENABLETRACE
CBenchmark bmrk;
bmrk.Start ("SetupDiRemoveDevice");
#endif //ENABLETRACE
hr = HrSetupDiRemoveDevice (hdi, pdeid);
#ifdef ENABLETRACE
bmrk.Stop();
TraceTag(ttidBenchmark, "%s : %s seconds",
bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2));
#endif //ENABLETRACE
TraceHr (ttidError, FAL, hr, FALSE,
"HrRemoveNetAdapter::HrSetupDiRemoveDevice");
// Notify INetCfg if needed.
if ((S_OK == hr) && fNotifyINetCfg)
{
hr = HrDiNotifyINetCfgOfRemoval (pszPnpId);
if (FIsValidErrorFromINetCfgForDiHook (hr))
{
NIQ_INFO Info;
ZeroMemory(&Info, sizeof(Info));
Info.ClassGuid = pdeid->ClassGuid;
Info.eType = NCI_REMOVE;
Info.pszInfId = L"";
Info.pszPnpId = pszPnpId;
// Use Queue
hr = HrInsertItemIntoInstallQueue (&Info);
}
if (NETCFG_S_REBOOT == hr)
{
(VOID) HrSetupDiSetDeipFlags (hdi, pdeid, DI_NEEDREBOOT,
SDDFT_FLAGS, SDFBO_OR);
hr = S_OK;
}
}
}
if(SUCCEEDED(hr) && GUID_DEVCLASS_NET == pdeid->ClassGuid)
{
INetConnectionRefresh * pRefresh = NULL;
HRESULT hrTemp = HrCreateInstance(
CLSID_ConnectionManager,
CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
&pRefresh);
if(SUCCEEDED(hrTemp))
{
hrTemp = pRefresh->RefreshAll();
ReleaseObj(pRefresh);
}
}
TraceHr (ttidError, FAL, hr, FALSE, "HrDiRemoveNetAdapter");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrNetClassInstaller
//
// Purpose: This function is called by the Device Installer for a
// variety of functions defined by dif.
// See SetupDiCallClassInstaller in the Device Installer
// documentation for more information.
// Arguments:
// dif [in] See Device Installer Api
// hdi [in]
// pdeid [in]
//
// Returns: DWORD. Win32/Device Installer error code
//
// Author: billbe 8 May 1997
//
// Notes:
//
HRESULT _HrNetClassInstaller(DI_FUNCTION dif,
HDEVINFO hdi,
PSP_DEVINFO_DATA pdeid)
{
HRESULT hr = SPAPI_E_DI_DO_DEFAULT;
// The time it takes to remove a device.
static const DWORD c_cmsNetComponentRemove = 30000;
if ((DIF_INSTALLDEVICE == dif) || (DIF_REMOVE == dif))
{
WCHAR szPnpId[MAX_DEVICE_ID_LEN] = {0};
hr = HrSetupDiGetDeviceInstanceId(hdi, pdeid, szPnpId,
MAX_DEVICE_ID_LEN, NULL);
if (S_OK == hr)
{
#ifdef DBG
if (FIsDebugFlagSet (dfidBreakOnNetInstall))
{
AssertSz(FALSE, "THIS IS NOT A BUG! The debug flag "
"\"BreakOnNetInstall\" has been set. Set your breakpoints now.");
}
#endif // DBG
HWND hwndParent = NULL;
// If this call fails we don't really care since it is a convenience.
(VOID) HrSetupDiGetParentWindow (hdi, pdeid, &hwndParent);
#ifdef ENABLETRACE
CBenchmark bmrk;
const int c_cchBenchmarkDesc = 156;
CHAR szBenchmarkDesc[c_cchBenchmarkDesc];
#endif // ENABLETRACE
if (DIF_INSTALLDEVICE == dif)
{
COMPONENT_INSTALL_INFO cii;
ZeroMemory(&cii, sizeof(cii));
cii.hwndParent = hwndParent;
cii.hdi = hdi;
cii.pdeid = pdeid;
cii.Class = NetClassEnumFromGuid (pdeid->ClassGuid);
cii.BusType = InterfaceTypeUndefined;
cii.InstanceGuid = GUID_NULL;
cii.pszPnpId = szPnpId;
#ifdef ENABLETRACE
TraceTag (ttidClassInst, "Installing %S", szPnpId);
_snprintf (szBenchmarkDesc, c_cchBenchmarkDesc,
"Installing %S", szPnpId);
bmrk.Start (szBenchmarkDesc);
#endif // ENABLETRACE
// Add the adapter to the network configuration.
hr = HrDiInstallNetAdapter (&cii);
}
else // DIF_REMOVEDEVICE
{
#ifdef ENABLETRACE
TraceTag (ttidClassInst, "Removing %S", szPnpId);
_snprintf (szBenchmarkDesc, c_cchBenchmarkDesc,
"Total Time Removing %S", szPnpId);
#endif //ENABLETRACE
// We need to reset the hresult from SPAPI_E_DO_DEFAULT to S_OK
// since we check for success a bit later.
hr = S_OK;
// Check to see it another net class installer thread is
// currently deleting this component.
//
// The event name will be the adapter instance Id with slashes
// converted to ampersands. If we can't get the instance
// id, we will attempt to remove the adapter without it
//
// convert the slashes in the instance id to ampersands
//
WCHAR szEventName[MAX_DEVICE_ID_LEN];
wcscpy (szEventName, szPnpId);
for (UINT i = 0; i < wcslen (szEventName); ++i)
{
if ('\\' == szEventName[i])
{
szEventName[i] = L'&';
}
}
// create the event in the non-signaled state
BOOL fAlreadyExists;
HANDLE hRemoveEvent = NULL;
hr = HrCreateEventWithWorldAccess (szEventName, FALSE, FALSE,
&fAlreadyExists, &hRemoveEvent);
if ((S_OK == hr) && fAlreadyExists)
{
// another instance of netclassinstaller is deleting this
// component, so wait till it is finished. If the following
// times out, we still return success. We are only waiting to
// give the other NetClassInstaller time to finish the state
// of this component
DWORD dwRet = WaitForSingleObject (hRemoveEvent,
c_cmsNetComponentRemove);
// if the other installer finished okay, we have the event
// so we signal (in case yet another process is waiting
// for the remove to finish) and close the handle.
// If we timeout, we just close the handle
if (WAIT_ABANDONED != dwRet)
{
if (WAIT_OBJECT_0 == dwRet)
{
SetEvent (hRemoveEvent);
}
CloseHandle (hRemoveEvent);
return S_OK;
}
// The event was abandoned so let's try to finish the job
//
}
else if (!hRemoveEvent)
{
hr = HrFromLastWin32Error ();
}
if (S_OK == hr)
{
// We created an event so we must make sure to remove it
// even if there is an exception.
//
NC_TRY
{
#ifdef ENABLETRACE
bmrk.Start (szBenchmarkDesc);
#endif // ENABLETRACE
hr = HrDiRemoveNetAdapter (hdi, pdeid, szPnpId,
hwndParent);
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
// We are done. If we created an event, we need to
// signal it and close our handle.
if (hRemoveEvent)
{
SetEvent (hRemoveEvent);
CloseHandle (hRemoveEvent);
}
}
}
#ifdef ENABLETRACE
if (S_OK == hr)
{
bmrk.Stop ();
TraceTag (ttidBenchmark, "%s : %s seconds",
bmrk.SznDescription (), bmrk.SznBenchmarkSeconds (2));
}
#endif // ENABLETRACE
}
}
else if (DIF_DESTROYPRIVATEDATA == dif)
{
SP_DEVINSTALL_PARAMS deip;
hr = HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
MemFree ((VOID*)deip.ClassInstallReserved);
}
else if (DIF_REGISTERDEVICE == dif)
{
// We handle 5 classes of components but we only
// want to allow registration for two of them
// (The ones considered NetClassComponents)
Assert(pdeid);
if (pdeid)
{
if (FIsHandledByClassInstaller(pdeid->ClassGuid))
{
if (!FIsEnumerated(pdeid->ClassGuid))
{
// Don't let the device installer register
// devices that are not considered net class
hr = S_OK;
}
}
}
}
else if (DIF_SELECTDEVICE == dif)
{
// This will set the proper description strings in the select device
// dialog. If it fails, we can still show the dialog
(VOID) HrCiPrepareSelectDeviceDialog(hdi, pdeid);
}
else if (DIF_NEWDEVICEWIZARD_FINISHINSTALL == dif)
{
hr = HrAddIsdnWizardPagesIfAppropriate(hdi, pdeid);
}
else if (DIF_ALLOW_INSTALL == dif)
{
// Get the selected driver for this device
//
SP_DRVINFO_DATA drid;
hr = HrSetupDiGetSelectedDriver(hdi, pdeid, &drid);
if (S_OK == hr)
{
// Now get the driver's detailed information
//
PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
hr = HrSetupDiGetDriverInfoDetail(hdi, pdeid,
&drid, &pdridd);
if (S_OK == hr)
{
// Open the component's inf file
//
HINF hinf = NULL;
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 = SPAPI_E_DI_DO_DEFAULT;
}
}
MemFree (pdridd);
}
}
}
else if (DIF_POWERMESSAGEWAKE == dif)
{
SP_POWERMESSAGEWAKE_PARAMS_W wakeParams;
// Get the power message wake params.
//
hr = HrSetupDiGetFixedSizeClassInstallParams(hdi, pdeid,
(PSP_CLASSINSTALL_HEADER)&wakeParams, sizeof(wakeParams));
if (S_OK == hr)
{
Assert (DIF_POWERMESSAGEWAKE ==
wakeParams.ClassInstallHeader.InstallFunction);
// Copy in our string for the power tab.
wcscpy (wakeParams.PowerMessageWake, SzLoadIds(IDS_POWER_MESSAGE_WAKE));
// Now we update the parameters.
hr = HrSetupDiSetClassInstallParams (hdi, pdeid,
(PSP_CLASSINSTALL_HEADER)&wakeParams,
sizeof(SP_POWERMESSAGEWAKE_PARAMS_W));
// If we failed to set the text just allow the device installer
// to do the default.
if (FAILED(hr))
{
hr = SPAPI_E_DI_DO_DEFAULT;
}
}
}
TraceHr (ttidClassInst, FAL, hr, (SPAPI_E_DI_DO_DEFAULT == hr) ||
(HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr),
"HrNetClassInstaller");
return hr;
}