windows-nt/Source/XPSP1/NT/enduser/windows.com/lib/install/drvinst.cpp
2020-09-26 16:20:57 +08:00

938 lines
26 KiB
C++

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: drvinst.cpp
//
// Description:
//
// Functions called to install drivers and printer drivers
//
//=======================================================================
#include <windows.h>
#include <wuiutest.h>
#include <tchar.h>
#include <winspool.h>
#include <setupapi.h>
#include <shlwapi.h>
#include <fileutil.h>
#include <install.h>
#include <logging.h>
#include <memutil.h>
#include <stringutil.h>
#include <iucommon.h>
#include <wusafefn.h>
#include <mistsafe.h>
#if defined(_X86_) || defined(i386)
const TCHAR SZ_PROCESSOR[] = _T("Intel");
#else // defined(_IA64_) || defined(IA64)
const TCHAR SZ_PROCESSOR[] = _T("IA64");
#endif
const TCHAR SZ_PRINTER[] = _T("Printer");
///////////////////////////////////////////////////////////////////////////
//
// InstallPrinterDriver
//
///////////////////////////////////////////////////////////////////////////
HRESULT InstallPrinterDriver(
IN LPCTSTR szDriverName,
IN LPCTSTR pszLocalDir, //Local directory where installation files are.
IN LPCTSTR szArchitecture,
OUT DWORD* pdwStatus
)
{
LOG_Block("InstallPrinterDriver");
USES_IU_CONVERSION;
HRESULT hr = S_OK;
DWORD dwError = ERROR_INVALID_FUNCTION;
TCHAR szFileName[MAX_PATH + 1];
HANDLE hFindFile = INVALID_HANDLE_VALUE;
OSVERSIONINFO osvi;
WIN32_FIND_DATA ffd;
HMODULE hLibModule = NULL;
LPWSTR pszwCmd = NULL;
HINF hInfFile = INVALID_HANDLE_VALUE;
if (NULL == szDriverName || NULL == pszLocalDir || NULL == pdwStatus)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
LOG_Driver(_T("Called with szDriverName = %s, pszLocalDir = %s, szArchitecture = %s"),
szDriverName, pszLocalDir, (NULL == szArchitecture) ? _T("NULL") : szArchitecture);
//
// DecompressFolderCabs may return S_FALSE if it didn't find a cab to decompress...
//
hr = DecompressFolderCabs(pszLocalDir);
if (S_OK != hr)
{
CleanUpIfFailedAndSetHr(E_FAIL);
}
//
// Find the first *.inf file in pszLocalDir
//
CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szFileName, ARRAYSIZE(szFileName), pszLocalDir, \
NULL, NULL, MISTSAFE_STRING_FLAGS));
CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFileName, ARRAYSIZE(szFileName), _T("*.inf")));
if (INVALID_HANDLE_VALUE == (hFindFile = FindFirstFile(szFileName, &ffd)))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
//
// 574593 During site printer install, we pass path to first INF - this may not be correct for MFD's or multi-platform CABs
//
// Find the first printer INF by calling SetupOpenInfFile() with class "Printer"
//
for (;;)
{
//
// Construct .inf path using FindXxxFile name
//
CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szFileName, ARRAYSIZE(szFileName), pszLocalDir, \
NULL, NULL, MISTSAFE_STRING_FLAGS));
CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFileName, ARRAYSIZE(szFileName), ffd.cFileName));
if (INVALID_HANDLE_VALUE == (hInfFile = SetupOpenInfFile(szFileName, SZ_PRINTER, INF_STYLE_WIN4, NULL)))
{
if (ERROR_CLASS_MISMATCH != GetLastError())
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
//
// If this isn't a Printer INF (ERROR_CLASS_MISMATCH) try the next file
//
if (0 == FindNextFile(hFindFile, &ffd))
{
//
// We ran out of *.inf files or hit other FindNextFile error before finding class match
//
Win32MsgSetHrGotoCleanup(GetLastError());
}
continue;
}
else
{
//
// We found the printer INF in the cab. NOTE: WHQL assumption that only one "Printer" class
// INF will exist in any particular cab.
//
SetupCloseInfFile(hInfFile);
hInfFile = INVALID_HANDLE_VALUE;
//
// Go use szFileName
//
break;
}
}
//
// We've broken out of for (;;) loop without jumping to CleanUp, so we have a
// "Printer" class INF path in szFileName
//
// Only works on NT 5 up and Millennium
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId && 4 == osvi.dwMajorVersion && 90 == osvi.dwMinorVersion)
{
#if !(defined(_UNICODE) || defined(UNICODE))
//
// Millennium (ANSI only)
//
typedef DWORD (WINAPI *PFN_InstallPrinterDriver)(LPCSTR lpszDriverName, LPCSTR lpszINF);
if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("msprint2.dll"))))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
PFN_InstallPrinterDriver pfnIPD;
if (NULL == (pfnIPD= (PFN_InstallPrinterDriver) GetProcAddress(hLibModule, "InstallPrinterDriver")))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
if (NO_ERROR != (dwError = pfnIPD(szDriverName, szFileName)))
{
LOG_Driver("pfnIPD(%s, %s) returns %d", szDriverName, szFileName, dwError);
Win32MsgSetHrGotoCleanup(dwError);
}
#endif
}
else if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && 5 <= osvi.dwMajorVersion)
{
//
// Windows 2000 and Whistler: PrintUIEntryW is the only supported method of installing printer drivers.
// Don't try and use PnPInterface() defined in printui.dll (and don't ask *me* why PrintUIEntryW isn't
// typedef'ed there...)
//
// Type "rundll32.exe printui.dll,PrintUIEntry /?" from a cmd prompt for help on the command parameters.
//
// Private typedef since this isn't exposed in any internal or external SDK headers
//
typedef DWORD (*PFN_PrintUIEntryW)(
IN HWND hwnd,
IN HINSTANCE hInstance,
IN LPCWSTR pszCmdLine,
IN UINT nCmdShow
);
///////////////////////////////////
if (NULL == szArchitecture)
{
szArchitecture = (LPCTSTR) &SZ_PROCESSOR;
}
//
// 491157 Trying to update an English language printer driver installed on a German build through the German WU website fails.
//
// Don't pass optional /u, /h, and /v parameters (localized). They aren't required since we always provide
// drivers for the client architecture and OS.
//
// 574593 Per attached discussion we need to pass an undocumented upper-case 'U' flag.
//
const WCHAR szwCmdLineFormat[] = L"/ia /m \"%s\" /f \"%s\" /q /U";
const size_t nCmdLineFormatLength = wcslen(szwCmdLineFormat);
#define MAX_PLATFORMVERSION 20 // NOTE:: Max Version Length Needs to be Updated if the OS Strings in the Below Command Line Change
// NOTE: this doesn't bother to remove the length of the %s characters from nCmdLineFormatLength
DWORD dwLength=(nCmdLineFormatLength + lstrlen(szDriverName) + lstrlen(szArchitecture) + MAX_PLATFORMVERSION + lstrlen(szFileName) + 1);
pszwCmd = (LPWSTR) HeapAlloc(
GetProcessHeap(),
0,
dwLength * sizeof(WCHAR));
CleanUpFailedAllocSetHrMsg(pszwCmd);
// OK to cast away const-ness on string params so T2OLE works, since it doesn't modify them anyway
hr=StringCchPrintfExW(pszwCmd,dwLength,NULL,NULL,MISTSAFE_STRING_FLAGS,(LPCWSTR) szwCmdLineFormat,
T2OLE(const_cast<TCHAR*>(szDriverName)),
T2OLE(const_cast<TCHAR*>(szFileName)) );
CleanUpIfFailedAndSetHr(hr);
// Load printui.dll
if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("printui.dll"))))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
PFN_PrintUIEntryW pfnPrintUIEntryW;
if (NULL == (pfnPrintUIEntryW = (PFN_PrintUIEntryW) GetProcAddress(hLibModule, "PrintUIEntryW")))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
if (NO_ERROR != (dwError = pfnPrintUIEntryW(GetActiveWindow(), 0, pszwCmd, SW_HIDE)))
{
LOG_Driver(_T("pfnPrintUIEntryW(%s) returns %d"), OLE2T(pszwCmd), dwError);
Win32MsgSetHrGotoCleanup(dwError);
}
}
else
{
SetHrMsgAndGotoCleanUp(E_NOTIMPL);
}
*pdwStatus = ITEM_STATUS_SUCCESS;
CleanUp:
SafeHeapFree(pszwCmd);
if (INVALID_HANDLE_VALUE != hFindFile)
{
FindClose(hFindFile);
}
if (INVALID_HANDLE_VALUE != hInfFile)
{
SetupCloseInfFile(hInfFile);
}
if (NULL != hLibModule)
{
FreeLibrary(hLibModule);
}
if (FAILED(hr))
{
if (NULL != pdwStatus)
{
*pdwStatus = ITEM_STATUS_FAILED;
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
//
// InstallDriver and helper functions
//
///////////////////////////////////////////////////////////////////////////
DWORD OpenReinstallKey(HKEY* phKeyReinstall)
{
return RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reinstall"),
0, KEY_ALL_ACCESS, phKeyReinstall);
}
//-----------------------------------------------------------------------------------
// LaunchProcess
// Launches pszCmd and optionally waits till the process terminates
//-----------------------------------------------------------------------------------
static HRESULT LaunchProcess(LPTSTR pszCmd, LPCTSTR pszDir, UINT uShow, BOOL bWait)
{
LOG_Block("LaunchProcess");
HRESULT hr = S_OK;
STARTUPINFO startInfo;
PROCESS_INFORMATION processInfo;
ZeroMemory(&startInfo, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
startInfo.dwFlags |= STARTF_USESHOWWINDOW;
startInfo.wShowWindow = (USHORT)uShow;
BOOL bRet = CreateProcess(NULL, pszCmd, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS, NULL, pszDir, &startInfo, &processInfo);
if (!bRet)
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
CloseHandle(processInfo.hThread);
if (bWait)
{
BOOL bDone = FALSE;
while (!bDone)
{
DWORD dwObject = MsgWaitForMultipleObjects(1, &processInfo.hProcess, FALSE,INFINITE, QS_ALLINPUT);
if (dwObject == WAIT_OBJECT_0 || dwObject == WAIT_FAILED)
{
bDone = TRUE;
}
else
{
MSG msg;
while (PeekMessage(&msg, NULL,0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
} // while
} // bWait
CloseHandle(processInfo.hProcess);
CleanUp:
return hr;
}
// "@rundll sysdm.cpl,UpdateDriver_Start"
// "@rundll sysdm.cpl,UpdateDriver_RunDLL .\,,1,Win98 signed test pkg for System Devices"
// "@rundll sysdm.cpl,UpdateDriver_Finish 0"
// "@rundll sysdm.cpl,UpdateDriver_RunDLL .\,,1,Win98 signed test pkg for System Devices"
//Note: Windows 98 uses rundll.exe to call device manager. This is because sysdm.cpl which
//is device manager for 98 is a 16 bit dll. Since we would need to create something that
//worked similar to rundll in order call device manager we have brought the existing code
//across with some minor clean ups. win98 device manager provides three apis for our use
//in installing device drivers. These are:
// UpdateDriver_Start() - Start the device installation
// UpdateDriver_RunDLL(inf Directory,hardware id, force flag, display string)
// UpdateDriver_Finish 0 - finish the installation.
//The UpdateDriver_RunDLL() command
//Comma separated string in following format:
//INFPath,HardwareID,flags,DisplayName
//INFPath = Path to INF and installation files
//HardwareID = PnpHardware ID
//flags = '1' = force driver, '0' = do not force driver.
//Note: A Reinstall driver is detected based on the location of the INF path. If INF path
//is the same path as the reinstallbackups registry key then reinstall is selected.
//DisplayName = Name to display in install dialogs.
//This method installs a CDM driver for Windows 98.
static HRESULT Install98(
LPCTSTR pszHardwareID,
LPCTSTR pszLocalDir, // location of INF and other driver install files
LPCTSTR pszDisplayName,
PDWORD pdwReboot
)
{
LOG_Block("Install98");
HRESULT hr = E_NOTIMPL;
DWORD dwStatus = 0;
LPTSTR pszCmd = NULL;
DWORD dwLen;
LONG lRet;
DWORD dwSize;
if (NULL == pdwReboot)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
#if defined(DBG)
// checked by caller
if (NULL == pszHardwareID || NULL == pszLocalDir || NULL == pszDisplayName)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
#endif
#if !(defined(_UNICODE) || defined(UNICODE))
//
// Win98 and WinME (ANSI only)
//
// Start
CleanUpIfFailedAndSetHr(LaunchProcess(_T("rundll32 sysdm.cpl,UpdateDriver_Start"), NULL, SW_NORMAL, TRUE));
TCHAR szShortInfPathName[MAX_PATH] = {0};
dwLen = GetShortPathName(pszLocalDir, szShortInfPathName, ARRAYSIZE(szShortInfPathName));
//Note: The maximum a hardware or compatible ID can be is 200 characters
// (MAX_DEVICE_ID_LEN defined in sdk\inc\cfgmgr32.h)
DWORD dwBuffLength=( lstrlen(szShortInfPathName) + lstrlen(pszHardwareID) + lstrlen(pszDisplayName) + 64);
CleanUpFailedAllocSetHrMsg(pszCmd = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
dwLen * sizeof(TCHAR)));
hr=StringCchPrintfEx(pszCmd,dwBuffLength,NULL,NULL,MISTSAFE_STRING_FLAGS,
_T("rundll32 sysdm.cpl,UpdateDriver_RunDLL %s,%s,%d,%s"),
szShortInfPathName, pszHardwareID,0,pszDisplayName);
CleanUpIfFailedAndSetHr(hr);
// RunDLL
LOG_Driver(_T("LaunchProcess(%s)"), pszCmd);
CleanUpIfFailedAndSetHr(LaunchProcess(pszCmd, NULL, SW_NORMAL, TRUE));
// Get resulting code
HKEY hKeyReinstall;
if (ERROR_SUCCESS == (lRet = OpenReinstallKey(&hKeyReinstall)))
{
dwSize = sizeof(dwStatus);
if (ERROR_SUCCESS == (lRet = RegQueryValueEx(hKeyReinstall, _T("LastInstallStatus"), NULL, NULL, (LPBYTE)&dwStatus, &dwSize)))
{
if (3 == dwStatus)
{
//Check if we need to reboot
HKEY hKeySysDM;
*pdwReboot = 0;
dwSize = sizeof(*pdwReboot);
if (ERROR_SUCCESS == (lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SysDM"), 0, KEY_READ, &hKeySysDM)))
{
if (ERROR_SUCCESS != (lRet = RegQueryValueEx(hKeySysDM, "UpgradeDeviceFlags", NULL, NULL, (LPBYTE)&pdwReboot, &dwSize)))
{
LOG_ErrorMsg(lRet);
hr = HRESULT_FROM_WIN32(lRet);
}
RegCloseKey(hKeySysDM);
}
else
{
LOG_ErrorMsg(lRet);
hr = HRESULT_FROM_WIN32(lRet);
}
}
}
else
{
LOG_ErrorMsg(lRet);
hr = HRESULT_FROM_WIN32(lRet);
}
LOG_Driver(_T("Reboot %srequired"), *pdwReboot ? _T(" ") : _T("not "));
RegCloseKey(hKeyReinstall);
}
else
{
LOG_ErrorMsg(lRet);
hr = HRESULT_FROM_WIN32(lRet);
}
// Finish no reboot
CleanUpIfFailedAndSetHr(LaunchProcess(_T("rundll32 sysdm.cpl,UpdateDriver_Finish 2"), NULL, SW_NORMAL, TRUE));
if (3 != dwStatus)
{
LOG_Error("3 != dwStatus");
hr = E_FAIL;
}
else
{
hr = S_OK;
}
#endif // #if !(defined(_UNICODE) || defined(UNICODE))
CleanUp:
SafeHeapFree(pszCmd);
return hr;
}
//This function installs a driver on Windows NT.
// Its prototype is:
// BOOL
// InstallWindowsUpdateDriver(
// HWND hwndParent,
// LPCWSTR HardwareId,
// LPCWSTR InfPathName,
// LPCWSTR DisplayName,
// BOOL Force,
// BOOL Backup,
// PDWORD pReboot
// )
// This API takes a HardwareID. Newdev will cycle through all devices that match this hardware ID
// and install the specified driver on them all.
// It also takes a BOOL value Backup which specifies whether or not to backup the current drivers.
// This should always be TRUE.
static HRESULT InstallNT(
LPCTSTR pszHardwareID,
LPCTSTR pszLocalDir, // passed to InstallWindowsUpdateDriver(... InfPathName, ...)
LPCTSTR pszDisplayName,
PDWORD pdwReboot
)
{
USES_IU_CONVERSION;
LOG_Block("InstallNT");
//
// InstallWindowsUpdateDriver function found in $(BASEDIR)\shell\osshell\cpls\newdev\init.c (not in any headers)
//
typedef BOOL (*PFN_InstallWindowsUpdateDriver)(HWND hwndParent, LPCWSTR HardwareId, LPCWSTR InfPathName, LPCWSTR DisplayName, BOOL Force, BOOL Backup, PDWORD pReboot);
HRESULT hr = S_OK;
HMODULE hLibModule = NULL;
PFN_InstallWindowsUpdateDriver pfnInstallWindowsUpdateDriver;
if (NULL == pdwReboot)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
#if defined(DBG)
// checked by caller
if (NULL == pszHardwareID || NULL == pszLocalDir || NULL == pszDisplayName)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
#endif
// Load newdev.dll and get pointer to our function
if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("newdev.dll"))))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
if (NULL == (pfnInstallWindowsUpdateDriver = (PFN_InstallWindowsUpdateDriver)GetProcAddress(hLibModule,"InstallWindowsUpdateDriver")))
{
Win32MsgSetHrGotoCleanup(GetLastError());
}
// Industry Update RAID # 461 waltw May need to massage HWID's for site Driver Install for Win2K
//
// Linked to: RAID # 12021 in Windows Update Database - This logic (required for Win2K) is implemented
// on the server rather than the client in IU (V3 Wuv3is implements this on the client)
//
// first, we search for a matching SPDRP_HARDWAREID
// if we didn't find a Hardware ID, we search for a matching SPDRP_COMPATIBLEID,
// and we pass the last SPDRP_HARDWAREID associated with the same device.
#if (defined(UNICODE) || defined(_UNICODE))
LOG_Driver (_T("InstallWindowsUpdateDriver(GetActiveWindow(), %s, %s, %s, fForce=%d, fBackup=%d)"),
pszHardwareID, pszLocalDir, pszDisplayName, FALSE, TRUE);
#endif
//
// NOTES on calling InstallWindowsUpdateDriver():
// * Never pass TRUE in Force flag (only used if we are doing uninstall, which we don't support).
// * Always pass TRUE in Backup flag.
// * OK to cast away const-ness on strings since InstallWindowsUpdateDriver takes const wide strings
if(!(pfnInstallWindowsUpdateDriver)(GetActiveWindow(),
T2OLE(const_cast<TCHAR*>(pszHardwareID)),
T2OLE(const_cast<TCHAR*>(pszLocalDir)),
T2OLE(const_cast<TCHAR*>(pszDisplayName)), FALSE, TRUE, pdwReboot))
{
LOG_Driver(_T("InstallWindowsUpdateDriver returned false. Driver was not be updated."));
Win32MsgSetHrGotoCleanup(GetLastError());
}
CleanUp:
if (NULL != hLibModule)
{
FreeLibrary(hLibModule);
hLibModule = NULL;
}
return hr;
}
//
// MatchHardwareID (used only on Windows 2000)
//
// Takes as input a hardware or compatible ID and returns an allocated
// buffer with the same hardware ID or, if it was a compatible ID the
// most general hardware ID for the device node that matched the
// given compatible ID.
//
// Return: S_OK if a match was found, else a failure code
//
// *ppszMatchingHWID must be NULL on entry, and if S_OK is returned
// the buffer must be heap-freed by the caller.
//
HRESULT MatchHardwareID(LPCWSTR pwszHwOrCompatID, LPWSTR * ppszMatchingHWID)
{
LOG_Block("MatchHardwareID");
HRESULT hr = E_FAIL;
SP_DEVINFO_DATA DeviceInfoData;
DWORD dwIndex = 0;
DWORD dwSize = 0;
LPWSTR pwszHardwareIDList = NULL;
LPWSTR pwszCompatibleIDList = NULL;
LPWSTR pwszSingleID = NULL;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
BOOL fRet;
ZeroMemory((void*)&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (NULL == pwszHwOrCompatID || NULL == ppszMatchingHWID || NULL != *ppszMatchingHWID)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
// get a handle to the class devices
hDevInfo = SetupDiGetClassDevs(NULL,
NULL,
GetActiveWindow(),
DIGCF_ALLCLASSES | DIGCF_PRESENT
);
if (INVALID_HANDLE_VALUE == hDevInfo)
{
Win32MsgSetHrGotoCleanup(ERROR_INVALID_HANDLE);
}
//loop through all devices
DWORD dwBufLen=0;
while ((NULL == *ppszMatchingHWID) && SetupDiEnumDeviceInfo(hDevInfo,
dwIndex++,
&DeviceInfoData
))
{
//
// Free up buffers for each device node loop (if allocated)
//
SafeHeapFree(pwszHardwareIDList);
SafeHeapFree(pwszCompatibleIDList);
dwSize = 0;
//
// Get the list of Hardware Ids for this device
//
fRet = SetupDiGetDeviceRegistryPropertyW(hDevInfo,
&DeviceInfoData,
SPDRP_HARDWAREID,
NULL,
NULL,
0,
&dwSize
);
if (0 == dwSize || (FALSE == fRet && ERROR_INSUFFICIENT_BUFFER != GetLastError()))
{
//
// FIX: NTRAID#NTBUG9-500223-2001/11/28- IU - Dual mode USB camera install fails while installing of web site
//
// If we hit a node without a HWID before finding device node we are looking for, just continue. If the node
// we ARE looking for doesn't have a HWID then we will fail later anyway when we run out of nodes.
//
LOG_Out(_T("No HWID's found for device node"));
continue;
}
if (MAX_SETUP_MULTI_SZ_SIZE_W < dwSize)
{
//
// Something is very wrong - bail
//
CleanUpIfFailedAndSetHrMsg(ERROR_INSUFFICIENT_BUFFER);
}
//
// We got the expected ERROR_INSUFFICIENT_BUFFER with a reasonable dwSize
//
// Now guarantee we are double-NULL terminated by allocating two extra WCHARs we don't tell SetupDi about
//
pwszHardwareIDList = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + (sizeof(WCHAR) * 2));
CleanUpFailedAllocSetHrMsg(pwszHardwareIDList);
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo,
&DeviceInfoData,
SPDRP_HARDWAREID,
NULL,
(PBYTE)pwszHardwareIDList,
dwSize,
&dwSize
))
{
//
// If any of the devices HardwareIDs match the input ID then
// we copy the incoming argument to a new buffer and return true
//
for (pwszSingleID = pwszHardwareIDList;
*pwszSingleID;
pwszSingleID += lstrlenW(pwszSingleID) + 1)
{
if (0 == lstrcmpiW(pwszSingleID, pwszHwOrCompatID))
{
// return the hardware ID we matched
dwBufLen=(lstrlenW(pwszHwOrCompatID) + 1);
*ppszMatchingHWID = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
dwBufLen * sizeof(WCHAR));
CleanUpFailedAllocSetHrMsg(*ppszMatchingHWID);
hr=StringCchCopyExW(*ppszMatchingHWID,dwBufLen,pwszHwOrCompatID,NULL,NULL,MISTSAFE_STRING_FLAGS);
goto CleanUp;
}
}
}
//
// Hardware match not found, let's try to match to a
// compatible ID then return the (most generic) Hardware ID
// associated with the same device node
//
fRet = SetupDiGetDeviceRegistryPropertyW(hDevInfo,
&DeviceInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
NULL,
0,
&dwSize
);
if (0 == dwSize || (FALSE == fRet && ERROR_INSUFFICIENT_BUFFER != GetLastError()))
{
LOG_Out(_T("No Compatible ID's found for device node"));
continue;
}
if (MAX_SETUP_MULTI_SZ_SIZE_W < dwSize)
{
//
// Something is very wrong - bail
//
CleanUpIfFailedAndSetHrMsg(ERROR_INSUFFICIENT_BUFFER);
}
//
// We got the expected ERROR_INSUFFICIENT_BUFFER with a reasonable dwSize
//
// Now guarantee we are double-NULL terminated by allocating two extra WCHARs we don't tell SetupDi about
//
pwszCompatibleIDList = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + (sizeof(WCHAR) * 2));
CleanUpFailedAllocSetHrMsg(pwszCompatibleIDList);
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo,
&DeviceInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
(PBYTE)pwszCompatibleIDList,
dwSize,
&dwSize
))
{
for (pwszSingleID = pwszCompatibleIDList;
*pwszSingleID;
pwszSingleID += lstrlenW(pwszSingleID) + 1)
{
if (0 == lstrcmpiW(pwszSingleID, pwszHwOrCompatID))
{
//
// We found a compatible match, now return the most general HWID
// for this device node. Must be at least one character long.
//
if (NULL != pwszHardwareIDList && NULL != *pwszHardwareIDList)
{
LPWSTR lpwszLastID = NULL;
for(pwszSingleID = pwszHardwareIDList;
*pwszSingleID;
pwszSingleID += lstrlenW(pwszSingleID) + 1)
{
//
// Remember last ID before NULL string
//
lpwszLastID = pwszSingleID;
}
// copy the last HWID into a new buffer
dwBufLen=(lstrlenW(lpwszLastID) + 1);
*ppszMatchingHWID = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
dwBufLen * sizeof(WCHAR));
CleanUpFailedAllocSetHrMsg(*ppszMatchingHWID);
hr=StringCchCopyExW(*ppszMatchingHWID,dwBufLen,lpwszLastID,NULL,NULL,MISTSAFE_STRING_FLAGS);
goto CleanUp;
}
}
}
}
} // end while
CleanUp:
if (INVALID_HANDLE_VALUE != hDevInfo)
{
SetupDiDestroyDeviceInfoList(hDevInfo);
}
//
// Free up any allocated buffers (except *ppszMatchingHWID)
//
if(FAILED(hr))
{
SafeHeapFree(*ppszMatchingHWID);
}
SafeHeapFree(pwszHardwareIDList);
SafeHeapFree(pwszCompatibleIDList);
return hr;
}
//This function handles installation of a Device driver package.
HRESULT InstallDriver(
LPCTSTR pszLocalDir, // Local directory where installation files are.
LPCTSTR pszDisplayName, // Description of package, Device Manager displays this in its install dialog.
LPCTSTR pszHardwareID, // ID from XML matched to client hardware via GetManifest()
DWORD* pdwStatus
)
{
LOG_Block("InstallDriver");
USES_IU_CONVERSION;
HRESULT hr;
OSVERSIONINFO osvi;
DWORD dwReboot = 0;
LPWSTR pszwMatchingHWID = NULL;
if (NULL == pszLocalDir || NULL == pszDisplayName || NULL == pszHardwareID || NULL == pdwStatus)
{
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
}
//
// DecompressFolderCabs may return S_FALSE if it didn't find a cab to decompress...
//
hr = DecompressFolderCabs(pszLocalDir);
if (S_OK != hr)
{
CleanUpIfFailedAndSetHr(E_FAIL);
}
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && 4 < osvi.dwMajorVersion)
{
//
// Win2K or higher NT
//
if (5 == osvi.dwMajorVersion && 0 == osvi.dwMinorVersion)
{
//
// Windows 2000
// NTBUG9-485554 Convert compatible IDs to hardware IDs for site Driver Install for Win2K
//
// OK to cast away const-ness on string params so T2OLE works, since it doesn't modify them anyway
CleanUpIfFailedAndSetHr(MatchHardwareID(T2OLE((LPTSTR)pszHardwareID), &pszwMatchingHWID));
hr = InstallNT(OLE2T(pszwMatchingHWID), pszLocalDir, pszDisplayName, &dwReboot);
// pszMatchingHWID must be non-null if we got here
SafeHeapFree(pszwMatchingHWID);
}
else
{
//
// Normal case, just install
//
CleanUpIfFailedAndSetHr(InstallNT(pszHardwareID, pszLocalDir, pszDisplayName, &dwReboot));
}
}
else if (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId &&
(4 < osvi.dwMajorVersion) ||
( (4 == osvi.dwMajorVersion) &&
(0 < osvi.dwMinorVersion) ) )
{
//
// Win98 or higher (WinME)
//
CleanUpIfFailedAndSetHr(Install98(pszHardwareID, pszLocalDir, pszDisplayName, &dwReboot));
}
else
{
*pdwStatus = ITEM_STATUS_FAILED;
SetHrMsgAndGotoCleanUp(E_NOTIMPL);
}
if (DI_NEEDRESTART & dwReboot || DI_NEEDREBOOT & dwReboot)
*pdwStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED;
else
*pdwStatus = ITEM_STATUS_SUCCESS;
CleanUp:
if (FAILED(hr))
{
if (NULL != pdwStatus)
{
*pdwStatus = ITEM_STATUS_FAILED;
}
}
return hr;
}