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.

3114 lines
100 KiB

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