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.

1300 lines
39 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: rconfirm.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "HotPlug.h"
  11. #define NOTIFYICONDATA_SZINFO 256
  12. #define NOTIFYICONDATA_SZINFOTITLE 64
  13. #define WM_NOTIFY_MESSAGE (WM_USER + 100)
  14. extern HMODULE hHotPlug;
  15. DWORD
  16. WaitDlgMessagePump(
  17. HWND hDlg,
  18. DWORD nCount,
  19. LPHANDLE Handles
  20. )
  21. {
  22. DWORD WaitReturn;
  23. MSG Msg;
  24. while ((WaitReturn = MsgWaitForMultipleObjects(nCount,
  25. Handles,
  26. FALSE,
  27. INFINITE,
  28. QS_ALLINPUT
  29. ))
  30. == nCount)
  31. {
  32. while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {
  33. if (!IsDialogMessage(hDlg,&Msg)) {
  34. TranslateMessage(&Msg);
  35. DispatchMessage(&Msg);
  36. }
  37. }
  38. }
  39. return WaitReturn;
  40. }
  41. int
  42. InsertDeviceNodeListView(
  43. HWND hwndList,
  44. PDEVICETREE DeviceTree,
  45. PDEVTREENODE DeviceTreeNode,
  46. INT lvIndex
  47. )
  48. {
  49. LV_ITEM lviItem;
  50. TCHAR Buffer[MAX_PATH];
  51. lviItem.mask = LVIF_TEXT | LVIF_PARAM;
  52. lviItem.iItem = lvIndex;
  53. lviItem.iSubItem = 0;
  54. if (SetupDiGetClassImageIndex(&DeviceTree->ClassImageList,
  55. &DeviceTreeNode->ClassGuid,
  56. &lviItem.iImage
  57. ))
  58. {
  59. lviItem.mask |= LVIF_IMAGE;
  60. }
  61. lviItem.pszText = FetchDeviceName(DeviceTreeNode);
  62. if (!lviItem.pszText) {
  63. lviItem.pszText = Buffer;
  64. StringCchPrintf(Buffer,
  65. SIZECHARS(Buffer),
  66. TEXT("%s %s"),
  67. szUnknown,
  68. DeviceTreeNode->Location ? DeviceTreeNode->Location : TEXT("")
  69. );
  70. }
  71. lviItem.lParam = (LPARAM) DeviceTreeNode;
  72. return ListView_InsertItem(hwndList, &lviItem);
  73. }
  74. DWORD
  75. RemoveThread(
  76. PVOID pvDeviceTree
  77. )
  78. {
  79. PDEVICETREE DeviceTree = (PDEVICETREE)pvDeviceTree;
  80. PDEVTREENODE DeviceTreeNode;
  81. DeviceTreeNode = DeviceTree->ChildRemovalList;
  82. return(CM_Request_Device_Eject_Ex(DeviceTreeNode->DevInst,
  83. NULL,
  84. NULL,
  85. 0,
  86. 0,
  87. NULL
  88. ));
  89. }
  90. BOOL
  91. OnOkRemove(
  92. HWND hDlg,
  93. PDEVICETREE DeviceTree
  94. )
  95. {
  96. HCURSOR hCursor;
  97. PDEVTREENODE DeviceTreeNode;
  98. HANDLE hThread;
  99. DWORD ThreadId;
  100. DWORD WaitReturn;
  101. BOOL bSuccess;
  102. //
  103. // disable the ok\cancel buttons
  104. //
  105. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  106. EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
  107. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  108. DeviceTreeNode = DeviceTree->ChildRemovalList;
  109. DeviceTree->RedrawWait = TRUE;
  110. hThread = CreateThread(NULL,
  111. 0,
  112. RemoveThread,
  113. DeviceTree,
  114. 0,
  115. &ThreadId
  116. );
  117. if (!hThread) {
  118. return FALSE;
  119. }
  120. WaitReturn = WaitDlgMessagePump(hDlg, 1, &hThread);
  121. bSuccess =
  122. (WaitReturn == 0 &&
  123. GetExitCodeThread(hThread, &WaitReturn) &&
  124. WaitReturn == CR_SUCCESS );
  125. SetCursor(hCursor);
  126. DeviceTree->RedrawWait = FALSE;
  127. CloseHandle(hThread);
  128. return bSuccess;
  129. }
  130. #define idh_hwwizard_confirm_stop_list 15321 // "" (SysListView32)
  131. DWORD RemoveConfirmHelpIDs[] = {
  132. IDC_REMOVELIST, idh_hwwizard_confirm_stop_list,
  133. IDC_NOHELP1, NO_HELP,
  134. IDC_NOHELP2, NO_HELP,
  135. IDC_NOHELP3, NO_HELP,
  136. 0,0
  137. };
  138. BOOL
  139. InitRemoveConfirmDlgProc(
  140. HWND hDlg,
  141. PDEVICETREE DeviceTree
  142. )
  143. {
  144. HWND hwndList;
  145. PDEVTREENODE DeviceTreeNode;
  146. int lvIndex;
  147. LV_COLUMN lvcCol;
  148. HICON hIcon;
  149. hIcon = LoadIcon(hHotPlug,MAKEINTRESOURCE(IDI_HOTPLUGICON));
  150. if (hIcon) {
  151. SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
  152. SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
  153. }
  154. DeviceTreeNode = DeviceTree->ChildRemovalList;
  155. if (!DeviceTreeNode) {
  156. return FALSE;
  157. }
  158. DeviceTree->hwndRemove = hDlg;
  159. hwndList = GetDlgItem(hDlg, IDC_REMOVELIST);
  160. ListView_SetImageList(hwndList, DeviceTree->ClassImageList.ImageList, LVSIL_SMALL);
  161. ListView_DeleteAllItems(hwndList);
  162. // Insert a column for the class list
  163. lvcCol.mask = LVCF_FMT | LVCF_WIDTH;
  164. lvcCol.fmt = LVCFMT_LEFT;
  165. lvcCol.iSubItem = 0;
  166. ListView_InsertColumn(hwndList, 0, (LV_COLUMN FAR *)&lvcCol);
  167. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  168. //
  169. // Walk the removal list and add each of them to the listbox.
  170. //
  171. lvIndex = 0;
  172. do {
  173. InsertDeviceNodeListView(hwndList, DeviceTree, DeviceTreeNode, lvIndex++);
  174. DeviceTreeNode = DeviceTreeNode->NextChildRemoval;
  175. } while (DeviceTreeNode != DeviceTree->ChildRemovalList);
  176. ListView_SetItemState(hwndList, 0, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
  177. ListView_EnsureVisible(hwndList, 0, FALSE);
  178. ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE_USEHEADER);
  179. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  180. return TRUE;
  181. }
  182. INT_PTR CALLBACK
  183. RemoveConfirmDlgProc(
  184. HWND hDlg,
  185. UINT message,
  186. WPARAM wParam,
  187. LPARAM lParam
  188. )
  189. /*++
  190. Routine Description:
  191. DialogProc to confirm user really wants to remove the devices.
  192. Arguments:
  193. standard stuff.
  194. Return Value:
  195. LRESULT
  196. --*/
  197. {
  198. PDEVICETREE DeviceTree=NULL;
  199. if (message == WM_INITDIALOG) {
  200. DeviceTree = (PDEVICETREE)lParam;
  201. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)DeviceTree);
  202. if (DeviceTree) {
  203. InitRemoveConfirmDlgProc(hDlg, DeviceTree);
  204. }
  205. return TRUE;
  206. }
  207. //
  208. // retrieve private data from window long (stored there during WM_INITDIALOG)
  209. //
  210. DeviceTree = (PDEVICETREE)GetWindowLongPtr(hDlg, DWLP_USER);
  211. switch (message) {
  212. case WM_DESTROY:
  213. DeviceTree->hwndRemove = NULL;
  214. break;
  215. case WM_CLOSE:
  216. SendMessage (hDlg, WM_COMMAND, IDCANCEL, 0L);
  217. break;
  218. case WM_COMMAND:
  219. switch(wParam) {
  220. case IDOK:
  221. EndDialog(hDlg, OnOkRemove(hDlg, DeviceTree) ? IDOK : IDCANCEL);
  222. break;
  223. case IDCLOSE:
  224. case IDCANCEL:
  225. EndDialog(hDlg, IDCANCEL);
  226. break;
  227. }
  228. break;
  229. case WUM_EJECTDEVINST:
  230. EndDialog(hDlg, OnOkRemove(hDlg, DeviceTree) ? IDOK : IDCANCEL);
  231. break;
  232. case WM_SYSCOLORCHANGE:
  233. break;
  234. case WM_CONTEXTMENU:
  235. WinHelp((HWND)wParam,
  236. TEXT("hardware.hlp"),
  237. HELP_CONTEXTMENU,
  238. (DWORD_PTR)(LPVOID)(PDWORD)RemoveConfirmHelpIDs
  239. );
  240. return FALSE;
  241. case WM_HELP:
  242. OnContextHelp((LPHELPINFO)lParam, RemoveConfirmHelpIDs);
  243. break;
  244. case WM_SETCURSOR:
  245. if (DeviceTree->RedrawWait || DeviceTree->RefreshEvent) {
  246. SetCursor(LoadCursor(NULL, IDC_WAIT));
  247. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
  248. }
  249. break;
  250. default:
  251. return FALSE;
  252. }
  253. return TRUE;
  254. }
  255. LRESULT CALLBACK
  256. SafeRemovalBalloonProc(
  257. HWND hWnd,
  258. UINT message,
  259. WPARAM wParam,
  260. LPARAM lParam
  261. )
  262. {
  263. NOTIFYICONDATA nid;
  264. static HICON hHotPlugIcon = NULL;
  265. TCHAR szFormat[512];
  266. PDEVICE_COLLECTION safeRemovalCollection;
  267. static BOOL bCheckIfDeviceIsRemoved = FALSE;
  268. switch (message) {
  269. case WM_CREATE:
  270. safeRemovalCollection = (PDEVICE_COLLECTION) ((CREATESTRUCT*)lParam)->lpCreateParams;
  271. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) safeRemovalCollection);
  272. ZeroMemory(&nid, sizeof(nid));
  273. nid.cbSize = sizeof(nid);
  274. nid.hWnd = hWnd;
  275. nid.uID = WM_NOTIFY_MESSAGE;
  276. LoadString(hHotPlug, IDS_REMOVAL_COMPLETE_TEXT, szFormat, SIZECHARS(szFormat));
  277. if (!DeviceCollectionFormatDeviceText(
  278. safeRemovalCollection,
  279. 0,
  280. szFormat,
  281. SIZECHARS(nid.szInfo),
  282. nid.szInfo
  283. )) {
  284. return FALSE;
  285. }
  286. hHotPlugIcon = (HICON)LoadImage(hHotPlug,
  287. MAKEINTRESOURCE(IDI_HOTPLUGICON),
  288. IMAGE_ICON,
  289. GetSystemMetrics(SM_CXSMICON),
  290. GetSystemMetrics(SM_CYSMICON),
  291. 0
  292. );
  293. nid.hIcon = hHotPlugIcon;
  294. nid.uFlags = NIF_MESSAGE | NIF_ICON;
  295. nid.uCallbackMessage = WM_NOTIFY_MESSAGE;
  296. Shell_NotifyIcon(NIM_ADD, &nid);
  297. nid.uVersion = NOTIFYICON_VERSION;
  298. Shell_NotifyIcon(NIM_SETVERSION, &nid);
  299. nid.uFlags = NIF_INFO;
  300. nid.uTimeout = 10000;
  301. nid.dwInfoFlags = NIIF_INFO;
  302. LoadString(hHotPlug,
  303. IDS_REMOVAL_COMPLETE_TITLE,
  304. nid.szInfoTitle,
  305. SIZECHARS(nid.szInfoTitle)
  306. );
  307. Shell_NotifyIcon(NIM_MODIFY, &nid);
  308. SetTimer(hWnd, TIMERID_DEVICECHANGE, 5000, NULL);
  309. break;
  310. case WM_NOTIFY_MESSAGE:
  311. switch(lParam) {
  312. case NIN_BALLOONTIMEOUT:
  313. case NIN_BALLOONUSERCLICK:
  314. DestroyWindow(hWnd);
  315. break;
  316. default:
  317. break;
  318. }
  319. break;
  320. case WM_DEVICECHANGE:
  321. if ((DBT_DEVNODES_CHANGED == wParam) && bCheckIfDeviceIsRemoved) {
  322. SetTimer(hWnd, TIMERID_DEVICECHANGE, 1000, NULL);
  323. }
  324. break;
  325. case WM_TIMER:
  326. if (wParam == TIMERID_DEVICECHANGE) {
  327. KillTimer(hWnd, TIMERID_DEVICECHANGE);
  328. bCheckIfDeviceIsRemoved = TRUE;
  329. safeRemovalCollection = (PDEVICE_COLLECTION) GetWindowLongPtr(hWnd, GWLP_USERDATA);
  330. if (DeviceCollectionCheckIfAllRemoved(safeRemovalCollection)) {
  331. DestroyWindow(hWnd);
  332. }
  333. }
  334. break;
  335. case WM_DESTROY:
  336. ZeroMemory(&nid, sizeof(nid));
  337. nid.cbSize = sizeof(nid);
  338. nid.hWnd = hWnd;
  339. nid.uID = WM_NOTIFY_MESSAGE;
  340. Shell_NotifyIcon(NIM_DELETE, &nid);
  341. if (hHotPlugIcon) {
  342. DestroyIcon(hHotPlugIcon);
  343. }
  344. PostQuitMessage(0);
  345. break;
  346. default:
  347. break;
  348. }
  349. return DefWindowProc(hWnd, message, wParam, lParam);
  350. }
  351. LRESULT CALLBACK
  352. DockSafeRemovalBalloonProc(
  353. HWND hWnd,
  354. UINT message,
  355. WPARAM wParam,
  356. LPARAM lParam
  357. )
  358. {
  359. NOTIFYICONDATA nid;
  360. static HICON hHotPlugIcon = NULL;
  361. TCHAR szFormat[512];
  362. PDEVICE_COLLECTION safeRemovalCollection;
  363. static BOOL bCheckIfReDocked = FALSE;
  364. BOOL bIsDockStationPresent;
  365. switch (message) {
  366. case WM_CREATE:
  367. safeRemovalCollection = (PDEVICE_COLLECTION) ((CREATESTRUCT*)lParam)->lpCreateParams;
  368. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) safeRemovalCollection);
  369. ZeroMemory(&nid, sizeof(nid));
  370. nid.cbSize = sizeof(nid);
  371. nid.hWnd = hWnd;
  372. nid.uID = WM_NOTIFY_MESSAGE;
  373. LoadString(hHotPlug, IDS_UNDOCK_COMPLETE_TEXT, szFormat, SIZECHARS(szFormat));
  374. if (!DeviceCollectionFormatDeviceText(
  375. safeRemovalCollection,
  376. 0,
  377. szFormat,
  378. SIZECHARS(nid.szInfo),
  379. nid.szInfo
  380. )) {
  381. return FALSE;
  382. }
  383. hHotPlugIcon = (HICON)LoadImage(hHotPlug,
  384. MAKEINTRESOURCE(IDI_UNDOCKICON),
  385. IMAGE_ICON,
  386. GetSystemMetrics(SM_CXSMICON),
  387. GetSystemMetrics(SM_CYSMICON),
  388. 0
  389. );
  390. nid.hIcon = hHotPlugIcon;
  391. nid.uFlags = NIF_MESSAGE | NIF_ICON;
  392. nid.uCallbackMessage = WM_NOTIFY_MESSAGE;
  393. Shell_NotifyIcon(NIM_ADD, &nid);
  394. nid.uVersion = NOTIFYICON_VERSION;
  395. Shell_NotifyIcon(NIM_SETVERSION, &nid);
  396. nid.uFlags = NIF_INFO;
  397. nid.uTimeout = 10000;
  398. nid.dwInfoFlags = NIIF_INFO;
  399. LoadString(hHotPlug,
  400. IDS_UNDOCK_COMPLETE_TITLE,
  401. nid.szInfoTitle,
  402. SIZECHARS(nid.szInfoTitle)
  403. );
  404. Shell_NotifyIcon(NIM_MODIFY, &nid);
  405. SetTimer(hWnd, TIMERID_DEVICECHANGE, 5000, NULL);
  406. break;
  407. case WM_NOTIFY_MESSAGE:
  408. switch(lParam) {
  409. case NIN_BALLOONTIMEOUT:
  410. case NIN_BALLOONUSERCLICK:
  411. DestroyWindow(hWnd);
  412. break;
  413. default:
  414. break;
  415. }
  416. break;
  417. case WM_DEVICECHANGE:
  418. if ((DBT_CONFIGCHANGED == wParam) && bCheckIfReDocked) {
  419. SetTimer(hWnd, TIMERID_DEVICECHANGE, 1000, NULL);
  420. }
  421. break;
  422. case WM_TIMER:
  423. if (wParam == TIMERID_DEVICECHANGE) {
  424. KillTimer(hWnd, TIMERID_DEVICECHANGE);
  425. bCheckIfReDocked = TRUE;
  426. //
  427. // Check if the docking station is now present, this means that the
  428. // user redocked the machine and that we should kill the safe to
  429. // undock balloon.
  430. //
  431. bIsDockStationPresent = FALSE;
  432. CM_Is_Dock_Station_Present(&bIsDockStationPresent);
  433. if (bIsDockStationPresent) {
  434. DestroyWindow(hWnd);
  435. }
  436. }
  437. break;
  438. case WM_DESTROY:
  439. ZeroMemory(&nid, sizeof(nid));
  440. nid.cbSize = sizeof(nid);
  441. nid.hWnd = hWnd;
  442. nid.uID = WM_NOTIFY_MESSAGE;
  443. Shell_NotifyIcon(NIM_DELETE, &nid);
  444. if (hHotPlugIcon) {
  445. DestroyIcon(hHotPlugIcon);
  446. }
  447. PostQuitMessage(0);
  448. break;
  449. default:
  450. break;
  451. }
  452. return DefWindowProc(hWnd, message, wParam, lParam);
  453. }
  454. BOOL
  455. VetoedRemovalUI(
  456. IN PVETO_DEVICE_COLLECTION VetoedRemovalCollection
  457. )
  458. {
  459. HANDLE hVetoEvent = NULL;
  460. TCHAR szEventName[MAX_PATH];
  461. TCHAR szFormat[512];
  462. TCHAR szMessage[512];
  463. TCHAR szTitle[256];
  464. PTSTR culpritDeviceId;
  465. PTSTR vetoedDeviceInstancePath;
  466. PTCHAR pStr;
  467. ULONG messageBase;
  468. //
  469. // The first device in the list is the device that failed ejection.
  470. // The next "device" is the name of the vetoer. It may in fact not be a
  471. // device.
  472. //
  473. vetoedDeviceInstancePath = DeviceCollectionGetDeviceInstancePath(
  474. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  475. 0
  476. );
  477. culpritDeviceId = DeviceCollectionGetDeviceInstancePath(
  478. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  479. 1
  480. );
  481. //
  482. // We will now check to see if this same veto message is already being
  483. // displayed. We do this by creating a named event where the name
  484. // contains the three elements that make a veto message unique:
  485. // 1) device instance id
  486. // 2) veto type
  487. // 3) veto operation
  488. //
  489. // If we find an identical veto message already being displayed then we wil
  490. // just go away silently. This prevents multiple identical veto messages
  491. // from showing up on the screen.
  492. //
  493. StringCchPrintf(szEventName,
  494. SIZECHARS(szEventName),
  495. TEXT("Local\\VETO-%d-%d-%s"),
  496. (DWORD)VetoedRemovalCollection->VetoType,
  497. VetoedRemovalCollection->VetoedOperation,
  498. culpritDeviceId
  499. );
  500. //
  501. // Replace all of the backslashes (except the first one for Local\)
  502. // with pound characters since CreateEvent does not like backslashes.
  503. //
  504. pStr = StrChr(szEventName, TEXT('\\'));
  505. if (pStr) {
  506. pStr++;
  507. }
  508. while ((pStr = StrChr(pStr, TEXT('\\'))) != NULL) {
  509. *pStr = TEXT('#');
  510. }
  511. hVetoEvent = CreateEvent(NULL,
  512. FALSE,
  513. TRUE,
  514. szEventName
  515. );
  516. if (hVetoEvent) {
  517. if (WaitForSingleObject(hVetoEvent, 0) != WAIT_OBJECT_0) {
  518. //
  519. // This means that this veto message is already being displayed
  520. // by another hotplug process...so just go away.
  521. //
  522. CloseHandle(hVetoEvent);
  523. return FALSE;
  524. }
  525. }
  526. //
  527. // Create the veto text
  528. //
  529. switch(VetoedRemovalCollection->VetoedOperation) {
  530. case VETOED_UNDOCK:
  531. case VETOED_WARM_UNDOCK:
  532. messageBase = IDS_DOCKVETO_BASE;
  533. break;
  534. case VETOED_STANDBY:
  535. messageBase = IDS_SLEEPVETO_BASE;
  536. break;
  537. case VETOED_HIBERNATE:
  538. messageBase = IDS_HIBERNATEVETO_BASE;
  539. break;
  540. case VETOED_REMOVAL:
  541. case VETOED_EJECT:
  542. case VETOED_WARM_EJECT:
  543. default:
  544. messageBase = IDS_VETO_BASE;
  545. break;
  546. }
  547. switch(VetoedRemovalCollection->VetoType) {
  548. case PNP_VetoWindowsApp:
  549. if (culpritDeviceId) {
  550. //
  551. // Tell our user the name of the offending application.
  552. //
  553. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szFormat, SIZECHARS(szFormat));
  554. DeviceCollectionFormatDeviceText(
  555. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  556. 1,
  557. szFormat,
  558. SIZECHARS(szMessage),
  559. szMessage
  560. );
  561. } else {
  562. //
  563. // No application, use the "some app" message.
  564. //
  565. messageBase += (IDS_VETO_UNKNOWNWINDOWSAPP - IDS_VETO_WINDOWSAPP);
  566. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szMessage, SIZECHARS(szMessage));
  567. }
  568. break;
  569. case PNP_VetoWindowsService:
  570. case PNP_VetoDriver:
  571. case PNP_VetoLegacyDriver:
  572. //
  573. // PNP_VetoWindowsService, PNP_VetoDriver and PNP_VetoLegacyDriver
  574. // are passed through the service manager to get friendlier names.
  575. //
  576. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szFormat, SIZECHARS(szFormat));
  577. //
  578. // For these veto types, entry index 1 is the vetoing service.
  579. //
  580. DeviceCollectionFormatServiceText(
  581. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  582. 1,
  583. szFormat,
  584. SIZECHARS(szMessage),
  585. szMessage
  586. );
  587. break;
  588. case PNP_VetoDevice:
  589. if ((VetoedRemovalCollection->VetoedOperation == VETOED_WARM_UNDOCK) &&
  590. (!lstrcmp(culpritDeviceId, vetoedDeviceInstancePath))) {
  591. messageBase += (IDS_DOCKVETO_WARM_EJECT - IDS_DOCKVETO_DEVICE);
  592. }
  593. //
  594. // Fall through.
  595. //
  596. case PNP_VetoLegacyDevice:
  597. case PNP_VetoPendingClose:
  598. case PNP_VetoOutstandingOpen:
  599. case PNP_VetoNonDisableable:
  600. case PNP_VetoIllegalDeviceRequest:
  601. //
  602. // Include the veto ID in the display output
  603. //
  604. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szFormat, SIZECHARS(szFormat));
  605. DeviceCollectionFormatDeviceText(
  606. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  607. 1,
  608. szFormat,
  609. SIZECHARS(szMessage),
  610. szMessage
  611. );
  612. break;
  613. case PNP_VetoInsufficientRights:
  614. //
  615. // Use the device itself in the display, but only if we are not
  616. // in the dock case.
  617. //
  618. if ((VetoedRemovalCollection->VetoedOperation == VETOED_UNDOCK)||
  619. (VetoedRemovalCollection->VetoedOperation == VETOED_WARM_UNDOCK)) {
  620. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szMessage, SIZECHARS(szMessage));
  621. break;
  622. }
  623. //
  624. // Fall through.
  625. //
  626. case PNP_VetoInsufficientPower:
  627. case PNP_VetoTypeUnknown:
  628. //
  629. // Use the device itself in the display
  630. //
  631. LoadString(hHotPlug, messageBase+VetoedRemovalCollection->VetoType, szFormat, SIZECHARS(szFormat));
  632. DeviceCollectionFormatDeviceText(
  633. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  634. 0,
  635. szFormat,
  636. SIZECHARS(szMessage),
  637. szMessage
  638. );
  639. break;
  640. default:
  641. ASSERT(0);
  642. LoadString(hHotPlug, messageBase+PNP_VetoTypeUnknown, szFormat, SIZECHARS(szFormat));
  643. DeviceCollectionFormatDeviceText(
  644. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  645. 0,
  646. szFormat,
  647. SIZECHARS(szMessage),
  648. szMessage
  649. );
  650. break;
  651. }
  652. switch(VetoedRemovalCollection->VetoedOperation) {
  653. case VETOED_EJECT:
  654. case VETOED_WARM_EJECT:
  655. LoadString(hHotPlug, IDS_VETOED_EJECT_TITLE, szFormat, SIZECHARS(szFormat));
  656. break;
  657. case VETOED_UNDOCK:
  658. case VETOED_WARM_UNDOCK:
  659. LoadString(hHotPlug, IDS_VETOED_UNDOCK_TITLE, szFormat, SIZECHARS(szFormat));
  660. break;
  661. case VETOED_STANDBY:
  662. LoadString(hHotPlug, IDS_VETOED_STANDBY_TITLE, szFormat, SIZECHARS(szFormat));
  663. break;
  664. case VETOED_HIBERNATE:
  665. LoadString(hHotPlug, IDS_VETOED_HIBERNATION_TITLE, szFormat, SIZECHARS(szFormat));
  666. break;
  667. default:
  668. ASSERT(0);
  669. //
  670. // Fall through, display something at least...
  671. //
  672. case VETOED_REMOVAL:
  673. LoadString(hHotPlug, IDS_VETOED_REMOVAL_TITLE, szFormat, SIZECHARS(szFormat));
  674. break;
  675. }
  676. switch(VetoedRemovalCollection->VetoedOperation) {
  677. case VETOED_STANDBY:
  678. case VETOED_HIBERNATE:
  679. StringCchCopy(szTitle, SIZECHARS(szTitle), szFormat);
  680. break;
  681. case VETOED_EJECT:
  682. case VETOED_WARM_EJECT:
  683. case VETOED_UNDOCK:
  684. case VETOED_WARM_UNDOCK:
  685. case VETOED_REMOVAL:
  686. default:
  687. DeviceCollectionFormatDeviceText(
  688. (PDEVICE_COLLECTION) VetoedRemovalCollection,
  689. 0,
  690. szFormat,
  691. SIZECHARS(szTitle),
  692. szTitle
  693. );
  694. break;
  695. }
  696. MessageBox(NULL, szMessage, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST);
  697. if (hVetoEvent) {
  698. CloseHandle(hVetoEvent);
  699. }
  700. return TRUE;
  701. }
  702. void
  703. DisplayDriverBlockBalloon(
  704. IN PDEVICE_COLLECTION blockedDriverCollection
  705. )
  706. {
  707. HRESULT hr;
  708. TCHAR szMessage[NOTIFYICONDATA_SZINFO]; // same size as NOTIFYICONDATA.szInfo
  709. TCHAR szFormat[NOTIFYICONDATA_SZINFO]; // same size as NOTIFYICONDATA.szInfo
  710. TCHAR szTitle[NOTIFYICONDATA_SZINFOTITLE]; // same size as NOTIFYICONDATA.szInfoTitle
  711. HICON hicon = NULL;
  712. HANDLE hShellReadyEvent = NULL;
  713. INT ShellReadyEventCount = 0;
  714. GUID guidDB, guidID;
  715. HAPPHELPINFOCONTEXT hAppHelpInfoContext = NULL;
  716. PTSTR Buffer;
  717. ULONG BufferSize, ApphelpURLBufferSize;
  718. if (!LoadString(hHotPlug, IDS_BLOCKDRIVER_TITLE, szTitle, SIZECHARS(szTitle))) {
  719. //
  720. // The machine is so low on memory that we can't even get the text strings, so
  721. // just exit.
  722. //
  723. return;
  724. }
  725. szMessage[0] = TEXT('\0');
  726. if (blockedDriverCollection->NumDevices == 1) {
  727. //
  728. // If we only have one device in the list then we will show specific
  729. // information about this blocked driver as well as directly launching the
  730. // help for this blocked driver.
  731. //
  732. if (SdbGetStandardDatabaseGUID(SDB_DATABASE_MAIN_DRIVERS, &guidDB) &&
  733. DeviceCollectionGetGuid((PDEVICE_COLLECTION)blockedDriverCollection,
  734. &guidID,
  735. 0)) {
  736. hAppHelpInfoContext = SdbOpenApphelpInformation(&guidDB, &guidID);
  737. Buffer = NULL;
  738. if ((hAppHelpInfoContext) &&
  739. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  740. ApphelpAppName,
  741. NULL,
  742. 0)) != 0) &&
  743. ((Buffer = (PTSTR)LocalAlloc(LPTR, BufferSize)) != NULL) &&
  744. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  745. ApphelpAppName,
  746. Buffer,
  747. BufferSize)) != 0)) {
  748. if (LoadString(hHotPlug, IDS_BLOCKDRIVER_FORMAT, szFormat, SIZECHARS(szFormat)) &&
  749. (lstrlen(szFormat) + lstrlen(Buffer) < NOTIFYICONDATA_SZINFO)) {
  750. //
  751. // The app name and format string will fit into the buffer so
  752. // use the format for the balloon message.
  753. //
  754. StringCchPrintf(szMessage,
  755. SIZECHARS(szMessage),
  756. szFormat,
  757. Buffer);
  758. } else {
  759. //
  760. // The app name is too large to be formated int he balloon
  761. // message, so just show the app name.
  762. //
  763. StringCchCopy(szMessage, SIZECHARS(szMessage), Buffer);
  764. }
  765. }
  766. if (Buffer) {
  767. LocalFree(Buffer);
  768. }
  769. }
  770. }
  771. if (szMessage[0] == TEXT('\0')) {
  772. //
  773. // We either have more than one driver, or an error occured while trying
  774. // to access the specific information about the one driver we received,
  775. // so just show the generic message.
  776. //
  777. if (!LoadString(hHotPlug, IDS_BLOCKDRIVER_MESSAGE, szMessage, SIZECHARS(szMessage))) {
  778. //
  779. // The machine is so low on memory that we can't even get the text strings, so
  780. // just exit.
  781. //
  782. return;
  783. }
  784. }
  785. hicon = (HICON)LoadImage(hHotPlug,
  786. MAKEINTRESOURCE(IDI_BLOCKDRIVER),
  787. IMAGE_ICON,
  788. GetSystemMetrics(SM_CXSMICON),
  789. GetSystemMetrics(SM_CYSMICON),
  790. 0
  791. );
  792. //
  793. // Make sure the shell is up and running so we can display the balloon.
  794. //
  795. while ((hShellReadyEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("ShellReadyEvent"))) == NULL) {
  796. //
  797. // Sleep for 1 second and then try again.
  798. //
  799. Sleep(5000);
  800. if (ShellReadyEventCount++ > 120) {
  801. //
  802. // We have been waiting for the shell for 10 minutes and it still
  803. // is not around.
  804. //
  805. break;
  806. }
  807. }
  808. if (hShellReadyEvent) {
  809. WaitForSingleObject(hShellReadyEvent, INFINITE);
  810. CloseHandle(hShellReadyEvent);
  811. if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
  812. IUserNotification *pun;
  813. hr = CoCreateInstance(CLSID_UserNotification,
  814. NULL,
  815. CLSCTX_INPROC_SERVER,
  816. IID_IUserNotification,
  817. (void**)&pun);
  818. if (SUCCEEDED(hr)) {
  819. pun->SetIconInfo(hicon, szTitle);
  820. pun->SetBalloonInfo(szTitle, szMessage, NIIF_WARNING);
  821. //
  822. // Try once for 20 seconds
  823. //
  824. pun->SetBalloonRetry((20 * 1000), (DWORD)-1, 0);
  825. hr = pun->Show(NULL, 0);
  826. //
  827. // if hr is S_OK then user clicked on the balloon, if it is ERROR_CANCELLED
  828. // then the balloon timedout.
  829. //
  830. if (hr == S_OK) {
  831. if ((blockedDriverCollection->NumDevices == 1) &&
  832. (hAppHelpInfoContext != NULL)) {
  833. //
  834. // If we only have one device in the list then just
  835. // launch the help for that blocked driver.
  836. //
  837. ApphelpURLBufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  838. ApphelpHelpCenterURL,
  839. NULL,
  840. 0);
  841. if (ApphelpURLBufferSize) {
  842. BufferSize = ApphelpURLBufferSize + (lstrlen(TEXT("HELPCTR.EXE -url ")) * sizeof(TCHAR));
  843. if ((Buffer = (PTSTR)LocalAlloc(LPTR, BufferSize)) != NULL) {
  844. if (SUCCEEDED(StringCbCopy(Buffer, BufferSize, TEXT("HELPCTR.EXE -url ")))) {
  845. SdbQueryApphelpInformation(hAppHelpInfoContext,
  846. ApphelpHelpCenterURL,
  847. (PVOID)&Buffer[lstrlen(TEXT("HELPCTR.EXE -url "))],
  848. ApphelpURLBufferSize);
  849. ShellExecute(NULL,
  850. TEXT("open"),
  851. TEXT("HELPCTR.EXE"),
  852. Buffer,
  853. NULL,
  854. SW_SHOWNORMAL);
  855. }
  856. LocalFree(Buffer);
  857. }
  858. }
  859. } else {
  860. //
  861. // We have more than one device in the list so launch
  862. // the summary blocked driver page.
  863. //
  864. ShellExecute(NULL,
  865. TEXT("open"),
  866. TEXT("HELPCTR.EXE"),
  867. TEXT("HELPCTR.EXE -url hcp://services/centers/support?topic=hcp://system/sysinfo/sysHealthInfo.htm"),
  868. NULL,
  869. SW_SHOWNORMAL
  870. );
  871. }
  872. }
  873. pun->Release();
  874. }
  875. CoUninitialize();
  876. }
  877. }
  878. if (hicon) {
  879. DestroyIcon(hicon);
  880. }
  881. if (hAppHelpInfoContext) {
  882. SdbCloseApphelpInformation(hAppHelpInfoContext);
  883. }
  884. }
  885. void
  886. DisplayChildWithInvalidIdBalloon(
  887. IN PDEVICE_COLLECTION childWithInvalidCollection
  888. )
  889. {
  890. HRESULT hr;
  891. TCHAR szMessage[NOTIFYICONDATA_SZINFO]; // same size as NOTIFYICONDATA.szInfo
  892. TCHAR szFormat[NOTIFYICONDATA_SZINFO]; // same size as NOTIFYICONDATA.szInfo
  893. TCHAR szTitle[NOTIFYICONDATA_SZINFOTITLE]; // same size as NOTIFYICONDATA.szInfoTitle
  894. HICON hicon = NULL;
  895. HANDLE hShellReadyEvent = NULL;
  896. INT ShellReadyEventCount = 0;
  897. PTSTR deviceFriendlyName;
  898. GUID ClassGuid;
  899. INT ImageIndex;
  900. SP_CLASSIMAGELIST_DATA ClassImageListData;
  901. ClassImageListData.cbSize = 0;
  902. if (!LoadString(hHotPlug, IDS_CHILDWITHINVALIDID_TITLE, szTitle, SIZECHARS(szTitle))) {
  903. //
  904. // The machine is so low on memory that we can't even get the text strings, so
  905. // just exit.
  906. //
  907. return;
  908. }
  909. if (!LoadString(hHotPlug, IDS_CHILDWITHINVALIDID_FORMAT, szFormat, SIZECHARS(szFormat))) {
  910. //
  911. // The machine is so low on memory that we can't even get the text strings, so
  912. // just exit.
  913. //
  914. return;
  915. }
  916. szMessage[0] = TEXT('\0');
  917. deviceFriendlyName = DeviceCollectionGetDeviceFriendlyName(
  918. (PDEVICE_COLLECTION)childWithInvalidCollection,
  919. 0
  920. );
  921. if (deviceFriendlyName) {
  922. if (lstrlen(szFormat) + lstrlen(deviceFriendlyName) < NOTIFYICONDATA_SZINFO) {
  923. //
  924. // The device friendly name and format string will fit into
  925. // the buffer.
  926. //
  927. StringCchPrintf(szMessage,
  928. SIZECHARS(szMessage),
  929. szFormat,
  930. deviceFriendlyName);
  931. } else {
  932. //
  933. // The device friendly name is too large to be formated int the
  934. // balloon message, so just show the device friendly name.
  935. //
  936. StringCchCopy(szMessage, SIZECHARS(szMessage), deviceFriendlyName);
  937. }
  938. }
  939. if (szMessage[0] == TEXT('\0')) {
  940. return;
  941. }
  942. //
  943. // We have to go through a hole bunch of code to get the small class icon
  944. // for a device. The reason for this is setupapi only has an API to get
  945. // the large class icon, and not the small class icon. To get the small
  946. // class icon we must get get the device's class GUID, then have setupapi
  947. // build up a image list of class icons (which are made up of small icons),
  948. // then get the index of the class icon in this list, and finally extract
  949. // the small icon from the image list.
  950. //
  951. if (DeviceCollectionGetGuid((PDEVICE_COLLECTION)childWithInvalidCollection,
  952. &ClassGuid,
  953. 0)) {
  954. //
  955. // Have setupapi build up the image list of class icons.
  956. //
  957. ClassImageListData.cbSize = sizeof(ClassImageListData);
  958. if (SetupDiGetClassImageList(&ClassImageListData)) {
  959. //
  960. // Get the index of the class icon for this device.
  961. //
  962. if (SetupDiGetClassImageIndex(&ClassImageListData,
  963. &ClassGuid,
  964. &ImageIndex)) {
  965. //
  966. // We now have the ImageIndex of the class icon for this device
  967. // in the ImageList. Class ImageList_GetIcon to get the icon
  968. // for the device class.
  969. //
  970. hicon = ImageList_GetIcon(ClassImageListData.ImageList,
  971. ImageIndex,
  972. ILD_NORMAL);
  973. }
  974. } else {
  975. //
  976. // We failed to build the class image list so set the cbSize field
  977. // to 0 so we no we don't have to call SetupDiDestroyClassImageList
  978. //
  979. ClassImageListData.cbSize = 0;
  980. }
  981. }
  982. //
  983. // Make sure the shell is up and running so we can display the balloon.
  984. //
  985. while ((hShellReadyEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("ShellReadyEvent"))) == NULL) {
  986. //
  987. // Sleep for 5 second and then try again.
  988. //
  989. Sleep(5000);
  990. if (ShellReadyEventCount++ > 120) {
  991. //
  992. // We have been waiting for the shell for 10 minutes and it still
  993. // is not around.
  994. //
  995. break;
  996. }
  997. }
  998. if (hShellReadyEvent) {
  999. WaitForSingleObject(hShellReadyEvent, INFINITE);
  1000. CloseHandle(hShellReadyEvent);
  1001. if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
  1002. IUserNotification *pun;
  1003. hr = CoCreateInstance(CLSID_UserNotification,
  1004. NULL,
  1005. CLSCTX_INPROC_SERVER,
  1006. IID_IUserNotification,
  1007. (void**)&pun);
  1008. if (SUCCEEDED(hr)) {
  1009. pun->SetIconInfo(hicon, szTitle);
  1010. pun->SetBalloonInfo(szTitle, szMessage, NIIF_WARNING);
  1011. //
  1012. // Try once for 20 seconds
  1013. //
  1014. pun->SetBalloonRetry((20 * 1000), (DWORD)-1, 0);
  1015. hr = pun->Show(NULL, 0);
  1016. //
  1017. // if hr is S_OK then user clicked on the balloon, if it is ERROR_CANCELLED
  1018. // then the balloon timedout.
  1019. //
  1020. if (hr == S_OK) {
  1021. //
  1022. // ISSUE: Launch helpcenter.
  1023. //
  1024. }
  1025. pun->Release();
  1026. }
  1027. CoUninitialize();
  1028. }
  1029. }
  1030. if (hicon) {
  1031. DestroyIcon(hicon);
  1032. }
  1033. if (ClassImageListData.cbSize != 0) {
  1034. SetupDiDestroyClassImageList(&ClassImageListData);
  1035. }
  1036. }