//======================================================================= // // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. // // File: drvinst.cpp // // Description: // // Functions called to install drivers and printer drivers // //======================================================================= #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(szDriverName)), T2OLE(const_cast(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(pszHardwareID)), T2OLE(const_cast(pszLocalDir)), T2OLE(const_cast(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; }