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.

531 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: update.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "newdevp.h"
  11. #define INSTALL_UI_TIMERID 1423
  12. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo={0};
  13. //
  14. // returns TRUE if we were able to find a reasonable name
  15. // (something besides unknown device).
  16. //
  17. void
  18. SetDriverDescription(
  19. HWND hDlg,
  20. int iControl,
  21. PNEWDEVWIZ NewDevWiz
  22. )
  23. {
  24. PTCHAR FriendlyName;
  25. SP_DRVINFO_DATA DriverInfoData;
  26. //
  27. // If there is a selected driver use its driver description,
  28. // since this is what the user is going to install.
  29. //
  30. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  31. if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo,
  32. &NewDevWiz->DeviceInfoData,
  33. &DriverInfoData
  34. )
  35. &&
  36. *(DriverInfoData.Description)) {
  37. StringCchCopy(NewDevWiz->DriverDescription,
  38. SIZECHARS(NewDevWiz->DriverDescription),
  39. DriverInfoData.Description);
  40. SetDlgItemText(hDlg, iControl, NewDevWiz->DriverDescription);
  41. return;
  42. }
  43. FriendlyName = BuildFriendlyName(NewDevWiz->DeviceInfoData.DevInst, FALSE, NULL);
  44. if (FriendlyName) {
  45. SetDlgItemText(hDlg, iControl, FriendlyName);
  46. LocalFree(FriendlyName);
  47. return;
  48. }
  49. SetDlgItemText(hDlg, iControl, szUnknown);
  50. return;
  51. }
  52. BOOL
  53. IntializeDeviceMapInfo(
  54. void
  55. )
  56. /*++
  57. Routine Description:
  58. Initializes\Updates the global ProcessDeviceMapInfo which is
  59. used by GetNextDriveByType().
  60. Arguments:
  61. none
  62. Return Value:
  63. TRUE if we can get the device map information, FALSE otherwise.
  64. --*/
  65. {
  66. NTSTATUS Status;
  67. Status = NtQueryInformationProcess(NtCurrentProcess(),
  68. ProcessDeviceMap,
  69. &ProcessDeviceMapInfo.Query,
  70. sizeof(ProcessDeviceMapInfo.Query),
  71. NULL
  72. );
  73. if (!NT_SUCCESS(Status)) {
  74. RtlZeroMemory(&ProcessDeviceMapInfo, sizeof(ProcessDeviceMapInfo));
  75. return FALSE;
  76. }
  77. return TRUE;
  78. }
  79. UINT
  80. GetNextDriveByType(
  81. UINT DriveType,
  82. UINT DriveNumber
  83. )
  84. /*++
  85. Routine Description:
  86. Inspects each drive starting from DriveNumber in ascending order to find the
  87. first drive of the specified DriveType from the global ProcessDeviceMapInfo.
  88. The ProcessDeviceMapInfo must have been intialized and may need refreshing before
  89. invoking this function. Invoke IntializeDeviceMapInfo to initialize or update
  90. the DeviceMapInfo.
  91. Arguments:
  92. DriveType - DriveType as defined in winbase, GetDriveType().
  93. DriveNumber - Starting DriveNumber, 1 based.
  94. Return Value:
  95. DriveNumber - if nonzero Drive found, 1 based.
  96. --*/
  97. {
  98. //
  99. // OneBased DriveNumber to ZeroBased.
  100. //
  101. DriveNumber--;
  102. while (DriveNumber < 26) {
  103. if ((ProcessDeviceMapInfo.Query.DriveMap & (1<< DriveNumber)) &&
  104. ProcessDeviceMapInfo.Query.DriveType[DriveNumber] == DriveType) {
  105. return DriveNumber+1; // return 1 based DriveNumber found.
  106. }
  107. DriveNumber++;
  108. }
  109. return 0;
  110. }
  111. void
  112. InstallSilentChildSiblings(
  113. HWND hwndParent,
  114. PNEWDEVWIZ NewDevWiz,
  115. DEVINST DeviceInstance
  116. )
  117. {
  118. CONFIGRET ConfigRet;
  119. DEVINST ChildDeviceInstance;
  120. ULONG Ulong, ulValue;
  121. BOOL NeedsInstall, IsSilent;
  122. do {
  123. //
  124. // Assume the device is not a silent install.
  125. //
  126. IsSilent = FALSE;
  127. //
  128. // Check if the device should be silently installed by seeing if the
  129. // CM_DEVCAP_SILENTINSTALL capability flag is set.
  130. //
  131. Ulong = sizeof(ulValue);
  132. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DeviceInstance,
  133. CM_DRP_CAPABILITIES,
  134. NULL,
  135. (PVOID)&ulValue,
  136. &Ulong,
  137. 0,
  138. NULL
  139. );
  140. if (ConfigRet == CR_SUCCESS && (ulValue & CM_DEVCAP_SILENTINSTALL)) {
  141. IsSilent = TRUE;
  142. }
  143. if (IsSilent) {
  144. //
  145. // The device is a silent install device, so now check if it
  146. // needs to be installed.
  147. // A device needs to be installed if it has the
  148. // CONFIGFLAG_FINISH_INSTALL flag set, or if it has the problems
  149. // CM_PROB_REINSTALL or CM_PROB_NOT_CONFIGURED.
  150. //
  151. Ulong = sizeof(ulValue);
  152. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DeviceInstance,
  153. CM_DRP_CONFIGFLAGS,
  154. NULL,
  155. (PVOID)&ulValue,
  156. &Ulong,
  157. 0,
  158. NULL
  159. );
  160. if (ConfigRet == CR_SUCCESS && (ulValue & CONFIGFLAG_FINISH_INSTALL)) {
  161. NeedsInstall = TRUE;
  162. } else {
  163. ConfigRet = CM_Get_DevNode_Status(&Ulong,
  164. &ulValue,
  165. DeviceInstance,
  166. 0
  167. );
  168. NeedsInstall = ConfigRet == CR_SUCCESS &&
  169. (ulValue == CM_PROB_REINSTALL ||
  170. ulValue == CM_PROB_NOT_CONFIGURED
  171. );
  172. }
  173. if (NeedsInstall) {
  174. //
  175. // Install the device by calling InstallDevInst.
  176. //
  177. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  178. ConfigRet = CM_Get_Device_ID(DeviceInstance,
  179. DeviceInstanceId,
  180. SIZECHARS(DeviceInstanceId),
  181. 0
  182. );
  183. if (ConfigRet == CR_SUCCESS) {
  184. if (InstallDevInst(hwndParent,
  185. DeviceInstanceId,
  186. FALSE,
  187. &Ulong
  188. )) {
  189. NewDevWiz->Reboot |= Ulong;
  190. }
  191. //
  192. // If this devinst has children, then recurse to install
  193. // them as well.
  194. //
  195. ConfigRet = CM_Get_Child_Ex(&ChildDeviceInstance,
  196. DeviceInstance,
  197. 0,
  198. NULL
  199. );
  200. if (ConfigRet == CR_SUCCESS) {
  201. InstallSilentChildSiblings(hwndParent, NewDevWiz, ChildDeviceInstance);
  202. }
  203. }
  204. }
  205. }
  206. //
  207. // Next sibling ...
  208. //
  209. ConfigRet = CM_Get_Sibling_Ex(&DeviceInstance,
  210. DeviceInstance,
  211. 0,
  212. NULL
  213. );
  214. } while (ConfigRet == CR_SUCCESS);
  215. }
  216. void
  217. InstallSilentChilds(
  218. HWND hwndParent,
  219. PNEWDEVWIZ NewDevWiz
  220. )
  221. {
  222. CONFIGRET ConfigRet;
  223. DEVINST ChildDeviceInstance;
  224. ConfigRet = CM_Get_Child_Ex(&ChildDeviceInstance,
  225. NewDevWiz->DeviceInfoData.DevInst,
  226. 0,
  227. NULL
  228. );
  229. if (ConfigRet == CR_SUCCESS) {
  230. InstallSilentChildSiblings(hwndParent, NewDevWiz, ChildDeviceInstance);
  231. }
  232. }
  233. void
  234. SendMessageToUpdateBalloonInfo(
  235. PTSTR DeviceDesc
  236. )
  237. {
  238. HWND hBalloonInfoWnd;
  239. COPYDATASTRUCT cds;
  240. hBalloonInfoWnd = FindWindow(NEWDEV_CLASS_NAME, NULL);
  241. if (hBalloonInfoWnd) {
  242. cds.dwData = 0;
  243. cds.cbData = (lstrlen(DeviceDesc) + 1) * sizeof(TCHAR);
  244. cds.lpData = DeviceDesc;
  245. SendMessage(hBalloonInfoWnd, WM_COPYDATA, 0, (LPARAM)&cds);
  246. }
  247. }
  248. void
  249. UpdateBalloonInfo(
  250. HWND hWnd,
  251. PTSTR DeviceDesc OPTIONAL,
  252. DEVINST DevInst OPTIONAL,
  253. BOOL bPlaySound
  254. )
  255. {
  256. PTCHAR FriendlyName = NULL;
  257. NOTIFYICONDATA nid;
  258. ZeroMemory(&nid, sizeof(nid));
  259. nid.cbSize = sizeof(nid);
  260. nid.hWnd = hWnd;
  261. nid.uID = 1;
  262. if (DeviceDesc || DevInst) {
  263. if (DeviceDesc) {
  264. //
  265. // First use the DeviceDesc string that is passed into this API
  266. //
  267. StringCchCopy(nid.szInfo, SIZECHARS(nid.szInfo), DeviceDesc);
  268. } else if ((FriendlyName = BuildFriendlyName(DevInst, TRUE, NULL)) != NULL) {
  269. //
  270. // If no DeviceDesc string was passed in then use the DevInst to get
  271. // the Device's FriendlyName or DeviceDesc property
  272. //
  273. StringCchCopy(nid.szInfo, SIZECHARS(nid.szInfo), FriendlyName);
  274. LocalFree(FriendlyName);
  275. } else {
  276. //
  277. // If we could not get a friendly name for the device or no device was specified
  278. // so just display the Searching... text.
  279. //
  280. LoadString(hNewDev, IDS_NEWSEARCH, nid.szInfo, SIZECHARS(nid.szInfo));
  281. }
  282. nid.uFlags = NIF_INFO;
  283. nid.uTimeout = 60000;
  284. nid.dwInfoFlags = NIIF_INFO | (bPlaySound ? 0 : NIIF_NOSOUND);
  285. LoadString(hNewDev, IDS_FOUNDNEWHARDWARE, nid.szInfoTitle, SIZECHARS(nid.szInfoTitle));
  286. Shell_NotifyIcon(NIM_MODIFY, &nid);
  287. }
  288. }
  289. LRESULT CALLBACK
  290. BalloonInfoProc(
  291. HWND hWnd,
  292. UINT message,
  293. WPARAM wParam,
  294. LPARAM lParam
  295. )
  296. {
  297. static HICON hNewDevIcon = NULL;
  298. static BOOL bCanExit;
  299. NOTIFYICONDATA nid;
  300. switch (message) {
  301. case WM_CREATE:
  302. hNewDevIcon = LoadImage(hNewDev,
  303. MAKEINTRESOURCE(IDI_NEWDEVICEICON),
  304. IMAGE_ICON,
  305. GetSystemMetrics(SM_CXSMICON),
  306. GetSystemMetrics(SM_CYSMICON),
  307. 0
  308. );
  309. ZeroMemory(&nid, sizeof(nid));
  310. nid.cbSize = sizeof(nid);
  311. nid.hWnd = hWnd;
  312. nid.uID = 1;
  313. nid.hIcon = hNewDevIcon;
  314. nid.uVersion = NOTIFYICON_VERSION;
  315. Shell_NotifyIcon(NIM_SETVERSION, &nid);
  316. nid.uFlags = NIF_ICON;
  317. Shell_NotifyIcon(NIM_ADD, &nid);
  318. //
  319. // We want the tray icon to be displayed for at least 3 seconds otherwise it flashes too
  320. // quickly and a user can't see it.
  321. //
  322. bCanExit = FALSE;
  323. SetTimer(hWnd, INSTALL_UI_TIMERID, 3000, NULL);
  324. break;
  325. case WM_DESTROY: {
  326. ZeroMemory(&nid, sizeof(nid));
  327. nid.cbSize = sizeof(nid);
  328. nid.hWnd = hWnd;
  329. nid.uID = 1;
  330. Shell_NotifyIcon(NIM_DELETE, &nid);
  331. if (hNewDevIcon) {
  332. DestroyIcon(hNewDevIcon);
  333. }
  334. break;
  335. }
  336. case WM_TIMER:
  337. if (INSTALL_UI_TIMERID == wParam) {
  338. //
  339. // At this point the tray icon has been displayed for at least 3
  340. // seconds so we can exit whenever we are finished. If bCanExit is
  341. // already TRUE then we have already been asked to exit so just do a
  342. // DestroyWindow at this point, otherwise set bCanExit to TRUE so we
  343. // can exit when we are finished installing devices.
  344. //
  345. if (bCanExit) {
  346. DestroyWindow(hWnd);
  347. } else {
  348. KillTimer(hWnd, INSTALL_UI_TIMERID);
  349. bCanExit = TRUE;
  350. }
  351. }
  352. break;
  353. case WUM_UPDATEUI:
  354. if (wParam & TIP_HIDE_BALLOON) {
  355. //
  356. // Hide the balloon.
  357. //
  358. ZeroMemory(&nid, sizeof(nid));
  359. nid.cbSize = sizeof(nid);
  360. nid.hWnd = hWnd;
  361. nid.uID = 1;
  362. nid.uFlags = NIF_INFO;
  363. nid.uTimeout = 0;
  364. nid.dwInfoFlags = NIIF_INFO;
  365. Shell_NotifyIcon(NIM_MODIFY, &nid);
  366. } else if (wParam & TIP_LPARAM_IS_DEVICEINSTANCEID) {
  367. //
  368. // The lParam is a DeviceInstanceID. Convert it to a devnode
  369. // and then call UpdateBalloonInfo.
  370. //
  371. DEVINST DevInst = 0;
  372. if (lParam &&
  373. (CM_Locate_DevNode(&DevInst,
  374. (PTSTR)lParam,
  375. CM_LOCATE_DEVNODE_NORMAL
  376. ) == CR_SUCCESS)) {
  377. UpdateBalloonInfo(hWnd,
  378. NULL,
  379. DevInst,
  380. (wParam & TIP_PLAY_SOUND) ? TRUE : FALSE
  381. );
  382. }
  383. } else {
  384. //
  385. // The lParam is plain text (device description). Send it directly
  386. // to UpdateBalloonInfo.
  387. //
  388. UpdateBalloonInfo(hWnd,
  389. (PTSTR)lParam,
  390. 0,
  391. (wParam & TIP_PLAY_SOUND) ? TRUE : FALSE
  392. );
  393. }
  394. break;
  395. case WM_COPYDATA:
  396. {
  397. //
  398. // This is the case where we needed to launch another instance of
  399. // newdev.dll with Admin credentials to do the actuall device install.
  400. // In order for it to update the UI it will send the main newdev.dll a
  401. // WM_COPYDATA message which will contain the string to display in the
  402. // balloon tooltip.
  403. //
  404. PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
  405. if (pcds && pcds->lpData) {
  406. //
  407. // We assume that the lParam is plain text since the main newdev.dll
  408. // updated the balloon initially with the DeviceDesc.
  409. //
  410. UpdateBalloonInfo(hWnd, (PTSTR)pcds->lpData, 0, FALSE);
  411. }
  412. break;
  413. }
  414. case WUM_EXIT:
  415. if (bCanExit) {
  416. DestroyWindow(hWnd);
  417. } else {
  418. ShowWindow(hWnd, SW_SHOW);
  419. bCanExit = TRUE;
  420. }
  421. break;
  422. default:
  423. break;
  424. }
  425. return DefWindowProc(hWnd, message, wParam, lParam);
  426. }