401 lines
12 KiB
C++
401 lines
12 KiB
C++
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1999.
|
||
|
//
|
||
|
// File: A D A P T E R. C P P
|
||
|
//
|
||
|
// Contents: Class installer functions for eumerated devices.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: billbe 11 Nov 1996
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "adapter.h"
|
||
|
#include "benchmrk.h"
|
||
|
#include "classinst.h"
|
||
|
#include "ncreg.h"
|
||
|
#include "ncsvc.h"
|
||
|
#include "netcomm.h"
|
||
|
|
||
|
|
||
|
VOID
|
||
|
CiSetFriendlyNameIfNeeded(IN const COMPONENT_INSTALL_INFO &cii);
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCiGetBusInfoFromInf
|
||
|
//
|
||
|
// Purpose: Finds an adapter's bus information as listed in its inf
|
||
|
// file.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hinfFile [in] A handle to the component's inf file
|
||
|
// szSectionName [in] The inf section to search in
|
||
|
// peBusType [out] The bus type of the adapter
|
||
|
// pulAdapterId [out] The AdapterId of the adapter (Eisa and Mca)
|
||
|
// pulAdapterMask [out] The AdapterMask of the adapter (Eisa)
|
||
|
//
|
||
|
// Returns: HRESULT. S_OK if successful, error code otherwise
|
||
|
//
|
||
|
// Author: billbe 14 Jun 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
HrCiGetBusInfoFromInf (HINF hinfFile, COMPONENT_INSTALL_INFO* pcii)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
if (InterfaceTypeUndefined == pcii->BusType)
|
||
|
{
|
||
|
// Find the inf line that contains BusType and retrieve it
|
||
|
DWORD dwBusType;
|
||
|
hr = HrSetupGetFirstDword(hinfFile, pcii->pszSectionName,
|
||
|
L"BusType", &dwBusType);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
pcii->BusType = EInterfaceTypeFromDword(dwBusType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceTag (ttidError, "Inf missing BusType field.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetBusInfoFromInf");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCiInstallEnumeratedComponent
|
||
|
//
|
||
|
// Purpose: This function completes the install of an enumerated
|
||
|
// device.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hinf [in] SetupApi handle to an inf file
|
||
|
// hkeyInstance [in] The registry instance key of the adapter
|
||
|
// during inf processing.
|
||
|
// pcai [in] A structure containing the component information
|
||
|
// See compinst.h for definition
|
||
|
// hwndParent [in] The handle to the parent, for displaying UI
|
||
|
// hdi [in] See Device Installer Api for more info
|
||
|
// pdeid [in] See Device Installer Api for more info
|
||
|
//
|
||
|
// Returns: HRESULT. S_OK if successful and no restart required,
|
||
|
// NETCFG_S_REBOOT if a reboot is required,
|
||
|
// or error code otherwise
|
||
|
//
|
||
|
// Author: billbe 28 Apr 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
HrCiInstallEnumeratedComponent (
|
||
|
IN HINF hinf,
|
||
|
IN HKEY hkeyInstance,
|
||
|
IN const COMPONENT_INSTALL_INFO& cii)
|
||
|
{
|
||
|
Assert (IsValidHandle (hinf));
|
||
|
Assert (hkeyInstance);
|
||
|
Assert (IsValidHandle (cii.hdi));
|
||
|
Assert (cii.pdeid);
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Because adapters can share descriptions, we may need to append
|
||
|
// instance info so the user and other apps can differentiate.
|
||
|
//
|
||
|
// If the following fcn fails, we can still go on and
|
||
|
// install the adapter.
|
||
|
CiSetFriendlyNameIfNeeded (cii);
|
||
|
|
||
|
// Is this a PCI multiport adapter where each port has the same
|
||
|
// PnP Id? This is indicated by the inf value Port1DeviceNumber or
|
||
|
// Port1FunctionNumber in the main section.
|
||
|
//
|
||
|
if (PCIBus == cii.BusType)
|
||
|
{
|
||
|
INFCONTEXT ctx;
|
||
|
DWORD dwPortNumber;
|
||
|
BOOL fUseDeviceNumber;
|
||
|
DWORD dwFirstPort;
|
||
|
|
||
|
hr = HrSetupGetFirstDword (hinf, cii.pszSectionName,
|
||
|
L"Port1DeviceNumber", &dwFirstPort);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// The port number is based on the device number.
|
||
|
fUseDeviceNumber = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrSetupGetFirstDword (hinf, cii.pszSectionName,
|
||
|
L"Port1FunctionNumber", &dwFirstPort);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// The port number is based on the function number.
|
||
|
fUseDeviceNumber = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// We have a mapping so now we need to get the address of the
|
||
|
// device (device and function number).
|
||
|
//
|
||
|
|
||
|
DWORD dwAddress;
|
||
|
hr = HrSetupDiGetDeviceRegistryProperty(cii.hdi, cii.pdeid,
|
||
|
SPDRP_ADDRESS, NULL, (BYTE*)&dwAddress, sizeof(dwAddress),
|
||
|
NULL);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Use our mapping to get the correct port number.
|
||
|
//
|
||
|
DWORD dwPortLocation;
|
||
|
|
||
|
dwPortLocation = fUseDeviceNumber ?
|
||
|
HIWORD(dwAddress) : LOWORD(dwAddress);
|
||
|
|
||
|
// Make sure the port location (either device or
|
||
|
// function number) is greater than or equal to the first
|
||
|
// port number, otherwise we will get a bogus port number.
|
||
|
//
|
||
|
if (dwPortLocation >= dwFirstPort)
|
||
|
{
|
||
|
dwPortNumber = dwPortLocation - dwFirstPort + 1;
|
||
|
|
||
|
// Now store the port number in the device key for internal
|
||
|
// consumption.
|
||
|
HKEY hkeyDev;
|
||
|
hr = HrSetupDiCreateDevRegKey (cii.hdi, cii.pdeid,
|
||
|
DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL, &hkeyDev);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
(VOID) HrRegSetDword (hkeyDev, L"Port", dwPortNumber);
|
||
|
|
||
|
RegCloseKey (hkeyDev);
|
||
|
}
|
||
|
|
||
|
// Store the port in the driver key for public
|
||
|
// consumption.
|
||
|
//
|
||
|
(VOID) HrRegSetDword (hkeyInstance, L"Port",
|
||
|
dwPortNumber);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No mapping available, so we won't display port number.
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update any advanced parameters that do not have a current value
|
||
|
// with a default.
|
||
|
UpdateAdvancedParametersIfNeeded (cii.hdi, cii.pdeid);
|
||
|
|
||
|
// On fresh installs, INetCfg will be starting this adapter,
|
||
|
// so we have to make sure we don't.
|
||
|
//
|
||
|
if (!cii.fPreviouslyInstalled)
|
||
|
{
|
||
|
(VOID) HrSetupDiSetDeipFlags (cii.hdi, cii.pdeid, DI_DONOTCALLCONFIGMG,
|
||
|
SDDFT_FLAGS, SDFBO_OR);
|
||
|
}
|
||
|
|
||
|
// Now finish the install of the adapter.
|
||
|
//
|
||
|
|
||
|
TraceTag(ttidClassInst, "Calling SetupDiInstallDevice");
|
||
|
#ifdef ENABLETRACE
|
||
|
CBenchmark bmrk;
|
||
|
bmrk.Start("SetupDiInstallDevice");
|
||
|
#endif //ENABLETRACE
|
||
|
|
||
|
hr = HrSetupDiInstallDevice (cii.hdi, cii.pdeid);
|
||
|
|
||
|
#ifdef ENABLETRACE
|
||
|
bmrk.Stop();
|
||
|
TraceTag(ttidBenchmark, "%s : %s seconds",
|
||
|
bmrk.SznDescription(), bmrk.SznBenchmarkSeconds (2));
|
||
|
#endif //ENABLETRACE
|
||
|
|
||
|
if (!cii.fPreviouslyInstalled)
|
||
|
{
|
||
|
(VOID) HrSetupDiSetDeipFlags (cii.hdi, cii.pdeid, DI_DONOTCALLCONFIGMG,
|
||
|
SDDFT_FLAGS, SDFBO_XOR);
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr,
|
||
|
"HrCiInstallEnumeratedComponent");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCiRegOpenKeyFromEnumDevs
|
||
|
//
|
||
|
// Purpose: Enumerates through each device in an HDEVINFO and returns an
|
||
|
// hkey to its driver key.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hdi [in] See Device Installer Api
|
||
|
// dwIndex [inout] The index of the device to retrieve
|
||
|
// samDesired [in] The access level of the hkey
|
||
|
// phkey [out] The device's driver key
|
||
|
//
|
||
|
// Returns: HRESULT. S_OK if successful, an error code otherwise
|
||
|
//
|
||
|
// Author: billbe 13 Jun 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
HrCiRegOpenKeyFromEnumDevs(HDEVINFO hdi, DWORD* pIndex, REGSAM samDesired,
|
||
|
HKEY* phkey)
|
||
|
{
|
||
|
Assert(IsValidHandle(hdi));
|
||
|
Assert (phkey);
|
||
|
|
||
|
// Initialize output parameter.
|
||
|
*phkey = NULL;
|
||
|
|
||
|
SP_DEVINFO_DATA deid;
|
||
|
HRESULT hr;
|
||
|
|
||
|
// enumerate through the devices
|
||
|
while ((S_OK == (hr = HrSetupDiEnumDeviceInfo(hdi, *pIndex, &deid))))
|
||
|
{
|
||
|
// open the adapter's instance key
|
||
|
HRESULT hrT;
|
||
|
|
||
|
hrT = HrSetupDiOpenDevRegKey(hdi, &deid, DICS_FLAG_GLOBAL,
|
||
|
0, DIREG_DRV, samDesired, phkey);
|
||
|
if (S_OK == hrT)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If the key does not exists this is a phantom device,
|
||
|
// (or if this device is hosed, we want to ignore it too)
|
||
|
// move on to the next one and delete this one from
|
||
|
// our list
|
||
|
(*pIndex)++;
|
||
|
(VOID)SetupDiDeleteDeviceInfo(hdi, &deid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr,
|
||
|
HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr,
|
||
|
"HrCiRegOpenKeyFromEnumDevs");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
///////////////Legacy NT4 app support///////////////////////////////////
|
||
|
|
||
|
VOID
|
||
|
AddOrRemoveLegacyNt4AdapterKey (
|
||
|
IN HDEVINFO hdi,
|
||
|
IN PSP_DEVINFO_DATA pdeid,
|
||
|
IN const GUID* pInstanceGuid,
|
||
|
IN PCWSTR pszDescription,
|
||
|
IN LEGACY_NT4_KEY_OP Op)
|
||
|
{
|
||
|
Assert (IsValidHandle (hdi));
|
||
|
Assert (pdeid);
|
||
|
Assert (FImplies ((LEGACY_NT4_KEY_ADD == Op), pInstanceGuid));
|
||
|
Assert (FImplies ((LEGACY_NT4_KEY_ADD == Op), pszDescription));
|
||
|
|
||
|
extern const WCHAR c_szRegKeyNt4Adapters[];
|
||
|
const WCHAR c_szRegValDescription[] = L"Description";
|
||
|
const WCHAR c_szRegValServiceName[] = L"ServiceName";
|
||
|
|
||
|
PWSTR pszDriver;
|
||
|
HRESULT hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc (
|
||
|
hdi, pdeid, SPDRP_DRIVER, NULL, (BYTE**)&pszDriver);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
PWSTR pszNumber = wcsrchr (pszDriver, L'\\');
|
||
|
if (pszNumber && *(++pszNumber))
|
||
|
{
|
||
|
PWSTR pszStopString;
|
||
|
ULONG Instance = 0;
|
||
|
HKEY hkeyAdapters;
|
||
|
|
||
|
Instance = wcstoul (pszNumber, &pszStopString, c_nBase10);
|
||
|
|
||
|
// The NT4 key was one based so increment the instance number.
|
||
|
Instance++;
|
||
|
|
||
|
DWORD Disp;
|
||
|
hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyNt4Adapters,
|
||
|
0, KEY_WRITE, NULL, &hkeyAdapters, &Disp);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
WCHAR szInstanceNumber [12];
|
||
|
_snwprintf (szInstanceNumber, celems(szInstanceNumber) - 1,
|
||
|
L"%d", Instance);
|
||
|
|
||
|
HKEY hkeyInstance;
|
||
|
|
||
|
if (LEGACY_NT4_KEY_ADD == Op)
|
||
|
{
|
||
|
hr = HrRegCreateKeyEx (hkeyAdapters, szInstanceNumber, 0,
|
||
|
KEY_WRITE, NULL, &hkeyInstance, NULL);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
WCHAR szGuid[c_cchGuidWithTerm];
|
||
|
StringFromGUID2 (*pInstanceGuid, szGuid,
|
||
|
c_cchGuidWithTerm);
|
||
|
hr = HrRegSetValueEx (hkeyInstance,
|
||
|
c_szRegValServiceName, REG_SZ,
|
||
|
(const BYTE*)szGuid, sizeof (szGuid));
|
||
|
TraceHr (ttidError, FAL, hr, FALSE,
|
||
|
"AddAdapterToNt4Key: Setting Service Name "
|
||
|
"in legacy registry");
|
||
|
|
||
|
hr = HrRegSetValueEx (hkeyInstance,
|
||
|
c_szRegValDescription, REG_SZ,
|
||
|
(const BYTE*)pszDescription,
|
||
|
CbOfSzAndTerm (pszDescription));
|
||
|
TraceHr (ttidError, FAL, hr, FALSE,
|
||
|
"AddAdapterToNt4Key: Setting Description in "
|
||
|
"legacy registry");
|
||
|
|
||
|
RegCloseKey (hkeyInstance);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrRegDeleteKey (hkeyAdapters, szInstanceNumber);
|
||
|
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hkeyAdapters);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] pszDriver;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|