Leaked source code of windows server 2003
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.

3157 lines
106 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: init.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "newdevp.h"
  11. #include "pnpipc.h"
  12. HMODULE hNewDev = NULL;
  13. BOOL bQueuedRebootNeeded = FALSE;
  14. BOOL GuiSetupInProgress = FALSE;
  15. HANDLE hTrayIconWnd = NULL;
  16. BOOL
  17. DllInitialize(
  18. IN PVOID hmod,
  19. IN ULONG ulReason,
  20. IN PCONTEXT pctx OPTIONAL
  21. )
  22. {
  23. UNREFERENCED_PARAMETER(pctx);
  24. hNewDev = hmod;
  25. UNREFERENCED_PARAMETER(pctx);
  26. switch (ulReason) {
  27. case DLL_PROCESS_ATTACH:
  28. DisableThreadLibraryCalls(hmod);
  29. if (!SHFusionInitializeFromModule(hmod)) {
  30. return FALSE;
  31. }
  32. IntializeDeviceMapInfo();
  33. GuiSetupInProgress = GetGuiSetupInProgress();
  34. LoadString(hNewDev,
  35. IDS_UNKNOWN,
  36. (PTCHAR)szUnknown,
  37. SIZECHARS(szUnknown)
  38. );
  39. LoadString(hNewDev,
  40. IDS_UNKNOWNDEVICE,
  41. (PTCHAR)szUnknownDevice,
  42. SIZECHARS(szUnknownDevice)
  43. );
  44. hSrClientDll = NULL;
  45. break;
  46. case DLL_PROCESS_DETACH:
  47. SHFusionUninitialize();
  48. break;
  49. }
  50. return TRUE;
  51. }
  52. BOOL
  53. pInstallDeviceInstanceNewDevice(
  54. HWND hwndParent,
  55. HWND hBalloonTiphWnd,
  56. PNEWDEVWIZ NewDevWiz
  57. )
  58. {
  59. ULONG DevNodeStatus = 0, Problem = 0;
  60. SP_DRVINFO_DATA DriverInfoData;
  61. SP_DRVINSTALL_PARAMS DriverInstallParams;
  62. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  63. BOOL bHaveDriver = TRUE;
  64. //
  65. // Set the DI_QUIETINSTALL flag for the Found New Hardware case
  66. //
  67. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  68. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  69. &NewDevWiz->DeviceInfoData,
  70. &DeviceInstallParams
  71. )) {
  72. DeviceInstallParams.Flags |= DI_QUIETINSTALL;
  73. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  74. &NewDevWiz->DeviceInfoData,
  75. &DeviceInstallParams
  76. );
  77. }
  78. //
  79. // Do a driver search by searching the default INF locations.
  80. //
  81. DoDriverSearch(hwndParent,
  82. NewDevWiz,
  83. SEARCH_DEFAULT,
  84. SPDIT_COMPATDRIVER,
  85. FALSE
  86. );
  87. //
  88. // Check if the Windows Update cache says it has a better driver if we are
  89. // connected to the Internet.
  90. //
  91. if (IsConnectedToInternet() &&
  92. SearchWindowsUpdateCache(NewDevWiz)) {
  93. //
  94. // The machine is connected to the Internet and the WU cache says it has
  95. // a better driver, so let's connect to the Internet and download this
  96. // driver from WU.
  97. //
  98. DoDriverSearch(hwndParent,
  99. NewDevWiz,
  100. SEARCH_INET,
  101. SPDIT_COMPATDRIVER,
  102. TRUE
  103. );
  104. }
  105. //
  106. // Lets see if we found a driver for this device.
  107. //
  108. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  109. if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo,
  110. &NewDevWiz->DeviceInfoData,
  111. &DriverInfoData
  112. )) {
  113. if (FAILED(StringCchCopy(NewDevWiz->DriverDescription,
  114. SIZECHARS(NewDevWiz->DriverDescription),
  115. DriverInfoData.Description))) {
  116. NewDevWiz->DriverDescription[0] = TEXT('\0');
  117. }
  118. //
  119. // fetch rank of driver found.
  120. //
  121. DriverInstallParams.cbSize = sizeof(DriverInstallParams);
  122. if (!SetupDiGetDriverInstallParams(NewDevWiz->hDeviceInfo,
  123. &NewDevWiz->DeviceInfoData,
  124. &DriverInfoData,
  125. &DriverInstallParams
  126. )) {
  127. DriverInstallParams.Rank = (DWORD)-1;
  128. }
  129. //
  130. // If we have a balloon tip window then have it update its UI.
  131. //
  132. if (hBalloonTiphWnd) {
  133. //
  134. // We have a new driver description for this device so use this to update the balloon
  135. // tip.
  136. //
  137. PostMessage(hBalloonTiphWnd,
  138. WUM_UPDATEUI,
  139. 0,
  140. (LPARAM)NewDevWiz->DriverDescription
  141. );
  142. } else if (NewDevWiz->Flags & IDI_FLAG_SECONDNEWDEVINSTANCE) {
  143. //
  144. // This is the second NEWDEV.DLL instance running with Administrator privileges. We need
  145. // to send a message to the main NEWDEV.DLL process and have it update it's balloon tooltip.
  146. //
  147. SendMessageToUpdateBalloonInfo(NewDevWiz->DriverDescription);
  148. }
  149. } else {
  150. *NewDevWiz->DriverDescription = L'\0';
  151. DriverInstallParams.Rank = (DWORD)-1;
  152. DriverInstallParams.Flags = 0;
  153. bHaveDriver = FALSE;
  154. //
  155. // If we have a balloon tip window then have it update its UI.
  156. //
  157. if (hBalloonTiphWnd) {
  158. //
  159. // We don't have a driver description, most likely because we didn't find a driver for this device,
  160. // so just update the balloon text using the DeviceInstanceId.
  161. //
  162. PostMessage(hBalloonTiphWnd,
  163. WUM_UPDATEUI,
  164. (WPARAM)TIP_LPARAM_IS_DEVICEINSTANCEID,
  165. (LPARAM)NewDevWiz->InstallDeviceInstanceId
  166. );
  167. }
  168. }
  169. //
  170. // Get the status of this devnode
  171. //
  172. CM_Get_DevNode_Status(&DevNodeStatus,
  173. &Problem,
  174. NewDevWiz->DeviceInfoData.DevInst,
  175. 0
  176. );
  177. //
  178. // If we have a Hardware ID match and the selected (best) driver is not
  179. // listed as InteractiveInstall in the INF then just install the driver
  180. // for this device.
  181. //
  182. if ((DriverInstallParams.Rank <= DRIVER_HARDWAREID_RANK) &&
  183. (!IsDriverNodeInteractiveInstall(NewDevWiz, &DriverInfoData))) {
  184. NewDevWiz->SilentMode = TRUE;
  185. DoDeviceWizard(hwndParent, NewDevWiz, FALSE);
  186. //
  187. // Install any new child devices that have come online due to the installation
  188. // of this device. If there are any then install them silently.
  189. //
  190. if (!(NewDevWiz->Capabilities & CM_DEVCAP_SILENTINSTALL)) {
  191. InstallSilentChilds(hwndParent, NewDevWiz);
  192. }
  193. } else if (!bHaveDriver &&
  194. (NewDevWiz->Capabilities & CM_DEVCAP_RAWDEVICEOK) &&
  195. (NewDevWiz->Capabilities & CM_DEVCAP_SILENTINSTALL) &&
  196. (DevNodeStatus & DN_STARTED)) {
  197. //
  198. // If the device is both RAW, silent install, and already started,
  199. // and we didn't find any drivers, then we just want to
  200. // install the NULL driver.
  201. //
  202. InstallNullDriver(NewDevWiz, FALSE);
  203. } else {
  204. //
  205. // This is the case where we don't have a hardware ID match and we don't have a special
  206. // RAW, silent, started device. So in this case we will bring up the Found New Hardware
  207. // Wizard so the user can install a driver for this device.
  208. //
  209. //
  210. // If we have a balloon tip window then hide it.
  211. //
  212. if (hBalloonTiphWnd) {
  213. PostMessage(hBalloonTiphWnd,
  214. WUM_UPDATEUI,
  215. (WPARAM)TIP_HIDE_BALLOON,
  216. 0
  217. );
  218. }
  219. //
  220. // We are bringing up the wizard, so clear the DI_QUIETINSTALL flag.
  221. //
  222. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  223. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  224. &NewDevWiz->DeviceInfoData,
  225. &DeviceInstallParams
  226. )) {
  227. DeviceInstallParams.Flags &= ~DI_QUIETINSTALL;
  228. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  229. &NewDevWiz->DeviceInfoData,
  230. &DeviceInstallParams
  231. );
  232. }
  233. //
  234. // Bring up the Found New Hardware Wizard
  235. //
  236. DoDeviceWizard(GetParent(hwndParent), NewDevWiz, TRUE);
  237. //
  238. // Install any new child devices that have come online due to the installation
  239. // of this device. If there are any then install them silently.
  240. //
  241. if (!(NewDevWiz->Capabilities & CM_DEVCAP_SILENTINSTALL)) {
  242. InstallSilentChilds(hwndParent, NewDevWiz);
  243. }
  244. }
  245. return (GetLastError() == ERROR_SUCCESS);
  246. }
  247. BOOL
  248. pInstallDeviceInstanceUpdateDevice(
  249. HWND hwndParent,
  250. PNEWDEVWIZ NewDevWiz
  251. )
  252. {
  253. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  254. //
  255. // We need to first check with the class/co-installers to give them the
  256. // change to bring up their own update driver UI. This needs to be done
  257. // because there are some cases when our default behavior can cause the
  258. // device not to work. This only currently happens in the multiple
  259. // identical device case.
  260. //
  261. if (SetupDiCallClassInstaller(DIF_UPDATEDRIVER_UI,
  262. NewDevWiz->hDeviceInfo,
  263. &NewDevWiz->DeviceInfoData
  264. ) ||
  265. (GetLastError() != ERROR_DI_DO_DEFAULT)) {
  266. //
  267. // If the class/co-installer returned NO_ERRROR, or some error other
  268. // than ERROR_DI_DO_DEFAULT then we will not display our default wizard.
  269. //
  270. return FALSE;
  271. }
  272. //
  273. // Jump directly into the Update Driver Wizard
  274. //
  275. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  276. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  277. &NewDevWiz->DeviceInfoData,
  278. &DeviceInstallParams
  279. ))
  280. {
  281. //
  282. // This shouldn't be a quiet install, since we are doing a normal Update Driver
  283. //
  284. DeviceInstallParams.Flags &= ~DI_QUIETINSTALL;
  285. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  286. &NewDevWiz->DeviceInfoData,
  287. &DeviceInstallParams
  288. );
  289. DoDeviceWizard(hwndParent, NewDevWiz, TRUE);
  290. }
  291. return (GetLastError() == ERROR_SUCCESS);
  292. }
  293. BOOL
  294. pInstallDeviceInstanceUpdateDeviceSilent(
  295. HWND hwndParent,
  296. PNEWDEVWIZ NewDevWiz
  297. )
  298. {
  299. ULONG SearchOptions;
  300. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  301. SP_DRVINFO_DATA DriverInfoData;
  302. if (NewDevWiz->UpdateDriverInfo &&
  303. NewDevWiz->UpdateDriverInfo->FromInternet) {
  304. //
  305. // Drivers are from the Internet (newdev API called from WU)
  306. //
  307. if (FAILED(StringCchCopy(NewDevWiz->BrowsePath,
  308. SIZECHARS(NewDevWiz->BrowsePath),
  309. NewDevWiz->UpdateDriverInfo->InfPathName))) {
  310. //
  311. // The path that was passed in was too large to fit in our buffer
  312. //
  313. SetLastError(ERROR_DI_BAD_PATH);
  314. return FALSE;
  315. }
  316. SearchOptions = SEARCH_WINDOWSUPDATE;
  317. } else {
  318. //
  319. // Normal app just telling us to update this device using the specified INF
  320. // or a driver rollback.
  321. //
  322. if (FAILED(StringCchCopy(NewDevWiz->SingleInfPath,
  323. SIZECHARS(NewDevWiz->SingleInfPath),
  324. NewDevWiz->UpdateDriverInfo->InfPathName))) {
  325. //
  326. // The path that was passed in was too large to fit in our buffer
  327. //
  328. SetLastError(ERROR_DI_BAD_PATH);
  329. return FALSE;
  330. }
  331. SearchOptions = SEARCH_SINGLEINF;
  332. }
  333. //
  334. // If this is not a Force install we want to compare the driver against
  335. // the currently installed driver. Note that we will only install the
  336. // device if it was found in the specified directory.
  337. //
  338. if (!(NewDevWiz->Flags & IDI_FLAG_FORCE)) {
  339. SearchOptions |= SEARCH_CURRENTDRIVER;
  340. }
  341. //
  342. // The silent update device code path always has the DI_QUIETINSTALL flag
  343. // set.
  344. //
  345. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  346. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  347. &NewDevWiz->DeviceInfoData,
  348. &DeviceInstallParams
  349. )) {
  350. DeviceInstallParams.Flags |= DI_QUIETINSTALL;
  351. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  352. &NewDevWiz->DeviceInfoData,
  353. &DeviceInstallParams
  354. );
  355. }
  356. //
  357. // Search the specified directory or INF for drivers
  358. //
  359. DoDriverSearch(hwndParent,
  360. NewDevWiz,
  361. SearchOptions,
  362. (NewDevWiz->Flags & IDI_FLAG_ROLLBACK) ?
  363. SPDIT_CLASSDRIVER : SPDIT_COMPATDRIVER,
  364. FALSE
  365. );
  366. //
  367. // At this point we should already have the best driver selected, but if this is
  368. // a driver rollback we want to select the driver node ourselves using the
  369. // DevDesc, ProviderName, and Mfg of the original driver installed on this device.
  370. // We need to do this because the driver that we rolled back might not be the best
  371. // driver node in this INF.
  372. //
  373. if ((NewDevWiz->Flags & IDI_FLAG_ROLLBACK) &&
  374. (NewDevWiz->UpdateDriverInfo->Description[0] != TEXT('\0')) &&
  375. (NewDevWiz->UpdateDriverInfo->MfgName[0] != TEXT('\0')) &&
  376. (NewDevWiz->UpdateDriverInfo->ProviderName[0] != TEXT('\0'))) {
  377. ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
  378. DriverInfoData.cbSize = sizeof(DriverInfoData);
  379. DriverInfoData.DriverType = SPDIT_CLASSDRIVER;
  380. DriverInfoData.Reserved = 0;
  381. if (FAILED(StringCchCopy(DriverInfoData.Description,
  382. SIZECHARS(DriverInfoData.Description),
  383. NewDevWiz->UpdateDriverInfo->Description)) ||
  384. FAILED(StringCchCopy(DriverInfoData.MfgName,
  385. SIZECHARS(DriverInfoData.MfgName),
  386. NewDevWiz->UpdateDriverInfo->MfgName)) ||
  387. FAILED(StringCchCopy(DriverInfoData.ProviderName,
  388. SIZECHARS(DriverInfoData.ProviderName),
  389. NewDevWiz->UpdateDriverInfo->ProviderName))) {
  390. //
  391. // If we somehow had strings in the registry that were too large for
  392. // setupapi's buffers, then just bail out now.
  393. //
  394. NewDevWiz->LastError = ERROR_NO_MORE_ITEMS;
  395. SetLastError(ERROR_NO_MORE_ITEMS);
  396. goto clean0;
  397. }
  398. SetupDiSetSelectedDriver(NewDevWiz->hDeviceInfo,
  399. &NewDevWiz->DeviceInfoData,
  400. &DriverInfoData
  401. );
  402. }
  403. //
  404. // Since we have UpdateDriverInfo and the caller specified a specfic InfPathName (whether
  405. // a full path to an INF or just the path where INFs live) then we want to verify
  406. // that the selected driver's INF lives in that specified path. If it does not then
  407. // do not automatically install it since that is not what the caller intended.
  408. //
  409. if (pVerifyUpdateDriverInfoPath(NewDevWiz)) {
  410. NewDevWiz->SilentMode = TRUE;
  411. //
  412. // Install the driver on this device.
  413. //
  414. DoDeviceWizard(hwndParent, NewDevWiz, FALSE);
  415. //
  416. // Quietly install any children of this device that are now present after bringing this
  417. // device online.
  418. //
  419. if (!NewDevWiz->UpdateDriverInfo ||
  420. !NewDevWiz->UpdateDriverInfo->FromInternet) {
  421. InstallSilentChilds(hwndParent, NewDevWiz);
  422. }
  423. } else {
  424. //
  425. // If we get to this point then that means that the best driver we found was
  426. // not found in the specified directory or INF. In this case we will not
  427. // install the best driver found and we'll set the appropriate error
  428. //
  429. NewDevWiz->LastError = ERROR_NO_MORE_ITEMS;
  430. SetLastError(ERROR_NO_MORE_ITEMS);
  431. }
  432. clean0:
  433. return (GetLastError() == ERROR_SUCCESS);
  434. }
  435. BOOL
  436. InstallDeviceInstance(
  437. HWND hwndParent,
  438. HWND hBalloonTiphWnd,
  439. LPCTSTR DeviceInstanceId,
  440. PDWORD pReboot,
  441. PUPDATEDRIVERINFO UpdateDriverInfo,
  442. DWORD Flags,
  443. DWORD InstallType,
  444. HMODULE *hCdmInstance,
  445. HANDLE *hCdmContext,
  446. PBOOL pbLogDriverNotFound,
  447. PBOOL pbSetRestorePoint
  448. )
  449. /*++
  450. Routine Description:
  451. This is the main function where most of the exported functions to install drivers end up
  452. after they do some preprocessing. This function will install or update the device
  453. depending on the parameters.
  454. Arguments:
  455. hwndParent - Window handle of the top-level window to use for any UI related
  456. to installing the device.
  457. hBalloonTiphWnd - Handle to the WNDPROC that does all of the new Balloon tip UI. This
  458. is currently only used in the NDWTYPE_FOUNDNEW case.
  459. DeviceInstanceId - Supplies the ID of the device instance. This is the registry
  460. path (relative to the Enum branch) of the device instance key.
  461. pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
  462. UpdateDriverInfo -
  463. Flags -
  464. IDI_FLAG_SILENTINSTALL - means the balloon tooltip will not be displayed
  465. IDI_FLAG_SECONDNEWDEVINSTANCE - means this is the second instance of newdev.dll
  466. that is running and the UI data should be sent
  467. over to the first instance of newdev.dll that
  468. is running.
  469. IDI_FLAG_NOBACKUP - Don't backup the old drivers.
  470. IDI_FLAG_READONLY_INSTALL - means the install is readonly (no file copy)
  471. IDI_FLAG_NONINTERACTIVE - Any UI will cause the API to fail.
  472. IDI_FLAG_ROLLBACK - set if we are doing a rollback
  473. IDI_FLAG_FORCE - set if we are to force install this driver, which means
  474. install it even if it is not better then the currently
  475. installed driver.
  476. IDI_FLAG_MANUALINSTALL - set if this is a manuall installed device.
  477. IDI_FLAG_SETRESTOREPOINT - set if we are to set a restore point if the
  478. drivers that are getting installed are not
  479. digitally signed. Currently we only set
  480. restore points if the INF, catalog, or one
  481. of the copied files is not signed.
  482. InstallType - There are currently three different install types.
  483. NDWTYPE_FOUNDNEW - used to install drivers on a brand new device.
  484. NDWTYPE_UPDATE - used to bring up the Update Driver Wizard.
  485. NDWTYPE_UPDATE_SILENT - used to silently update the drivers for a device. The Update Driver Wizard
  486. won't be dispalyed in this case.
  487. hCdmInstance - A pointer to a hmodule that will receive the handle of the CDM
  488. library when when and if we need to load it.
  489. hCdmContext - A pointer to a Cdm context handle that will receive the Cdm
  490. context handle if it is opened.
  491. pbLogDriverNotFound - pointer to a BOOL that receives information on whether or not we
  492. logged to Cdm.dll that we could not find a driver for this device.
  493. pbSetRestorePoint - pointer to a BOOL that is set to TRUE if we needed to set
  494. a system restore point because the drivers we were
  495. installing were not digitally signed. It is assumed that
  496. if the caller wants to know if we called SRSetRestorePoint
  497. then it is their responsiblity to call it again with
  498. END_NESTED_SYSTEM_CHANGE to end the restore point. If
  499. the caller does not want this responsibility then they
  500. should pass in NULL for this value and this function
  501. will handle calling SRSetRestorePoint with
  502. END_NESTED_SYSTEM_CHANGE.
  503. Return Value:
  504. BOOL TRUE for success (does not mean device was installed or updated),
  505. FALSE unexpected error. GetLastError returns the winerror code.
  506. --*/
  507. {
  508. ULONG ConfigFlag;
  509. NEWDEVWIZ NewDevWiz;
  510. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  511. CLOSE_CDM_CONTEXT_PROC pfnCloseCDMContext;
  512. if (pbSetRestorePoint) {
  513. *pbSetRestorePoint = FALSE;
  514. }
  515. //
  516. // ensure we have a device instance.
  517. //
  518. if (!DeviceInstanceId || !*DeviceInstanceId) {
  519. SetLastError(ERROR_INVALID_PARAMETER);
  520. return FALSE;
  521. }
  522. //
  523. // If the InstallType is NDWTYPE_UPDATE_SILENT then they must pass in
  524. // an UpdateDriverInfo structure
  525. //
  526. if ((InstallType == NDWTYPE_UPDATE_SILENT) && !UpdateDriverInfo) {
  527. SetLastError(ERROR_INVALID_PARAMETER);
  528. return FALSE;
  529. }
  530. memset(&NewDevWiz, 0, sizeof(NewDevWiz));
  531. NewDevWiz.InstallType = InstallType;
  532. NewDevWiz.SilentMode = FALSE;
  533. NewDevWiz.UpdateDriverInfo = UpdateDriverInfo;
  534. NewDevWiz.hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, hwndParent);
  535. if (NewDevWiz.hDeviceInfo == INVALID_HANDLE_VALUE) {
  536. return FALSE;
  537. }
  538. NewDevWiz.LastError = ERROR_SUCCESS;
  539. NewDevWiz.Flags = Flags;
  540. try {
  541. //
  542. // Set the PSPGF_NONINTERACTIVE SetupGlobalFlag if we are in NonInteractive
  543. // mode. This means that setupapi will fail if it needs to display any UI
  544. // at all.
  545. //
  546. if (Flags & IDI_FLAG_NONINTERACTIVE) {
  547. pSetupSetGlobalFlags(pSetupGetGlobalFlags() | PSPGF_NONINTERACTIVE);
  548. }
  549. NewDevWiz.DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  550. if (!SetupDiOpenDeviceInfo(NewDevWiz.hDeviceInfo,
  551. DeviceInstanceId,
  552. hwndParent,
  553. 0,
  554. &NewDevWiz.DeviceInfoData
  555. ))
  556. {
  557. NewDevWiz.LastError = GetLastError();
  558. goto IDIExit;
  559. }
  560. if (FAILED(StringCchCopy(NewDevWiz.InstallDeviceInstanceId,
  561. SIZECHARS(NewDevWiz.InstallDeviceInstanceId),
  562. DeviceInstanceId))) {
  563. NewDevWiz.LastError = ERROR_INVALID_DEVINST_NAME;
  564. goto IDIExit;
  565. }
  566. SetupDiSetSelectedDevice(NewDevWiz.hDeviceInfo, &NewDevWiz.DeviceInfoData);
  567. //
  568. // Get the ConfigFlags
  569. //
  570. if (SetupDiGetDeviceRegistryProperty(NewDevWiz.hDeviceInfo,
  571. &NewDevWiz.DeviceInfoData,
  572. SPDRP_CONFIGFLAGS,
  573. NULL,
  574. (PVOID)&ConfigFlag,
  575. sizeof(ConfigFlag),
  576. NULL) &&
  577. (ConfigFlag & CONFIGFLAG_MANUAL_INSTALL)) {
  578. NewDevWiz.Flags |= IDI_FLAG_MANUALINSTALL;
  579. }
  580. //
  581. // Get the device capabilities
  582. //
  583. if (!SetupDiGetDeviceRegistryProperty(NewDevWiz.hDeviceInfo,
  584. &NewDevWiz.DeviceInfoData,
  585. SPDRP_CAPABILITIES,
  586. NULL,
  587. (PVOID)&NewDevWiz.Capabilities,
  588. sizeof(NewDevWiz.Capabilities),
  589. NULL)) {
  590. NewDevWiz.Capabilities = 0;
  591. }
  592. //
  593. // initialize DeviceInstallParams
  594. //
  595. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  596. if (SetupDiGetDeviceInstallParams(NewDevWiz.hDeviceInfo,
  597. &NewDevWiz.DeviceInfoData,
  598. &DeviceInstallParams
  599. ))
  600. {
  601. DeviceInstallParams.Flags |= DI_SHOWOEM;
  602. DeviceInstallParams.hwndParent = hwndParent;
  603. //
  604. // If not manually installed, allow excluded drivers.
  605. //
  606. if (!(NewDevWiz.Flags & IDI_FLAG_MANUALINSTALL)) {
  607. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
  608. }
  609. SetupDiSetDeviceInstallParams(NewDevWiz.hDeviceInfo,
  610. &NewDevWiz.DeviceInfoData,
  611. &DeviceInstallParams
  612. );
  613. }
  614. else {
  615. NewDevWiz.LastError = GetLastError();
  616. goto IDIExit;
  617. }
  618. //
  619. // Set the ClassGuidSelected and ClassName field of NewDevWiz so we can have
  620. // the correct icon and class name for the device.
  621. //
  622. if (!IsEqualGUID(&NewDevWiz.DeviceInfoData.ClassGuid, &GUID_NULL)) {
  623. NewDevWiz.ClassGuidSelected = &NewDevWiz.DeviceInfoData.ClassGuid;
  624. if (!SetupDiClassNameFromGuid(NewDevWiz.ClassGuidSelected,
  625. NewDevWiz.ClassName,
  626. sizeof(NewDevWiz.ClassName),
  627. NULL
  628. )) {
  629. NewDevWiz.ClassGuidSelected = NULL;
  630. *(NewDevWiz.ClassName) = TEXT('\0');
  631. }
  632. }
  633. //
  634. // Create the CancelEvent in case the user wants to cancel out of the driver search
  635. //
  636. NewDevWiz.CancelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  637. //
  638. // At this point we have three different cases.
  639. //
  640. // 1) Normal Update Driver case - In this case we jump directly to the Update Driver wizard code
  641. // 2) Silent Update Driver case - This case is treated very similar to the new hardware case. We
  642. // will silently search for an updated driver in the given path or INF and if we find a (better)
  643. // driver then we will install it.
  644. // 3) Normal New Hardware case - In this case we will do an initial search for drivers with the only
  645. // UI being the balloon tip on the tray. If we can't find a driver for this device then we will
  646. // Jump into the wizard case.
  647. //
  648. //
  649. // For UPDATE, search all drivers, including old internet drivers
  650. //
  651. switch (NewDevWiz.InstallType) {
  652. case NDWTYPE_FOUNDNEW:
  653. pInstallDeviceInstanceNewDevice(hwndParent, hBalloonTiphWnd, &NewDevWiz);
  654. break;
  655. case NDWTYPE_UPDATE:
  656. pInstallDeviceInstanceUpdateDevice(hwndParent, &NewDevWiz);
  657. break;
  658. case NDWTYPE_UPDATE_SILENT:
  659. pInstallDeviceInstanceUpdateDeviceSilent(hwndParent, &NewDevWiz);
  660. break;
  661. }
  662. //
  663. // Cleanup
  664. //
  665. if (NewDevWiz.CancelEvent) {
  666. CloseHandle(NewDevWiz.CancelEvent);
  667. }
  668. //
  669. // Launch Help Center if we could not find a driver for this device.
  670. //
  671. if (NewDevWiz.LogDriverNotFound) {
  672. OpenCdmContextIfNeeded(&NewDevWiz.hCdmInstance,
  673. &NewDevWiz.hCdmContext
  674. );
  675. CdmLogDriverNotFound(NewDevWiz.hCdmInstance,
  676. NewDevWiz.hCdmContext,
  677. DeviceInstanceId,
  678. 0
  679. );
  680. //
  681. // Let the caller know that we logged to cdm.dll that a driver
  682. // was not found.
  683. //
  684. if (pbLogDriverNotFound) {
  685. *pbLogDriverNotFound = TRUE;
  686. } else {
  687. //
  688. // If the caller did not want to know if we logged a 'not found'
  689. // driver to cdm.dll then at this point we need to tell Cdm
  690. // to call help center with it's list of 'not found' drivers.
  691. //
  692. CdmLogDriverNotFound(NewDevWiz.hCdmInstance,
  693. NewDevWiz.hCdmContext,
  694. NULL,
  695. 0x00000002
  696. );
  697. }
  698. } else if (pbLogDriverNotFound) {
  699. *pbLogDriverNotFound = FALSE;
  700. }
  701. //
  702. // Let the caller know whether we had to set a system restore point or
  703. // not, if they want to know.
  704. //
  705. if (pbSetRestorePoint) {
  706. *pbSetRestorePoint = NewDevWiz.SetRestorePoint;
  707. } else if (NewDevWiz.SetRestorePoint) {
  708. //
  709. // If the caller did not want to know if we set a restore point and
  710. // we did set a restore point, then we need to END the restore point
  711. // by calling SRSetRestorePoint with END_NESTED_SYSTEM_CHANGE.
  712. //
  713. pSetSystemRestorePoint(FALSE, FALSE, 0);
  714. }
  715. //
  716. // copy out the reboot flags for the caller
  717. // or put up the restart dialog if caller didn't ask for the reboot flag
  718. //
  719. if (pReboot) {
  720. *pReboot = NewDevWiz.Reboot;
  721. }
  722. else if (NewDevWiz.Reboot) {
  723. RestartDialogEx(hwndParent, NULL, EWX_REBOOT, REASON_PLANNED_FLAG | REASON_HWINSTALL);
  724. }
  725. IDIExit:
  726. ;
  727. } except(NdwUnhandledExceptionFilter(GetExceptionInformation())) {
  728. NewDevWiz.LastError = RtlNtStatusToDosError(GetExceptionCode());
  729. }
  730. if (NewDevWiz.hDeviceInfo &&
  731. (NewDevWiz.hDeviceInfo != INVALID_HANDLE_VALUE)) {
  732. SetupDiDestroyDeviceInfoList(NewDevWiz.hDeviceInfo);
  733. NewDevWiz.hDeviceInfo = NULL;
  734. }
  735. //
  736. // If the caller wants the CdmInstance hmodule and context handle then pass
  737. // them back, otherwise close them.
  738. //
  739. if (hCdmContext) {
  740. *hCdmContext = NewDevWiz.hCdmContext;
  741. } else {
  742. //
  743. // The caller doesn't want the cdm context so close it if we have loaded
  744. // cdm.dll and opened a context.
  745. //
  746. if (NewDevWiz.hCdmInstance && NewDevWiz.hCdmContext) {
  747. pfnCloseCDMContext = (CLOSE_CDM_CONTEXT_PROC)GetProcAddress(NewDevWiz.hCdmInstance,
  748. "CloseCDMContext"
  749. );
  750. if (pfnCloseCDMContext) {
  751. pfnCloseCDMContext(NewDevWiz.hCdmContext);
  752. }
  753. }
  754. }
  755. if (hCdmInstance) {
  756. *hCdmInstance = NewDevWiz.hCdmInstance;
  757. } else {
  758. FreeLibrary(NewDevWiz.hCdmInstance);
  759. }
  760. //
  761. // Clear the PSPGF_NONINTERACTIVE SetupGlobalFlag
  762. //
  763. if (Flags & IDI_FLAG_NONINTERACTIVE) {
  764. pSetupSetGlobalFlags(pSetupGetGlobalFlags() &~ PSPGF_NONINTERACTIVE);
  765. }
  766. SetLastError(NewDevWiz.LastError);
  767. return NewDevWiz.LastError == ERROR_SUCCESS;
  768. }
  769. BOOL
  770. InstallDevInstEx(
  771. HWND hwndParent,
  772. LPCWSTR DeviceInstanceId,
  773. BOOL UpdateDriver,
  774. PDWORD pReboot,
  775. BOOL SilentInstall
  776. )
  777. /*++
  778. Routine Description:
  779. Exported Entry point from newdev.dll. Installs an existing Device Instance,
  780. and is invoked by Device Mgr to update a driver, or by Config mgr when a new
  781. device was found. In both cases the Device Instance exists in the registry.
  782. Arguments:
  783. hwndParent - Window handle of the top-level window to use for any UI related
  784. to installing the device.
  785. DeviceInstanceId - Supplies the ID of the device instance. This is the registry
  786. path (relative to the Enum branch) of the device instance key.
  787. UpdateDriver - TRUE only newer or higher rank drivers are installed.
  788. pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
  789. SilentInstall - TRUE means the "New Hardware Found" dialog will not be displayed
  790. Return Value:
  791. BOOL TRUE for success (does not mean device was installed or updated),
  792. FALSE unexpected error. GetLastError returns the winerror code.
  793. --*/
  794. {
  795. DWORD InstallType = UpdateDriver ? NDWTYPE_UPDATE : NDWTYPE_FOUNDNEW;
  796. //
  797. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  798. // to fail and set the last error to ERROR_IN_WOW64.
  799. //
  800. if (GetIsWow64()) {
  801. SetLastError(ERROR_IN_WOW64);
  802. return FALSE;
  803. }
  804. //
  805. // Verify that the process has sufficient Administrator privileges.
  806. //
  807. if (!pSetupIsUserAdmin()) {
  808. SetLastError(ERROR_ACCESS_DENIED);
  809. return FALSE;
  810. }
  811. //
  812. // Validate parameters
  813. //
  814. if ((DeviceInstanceId == NULL) ||
  815. (DeviceInstanceId[0] == TEXT('\0'))) {
  816. SetLastError(ERROR_INVALID_PARAMETER);
  817. return FALSE;
  818. }
  819. return InstallDeviceInstance(hwndParent,
  820. NULL,
  821. DeviceInstanceId,
  822. pReboot,
  823. NULL,
  824. IDI_FLAG_SETRESTOREPOINT |
  825. (SilentInstall ? IDI_FLAG_SILENTINSTALL : 0),
  826. InstallType,
  827. NULL,
  828. NULL,
  829. NULL,
  830. NULL
  831. );
  832. }
  833. BOOL
  834. InstallDevInst(
  835. HWND hwndParent,
  836. LPCWSTR DeviceInstanceId,
  837. BOOL UpdateDriver,
  838. PDWORD pReboot
  839. )
  840. {
  841. return InstallDevInstEx(hwndParent,
  842. DeviceInstanceId,
  843. UpdateDriver,
  844. pReboot,
  845. FALSE);
  846. }
  847. BOOL
  848. EnumAndUpgradeDevices(
  849. HWND hwndParent,
  850. LPCWSTR HardwareId,
  851. PUPDATEDRIVERINFO UpdateDriverInfo,
  852. DWORD Flags,
  853. PDWORD pReboot
  854. )
  855. {
  856. HDEVINFO hDevInfo;
  857. SP_DEVINFO_DATA DeviceInfoData;
  858. DWORD Index;
  859. DWORD Size;
  860. TCHAR DeviceIdList[REGSTR_VAL_MAX_HCID_LEN];
  861. LPWSTR SingleDeviceId;
  862. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  863. BOOL Match;
  864. BOOL Result = TRUE;
  865. BOOL NoSuchDevNode = TRUE;
  866. ULONG InstallFlags = Flags;
  867. DWORD SingleNeedsReboot;
  868. DWORD TotalNeedsReboot = 0;
  869. DWORD Err = ERROR_SUCCESS;
  870. int i, count;
  871. HKEY hKey;
  872. BOOL bSingleDeviceSetRestorePoint = FALSE;
  873. BOOL bSetRestorePoint = FALSE;
  874. count = 0;
  875. if (pReboot) {
  876. *pReboot = 0;
  877. }
  878. hDevInfo = SetupDiGetClassDevs(NULL,
  879. NULL,
  880. hwndParent,
  881. DIGCF_ALLCLASSES | DIGCF_PRESENT
  882. );
  883. if (INVALID_HANDLE_VALUE == hDevInfo) {
  884. return FALSE;
  885. }
  886. ZeroMemory(&DeviceInfoData, sizeof(DeviceInfoData));
  887. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  888. Index = 0;
  889. //
  890. // Enumerate through all of the devices until we hit an installation error
  891. // or we run out of devices
  892. //
  893. while (Result &&
  894. SetupDiEnumDeviceInfo(hDevInfo,
  895. Index++,
  896. &DeviceInfoData
  897. )) {
  898. Match = FALSE;
  899. for (i = 0; i < 2; i++) {
  900. ZeroMemory(DeviceIdList, sizeof(DeviceIdList));
  901. Size = sizeof(DeviceIdList);
  902. if (SetupDiGetDeviceRegistryProperty(hDevInfo,
  903. &DeviceInfoData,
  904. (i ? SPDRP_HARDWAREID : SPDRP_COMPATIBLEIDS),
  905. NULL,
  906. (PBYTE)DeviceIdList,
  907. Size,
  908. &Size
  909. )) {
  910. //
  911. // If any of the devices Hardware Ids or Compatible Ids match the given ID then
  912. // we have a match and need to upgrade the drivers on this device.
  913. //
  914. for (SingleDeviceId = DeviceIdList;
  915. *SingleDeviceId;
  916. SingleDeviceId += lstrlen(SingleDeviceId) + 1) {
  917. if (_wcsicmp(SingleDeviceId, HardwareId) == 0) {
  918. Match = TRUE;
  919. NoSuchDevNode = FALSE;
  920. break;
  921. }
  922. }
  923. }
  924. }
  925. //
  926. // If we have a match then install the drivers on this device instance
  927. //
  928. if (Match) {
  929. if (SetupDiGetDeviceInstanceId(hDevInfo,
  930. &DeviceInfoData,
  931. DeviceInstanceId,
  932. SIZECHARS(DeviceInstanceId),
  933. &Size
  934. )) {
  935. SingleNeedsReboot = 0;
  936. //
  937. // Since this API is used only by InstallWindowsUpdateDriver and
  938. // UpdateDriverForPlugAndPlayDevice then specifiy the NDWTYPE_UPDATE_SILENT
  939. // Flag. This will tell the device install code not to show the Found New Hardware
  940. // balloon tip in the tray and not to bring up the Update Driver Wizard if it can't
  941. // find a driver in the specified location.
  942. //
  943. Result = InstallDeviceInstance(hwndParent,
  944. NULL,
  945. DeviceInstanceId,
  946. &SingleNeedsReboot,
  947. UpdateDriverInfo,
  948. InstallFlags,
  949. NDWTYPE_UPDATE_SILENT,
  950. NULL,
  951. NULL,
  952. NULL,
  953. &bSingleDeviceSetRestorePoint
  954. );
  955. //
  956. // Save the last error code from the install. Since we will be
  957. // doing multiple installs we want to save any error codes that
  958. // we get so we will only reset the last error code if our saved
  959. // error is ERROR_SUCCESS.
  960. //
  961. if (!Result && (Err == ERROR_SUCCESS)) {
  962. Err = GetLastError();
  963. }
  964. count++;
  965. TotalNeedsReboot |= SingleNeedsReboot;
  966. //
  967. // We only want to backup the first device we install...not every one.
  968. //
  969. InstallFlags |= IDI_FLAG_NOBACKUP;
  970. //
  971. // If we just set a restore point when installing the last device
  972. // then clear the IDI_FLAG_SETRESTOREPOINT flag so we don't do
  973. // it for any of the other devices we install.
  974. //
  975. if (bSingleDeviceSetRestorePoint) {
  976. bSetRestorePoint = TRUE;
  977. InstallFlags &= ~IDI_FLAG_SETRESTOREPOINT;
  978. }
  979. //
  980. // If we performed a backup and this is not the first device, then we need to add
  981. // this devices DeviceInstanceId to the backup key.
  982. //
  983. if ((count > 1) &&
  984. (UpdateDriverInfo->BackupRegistryKey[0] != TEXT('\0'))) {
  985. DWORD cbData, cbTotalSize;
  986. PTSTR DeviceIdsBuffer;
  987. PTSTR p;
  988. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  989. UpdateDriverInfo->BackupRegistryKey,
  990. 0,
  991. KEY_READ | KEY_WRITE,
  992. &hKey) == ERROR_SUCCESS) {
  993. //
  994. // Lets see how big the DeviceInstanceIds buffer is so we can allocate enough
  995. // memory.
  996. //
  997. cbData = 0;
  998. if ((RegQueryValueEx(hKey,
  999. REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  1000. NULL,
  1001. NULL,
  1002. NULL,
  1003. &cbData
  1004. ) == ERROR_SUCCESS) &&
  1005. (cbData)) {
  1006. //
  1007. // Allocate a buffer large enough to hold the current list of DeviceInstanceIds,
  1008. // as well as the current DeviceInstanceId.
  1009. //
  1010. cbTotalSize = cbData + ((lstrlen(DeviceInstanceId) + 1) * sizeof(TCHAR));
  1011. DeviceIdsBuffer = malloc(cbTotalSize);
  1012. if (DeviceIdsBuffer) {
  1013. ZeroMemory(DeviceIdsBuffer, cbTotalSize);
  1014. if (RegQueryValueEx(hKey,
  1015. REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  1016. NULL,
  1017. NULL,
  1018. (LPBYTE)DeviceIdsBuffer,
  1019. &cbData) == ERROR_SUCCESS) {
  1020. for (p = DeviceIdsBuffer; *p; p+= (lstrlen(p) + 1)) {
  1021. ;
  1022. }
  1023. //
  1024. // p now points to the second terminating NULL character at the end of
  1025. // the MULTI_SZ buffer. This is where we'll put the new DeviceInstanceId.
  1026. //
  1027. lstrcpyn(p, DeviceInstanceId, lstrlen(DeviceInstanceId));
  1028. //
  1029. // Write the new string back into the registry.
  1030. //
  1031. RegSetValueEx(hKey,
  1032. REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  1033. 0,
  1034. REG_MULTI_SZ,
  1035. (LPBYTE)DeviceIdsBuffer,
  1036. cbTotalSize
  1037. );
  1038. }
  1039. free(DeviceIdsBuffer);
  1040. }
  1041. }
  1042. RegCloseKey(hKey);
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. SetupDiDestroyDeviceInfoList(hDevInfo);
  1049. //
  1050. // If we had to set a system restore point because one of the drivers we
  1051. // installed was not digitally signed, then at this point we need to call
  1052. // SRSetRestorePoint with END_NESTED_SYSTEM_CHANGE.
  1053. //
  1054. if (bSetRestorePoint) {
  1055. pSetSystemRestorePoint(FALSE, FALSE, 0);
  1056. }
  1057. //
  1058. // If the caller wants to handle the reboot themselves then pass the information
  1059. // back to them.
  1060. //
  1061. if (pReboot) {
  1062. *pReboot = TotalNeedsReboot;
  1063. }
  1064. //
  1065. // The caller did not specify a pointer to a Reboot DWORD so we will handle the
  1066. // rebooting ourselves if necessary
  1067. //
  1068. else {
  1069. if (TotalNeedsReboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
  1070. RestartDialogEx(hwndParent, NULL, EWX_REBOOT, REASON_PLANNED_FLAG | REASON_HWINSTALL);
  1071. }
  1072. }
  1073. //
  1074. // If NoSuchDevNode is TRUE then we were unable to match the specified Hardware ID against
  1075. // any of the devices on the system. In this case we will set the last error to
  1076. // ERROR_NO_SUCH_DEVINST.
  1077. //
  1078. if (NoSuchDevNode) {
  1079. Err = ERROR_NO_SUCH_DEVINST;
  1080. }
  1081. SetLastError(Err);
  1082. return (Err == ERROR_SUCCESS);
  1083. }
  1084. BOOL
  1085. pDoRollbackDriverCleanup(
  1086. LPCSTR RegistryKeyName,
  1087. PDELINFNODE pDelInfNodeHead
  1088. )
  1089. {
  1090. HKEY hKey, hSubKey;
  1091. DWORD Error;
  1092. DWORD cbData;
  1093. TCHAR ReinstallString[MAX_PATH];
  1094. PDELINFNODE pDelInfNodeCur;
  1095. if ((Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1096. REGSTR_PATH_REINSTALL,
  1097. 0,
  1098. DELETE | KEY_READ,
  1099. &hKey)) != ERROR_SUCCESS) {
  1100. SetLastError(Error);
  1101. return FALSE;
  1102. }
  1103. //
  1104. // Open up the subkey so we can get the ReinstallString which will give us the directory
  1105. // that we need to delete.
  1106. //
  1107. if (RegOpenKeyEx(hKey,
  1108. (PTSTR)RegistryKeyName,
  1109. 0,
  1110. KEY_READ,
  1111. &hSubKey) == ERROR_SUCCESS) {
  1112. cbData = sizeof(ReinstallString);
  1113. if (RegQueryValueEx(hSubKey,
  1114. REGSTR_VAL_REINSTALL_STRING,
  1115. NULL,
  1116. NULL,
  1117. (LPBYTE)ReinstallString,
  1118. &cbData) == ERROR_SUCCESS) {
  1119. //
  1120. // We have verified that this directory is a subdirectory of
  1121. // %windir%\system32\ReinstallBackups so let's delete it.
  1122. // Note that the string contains a foo.inf on the end, so strip that
  1123. // off first.
  1124. //
  1125. PTSTR p = _tcsrchr(ReinstallString, TEXT('\\'));
  1126. if (p) {
  1127. *p = 0;
  1128. RemoveCdmDirectory(ReinstallString);
  1129. }
  1130. }
  1131. RegCloseKey(hSubKey);
  1132. }
  1133. RegDeleteKey(hKey, (PTSTR)RegistryKeyName);
  1134. RegCloseKey(hKey);
  1135. //
  1136. // Now attempt to uninstall any 3rd party INFs that were just rolled
  1137. // back over. SetupUninstallOEMInf will fail if another device is still
  1138. // using this INF.
  1139. //
  1140. if (pDelInfNodeHead) {
  1141. for (pDelInfNodeCur = pDelInfNodeHead;
  1142. pDelInfNodeCur;
  1143. pDelInfNodeCur = pDelInfNodeCur->pNext) {
  1144. SetupUninstallOEMInf(pDelInfNodeCur->szInf,
  1145. 0,
  1146. NULL
  1147. );
  1148. }
  1149. }
  1150. return TRUE;
  1151. }
  1152. BOOL
  1153. RollbackDriver(
  1154. HWND hwndParent,
  1155. LPCSTR RegistryKeyName,
  1156. DWORD Flags,
  1157. PDWORD pReboot OPTIONAL
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Exported Entry point from newdev.dll. It is invoked by Windows Update to update a driver.
  1162. This function will scan through all of the devices on the machine and attempt to install
  1163. these drivers on any devices that match the given HardwareId.
  1164. Arguments:
  1165. hwndParent - Window handle of the top-level window to use for any UI related
  1166. to installing the device.
  1167. RegistryKeyName - This is a subkey of HKLM\Software\Microsoft\Windows\CurrentVersion\Reinstall
  1168. Flags - The following flags are defined:
  1169. ROLLBACK_FLAG_FORCE - Force the rollback even if it is not better than the current driver
  1170. ROLLBACK_FLAG_DO_CLEANUP - Do the necessary cleanup if the rollback was successful. This
  1171. includes deleting the registry key as well as deleting the backup directory.
  1172. pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
  1173. Return Value:
  1174. BOOL TRUE if driver rollback succeedes.
  1175. FALSE if no rollback occured.
  1176. GetLastError() will return one of the following values:
  1177. --*/
  1178. {
  1179. DWORD Error;
  1180. HKEY hKey;
  1181. TCHAR DriverRollbackKey[MAX_DEVICE_ID_LEN];
  1182. TCHAR ReinstallString[MAX_PATH];
  1183. DWORD InstallDeviceFlags;
  1184. DWORD cbData;
  1185. DWORD TotalNeedsReboot = 0, SingleNeedsReboot;
  1186. BOOL Result = FALSE;
  1187. BOOL bSingleDeviceSetRestorePoint = FALSE;
  1188. BOOL bSetRestorePoint = FALSE;
  1189. UPDATEDRIVERINFO UpdateDriverInfo;
  1190. LPTSTR DeviceInstanceIds = NULL;
  1191. LPTSTR p;
  1192. TCHAR CurrentlyInstalledInf[MAX_PATH];
  1193. DWORD cbSize;
  1194. PDELINFNODE pDelInfNodeHead = NULL, pDelInfNodeCur;
  1195. //
  1196. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  1197. // to fail and set the last error to ERROR_IN_WOW64.
  1198. //
  1199. if (GetIsWow64()) {
  1200. SetLastError(ERROR_IN_WOW64);
  1201. return FALSE;
  1202. }
  1203. //
  1204. // Verify that the process has sufficient Administrator privileges.
  1205. //
  1206. if (!pSetupIsUserAdmin()) {
  1207. SetLastError(ERROR_ACCESS_DENIED);
  1208. return FALSE;
  1209. }
  1210. if (!RegistryKeyName || (RegistryKeyName[0] == TEXT('\0'))) {
  1211. SetLastError(ERROR_INVALID_PARAMETER);
  1212. return FALSE;
  1213. }
  1214. if (Flags &~ ROLLBACK_BITS) {
  1215. SetLastError(ERROR_INVALID_FLAGS);
  1216. return FALSE;
  1217. }
  1218. if (FAILED(StringCchCopy(DriverRollbackKey, SIZECHARS(DriverRollbackKey), REGSTR_PATH_REINSTALL)) ||
  1219. FAILED(StringCchCat(DriverRollbackKey, SIZECHARS(DriverRollbackKey), TEXT("\\"))) ||
  1220. FAILED(StringCchCat(DriverRollbackKey, SIZECHARS(DriverRollbackKey), (PTSTR)RegistryKeyName))) {
  1221. //
  1222. // The RegistryKeyName the user passed in is too large to fit in our buffer
  1223. // which means they must have passed in a bad key name.
  1224. //
  1225. SetLastError(ERROR_INVALID_PARAMETER);
  1226. return FALSE;
  1227. }
  1228. if ((Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1229. DriverRollbackKey,
  1230. 0,
  1231. KEY_READ,
  1232. &hKey)) != ERROR_SUCCESS) {
  1233. //
  1234. // The registry key does not exist, the user probably passed us in a
  1235. // bad RegistryKeyName value.
  1236. //
  1237. SetLastError(Error);
  1238. return FALSE;
  1239. }
  1240. InstallDeviceFlags = (IDI_FLAG_NOBACKUP | IDI_FLAG_ROLLBACK);
  1241. if (Flags & ROLLBACK_FLAG_FORCE) {
  1242. InstallDeviceFlags |= IDI_FLAG_FORCE;
  1243. }
  1244. //
  1245. // Set the IDI_FLAG_SETRESTOREPOINT so if the driver we are rolling back
  1246. // to is not digitally signed then we will set a system restore point
  1247. // in case the user needs to rollback from the rollback.
  1248. //
  1249. InstallDeviceFlags |= IDI_FLAG_SETRESTOREPOINT;
  1250. ZeroMemory(&UpdateDriverInfo, sizeof(UpdateDriverInfo));
  1251. //
  1252. // Assume failure
  1253. //
  1254. UpdateDriverInfo.DriverWasUpgraded = FALSE;
  1255. //
  1256. // Read the "ReinstallString" string value. This contains the path to rollback the drivers
  1257. // from.
  1258. //
  1259. cbData = sizeof(ReinstallString);
  1260. if ((Error = RegQueryValueEx(hKey,
  1261. REGSTR_VAL_REINSTALL_STRING,
  1262. NULL,
  1263. NULL,
  1264. (LPBYTE)ReinstallString,
  1265. &cbData)) != ERROR_SUCCESS) {
  1266. //
  1267. // If we can't read the ReinstallString then we can't rollback any drivers!
  1268. //
  1269. SetLastError(Error);
  1270. goto clean0;
  1271. } else if (!cbData) {
  1272. //
  1273. // The ReinstallString value must contain something!
  1274. //
  1275. SetLastError(ERROR_INVALID_PARAMETER);
  1276. goto clean0;
  1277. }
  1278. UpdateDriverInfo.InfPathName = ReinstallString;
  1279. UpdateDriverInfo.FromInternet = FALSE;
  1280. //
  1281. // Get the DevDesc, ProviderName, and Mfg from the Reinstall registry key
  1282. // so we know which specific driver node to reinstall from this INF.
  1283. //
  1284. // We have to have a Description and a MfgName value, but there are rare
  1285. // cases where there might not be a ProviderName value.
  1286. //
  1287. cbData = sizeof(UpdateDriverInfo.Description);
  1288. if ((Error = RegQueryValueEx(hKey,
  1289. REGSTR_VAL_DEVDESC,
  1290. NULL,
  1291. NULL,
  1292. (LPBYTE)UpdateDriverInfo.Description,
  1293. &cbData
  1294. )) != ERROR_SUCCESS) {
  1295. SetLastError(Error);
  1296. goto clean0;
  1297. }
  1298. cbData = sizeof(UpdateDriverInfo.MfgName);
  1299. if ((Error = RegQueryValueEx(hKey,
  1300. REGSTR_VAL_MFG,
  1301. NULL,
  1302. NULL,
  1303. (LPBYTE)UpdateDriverInfo.MfgName,
  1304. &cbData
  1305. )) != ERROR_SUCCESS) {
  1306. SetLastError(Error);
  1307. goto clean0;
  1308. }
  1309. cbData = sizeof(UpdateDriverInfo.ProviderName);
  1310. Error = RegQueryValueEx(hKey,
  1311. REGSTR_VAL_PROVIDER_NAME,
  1312. NULL,
  1313. NULL,
  1314. (LPBYTE)UpdateDriverInfo.ProviderName,
  1315. &cbData
  1316. );
  1317. //
  1318. // For the ProviderName, it is valid if we get back FileNotFound because
  1319. // the value is not present in the registry, however any other error is
  1320. // not acceptable.
  1321. //
  1322. if (Error == ERROR_FILE_NOT_FOUND) {
  1323. UpdateDriverInfo.ProviderName[0] = TEXT('\0');
  1324. } else if (Error != ERROR_SUCCESS) {
  1325. SetLastError(Error);
  1326. goto clean0;
  1327. }
  1328. //
  1329. // We need to get the DeviceInstanceIds MULTI_SZ string. This will contain a list of
  1330. // DeviceInstanceIds that we need to rollback.
  1331. //
  1332. if ((Error = RegQueryValueEx(hKey,
  1333. REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  1334. NULL,
  1335. NULL,
  1336. NULL,
  1337. &cbData)) != ERROR_SUCCESS) {
  1338. SetLastError(Error);
  1339. goto clean0;
  1340. } else if (!cbData) {
  1341. //
  1342. // No DeviceInstanceIds to reinstall
  1343. //
  1344. SetLastError(ERROR_SUCCESS);
  1345. goto clean0;
  1346. }
  1347. DeviceInstanceIds = malloc(cbData + sizeof(TCHAR));
  1348. if (!DeviceInstanceIds) {
  1349. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1350. goto clean0;
  1351. }
  1352. ZeroMemory(DeviceInstanceIds, cbData + sizeof(TCHAR));
  1353. if ((Error = RegQueryValueEx(hKey,
  1354. REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  1355. NULL,
  1356. NULL,
  1357. (LPBYTE)DeviceInstanceIds,
  1358. &cbData)) != ERROR_SUCCESS) {
  1359. SetLastError(Error);
  1360. goto clean0;
  1361. }
  1362. //
  1363. // Enumerate through the list of DeviceInstanceIds and call InstallDeviceInstance() on
  1364. // each one.
  1365. //
  1366. for (p = DeviceInstanceIds; *p; p += lstrlen(p) + 1) {
  1367. SingleNeedsReboot = 0;
  1368. //
  1369. // We we are going to do the cleanup then we need to remember the INF files
  1370. // that were installed before we do the rollback.
  1371. //
  1372. if (Flags & ROLLBACK_FLAG_DO_CLEANUP) {
  1373. cbSize = sizeof(CurrentlyInstalledInf);
  1374. if (GetInstalledInf(0, p, CurrentlyInstalledInf, &cbSize) &&
  1375. IsInfFromOem(CurrentlyInstalledInf)) {
  1376. //
  1377. // Let's check to see if this Inf is already in our list
  1378. //
  1379. for (pDelInfNodeCur = pDelInfNodeHead;
  1380. pDelInfNodeCur;
  1381. pDelInfNodeCur = pDelInfNodeCur->pNext) {
  1382. if (!lstrcmpi(pDelInfNodeCur->szInf, CurrentlyInstalledInf)) {
  1383. break;
  1384. }
  1385. }
  1386. //
  1387. // if pDelInfNodeCur is NULL then that means we walked all the way
  1388. // through the linked list and did not find a match for the
  1389. // CurrentlyInstalledInf...so we will add a node.
  1390. //
  1391. if (!pDelInfNodeCur) {
  1392. pDelInfNodeCur = malloc(sizeof(DELINFNODE));
  1393. if (pDelInfNodeCur) {
  1394. if (SUCCEEDED(StringCchCopy(pDelInfNodeCur->szInf,
  1395. SIZECHARS(pDelInfNodeCur->szInf),
  1396. CurrentlyInstalledInf))) {
  1397. pDelInfNodeCur->pNext = pDelInfNodeHead;
  1398. pDelInfNodeHead = pDelInfNodeCur;
  1399. } else {
  1400. //
  1401. // This should never happen, but if we can't copy the name of
  1402. // the INF file into our local buffer so we know to delete
  1403. // it later, then free the buffer now since we won't
  1404. // be using it.
  1405. //
  1406. free(pDelInfNodeCur);
  1407. }
  1408. }
  1409. }
  1410. }
  1411. }
  1412. Result = InstallDeviceInstance(hwndParent,
  1413. NULL,
  1414. p,
  1415. &SingleNeedsReboot,
  1416. &UpdateDriverInfo,
  1417. InstallDeviceFlags,
  1418. NDWTYPE_UPDATE_SILENT,
  1419. NULL,
  1420. NULL,
  1421. NULL,
  1422. &bSingleDeviceSetRestorePoint
  1423. );
  1424. TotalNeedsReboot |= SingleNeedsReboot;
  1425. if (bSingleDeviceSetRestorePoint) {
  1426. bSetRestorePoint = TRUE;
  1427. InstallDeviceFlags &= ~IDI_FLAG_SETRESTOREPOINT;
  1428. }
  1429. //
  1430. // If we hit an installation error, bail out.
  1431. //
  1432. if (!Result) {
  1433. break;
  1434. }
  1435. }
  1436. clean0:
  1437. RegCloseKey(hKey);
  1438. if (DeviceInstanceIds) {
  1439. free(DeviceInstanceIds);
  1440. }
  1441. //
  1442. // If we were successful then lets see if the caller wants us to do the cleanup
  1443. //
  1444. if ((Flags & ROLLBACK_FLAG_DO_CLEANUP) &&
  1445. Result &&
  1446. UpdateDriverInfo.DriverWasUpgraded) {
  1447. pDoRollbackDriverCleanup(RegistryKeyName, pDelInfNodeHead);
  1448. }
  1449. //
  1450. // If we had to set a system restore point because one of the drivers we
  1451. // installed was not digitally signed, then at this point we need to call
  1452. // SRSetRestorePoint with END_NESTED_SYSTEM_CHANGE.
  1453. //
  1454. if (bSetRestorePoint) {
  1455. pSetSystemRestorePoint(FALSE, FALSE, 0);
  1456. }
  1457. //
  1458. // Free up any memory we allocated to store 3rd party Infs that we want to delete.
  1459. //
  1460. while (pDelInfNodeHead) {
  1461. pDelInfNodeCur = pDelInfNodeHead->pNext;
  1462. free(pDelInfNodeHead);
  1463. pDelInfNodeHead = pDelInfNodeCur;
  1464. }
  1465. //
  1466. // If the caller wants to handle the reboot themselves then pass the information
  1467. // back to them.
  1468. //
  1469. if (pReboot) {
  1470. *pReboot = TotalNeedsReboot;
  1471. } else {
  1472. //
  1473. // The caller did not specify a pointer to a Reboot DWORD so we will handle the
  1474. // rebooting ourselves if necessary
  1475. if (TotalNeedsReboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
  1476. RestartDialogEx(hwndParent, NULL, EWX_REBOOT, REASON_PLANNED_FLAG | REASON_HWINSTALL);
  1477. }
  1478. }
  1479. return UpdateDriverInfo.DriverWasUpgraded;
  1480. }
  1481. BOOL
  1482. InstallWindowsUpdateDriver(
  1483. HWND hwndParent,
  1484. LPCWSTR HardwareId,
  1485. LPCWSTR InfPathName,
  1486. LPCWSTR Reserved,
  1487. BOOL Force,
  1488. BOOL Backup,
  1489. PDWORD pReboot
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. Exported Entry point from newdev.dll. It is invoked by Windows Update to update a driver.
  1494. This function will scan through all of the devices on the machine and attempt to install
  1495. these drivers on any devices that match the given HardwareId.
  1496. Arguments:
  1497. hwndParent - Window handle of the top-level window to use for any UI related
  1498. to installing the device.
  1499. HardwareId - Supplies the Hardware ID to match agaist existing devices on the
  1500. system.
  1501. InfPathName - Inf Pathname and associated driver files.
  1502. Reserved - ignored, should be NULL.
  1503. Force - if TRUE this API will only look for infs in the directory specified by InfLocation.
  1504. Backup - if TRUE this API will backup the existing drivers before installing the drivers
  1505. from Windows Update.
  1506. pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
  1507. Return Value:
  1508. BOOL TRUE if a device was upgraded to a CDM driver.
  1509. FALSE if no devices were upgraded to a CDM driver. GetLastError()
  1510. will be ERROR_SUCCESS if nothing went wrong, this driver
  1511. simply wasn't for any devices on the machine or wasn't
  1512. better than the current driver. If GetLastError() returns
  1513. any other error then there was an error during the installation
  1514. of this driver.
  1515. --*/
  1516. {
  1517. UPDATEDRIVERINFO UpdateDriverInfo;
  1518. DWORD Flags = 0;
  1519. TCHAR FullyQualifiedInfPath[MAX_PATH];
  1520. WIN32_FIND_DATA finddata;
  1521. LPTSTR lpFilePart;
  1522. UNREFERENCED_PARAMETER(Reserved);
  1523. //
  1524. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  1525. // to fail and set the last error to ERROR_IN_WOW64.
  1526. //
  1527. if (GetIsWow64()) {
  1528. SetLastError(ERROR_IN_WOW64);
  1529. return FALSE;
  1530. }
  1531. //
  1532. // Verify that the process has sufficient Administrator privileges.
  1533. //
  1534. if (!pSetupIsUserAdmin()) {
  1535. SetLastError(ERROR_ACCESS_DENIED);
  1536. return FALSE;
  1537. }
  1538. //
  1539. // Validate the input paramters
  1540. //
  1541. if ((HardwareId == NULL) ||
  1542. (HardwareId[0] == TEXT('\0'))) {
  1543. SetLastError(ERROR_INVALID_PARAMETER);
  1544. return FALSE;
  1545. }
  1546. if ((InfPathName == NULL) ||
  1547. (InfPathName[0] == TEXT('\0'))) {
  1548. SetLastError(ERROR_INVALID_PARAMETER);
  1549. return FALSE;
  1550. }
  1551. //
  1552. // Make sure we get the fully qualified path and not a partial
  1553. // or relative path.
  1554. //
  1555. if (GetFullPathName(InfPathName,
  1556. SIZECHARS(FullyQualifiedInfPath),
  1557. FullyQualifiedInfPath,
  1558. &lpFilePart
  1559. ) == 0) {
  1560. SetLastError(ERROR_INVALID_PARAMETER);
  1561. return FALSE;
  1562. }
  1563. //
  1564. // Make sure that the FullyQualifiedInfPath exists and that it is
  1565. // a directory.
  1566. //
  1567. if (!FileExists(FullyQualifiedInfPath, &finddata) ||
  1568. !(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1569. SetLastError(ERROR_PATH_NOT_FOUND);
  1570. return FALSE;
  1571. }
  1572. ZeroMemory(&UpdateDriverInfo, sizeof(UpdateDriverInfo));
  1573. UpdateDriverInfo.InfPathName = FullyQualifiedInfPath;
  1574. UpdateDriverInfo.FromInternet = TRUE;
  1575. if (!Backup) {
  1576. Flags = IDI_FLAG_NOBACKUP;
  1577. }
  1578. if (Force) {
  1579. Flags = IDI_FLAG_FORCE;
  1580. }
  1581. //
  1582. // Assume that the upgrade will fail
  1583. //
  1584. UpdateDriverInfo.DriverWasUpgraded = FALSE;
  1585. //
  1586. // Call EnumAndUpgradeDevices which will enumerate through all the devices on the machine
  1587. // and for any that match the given hardware ID it will attempt to upgrade to the specified
  1588. // drivers.
  1589. //
  1590. EnumAndUpgradeDevices(hwndParent, HardwareId, &UpdateDriverInfo, Flags, pReboot);
  1591. return UpdateDriverInfo.DriverWasUpgraded;
  1592. }
  1593. BOOL
  1594. WINAPI
  1595. UpdateDriverForPlugAndPlayDevicesW(
  1596. HWND hwndParent,
  1597. LPCWSTR HardwareId,
  1598. LPCWSTR FullInfPath,
  1599. DWORD InstallFlags,
  1600. PBOOL bRebootRequired OPTIONAL
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This function will scan through all of the devices on the machine and attempt to install
  1605. the drivers in FullInfPath on any devices that match the given HardwareId. The default
  1606. behavior is to only install the specified drivers if the are better then the currently
  1607. installed driver.
  1608. Arguments:
  1609. hwndParent - Window handle of the top-level window to use for any UI related
  1610. to installing the device.
  1611. HardwareId - Supplies the Hardware ID to match agaist existing devices on the
  1612. system.
  1613. FullInfPath - Full path to an Inf and associated driver files.
  1614. InstallFlags - INSTALLFLAG_FORCE - If this flag is specified then newdev will not compare the
  1615. specified INF file with the current driver. The specified INF file and drivers
  1616. will always be installed unless an error occurs.
  1617. - INSTALLFALG_READONLY - if this flag is specified then newdev will attempt
  1618. a read-only install. This means that no file copy will be performed and
  1619. only the registry will be updated. Newdev.dll will do a presence check
  1620. on all of the files to verify that they are present first before
  1621. completing the install. If all of the files are not present then
  1622. ERROR_ACCESS_DENIED is returned.
  1623. - INSTALLFLAG_NONINTERACTIVE - absolutely no UI. If any UI needs to be displayed
  1624. then the API will fail!
  1625. pReboot - Optional address of BOOL to determine if a reboot is required or not.
  1626. If pReboot is NULL then newdev.dll will prompt for a reboot if one is needed. If
  1627. pReboot is a valid BOOL pointer then the reboot status is passed back to the
  1628. caller and it is the callers responsibility to prompt for a reboot if one is
  1629. needed.
  1630. Return Value:
  1631. BOOL TRUE if a device was upgraded to the specified driver.
  1632. FALSE if no devices were upgraded to the specified driver. GetLastError()
  1633. will be ERROR_SUCCESS if nothing went wrong, this driver
  1634. wasn't better than the current driver. If GetLastError() returns
  1635. any other error then there was an error during the installation
  1636. of this driver.
  1637. --*/
  1638. {
  1639. UPDATEDRIVERINFO UpdateDriverInfo;
  1640. DWORD NeedsReboot = 0;
  1641. TCHAR FullyQualifiedInfPath[MAX_PATH];
  1642. WIN32_FIND_DATA finddata;
  1643. LPTSTR lpFilePart;
  1644. DWORD Flags = 0;
  1645. //
  1646. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  1647. // to fail and set the last error to ERROR_IN_WOW64.
  1648. //
  1649. if (GetIsWow64()) {
  1650. SetLastError(ERROR_IN_WOW64);
  1651. return FALSE;
  1652. }
  1653. //
  1654. // Verify that the process has sufficient Administrator privileges.
  1655. //
  1656. if (!pSetupIsUserAdmin()) {
  1657. SetLastError(ERROR_ACCESS_DENIED);
  1658. return FALSE;
  1659. }
  1660. //
  1661. // Verify the parameters
  1662. //
  1663. if ((!HardwareId || (HardwareId[0] == TEXT('\0'))) ||
  1664. (!FullInfPath || (FullInfPath[0] == TEXT('\0')))) {
  1665. SetLastError(ERROR_INVALID_PARAMETER);
  1666. return FALSE;
  1667. }
  1668. if (InstallFlags &~ INSTALLFLAG_BITS) {
  1669. SetLastError(ERROR_INVALID_FLAGS);
  1670. return FALSE;
  1671. }
  1672. //
  1673. // Make sure we get the fully qualified path and not a partial path.
  1674. //
  1675. if (GetFullPathName(FullInfPath,
  1676. SIZECHARS(FullyQualifiedInfPath),
  1677. FullyQualifiedInfPath,
  1678. &lpFilePart
  1679. ) == 0) {
  1680. SetLastError(ERROR_INVALID_PARAMETER);
  1681. return FALSE;
  1682. }
  1683. //
  1684. // Make sure that the FullyQualifiedInfPath exists and that it is not
  1685. // a directory.
  1686. //
  1687. if (!FileExists(FullyQualifiedInfPath, &finddata) ||
  1688. (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1689. SetLastError(ERROR_FILE_NOT_FOUND);
  1690. return FALSE;
  1691. }
  1692. ZeroMemory(&UpdateDriverInfo, sizeof(UpdateDriverInfo));
  1693. UpdateDriverInfo.InfPathName = FullyQualifiedInfPath;
  1694. UpdateDriverInfo.FromInternet = FALSE;
  1695. //
  1696. // Assume that the upgrade will fail
  1697. //
  1698. UpdateDriverInfo.DriverWasUpgraded = FALSE;
  1699. //
  1700. // If the INSTALLFLAG_READONLY is set then we will set the internal
  1701. // IDI_FLAG_READONLY_INSTALL flag. The IDI_FLAG_NOBACKUP is also set since
  1702. // we don't want to attempt to backup files when doing a read-only
  1703. // install.
  1704. //
  1705. if (InstallFlags & INSTALLFLAG_READONLY) {
  1706. Flags |= (IDI_FLAG_READONLY_INSTALL | IDI_FLAG_NOBACKUP);
  1707. }
  1708. //
  1709. // If the INSTALLFLAG_NONINTERACTIVE flag is set then we will set the
  1710. // PSPGF_NONINTERACTIVE SetupGlobalFlag which tells setupapi to fail
  1711. // if any UI at all needs to be displayed.
  1712. //
  1713. if (InstallFlags & INSTALLFLAG_NONINTERACTIVE) {
  1714. Flags |= IDI_FLAG_NONINTERACTIVE;
  1715. }
  1716. //
  1717. // If the INSTALLFLAG_FORCE flag is set then we will set the
  1718. // IDI_FLAGS_FORCE flag which will tell us to not include the
  1719. // currently installed driver in our search for the best driver.
  1720. //
  1721. if (InstallFlags & INSTALLFLAG_FORCE) {
  1722. Flags |= IDI_FLAG_FORCE;
  1723. }
  1724. //
  1725. // Call EnumAndUpgradeDevices which will enumerate through all the devices on the machine
  1726. // and for any that match the given hardware ID it will attempt to upgrade to the specified
  1727. // drivers.
  1728. //
  1729. EnumAndUpgradeDevices(hwndParent, HardwareId, &UpdateDriverInfo, Flags, &NeedsReboot);
  1730. if (bRebootRequired) {
  1731. if (NeedsReboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
  1732. *bRebootRequired = TRUE;
  1733. } else {
  1734. *bRebootRequired = FALSE;
  1735. }
  1736. } else {
  1737. if (NeedsReboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
  1738. RestartDialogEx(hwndParent, NULL, EWX_REBOOT, REASON_PLANNED_FLAG | REASON_HWINSTALL);
  1739. }
  1740. }
  1741. return UpdateDriverInfo.DriverWasUpgraded;
  1742. }
  1743. BOOL
  1744. WINAPI
  1745. UpdateDriverForPlugAndPlayDevicesA(
  1746. HWND hwndParent,
  1747. LPCSTR HardwareId,
  1748. LPCSTR FullInfPath,
  1749. DWORD InstallFlags,
  1750. PBOOL bRebootRequired OPTIONAL
  1751. )
  1752. {
  1753. WCHAR UnicodeHardwareId[MAX_DEVICE_ID_LEN];
  1754. WCHAR UnicodeFullInfPath[MAX_PATH];
  1755. //
  1756. // Convert the HardwareId and FullInfPath to UNICODE and call
  1757. // InstallDriverForPlugAndPlayDevicesW
  1758. //
  1759. UnicodeHardwareId[0] = TEXT('\0');
  1760. UnicodeFullInfPath[0] = TEXT('\0');
  1761. MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, UnicodeHardwareId, SIZECHARS(UnicodeHardwareId));
  1762. MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, UnicodeFullInfPath, SIZECHARS(UnicodeFullInfPath));
  1763. return UpdateDriverForPlugAndPlayDevicesW(hwndParent,
  1764. UnicodeHardwareId,
  1765. UnicodeFullInfPath,
  1766. InstallFlags,
  1767. bRebootRequired
  1768. );
  1769. }
  1770. DWORD
  1771. WINAPI
  1772. DevInstallW(
  1773. HWND hwnd,
  1774. HINSTANCE hInst,
  1775. LPWSTR szCmd,
  1776. int nShow
  1777. )
  1778. /*++
  1779. Routine Description:
  1780. This function is called by newdev.dll itself when the current user is not an Admin.
  1781. UMPNPMGR.DLL calls NEWDEV.DLL ClientSideInstall to install devices. If the currently logged on
  1782. user does not have Administrator privilleges then NEWDEV.DLL prompts the user for an Administator
  1783. username and password. It then spawns another instance of newdev.dll using the
  1784. CreateProcessWithLogonW() API and calls this entry point. This entry point verifies that the
  1785. process has Administrator privileges and if it does it calls InstallDeviceInstance() to install
  1786. the device.
  1787. Arguments:
  1788. hwnd - Handle to the parent window.
  1789. hInst - This parameter is ignored.
  1790. szCmd - The command line is the DeviceInstanceId to install.
  1791. nShow - This parameter is ignored.
  1792. Return Value:
  1793. returns the last error set from InstallDeviceInstance if the API fails or ERROR_SUCCESS
  1794. if it succeedes.
  1795. --*/
  1796. {
  1797. DWORD RebootNeeded = 0;
  1798. DWORD LastError = ERROR_SUCCESS;
  1799. UNREFERENCED_PARAMETER(hInst);
  1800. UNREFERENCED_PARAMETER(nShow);
  1801. //
  1802. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  1803. // to fail and set the last error to ERROR_IN_WOW64.
  1804. //
  1805. if (GetIsWow64()) {
  1806. ExitProcess(ERROR_IN_WOW64);
  1807. }
  1808. //
  1809. // First verify that the process has sufficient Administrator privileges.
  1810. //
  1811. if (!pSetupIsUserAdmin()) {
  1812. ExitProcess(ERROR_ACCESS_DENIED);
  1813. }
  1814. InstallDeviceInstance(hwnd,
  1815. NULL,
  1816. szCmd,
  1817. &RebootNeeded,
  1818. NULL,
  1819. IDI_FLAG_SECONDNEWDEVINSTANCE | IDI_FLAG_SETRESTOREPOINT,
  1820. NDWTYPE_FOUNDNEW,
  1821. NULL,
  1822. NULL,
  1823. NULL,
  1824. NULL
  1825. );
  1826. LastError = GetLastError();
  1827. if ((LastError == ERROR_SUCCESS) &&
  1828. (RebootNeeded & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  1829. LastError = ERROR_SUCCESS_REBOOT_REQUIRED;
  1830. }
  1831. ExitProcess(LastError);
  1832. }
  1833. BOOL
  1834. SpecialRawDeviceInstallProblem(
  1835. DEVNODE DevNode
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. There are certain devices that have the RAW capability flag set that need
  1840. a driver to work. This means the results of the install for these devices
  1841. are special cased so that we display a negative finish balloon message
  1842. instead of a positive one.
  1843. We can tell these bus types by looking up the bus type GUID flags and
  1844. checking for the BIF_RAWDEVICENEEDSDRIVER flag.
  1845. Arguments:
  1846. DevNode
  1847. Return Value:
  1848. TRUE if this is one of the special RAW devices and we couldn't find
  1849. a driver to install.
  1850. --*/
  1851. {
  1852. BOOL bDeviceHasProblem = FALSE;
  1853. DWORD Capabilities = 0;
  1854. DWORD cbData, dwType;
  1855. cbData = sizeof(Capabilities);
  1856. if ((CM_Get_DevNode_Registry_Property(DevNode,
  1857. CM_DRP_CAPABILITIES,
  1858. &dwType,
  1859. (PVOID)&Capabilities,
  1860. &cbData,
  1861. 0) == CR_SUCCESS) &&
  1862. (Capabilities & CM_DEVCAP_RAWDEVICEOK) &&
  1863. (GetBusInformation(DevNode) & BIF_RAWDEVICENEEDSDRIVER) &&
  1864. (IsNullDriverInstalled(DevNode))) {
  1865. //
  1866. // This is a RAW device that has the BIF_RAWDEVICENEEDSDRIVER bus
  1867. // information flag set and it doesn't have any drivers installed on
  1868. // it. This means it has a problem so we can show the correct balloon
  1869. // text.
  1870. //
  1871. bDeviceHasProblem = TRUE;
  1872. }
  1873. return bDeviceHasProblem;
  1874. }
  1875. BOOL
  1876. PromptAndRunClientAsAdmin(
  1877. PCTSTR DeviceInstanceId,
  1878. DWORD *RebootRequired
  1879. )
  1880. {
  1881. DWORD Err = ERROR_SUCCESS;
  1882. CREDUI_INFO ci;
  1883. PTSTR UserName = NULL;
  1884. PTSTR User = NULL;
  1885. PTSTR Domain = NULL;
  1886. PTSTR Password = NULL;
  1887. PTSTR Caption = NULL;
  1888. PTSTR Message = NULL;
  1889. PTSTR Format = NULL;
  1890. DWORD Status = ERROR_SUCCESS;
  1891. BOOL bInstallSuccessful = FALSE;
  1892. BOOL bInstallComplete = FALSE;
  1893. int AlreadyTriedCount = 0;
  1894. PTCHAR FriendlyName;
  1895. TCHAR RunDll32Path[MAX_PATH];
  1896. HRESULT hr;
  1897. if (RebootRequired) {
  1898. *RebootRequired = 0;
  1899. }
  1900. //
  1901. // Allocate the memory that we need.
  1902. //
  1903. UserName = LocalAlloc(LPTR, CREDUI_MAX_USERNAME_LENGTH);
  1904. User = LocalAlloc(LPTR, CREDUI_MAX_USERNAME_LENGTH);
  1905. Domain = LocalAlloc(LPTR, CREDUI_MAX_DOMAIN_TARGET_LENGTH);
  1906. Password = LocalAlloc(LPTR, CREDUI_MAX_PASSWORD_LENGTH);
  1907. Caption = LocalAlloc(LPTR, CREDUI_MAX_CAPTION_LENGTH);
  1908. Message = LocalAlloc(LPTR, CREDUI_MAX_MESSAGE_LENGTH);
  1909. Format = LocalAlloc(LPTR, CREDUI_MAX_MESSAGE_LENGTH);
  1910. if (!UserName || !User || !Domain || !Password || !Caption ||
  1911. !Message || !Format) {
  1912. //
  1913. // Not enough memory to create all of the buffers we need to call
  1914. // CredUIPromptForCredentials, so bail out.
  1915. //
  1916. Err = ERROR_NOT_ENOUGH_MEMORY;
  1917. goto clean0;
  1918. }
  1919. LoadString(hNewDev, IDS_FOUNDNEWHARDWARE, Caption, CREDUI_MAX_CAPTION_LENGTH/sizeof(TCHAR));
  1920. if (LoadString(hNewDev, IDS_LOGON_TEXT, Format, CREDUI_MAX_MESSAGE_LENGTH/sizeof(TCHAR))) {
  1921. DEVNODE DevInst = 0;
  1922. CM_Locate_DevNode(&DevInst, (DEVINSTID)DeviceInstanceId, 0);
  1923. if ((DevInst != 0) &&
  1924. ((FriendlyName = BuildFriendlyName(DevInst, FALSE, NULL)) != NULL)) {
  1925. hr = StringCchPrintf(Message, CREDUI_MAX_MESSAGE_LENGTH/sizeof(TCHAR), Format, FriendlyName);
  1926. if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
  1927. Message[0] = TEXT('\0');
  1928. }
  1929. } else {
  1930. hr = StringCchPrintf(Message, CREDUI_MAX_MESSAGE_LENGTH/sizeof(TCHAR), Format, szUnknownDevice);
  1931. if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
  1932. Message[0] = TEXT('\0');
  1933. }
  1934. }
  1935. }
  1936. ZeroMemory(&ci, sizeof(ci));
  1937. ci.cbSize = sizeof( ci );
  1938. ci.pszCaptionText = Caption;
  1939. ci.pszMessageText = Message;
  1940. do {
  1941. //
  1942. // The user has not provided valid Admin credentials and they have not tried to
  1943. // provide them MAX_PASSWORD_TRIES times. So, we need to prompt them to provide
  1944. // valid Admin credentials.
  1945. //
  1946. Status = CredUIPromptForCredentials(&ci,
  1947. NULL,
  1948. NULL,
  1949. 0,
  1950. UserName,
  1951. CREDUI_MAX_USERNAME_LENGTH/sizeof(TCHAR),
  1952. Password,
  1953. CREDUI_MAX_PASSWORD_LENGTH/sizeof(TCHAR),
  1954. NULL,
  1955. CREDUI_FLAGS_DO_NOT_PERSIST |
  1956. CREDUI_FLAGS_REQUEST_ADMINISTRATOR |
  1957. CREDUI_FLAGS_INCORRECT_PASSWORD |
  1958. CREDUI_FLAGS_GENERIC_CREDENTIALS |
  1959. CREDUI_FLAGS_COMPLETE_USERNAME);
  1960. if (Status == ERROR_SUCCESS) {
  1961. PROCESS_INFORMATION pi;
  1962. STARTUPINFO si;
  1963. TCHAR szCmdLine[MAX_PATH];
  1964. DWORD dwExitCode = ERROR_SUCCESS;
  1965. BOOL bCreateProcessSuccess = FALSE;
  1966. User[0] = TEXT('\0');
  1967. Domain[0] = TEXT('\0');
  1968. CredUIParseUserName(UserName,
  1969. User,
  1970. CREDUI_MAX_USERNAME_LENGTH/sizeof(TCHAR),
  1971. Domain,
  1972. CREDUI_MAX_DOMAIN_TARGET_LENGTH/sizeof(TCHAR)
  1973. );
  1974. //
  1975. // We want to create a separate process using CreateProcessEx
  1976. //
  1977. ZeroMemory(&si, sizeof(si));
  1978. ZeroMemory(&pi, sizeof(pi));
  1979. si.cb = sizeof(si);
  1980. si.wShowWindow = SW_SHOW;
  1981. //
  1982. // Create a new process with the administrator credentials. The process
  1983. // that will be lanuched is:
  1984. //
  1985. // %windir%\system32\rundll32.exe newdev.dll,DevInstall <device instance Id>
  1986. //
  1987. if (GetSystemDirectory(RunDll32Path, SIZECHARS(RunDll32Path)) &&
  1988. pSetupConcatenatePaths(RunDll32Path, TEXT("RUNDLL32.EXE"), SIZECHARS(RunDll32Path), NULL) &&
  1989. SUCCEEDED(StringCchPrintf(szCmdLine,
  1990. SIZECHARS(szCmdLine),
  1991. TEXT("%s newdev.dll,DevInstall %s"),
  1992. RunDll32Path,
  1993. DeviceInstanceId))) {
  1994. bCreateProcessSuccess = CreateProcessWithLogonW(User,
  1995. Domain,
  1996. Password,
  1997. 0,
  1998. NULL,
  1999. szCmdLine,
  2000. 0,
  2001. NULL,
  2002. NULL,
  2003. &si,
  2004. &pi
  2005. );
  2006. }
  2007. SecureZeroMemory(Password, CREDUI_MAX_PASSWORD_LENGTH);
  2008. if (bCreateProcessSuccess) {
  2009. //
  2010. // Close the thread handle since all we need is the process handle.
  2011. //
  2012. CloseHandle(pi.hThread);
  2013. //
  2014. // The process was successfully created so we need to wait for it to finish.
  2015. //
  2016. WaitForSingleObject(pi.hProcess, INFINITE);
  2017. //
  2018. // Check the return value from the process. It should be one of the following
  2019. // return values:
  2020. // ERROR_SUCCESS if the install went successfully.
  2021. // ERROR_SUCCESS_REBOOT_REQUIRED if the install went successfully and a
  2022. // reboot is needed.
  2023. // ERROR _ACCESS_DENIED if the credentials provided were not admin credentials.
  2024. // Other - a error code returned because the install failed for some reason.
  2025. //
  2026. GetExitCodeProcess(pi.hProcess, &dwExitCode);
  2027. if ((dwExitCode == ERROR_SUCCESS) ||
  2028. (dwExitCode == ERROR_SUCCESS_REBOOT_REQUIRED)) {
  2029. //
  2030. // Mark this install as complete so we will break out of our loop.
  2031. //
  2032. bInstallComplete = TRUE;
  2033. bInstallSuccessful = TRUE;
  2034. //
  2035. // Check if we need to reboot.
  2036. //
  2037. if ((dwExitCode == ERROR_SUCCESS_REBOOT_REQUIRED) &&
  2038. RebootRequired) {
  2039. *RebootRequired = DI_NEEDREBOOT;
  2040. }
  2041. }
  2042. //
  2043. // If the error code is not ERROR_SUCCESS, ERROR_SUCCESS_REBOOT_REQUIRED,
  2044. // or ERROR_ACCESS_DENIED then it means the installed failed for some reason.
  2045. // for this case we will set bInstallComplete so we will break out
  2046. // of the loop since we don't want to attempt another install on this
  2047. // device.
  2048. //
  2049. else if (dwExitCode != ERROR_ACCESS_DENIED) {
  2050. //
  2051. // Mark this install as complete so we will break out of our loop.
  2052. //
  2053. bInstallComplete = TRUE;
  2054. }
  2055. else {
  2056. if (dwExitCode == ERROR_CANCELLED) {
  2057. Status = ERROR_CANCELLED;
  2058. }
  2059. //
  2060. // Some type of failure occured while installing this hardware.
  2061. //
  2062. Err = dwExitCode;
  2063. }
  2064. CloseHandle(pi.hProcess);
  2065. }
  2066. //
  2067. // If the CreateProcessWithLogonW failed or the exit code for the process
  2068. // was ERROR_ACCESS_DENIED then we need to display the bad credentials
  2069. // message box.
  2070. //
  2071. if (!bCreateProcessSuccess ||
  2072. (dwExitCode == ERROR_ACCESS_DENIED)) {
  2073. //
  2074. // The process failed, most likely because the user did not provide a username
  2075. // and password. So prompt a dialog and do it again.
  2076. //
  2077. TCHAR szWarningMsg[MAX_PATH];
  2078. TCHAR szWarningCaption[MAX_PATH];
  2079. if (LoadString(hNewDev,
  2080. IDS_NOTADMIN_ERROR,
  2081. szWarningMsg,
  2082. SIZECHARS(szWarningMsg))
  2083. &&
  2084. LoadString(hNewDev,
  2085. IDS_NEWDEVICENAME,
  2086. szWarningCaption,
  2087. SIZECHARS(szWarningCaption)))
  2088. {
  2089. MessageBox(NULL, szWarningMsg, szWarningCaption, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  2090. }
  2091. //
  2092. // Increment AlreadyTriedCount. If this gets passed a certain threshold
  2093. // then we should bail out.
  2094. //
  2095. AlreadyTriedCount++;
  2096. }
  2097. } else {
  2098. //
  2099. // Increment AlreadyTriedCount. If this gets passed a certain threshold
  2100. // then we should bail out.
  2101. //
  2102. AlreadyTriedCount++;
  2103. }
  2104. SecureZeroMemory(Password, CREDUI_MAX_PASSWORD_LENGTH);
  2105. //
  2106. // We will keep looping until one of the following things happen:
  2107. // 1) we successfully lauch the second instance of newdev to install the device.
  2108. // 2) the user cancels out of the password prompt dialog
  2109. // 3) the user entered bogus admin credentials more than MAX_PASSWORD_TRIES tims.
  2110. //
  2111. } while ((Status != ERROR_CANCELLED) &&
  2112. !bInstallComplete &&
  2113. (AlreadyTriedCount < MAX_PASSWORD_TRIES));
  2114. //
  2115. // If the install was not completed then the user either cancelled out of could not provide a
  2116. // valid admin credentials.
  2117. //
  2118. if (!bInstallComplete) {
  2119. NoPrivilegeWarning(NULL);
  2120. }
  2121. clean0:
  2122. //
  2123. // Free all of the memory that we allocated.
  2124. //
  2125. if (UserName) {
  2126. LocalFree(UserName);
  2127. }
  2128. if (User) {
  2129. LocalFree(User);
  2130. }
  2131. if (Domain) {
  2132. LocalFree(Domain);
  2133. }
  2134. if (Password) {
  2135. LocalFree(Password);
  2136. }
  2137. if (Caption) {
  2138. LocalFree(Caption);
  2139. }
  2140. if (Message) {
  2141. LocalFree(Message);
  2142. }
  2143. if (Format) {
  2144. LocalFree(Format);
  2145. }
  2146. SetLastError(Err);
  2147. return bInstallSuccessful;
  2148. }
  2149. DWORD
  2150. ClientSideInstallThread(
  2151. HANDLE hPipeRead
  2152. )
  2153. {
  2154. DWORD Err = ERROR_SUCCESS;
  2155. HMODULE hCdmInstance = NULL;
  2156. HANDLE hCdmContext = NULL;
  2157. BOOL bRunAsAdmin = TRUE;
  2158. HANDLE hDeviceInstallEvent = NULL;
  2159. ULONG InstallFlags = 0;
  2160. DWORD Flags = IDI_FLAG_SETRESTOREPOINT;
  2161. DEVNODE DevNode;
  2162. ULONG Status, Problem;
  2163. ULONG DeviceInstallEventLength = 0, DeviceInstanceIdLength = 0, BytesRead = 0;
  2164. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  2165. TCHAR DeviceInstallEventName[MAX_PATH];
  2166. DWORD InstallDeviceCount = 0;
  2167. TCHAR FinishText[MAX_PATH];
  2168. BOOL bTotalLogDriverNotFound = FALSE;
  2169. BOOL bSingleDeviceSetRestorePoint = FALSE;
  2170. BOOL bSetRestorePoint = FALSE;
  2171. CLOSE_CDM_CONTEXT_PROC pfnCloseCDMContext;
  2172. bQueuedRebootNeeded = FALSE;
  2173. //
  2174. // The very first thing in the pipe should be the size of the name of the
  2175. // event that we will signal after each device is finished being installed.
  2176. //
  2177. if (ReadFile(hPipeRead,
  2178. (LPVOID)&DeviceInstallEventLength,
  2179. sizeof(ULONG),
  2180. &BytesRead,
  2181. NULL)) {
  2182. ASSERT(DeviceInstallEventLength != 0);
  2183. if ((DeviceInstallEventLength == 0) ||
  2184. (DeviceInstallEventLength >= SIZECHARS(DeviceInstallEventName))) {
  2185. goto clean0;
  2186. }
  2187. //
  2188. // The next thing in the pipe should be the name of the event that we
  2189. // will signal after each device is finished being installed.
  2190. //
  2191. if (!ReadFile(hPipeRead,
  2192. (LPVOID)DeviceInstallEventName,
  2193. DeviceInstallEventLength,
  2194. &BytesRead,
  2195. NULL)) {
  2196. goto clean0;
  2197. }
  2198. } else {
  2199. if (GetLastError() == ERROR_INVALID_HANDLE) {
  2200. //
  2201. // The handle to the named pipe is not valid. Make sure we don't
  2202. // try to close it on exit.
  2203. //
  2204. hPipeRead = NULL;
  2205. }
  2206. goto clean0;
  2207. }
  2208. //
  2209. // Open a handle to the specified named event that we can set and wait on.
  2210. //
  2211. hDeviceInstallEvent = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE,
  2212. FALSE,
  2213. DeviceInstallEventName);
  2214. if (!hDeviceInstallEvent) {
  2215. goto clean0;
  2216. }
  2217. //
  2218. // Continue reading from the pipe until the other end is closed.
  2219. //
  2220. // The first thing in the pipe is a ULONG Flags value that tells us whether
  2221. // this is a full install or UI only.
  2222. //
  2223. while(ReadFile(hPipeRead,
  2224. (LPVOID)&InstallFlags,
  2225. sizeof(DWORD),
  2226. &BytesRead,
  2227. NULL)) {
  2228. //
  2229. // Check to see if server side install needs a reboot.
  2230. //
  2231. if (InstallFlags & DEVICE_INSTALL_FINISHED_REBOOT) {
  2232. bQueuedRebootNeeded = TRUE;
  2233. }
  2234. if (InstallFlags & DEVICE_INSTALL_BATCH_COMPLETE) {
  2235. //
  2236. // This is the last message that we should get from umpnpmgr.dll
  2237. // when it has drained it's device install queue. We will
  2238. // display a "Windows finished installing hardware" balloon that
  2239. // will hang around until umpnpmgr.dll closes the named pipe,
  2240. // or sends a new device install message.
  2241. //
  2242. // There are three different balloon messages that we can diaplay.
  2243. // 1) all successful
  2244. // 2) need reboot before hardware will work
  2245. // 3) problem installing one or more devices.
  2246. //
  2247. UINT FinishId;
  2248. //
  2249. // Check to see if one of the devices that was installed server-side
  2250. // ended up with a problem.
  2251. //
  2252. if (InstallFlags & DEVICE_INSTALL_PROBLEM) {
  2253. Err = ERROR_INSTALL_FAILURE;
  2254. }
  2255. if (bQueuedRebootNeeded) {
  2256. FinishId = IDS_FINISH_BALLOON_REBOOT;
  2257. } else if (Err != ERROR_SUCCESS) {
  2258. FinishId = IDS_FINISH_BALLOON_ERROR;
  2259. } else {
  2260. FinishId = IDS_FINISH_BALLOON_SUCCESS;
  2261. }
  2262. if (!LoadString(hNewDev,
  2263. FinishId,
  2264. FinishText,
  2265. SIZECHARS(FinishText)
  2266. )) {
  2267. FinishText[0] = TEXT('\0');
  2268. }
  2269. PostMessage(hTrayIconWnd,
  2270. WUM_UPDATEUI,
  2271. (WPARAM)TIP_PLAY_SOUND,
  2272. (LPARAM)FinishText
  2273. );
  2274. //
  2275. // If we could not find a driver for any of the new devices we just
  2276. // installed then we need to call Cdm.dll one last time telling it
  2277. // that we are done and it should send it's list to helpcenter.exe
  2278. //
  2279. // Note that we do this here as well as at the bottom of the loop
  2280. // since this finish message hangs around for 10 seconds and that
  2281. // is a long time to wait before we launch help center.
  2282. //
  2283. if (bTotalLogDriverNotFound) {
  2284. bTotalLogDriverNotFound = FALSE;
  2285. OpenCdmContextIfNeeded(&hCdmInstance,
  2286. &hCdmContext
  2287. );
  2288. CdmLogDriverNotFound(hCdmInstance,
  2289. hCdmContext,
  2290. NULL,
  2291. 0x00000002
  2292. );
  2293. }
  2294. }
  2295. //
  2296. // Read the DeviceInstanceId from the pipe if the DeviceInstanceIdLength
  2297. // is valid.
  2298. //
  2299. if (ReadFile(hPipeRead,
  2300. (LPVOID)&DeviceInstanceIdLength,
  2301. sizeof(ULONG),
  2302. &BytesRead,
  2303. NULL) &&
  2304. (DeviceInstanceIdLength)) {
  2305. if (DeviceInstanceIdLength >= SIZECHARS(DeviceInstanceId)) {
  2306. goto clean0;
  2307. }
  2308. if (!ReadFile(hPipeRead,
  2309. (LPVOID)DeviceInstanceId,
  2310. DeviceInstanceIdLength,
  2311. &BytesRead,
  2312. NULL)) {
  2313. //
  2314. // If this read fails then just close the UI and close the process.
  2315. //
  2316. goto clean0;
  2317. }
  2318. if (InstallFlags & DEVICE_INSTALL_UI_ONLY) {
  2319. //
  2320. // If this is a UI only install then send a WUM_UPDATEUI message to the installer
  2321. // window so that it can update the icon and message in the tray.
  2322. //
  2323. PostMessage(hTrayIconWnd,
  2324. WUM_UPDATEUI,
  2325. (WPARAM)(TIP_LPARAM_IS_DEVICEINSTANCEID |
  2326. ((InstallFlags & DEVICE_INSTALL_PLAY_SOUND) ? TIP_PLAY_SOUND : 0)),
  2327. (LPARAM)DeviceInstanceId
  2328. );
  2329. InstallDeviceCount++;
  2330. //
  2331. // If we are only installing a small amount of devices (less than 5) then we
  2332. // want to delay between each device so the user has time to read the balloon
  2333. // tip. If we are installing more than 5 devices then we want to skip the
  2334. // delay altogether since we have a lot of devices to install and the user
  2335. // probably wants this done as quickly as possible.
  2336. //
  2337. if (InstallDeviceCount < DEVICE_COUNT_FOR_DELAY) {
  2338. Sleep(DEVICE_COUNT_DELAY);
  2339. }
  2340. } else {
  2341. DWORD RebootNeeded = 0;
  2342. BOOL bLogDriverNotFound = FALSE;
  2343. bSingleDeviceSetRestorePoint= FALSE;
  2344. //
  2345. // This is a full installation.
  2346. //
  2347. PostMessage(hTrayIconWnd,
  2348. WUM_UPDATEUI,
  2349. (WPARAM)TIP_LPARAM_IS_DEVICEINSTANCEID,
  2350. (LPARAM)DeviceInstanceId
  2351. );
  2352. if (pSetupIsUserAdmin()) {
  2353. //
  2354. // This user is an Admin so simply install the device.
  2355. //
  2356. InstallDeviceInstance(NULL,
  2357. hTrayIconWnd,
  2358. DeviceInstanceId,
  2359. &RebootNeeded,
  2360. NULL,
  2361. Flags,
  2362. NDWTYPE_FOUNDNEW,
  2363. &hCdmInstance,
  2364. &hCdmContext,
  2365. &bLogDriverNotFound,
  2366. &bSingleDeviceSetRestorePoint
  2367. );
  2368. } else {
  2369. if (bRunAsAdmin) {
  2370. bRunAsAdmin = PromptAndRunClientAsAdmin(DeviceInstanceId,
  2371. &RebootNeeded
  2372. );
  2373. }
  2374. }
  2375. //
  2376. // Remember if there is a problem installing any of the devices.
  2377. //
  2378. if (GetLastError() != ERROR_SUCCESS) {
  2379. Err = GetLastError();
  2380. }
  2381. if (CM_Locate_DevNode(&DevNode, DeviceInstanceId, 0) == CR_SUCCESS) {
  2382. //
  2383. // If we located the devnode and it has a problem set the Err
  2384. // code so we can tell the user that something failed.
  2385. // If we cannot locate the devnode then the user most likely
  2386. // removed the device during the install process, so don't
  2387. // show this as an error.
  2388. //
  2389. if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) != CR_SUCCESS) ||
  2390. (Status & DN_HAS_PROBLEM) ||
  2391. SpecialRawDeviceInstallProblem(DevNode)) {
  2392. //
  2393. // Either we couldn't locate the device, or it has some problem,
  2394. // so set Err to ERROR_INSTALL_FAILURE. This error won't be
  2395. // shown, but it will trigger us to put up a different finish
  2396. // message in the balloon.
  2397. //
  2398. Err = ERROR_INSTALL_FAILURE;
  2399. }
  2400. }
  2401. if (RebootNeeded & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
  2402. bQueuedRebootNeeded = TRUE;
  2403. }
  2404. if (bLogDriverNotFound) {
  2405. bTotalLogDriverNotFound = TRUE;
  2406. }
  2407. //
  2408. // We only want to do one system restore point be batch of device
  2409. // installs, so if the last driver that was installed was not
  2410. // digitally signed and we did a system restore point, then
  2411. // clear the IDI_FLAG_SETRESTOREPOINT.
  2412. //
  2413. if (bSingleDeviceSetRestorePoint) {
  2414. bSetRestorePoint = TRUE;
  2415. Flags &= ~IDI_FLAG_SETRESTOREPOINT;
  2416. }
  2417. }
  2418. }
  2419. //
  2420. // We need to set the hDeviceInstallEvent event to let umpnpmgr.dll know that we are finished.
  2421. //
  2422. if (hDeviceInstallEvent) {
  2423. SetEvent(hDeviceInstallEvent);
  2424. }
  2425. }
  2426. clean0:
  2427. //
  2428. // If we could not find a driver for any of the new devices we just
  2429. // installed then we need to call Cdm.dll one last time telling it
  2430. // that we are done and it should send it's list to helpcenter.exe
  2431. //
  2432. if (bTotalLogDriverNotFound) {
  2433. OpenCdmContextIfNeeded(&hCdmInstance,
  2434. &hCdmContext
  2435. );
  2436. CdmLogDriverNotFound(hCdmInstance,
  2437. hCdmContext,
  2438. NULL,
  2439. 0x00000002
  2440. );
  2441. }
  2442. if (hCdmInstance) {
  2443. if (hCdmContext) {
  2444. pfnCloseCDMContext = (CLOSE_CDM_CONTEXT_PROC)GetProcAddress(hCdmInstance,
  2445. "CloseCDMContext"
  2446. );
  2447. if (pfnCloseCDMContext) {
  2448. pfnCloseCDMContext(hCdmContext);
  2449. }
  2450. }
  2451. FreeLibrary(hCdmInstance);
  2452. }
  2453. //
  2454. // If we had to set a system restore point because one of the drivers we
  2455. // installed was not digitally signed, then at this point we need to call
  2456. // SRSetRestorePoint with END_NESTED_SYSTEM_CHANGE.
  2457. //
  2458. if (bSetRestorePoint) {
  2459. pSetSystemRestorePoint(FALSE, FALSE, 0);
  2460. }
  2461. //
  2462. // Close the event handle
  2463. //
  2464. if (hDeviceInstallEvent) {
  2465. CloseHandle(hDeviceInstallEvent);
  2466. }
  2467. if (hPipeRead) {
  2468. CloseHandle(hPipeRead);
  2469. }
  2470. //
  2471. // Tell the UI to go away because we are done
  2472. //
  2473. PostMessage(hTrayIconWnd, WUM_EXIT, 0, 0);
  2474. return bQueuedRebootNeeded;
  2475. }
  2476. DWORD
  2477. WINAPI
  2478. ClientSideInstallW(
  2479. HWND hwnd,
  2480. HINSTANCE hInst,
  2481. LPWSTR szCmd,
  2482. int nShow
  2483. )
  2484. {
  2485. HANDLE hThread;
  2486. DWORD ThreadId;
  2487. HANDLE hPipeRead;
  2488. MSG Msg;
  2489. WNDCLASS wndClass;
  2490. UNREFERENCED_PARAMETER(hInst);
  2491. UNREFERENCED_PARAMETER(nShow);
  2492. //
  2493. // If someone calls the 32-bit newdev.dll on a 64-bit OS then we need
  2494. // to fail and set the last error to ERROR_IN_WOW64.
  2495. //
  2496. if (GetIsWow64()) {
  2497. ExitProcess(ERROR_IN_WOW64);
  2498. }
  2499. //
  2500. // NOTE: This API can be called in the process of a user that does NOT
  2501. // have administrator credentials. If it is then we will later prompt
  2502. // the user for administrator credentials and complet the install
  2503. // if they are provided.
  2504. //
  2505. //
  2506. // Make sure that a named pipe was specified in the cmd line.
  2507. //
  2508. if(!szCmd || !*szCmd) {
  2509. goto clean0;
  2510. }
  2511. //
  2512. // Wait 3 minutes for the specified named pipe to become available from
  2513. // the server.
  2514. //
  2515. if (!WaitNamedPipe(szCmd,
  2516. 180000)
  2517. ) {
  2518. goto clean0;
  2519. }
  2520. //
  2521. // Open a handle to the specified named pipe
  2522. //
  2523. hPipeRead = CreateFile(szCmd,
  2524. GENERIC_READ,
  2525. 0,
  2526. NULL,
  2527. OPEN_EXISTING,
  2528. 0,
  2529. NULL);
  2530. if (INVALID_HANDLE_VALUE == hPipeRead) {
  2531. //
  2532. // If we can't open the specified global named pipe, there is nothing
  2533. // more we can do.
  2534. //
  2535. goto clean0;
  2536. }
  2537. //
  2538. // Lets see if the class has been registered.
  2539. //
  2540. if (!GetClassInfo(hNewDev, NEWDEV_CLASS_NAME, &wndClass)) {
  2541. //
  2542. // register the class
  2543. //
  2544. memset(&wndClass, 0, sizeof(wndClass));
  2545. wndClass.lpfnWndProc = BalloonInfoProc;
  2546. wndClass.hInstance = hNewDev;
  2547. wndClass.lpszClassName = NEWDEV_CLASS_NAME;
  2548. if (!RegisterClass(&wndClass)) {
  2549. CloseHandle(hPipeRead);
  2550. goto clean0;
  2551. }
  2552. }
  2553. //
  2554. // Create a window.
  2555. //
  2556. hTrayIconWnd = CreateWindowEx(WS_EX_TOOLWINDOW,
  2557. NEWDEV_CLASS_NAME,
  2558. TEXT(""),
  2559. WS_DLGFRAME | WS_BORDER | WS_DISABLED,
  2560. CW_USEDEFAULT,
  2561. CW_USEDEFAULT,
  2562. 0,
  2563. 0,
  2564. NULL,
  2565. NULL,
  2566. hNewDev,
  2567. NULL
  2568. );
  2569. if (hTrayIconWnd == NULL) {
  2570. CloseHandle(hPipeRead);
  2571. goto clean0;
  2572. }
  2573. //
  2574. // Create the device install thread that will read from the named pipe.
  2575. // Note that once the ClientSideInstallThread is successfully created, it is
  2576. // responsible for closing the handle to the named pipe when its done with
  2577. // it.
  2578. //
  2579. hThread = CreateThread(NULL,
  2580. 0,
  2581. ClientSideInstallThread,
  2582. (PVOID)hPipeRead,
  2583. 0,
  2584. &ThreadId
  2585. );
  2586. if (!hThread) {
  2587. DestroyWindow(hTrayIconWnd);
  2588. CloseHandle(hPipeRead);
  2589. goto clean0;
  2590. }
  2591. while (IsWindow(hTrayIconWnd)) {
  2592. if (GetMessage(&Msg, NULL, 0, 0)) {
  2593. TranslateMessage(&Msg);
  2594. DispatchMessage(&Msg);
  2595. }
  2596. }
  2597. //
  2598. // Check if a reboot is needed.
  2599. //
  2600. if (bQueuedRebootNeeded) {
  2601. TCHAR RebootText[MAX_PATH];
  2602. LoadString(hNewDev, IDS_NEWDEVICE_REBOOT, RebootText, SIZECHARS(RebootText));
  2603. RestartDialogEx(hwnd, RebootText, EWX_REBOOT, REASON_PLANNED_FLAG | REASON_HWINSTALL);
  2604. }
  2605. clean0:
  2606. return 0;
  2607. }