Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

937 lines
26 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: drvinst.cpp
  6. //
  7. // Description:
  8. //
  9. // Functions called to install drivers and printer drivers
  10. //
  11. //=======================================================================
  12. #include <windows.h>
  13. #include <wuiutest.h>
  14. #include <tchar.h>
  15. #include <winspool.h>
  16. #include <setupapi.h>
  17. #include <shlwapi.h>
  18. #include <fileutil.h>
  19. #include <install.h>
  20. #include <logging.h>
  21. #include <memutil.h>
  22. #include <stringutil.h>
  23. #include <iucommon.h>
  24. #include <wusafefn.h>
  25. #include <mistsafe.h>
  26. #if defined(_X86_) || defined(i386)
  27. const TCHAR SZ_PROCESSOR[] = _T("Intel");
  28. #else // defined(_IA64_) || defined(IA64)
  29. const TCHAR SZ_PROCESSOR[] = _T("IA64");
  30. #endif
  31. const TCHAR SZ_PRINTER[] = _T("Printer");
  32. ///////////////////////////////////////////////////////////////////////////
  33. //
  34. // InstallPrinterDriver
  35. //
  36. ///////////////////////////////////////////////////////////////////////////
  37. HRESULT InstallPrinterDriver(
  38. IN LPCTSTR szDriverName,
  39. IN LPCTSTR pszLocalDir, //Local directory where installation files are.
  40. IN LPCTSTR szArchitecture,
  41. OUT DWORD* pdwStatus
  42. )
  43. {
  44. LOG_Block("InstallPrinterDriver");
  45. USES_IU_CONVERSION;
  46. HRESULT hr = S_OK;
  47. DWORD dwError = ERROR_INVALID_FUNCTION;
  48. TCHAR szFileName[MAX_PATH + 1];
  49. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  50. OSVERSIONINFO osvi;
  51. WIN32_FIND_DATA ffd;
  52. HMODULE hLibModule = NULL;
  53. LPWSTR pszwCmd = NULL;
  54. HINF hInfFile = INVALID_HANDLE_VALUE;
  55. if (NULL == szDriverName || NULL == pszLocalDir || NULL == pdwStatus)
  56. {
  57. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  58. }
  59. LOG_Driver(_T("Called with szDriverName = %s, pszLocalDir = %s, szArchitecture = %s"),
  60. szDriverName, pszLocalDir, (NULL == szArchitecture) ? _T("NULL") : szArchitecture);
  61. //
  62. // DecompressFolderCabs may return S_FALSE if it didn't find a cab to decompress...
  63. //
  64. hr = DecompressFolderCabs(pszLocalDir);
  65. if (S_OK != hr)
  66. {
  67. CleanUpIfFailedAndSetHr(E_FAIL);
  68. }
  69. //
  70. // Find the first *.inf file in pszLocalDir
  71. //
  72. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szFileName, ARRAYSIZE(szFileName), pszLocalDir, \
  73. NULL, NULL, MISTSAFE_STRING_FLAGS));
  74. CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFileName, ARRAYSIZE(szFileName), _T("*.inf")));
  75. if (INVALID_HANDLE_VALUE == (hFindFile = FindFirstFile(szFileName, &ffd)))
  76. {
  77. Win32MsgSetHrGotoCleanup(GetLastError());
  78. }
  79. //
  80. // 574593 During site printer install, we pass path to first INF - this may not be correct for MFD's or multi-platform CABs
  81. //
  82. // Find the first printer INF by calling SetupOpenInfFile() with class "Printer"
  83. //
  84. for (;;)
  85. {
  86. //
  87. // Construct .inf path using FindXxxFile name
  88. //
  89. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szFileName, ARRAYSIZE(szFileName), pszLocalDir, \
  90. NULL, NULL, MISTSAFE_STRING_FLAGS));
  91. CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFileName, ARRAYSIZE(szFileName), ffd.cFileName));
  92. if (INVALID_HANDLE_VALUE == (hInfFile = SetupOpenInfFile(szFileName, SZ_PRINTER, INF_STYLE_WIN4, NULL)))
  93. {
  94. if (ERROR_CLASS_MISMATCH != GetLastError())
  95. {
  96. Win32MsgSetHrGotoCleanup(GetLastError());
  97. }
  98. //
  99. // If this isn't a Printer INF (ERROR_CLASS_MISMATCH) try the next file
  100. //
  101. if (0 == FindNextFile(hFindFile, &ffd))
  102. {
  103. //
  104. // We ran out of *.inf files or hit other FindNextFile error before finding class match
  105. //
  106. Win32MsgSetHrGotoCleanup(GetLastError());
  107. }
  108. continue;
  109. }
  110. else
  111. {
  112. //
  113. // We found the printer INF in the cab. NOTE: WHQL assumption that only one "Printer" class
  114. // INF will exist in any particular cab.
  115. //
  116. SetupCloseInfFile(hInfFile);
  117. hInfFile = INVALID_HANDLE_VALUE;
  118. //
  119. // Go use szFileName
  120. //
  121. break;
  122. }
  123. }
  124. //
  125. // We've broken out of for (;;) loop without jumping to CleanUp, so we have a
  126. // "Printer" class INF path in szFileName
  127. //
  128. // Only works on NT 5 up and Millennium
  129. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  130. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  131. GetVersionEx(&osvi);
  132. if( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId && 4 == osvi.dwMajorVersion && 90 == osvi.dwMinorVersion)
  133. {
  134. #if !(defined(_UNICODE) || defined(UNICODE))
  135. //
  136. // Millennium (ANSI only)
  137. //
  138. typedef DWORD (WINAPI *PFN_InstallPrinterDriver)(LPCSTR lpszDriverName, LPCSTR lpszINF);
  139. if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("msprint2.dll"))))
  140. {
  141. Win32MsgSetHrGotoCleanup(GetLastError());
  142. }
  143. PFN_InstallPrinterDriver pfnIPD;
  144. if (NULL == (pfnIPD= (PFN_InstallPrinterDriver) GetProcAddress(hLibModule, "InstallPrinterDriver")))
  145. {
  146. Win32MsgSetHrGotoCleanup(GetLastError());
  147. }
  148. if (NO_ERROR != (dwError = pfnIPD(szDriverName, szFileName)))
  149. {
  150. LOG_Driver("pfnIPD(%s, %s) returns %d", szDriverName, szFileName, dwError);
  151. Win32MsgSetHrGotoCleanup(dwError);
  152. }
  153. #endif
  154. }
  155. else if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && 5 <= osvi.dwMajorVersion)
  156. {
  157. //
  158. // Windows 2000 and Whistler: PrintUIEntryW is the only supported method of installing printer drivers.
  159. // Don't try and use PnPInterface() defined in printui.dll (and don't ask *me* why PrintUIEntryW isn't
  160. // typedef'ed there...)
  161. //
  162. // Type "rundll32.exe printui.dll,PrintUIEntry /?" from a cmd prompt for help on the command parameters.
  163. //
  164. // Private typedef since this isn't exposed in any internal or external SDK headers
  165. //
  166. typedef DWORD (*PFN_PrintUIEntryW)(
  167. IN HWND hwnd,
  168. IN HINSTANCE hInstance,
  169. IN LPCWSTR pszCmdLine,
  170. IN UINT nCmdShow
  171. );
  172. ///////////////////////////////////
  173. if (NULL == szArchitecture)
  174. {
  175. szArchitecture = (LPCTSTR) &SZ_PROCESSOR;
  176. }
  177. //
  178. // 491157 Trying to update an English language printer driver installed on a German build through the German WU website fails.
  179. //
  180. // Don't pass optional /u, /h, and /v parameters (localized). They aren't required since we always provide
  181. // drivers for the client architecture and OS.
  182. //
  183. // 574593 Per attached discussion we need to pass an undocumented upper-case 'U' flag.
  184. //
  185. const WCHAR szwCmdLineFormat[] = L"/ia /m \"%s\" /f \"%s\" /q /U";
  186. const size_t nCmdLineFormatLength = wcslen(szwCmdLineFormat);
  187. #define MAX_PLATFORMVERSION 20 // NOTE:: Max Version Length Needs to be Updated if the OS Strings in the Below Command Line Change
  188. // NOTE: this doesn't bother to remove the length of the %s characters from nCmdLineFormatLength
  189. DWORD dwLength=(nCmdLineFormatLength + lstrlen(szDriverName) + lstrlen(szArchitecture) + MAX_PLATFORMVERSION + lstrlen(szFileName) + 1);
  190. pszwCmd = (LPWSTR) HeapAlloc(
  191. GetProcessHeap(),
  192. 0,
  193. dwLength * sizeof(WCHAR));
  194. CleanUpFailedAllocSetHrMsg(pszwCmd);
  195. // OK to cast away const-ness on string params so T2OLE works, since it doesn't modify them anyway
  196. hr=StringCchPrintfExW(pszwCmd,dwLength,NULL,NULL,MISTSAFE_STRING_FLAGS,(LPCWSTR) szwCmdLineFormat,
  197. T2OLE(const_cast<TCHAR*>(szDriverName)),
  198. T2OLE(const_cast<TCHAR*>(szFileName)) );
  199. CleanUpIfFailedAndSetHr(hr);
  200. // Load printui.dll
  201. if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("printui.dll"))))
  202. {
  203. Win32MsgSetHrGotoCleanup(GetLastError());
  204. }
  205. PFN_PrintUIEntryW pfnPrintUIEntryW;
  206. if (NULL == (pfnPrintUIEntryW = (PFN_PrintUIEntryW) GetProcAddress(hLibModule, "PrintUIEntryW")))
  207. {
  208. Win32MsgSetHrGotoCleanup(GetLastError());
  209. }
  210. if (NO_ERROR != (dwError = pfnPrintUIEntryW(GetActiveWindow(), 0, pszwCmd, SW_HIDE)))
  211. {
  212. LOG_Driver(_T("pfnPrintUIEntryW(%s) returns %d"), OLE2T(pszwCmd), dwError);
  213. Win32MsgSetHrGotoCleanup(dwError);
  214. }
  215. }
  216. else
  217. {
  218. SetHrMsgAndGotoCleanUp(E_NOTIMPL);
  219. }
  220. *pdwStatus = ITEM_STATUS_SUCCESS;
  221. CleanUp:
  222. SafeHeapFree(pszwCmd);
  223. if (INVALID_HANDLE_VALUE != hFindFile)
  224. {
  225. FindClose(hFindFile);
  226. }
  227. if (INVALID_HANDLE_VALUE != hInfFile)
  228. {
  229. SetupCloseInfFile(hInfFile);
  230. }
  231. if (NULL != hLibModule)
  232. {
  233. FreeLibrary(hLibModule);
  234. }
  235. if (FAILED(hr))
  236. {
  237. if (NULL != pdwStatus)
  238. {
  239. *pdwStatus = ITEM_STATUS_FAILED;
  240. }
  241. }
  242. return hr;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////
  245. //
  246. // InstallDriver and helper functions
  247. //
  248. ///////////////////////////////////////////////////////////////////////////
  249. DWORD OpenReinstallKey(HKEY* phKeyReinstall)
  250. {
  251. return RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  252. _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reinstall"),
  253. 0, KEY_ALL_ACCESS, phKeyReinstall);
  254. }
  255. //-----------------------------------------------------------------------------------
  256. // LaunchProcess
  257. // Launches pszCmd and optionally waits till the process terminates
  258. //-----------------------------------------------------------------------------------
  259. static HRESULT LaunchProcess(LPTSTR pszCmd, LPCTSTR pszDir, UINT uShow, BOOL bWait)
  260. {
  261. LOG_Block("LaunchProcess");
  262. HRESULT hr = S_OK;
  263. STARTUPINFO startInfo;
  264. PROCESS_INFORMATION processInfo;
  265. ZeroMemory(&startInfo, sizeof(startInfo));
  266. startInfo.cb = sizeof(startInfo);
  267. startInfo.dwFlags |= STARTF_USESHOWWINDOW;
  268. startInfo.wShowWindow = (USHORT)uShow;
  269. BOOL bRet = CreateProcess(NULL, pszCmd, NULL, NULL, FALSE,
  270. NORMAL_PRIORITY_CLASS, NULL, pszDir, &startInfo, &processInfo);
  271. if (!bRet)
  272. {
  273. Win32MsgSetHrGotoCleanup(GetLastError());
  274. }
  275. CloseHandle(processInfo.hThread);
  276. if (bWait)
  277. {
  278. BOOL bDone = FALSE;
  279. while (!bDone)
  280. {
  281. DWORD dwObject = MsgWaitForMultipleObjects(1, &processInfo.hProcess, FALSE,INFINITE, QS_ALLINPUT);
  282. if (dwObject == WAIT_OBJECT_0 || dwObject == WAIT_FAILED)
  283. {
  284. bDone = TRUE;
  285. }
  286. else
  287. {
  288. MSG msg;
  289. while (PeekMessage(&msg, NULL,0, 0, PM_REMOVE))
  290. {
  291. TranslateMessage(&msg);
  292. DispatchMessage(&msg);
  293. }
  294. }
  295. } // while
  296. } // bWait
  297. CloseHandle(processInfo.hProcess);
  298. CleanUp:
  299. return hr;
  300. }
  301. // "@rundll sysdm.cpl,UpdateDriver_Start"
  302. // "@rundll sysdm.cpl,UpdateDriver_RunDLL .\,,1,Win98 signed test pkg for System Devices"
  303. // "@rundll sysdm.cpl,UpdateDriver_Finish 0"
  304. // "@rundll sysdm.cpl,UpdateDriver_RunDLL .\,,1,Win98 signed test pkg for System Devices"
  305. //Note: Windows 98 uses rundll.exe to call device manager. This is because sysdm.cpl which
  306. //is device manager for 98 is a 16 bit dll. Since we would need to create something that
  307. //worked similar to rundll in order call device manager we have brought the existing code
  308. //across with some minor clean ups. win98 device manager provides three apis for our use
  309. //in installing device drivers. These are:
  310. // UpdateDriver_Start() - Start the device installation
  311. // UpdateDriver_RunDLL(inf Directory,hardware id, force flag, display string)
  312. // UpdateDriver_Finish 0 - finish the installation.
  313. //The UpdateDriver_RunDLL() command
  314. //Comma separated string in following format:
  315. //INFPath,HardwareID,flags,DisplayName
  316. //INFPath = Path to INF and installation files
  317. //HardwareID = PnpHardware ID
  318. //flags = '1' = force driver, '0' = do not force driver.
  319. //Note: A Reinstall driver is detected based on the location of the INF path. If INF path
  320. //is the same path as the reinstallbackups registry key then reinstall is selected.
  321. //DisplayName = Name to display in install dialogs.
  322. //This method installs a CDM driver for Windows 98.
  323. static HRESULT Install98(
  324. LPCTSTR pszHardwareID,
  325. LPCTSTR pszLocalDir, // location of INF and other driver install files
  326. LPCTSTR pszDisplayName,
  327. PDWORD pdwReboot
  328. )
  329. {
  330. LOG_Block("Install98");
  331. HRESULT hr = E_NOTIMPL;
  332. DWORD dwStatus = 0;
  333. LPTSTR pszCmd = NULL;
  334. DWORD dwLen;
  335. LONG lRet;
  336. DWORD dwSize;
  337. if (NULL == pdwReboot)
  338. {
  339. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  340. }
  341. #if defined(DBG)
  342. // checked by caller
  343. if (NULL == pszHardwareID || NULL == pszLocalDir || NULL == pszDisplayName)
  344. {
  345. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  346. }
  347. #endif
  348. #if !(defined(_UNICODE) || defined(UNICODE))
  349. //
  350. // Win98 and WinME (ANSI only)
  351. //
  352. // Start
  353. CleanUpIfFailedAndSetHr(LaunchProcess(_T("rundll32 sysdm.cpl,UpdateDriver_Start"), NULL, SW_NORMAL, TRUE));
  354. TCHAR szShortInfPathName[MAX_PATH] = {0};
  355. dwLen = GetShortPathName(pszLocalDir, szShortInfPathName, ARRAYSIZE(szShortInfPathName));
  356. //Note: The maximum a hardware or compatible ID can be is 200 characters
  357. // (MAX_DEVICE_ID_LEN defined in sdk\inc\cfgmgr32.h)
  358. DWORD dwBuffLength=( lstrlen(szShortInfPathName) + lstrlen(pszHardwareID) + lstrlen(pszDisplayName) + 64);
  359. CleanUpFailedAllocSetHrMsg(pszCmd = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  360. dwLen * sizeof(TCHAR)));
  361. hr=StringCchPrintfEx(pszCmd,dwBuffLength,NULL,NULL,MISTSAFE_STRING_FLAGS,
  362. _T("rundll32 sysdm.cpl,UpdateDriver_RunDLL %s,%s,%d,%s"),
  363. szShortInfPathName, pszHardwareID,0,pszDisplayName);
  364. CleanUpIfFailedAndSetHr(hr);
  365. // RunDLL
  366. LOG_Driver(_T("LaunchProcess(%s)"), pszCmd);
  367. CleanUpIfFailedAndSetHr(LaunchProcess(pszCmd, NULL, SW_NORMAL, TRUE));
  368. // Get resulting code
  369. HKEY hKeyReinstall;
  370. if (ERROR_SUCCESS == (lRet = OpenReinstallKey(&hKeyReinstall)))
  371. {
  372. dwSize = sizeof(dwStatus);
  373. if (ERROR_SUCCESS == (lRet = RegQueryValueEx(hKeyReinstall, _T("LastInstallStatus"), NULL, NULL, (LPBYTE)&dwStatus, &dwSize)))
  374. {
  375. if (3 == dwStatus)
  376. {
  377. //Check if we need to reboot
  378. HKEY hKeySysDM;
  379. *pdwReboot = 0;
  380. dwSize = sizeof(*pdwReboot);
  381. if (ERROR_SUCCESS == (lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  382. _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SysDM"), 0, KEY_READ, &hKeySysDM)))
  383. {
  384. if (ERROR_SUCCESS != (lRet = RegQueryValueEx(hKeySysDM, "UpgradeDeviceFlags", NULL, NULL, (LPBYTE)&pdwReboot, &dwSize)))
  385. {
  386. LOG_ErrorMsg(lRet);
  387. hr = HRESULT_FROM_WIN32(lRet);
  388. }
  389. RegCloseKey(hKeySysDM);
  390. }
  391. else
  392. {
  393. LOG_ErrorMsg(lRet);
  394. hr = HRESULT_FROM_WIN32(lRet);
  395. }
  396. }
  397. }
  398. else
  399. {
  400. LOG_ErrorMsg(lRet);
  401. hr = HRESULT_FROM_WIN32(lRet);
  402. }
  403. LOG_Driver(_T("Reboot %srequired"), *pdwReboot ? _T(" ") : _T("not "));
  404. RegCloseKey(hKeyReinstall);
  405. }
  406. else
  407. {
  408. LOG_ErrorMsg(lRet);
  409. hr = HRESULT_FROM_WIN32(lRet);
  410. }
  411. // Finish no reboot
  412. CleanUpIfFailedAndSetHr(LaunchProcess(_T("rundll32 sysdm.cpl,UpdateDriver_Finish 2"), NULL, SW_NORMAL, TRUE));
  413. if (3 != dwStatus)
  414. {
  415. LOG_Error("3 != dwStatus");
  416. hr = E_FAIL;
  417. }
  418. else
  419. {
  420. hr = S_OK;
  421. }
  422. #endif // #if !(defined(_UNICODE) || defined(UNICODE))
  423. CleanUp:
  424. SafeHeapFree(pszCmd);
  425. return hr;
  426. }
  427. //This function installs a driver on Windows NT.
  428. // Its prototype is:
  429. // BOOL
  430. // InstallWindowsUpdateDriver(
  431. // HWND hwndParent,
  432. // LPCWSTR HardwareId,
  433. // LPCWSTR InfPathName,
  434. // LPCWSTR DisplayName,
  435. // BOOL Force,
  436. // BOOL Backup,
  437. // PDWORD pReboot
  438. // )
  439. // This API takes a HardwareID. Newdev will cycle through all devices that match this hardware ID
  440. // and install the specified driver on them all.
  441. // It also takes a BOOL value Backup which specifies whether or not to backup the current drivers.
  442. // This should always be TRUE.
  443. static HRESULT InstallNT(
  444. LPCTSTR pszHardwareID,
  445. LPCTSTR pszLocalDir, // passed to InstallWindowsUpdateDriver(... InfPathName, ...)
  446. LPCTSTR pszDisplayName,
  447. PDWORD pdwReboot
  448. )
  449. {
  450. USES_IU_CONVERSION;
  451. LOG_Block("InstallNT");
  452. //
  453. // InstallWindowsUpdateDriver function found in $(BASEDIR)\shell\osshell\cpls\newdev\init.c (not in any headers)
  454. //
  455. typedef BOOL (*PFN_InstallWindowsUpdateDriver)(HWND hwndParent, LPCWSTR HardwareId, LPCWSTR InfPathName, LPCWSTR DisplayName, BOOL Force, BOOL Backup, PDWORD pReboot);
  456. HRESULT hr = S_OK;
  457. HMODULE hLibModule = NULL;
  458. PFN_InstallWindowsUpdateDriver pfnInstallWindowsUpdateDriver;
  459. if (NULL == pdwReboot)
  460. {
  461. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  462. }
  463. #if defined(DBG)
  464. // checked by caller
  465. if (NULL == pszHardwareID || NULL == pszLocalDir || NULL == pszDisplayName)
  466. {
  467. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  468. }
  469. #endif
  470. // Load newdev.dll and get pointer to our function
  471. if (NULL == (hLibModule = LoadLibraryFromSystemDir(_T("newdev.dll"))))
  472. {
  473. Win32MsgSetHrGotoCleanup(GetLastError());
  474. }
  475. if (NULL == (pfnInstallWindowsUpdateDriver = (PFN_InstallWindowsUpdateDriver)GetProcAddress(hLibModule,"InstallWindowsUpdateDriver")))
  476. {
  477. Win32MsgSetHrGotoCleanup(GetLastError());
  478. }
  479. // Industry Update RAID # 461 waltw May need to massage HWID's for site Driver Install for Win2K
  480. //
  481. // Linked to: RAID # 12021 in Windows Update Database - This logic (required for Win2K) is implemented
  482. // on the server rather than the client in IU (V3 Wuv3is implements this on the client)
  483. //
  484. // first, we search for a matching SPDRP_HARDWAREID
  485. // if we didn't find a Hardware ID, we search for a matching SPDRP_COMPATIBLEID,
  486. // and we pass the last SPDRP_HARDWAREID associated with the same device.
  487. #if (defined(UNICODE) || defined(_UNICODE))
  488. LOG_Driver (_T("InstallWindowsUpdateDriver(GetActiveWindow(), %s, %s, %s, fForce=%d, fBackup=%d)"),
  489. pszHardwareID, pszLocalDir, pszDisplayName, FALSE, TRUE);
  490. #endif
  491. //
  492. // NOTES on calling InstallWindowsUpdateDriver():
  493. // * Never pass TRUE in Force flag (only used if we are doing uninstall, which we don't support).
  494. // * Always pass TRUE in Backup flag.
  495. // * OK to cast away const-ness on strings since InstallWindowsUpdateDriver takes const wide strings
  496. if(!(pfnInstallWindowsUpdateDriver)(GetActiveWindow(),
  497. T2OLE(const_cast<TCHAR*>(pszHardwareID)),
  498. T2OLE(const_cast<TCHAR*>(pszLocalDir)),
  499. T2OLE(const_cast<TCHAR*>(pszDisplayName)), FALSE, TRUE, pdwReboot))
  500. {
  501. LOG_Driver(_T("InstallWindowsUpdateDriver returned false. Driver was not be updated."));
  502. Win32MsgSetHrGotoCleanup(GetLastError());
  503. }
  504. CleanUp:
  505. if (NULL != hLibModule)
  506. {
  507. FreeLibrary(hLibModule);
  508. hLibModule = NULL;
  509. }
  510. return hr;
  511. }
  512. //
  513. // MatchHardwareID (used only on Windows 2000)
  514. //
  515. // Takes as input a hardware or compatible ID and returns an allocated
  516. // buffer with the same hardware ID or, if it was a compatible ID the
  517. // most general hardware ID for the device node that matched the
  518. // given compatible ID.
  519. //
  520. // Return: S_OK if a match was found, else a failure code
  521. //
  522. // *ppszMatchingHWID must be NULL on entry, and if S_OK is returned
  523. // the buffer must be heap-freed by the caller.
  524. //
  525. HRESULT MatchHardwareID(LPCWSTR pwszHwOrCompatID, LPWSTR * ppszMatchingHWID)
  526. {
  527. LOG_Block("MatchHardwareID");
  528. HRESULT hr = E_FAIL;
  529. SP_DEVINFO_DATA DeviceInfoData;
  530. DWORD dwIndex = 0;
  531. DWORD dwSize = 0;
  532. LPWSTR pwszHardwareIDList = NULL;
  533. LPWSTR pwszCompatibleIDList = NULL;
  534. LPWSTR pwszSingleID = NULL;
  535. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  536. BOOL fRet;
  537. ZeroMemory((void*)&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
  538. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  539. if (NULL == pwszHwOrCompatID || NULL == ppszMatchingHWID || NULL != *ppszMatchingHWID)
  540. {
  541. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  542. }
  543. // get a handle to the class devices
  544. hDevInfo = SetupDiGetClassDevs(NULL,
  545. NULL,
  546. GetActiveWindow(),
  547. DIGCF_ALLCLASSES | DIGCF_PRESENT
  548. );
  549. if (INVALID_HANDLE_VALUE == hDevInfo)
  550. {
  551. Win32MsgSetHrGotoCleanup(ERROR_INVALID_HANDLE);
  552. }
  553. //loop through all devices
  554. DWORD dwBufLen=0;
  555. while ((NULL == *ppszMatchingHWID) && SetupDiEnumDeviceInfo(hDevInfo,
  556. dwIndex++,
  557. &DeviceInfoData
  558. ))
  559. {
  560. //
  561. // Free up buffers for each device node loop (if allocated)
  562. //
  563. SafeHeapFree(pwszHardwareIDList);
  564. SafeHeapFree(pwszCompatibleIDList);
  565. dwSize = 0;
  566. //
  567. // Get the list of Hardware Ids for this device
  568. //
  569. fRet = SetupDiGetDeviceRegistryPropertyW(hDevInfo,
  570. &DeviceInfoData,
  571. SPDRP_HARDWAREID,
  572. NULL,
  573. NULL,
  574. 0,
  575. &dwSize
  576. );
  577. if (0 == dwSize || (FALSE == fRet && ERROR_INSUFFICIENT_BUFFER != GetLastError()))
  578. {
  579. //
  580. // FIX: NTRAID#NTBUG9-500223-2001/11/28- IU - Dual mode USB camera install fails while installing of web site
  581. //
  582. // If we hit a node without a HWID before finding device node we are looking for, just continue. If the node
  583. // we ARE looking for doesn't have a HWID then we will fail later anyway when we run out of nodes.
  584. //
  585. LOG_Out(_T("No HWID's found for device node"));
  586. continue;
  587. }
  588. if (MAX_SETUP_MULTI_SZ_SIZE_W < dwSize)
  589. {
  590. //
  591. // Something is very wrong - bail
  592. //
  593. CleanUpIfFailedAndSetHrMsg(ERROR_INSUFFICIENT_BUFFER);
  594. }
  595. //
  596. // We got the expected ERROR_INSUFFICIENT_BUFFER with a reasonable dwSize
  597. //
  598. // Now guarantee we are double-NULL terminated by allocating two extra WCHARs we don't tell SetupDi about
  599. //
  600. pwszHardwareIDList = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + (sizeof(WCHAR) * 2));
  601. CleanUpFailedAllocSetHrMsg(pwszHardwareIDList);
  602. if (SetupDiGetDeviceRegistryPropertyW(hDevInfo,
  603. &DeviceInfoData,
  604. SPDRP_HARDWAREID,
  605. NULL,
  606. (PBYTE)pwszHardwareIDList,
  607. dwSize,
  608. &dwSize
  609. ))
  610. {
  611. //
  612. // If any of the devices HardwareIDs match the input ID then
  613. // we copy the incoming argument to a new buffer and return true
  614. //
  615. for (pwszSingleID = pwszHardwareIDList;
  616. *pwszSingleID;
  617. pwszSingleID += lstrlenW(pwszSingleID) + 1)
  618. {
  619. if (0 == lstrcmpiW(pwszSingleID, pwszHwOrCompatID))
  620. {
  621. // return the hardware ID we matched
  622. dwBufLen=(lstrlenW(pwszHwOrCompatID) + 1);
  623. *ppszMatchingHWID = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  624. dwBufLen * sizeof(WCHAR));
  625. CleanUpFailedAllocSetHrMsg(*ppszMatchingHWID);
  626. hr=StringCchCopyExW(*ppszMatchingHWID,dwBufLen,pwszHwOrCompatID,NULL,NULL,MISTSAFE_STRING_FLAGS);
  627. goto CleanUp;
  628. }
  629. }
  630. }
  631. //
  632. // Hardware match not found, let's try to match to a
  633. // compatible ID then return the (most generic) Hardware ID
  634. // associated with the same device node
  635. //
  636. fRet = SetupDiGetDeviceRegistryPropertyW(hDevInfo,
  637. &DeviceInfoData,
  638. SPDRP_COMPATIBLEIDS,
  639. NULL,
  640. NULL,
  641. 0,
  642. &dwSize
  643. );
  644. if (0 == dwSize || (FALSE == fRet && ERROR_INSUFFICIENT_BUFFER != GetLastError()))
  645. {
  646. LOG_Out(_T("No Compatible ID's found for device node"));
  647. continue;
  648. }
  649. if (MAX_SETUP_MULTI_SZ_SIZE_W < dwSize)
  650. {
  651. //
  652. // Something is very wrong - bail
  653. //
  654. CleanUpIfFailedAndSetHrMsg(ERROR_INSUFFICIENT_BUFFER);
  655. }
  656. //
  657. // We got the expected ERROR_INSUFFICIENT_BUFFER with a reasonable dwSize
  658. //
  659. // Now guarantee we are double-NULL terminated by allocating two extra WCHARs we don't tell SetupDi about
  660. //
  661. pwszCompatibleIDList = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + (sizeof(WCHAR) * 2));
  662. CleanUpFailedAllocSetHrMsg(pwszCompatibleIDList);
  663. if (SetupDiGetDeviceRegistryPropertyW(hDevInfo,
  664. &DeviceInfoData,
  665. SPDRP_COMPATIBLEIDS,
  666. NULL,
  667. (PBYTE)pwszCompatibleIDList,
  668. dwSize,
  669. &dwSize
  670. ))
  671. {
  672. for (pwszSingleID = pwszCompatibleIDList;
  673. *pwszSingleID;
  674. pwszSingleID += lstrlenW(pwszSingleID) + 1)
  675. {
  676. if (0 == lstrcmpiW(pwszSingleID, pwszHwOrCompatID))
  677. {
  678. //
  679. // We found a compatible match, now return the most general HWID
  680. // for this device node. Must be at least one character long.
  681. //
  682. if (NULL != pwszHardwareIDList && NULL != *pwszHardwareIDList)
  683. {
  684. LPWSTR lpwszLastID = NULL;
  685. for(pwszSingleID = pwszHardwareIDList;
  686. *pwszSingleID;
  687. pwszSingleID += lstrlenW(pwszSingleID) + 1)
  688. {
  689. //
  690. // Remember last ID before NULL string
  691. //
  692. lpwszLastID = pwszSingleID;
  693. }
  694. // copy the last HWID into a new buffer
  695. dwBufLen=(lstrlenW(lpwszLastID) + 1);
  696. *ppszMatchingHWID = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
  697. dwBufLen * sizeof(WCHAR));
  698. CleanUpFailedAllocSetHrMsg(*ppszMatchingHWID);
  699. hr=StringCchCopyExW(*ppszMatchingHWID,dwBufLen,lpwszLastID,NULL,NULL,MISTSAFE_STRING_FLAGS);
  700. goto CleanUp;
  701. }
  702. }
  703. }
  704. }
  705. } // end while
  706. CleanUp:
  707. if (INVALID_HANDLE_VALUE != hDevInfo)
  708. {
  709. SetupDiDestroyDeviceInfoList(hDevInfo);
  710. }
  711. //
  712. // Free up any allocated buffers (except *ppszMatchingHWID)
  713. //
  714. if(FAILED(hr))
  715. {
  716. SafeHeapFree(*ppszMatchingHWID);
  717. }
  718. SafeHeapFree(pwszHardwareIDList);
  719. SafeHeapFree(pwszCompatibleIDList);
  720. return hr;
  721. }
  722. //This function handles installation of a Device driver package.
  723. HRESULT InstallDriver(
  724. LPCTSTR pszLocalDir, // Local directory where installation files are.
  725. LPCTSTR pszDisplayName, // Description of package, Device Manager displays this in its install dialog.
  726. LPCTSTR pszHardwareID, // ID from XML matched to client hardware via GetManifest()
  727. DWORD* pdwStatus
  728. )
  729. {
  730. LOG_Block("InstallDriver");
  731. USES_IU_CONVERSION;
  732. HRESULT hr;
  733. OSVERSIONINFO osvi;
  734. DWORD dwReboot = 0;
  735. LPWSTR pszwMatchingHWID = NULL;
  736. if (NULL == pszLocalDir || NULL == pszDisplayName || NULL == pszHardwareID || NULL == pdwStatus)
  737. {
  738. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  739. }
  740. //
  741. // DecompressFolderCabs may return S_FALSE if it didn't find a cab to decompress...
  742. //
  743. hr = DecompressFolderCabs(pszLocalDir);
  744. if (S_OK != hr)
  745. {
  746. CleanUpIfFailedAndSetHr(E_FAIL);
  747. }
  748. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  749. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  750. GetVersionEx(&osvi);
  751. if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && 4 < osvi.dwMajorVersion)
  752. {
  753. //
  754. // Win2K or higher NT
  755. //
  756. if (5 == osvi.dwMajorVersion && 0 == osvi.dwMinorVersion)
  757. {
  758. //
  759. // Windows 2000
  760. // NTBUG9-485554 Convert compatible IDs to hardware IDs for site Driver Install for Win2K
  761. //
  762. // OK to cast away const-ness on string params so T2OLE works, since it doesn't modify them anyway
  763. CleanUpIfFailedAndSetHr(MatchHardwareID(T2OLE((LPTSTR)pszHardwareID), &pszwMatchingHWID));
  764. hr = InstallNT(OLE2T(pszwMatchingHWID), pszLocalDir, pszDisplayName, &dwReboot);
  765. // pszMatchingHWID must be non-null if we got here
  766. SafeHeapFree(pszwMatchingHWID);
  767. }
  768. else
  769. {
  770. //
  771. // Normal case, just install
  772. //
  773. CleanUpIfFailedAndSetHr(InstallNT(pszHardwareID, pszLocalDir, pszDisplayName, &dwReboot));
  774. }
  775. }
  776. else if (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId &&
  777. (4 < osvi.dwMajorVersion) ||
  778. ( (4 == osvi.dwMajorVersion) &&
  779. (0 < osvi.dwMinorVersion) ) )
  780. {
  781. //
  782. // Win98 or higher (WinME)
  783. //
  784. CleanUpIfFailedAndSetHr(Install98(pszHardwareID, pszLocalDir, pszDisplayName, &dwReboot));
  785. }
  786. else
  787. {
  788. *pdwStatus = ITEM_STATUS_FAILED;
  789. SetHrMsgAndGotoCleanUp(E_NOTIMPL);
  790. }
  791. if (DI_NEEDRESTART & dwReboot || DI_NEEDREBOOT & dwReboot)
  792. *pdwStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED;
  793. else
  794. *pdwStatus = ITEM_STATUS_SUCCESS;
  795. CleanUp:
  796. if (FAILED(hr))
  797. {
  798. if (NULL != pdwStatus)
  799. {
  800. *pdwStatus = ITEM_STATUS_FAILED;
  801. }
  802. }
  803. return hr;
  804. }