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.

972 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: hotplug.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "HotPlug.h"
  11. TCHAR szUnknown[64];
  12. TCHAR szHotPlugFlags[]=TEXT("HotPlugFlags");
  13. TCHAR HOTPLUG_NOTIFY_CLASS_NAME[] = TEXT("HotPlugNotifyClass");
  14. typedef int
  15. (*PDEVICEPROPERTIES)(
  16. HWND hwndParent,
  17. LPTSTR MachineName,
  18. LPTSTR DeviceID,
  19. BOOL ShowDeviceTree
  20. );
  21. //
  22. // colors used to highlight removal relationships for selected device
  23. //
  24. COLORREF RemovalImageBkColor;
  25. COLORREF NormalImageBkColor;
  26. COLORREF RemovalTextColor;
  27. HWND g_hwndNotify = NULL;
  28. HMODULE hDevMgr=NULL;
  29. PDEVICEPROPERTIES pDeviceProperties = NULL;
  30. #define IDH_DISABLEHELP ((DWORD)(-1))
  31. #define IDH_hwwizard_devices_list 15301 // (SysTreeView32)
  32. #define idh_hwwizard_stop 15305 // "&Stop" (Button)
  33. #define idh_hwwizard_display_components 15307 // "&Display device components" (Button)
  34. #define idh_hwwizard_properties 15311 // "&Properties" (Button)
  35. #define idh_hwwizard_close 15309 // "&Close" (Button)
  36. DWORD UnplugtHelpIDs[] = {
  37. IDC_STOPDEVICE, idh_hwwizard_stop, // "&Stop" (Button)
  38. IDC_PROPERTIES, idh_hwwizard_properties, // "&Properties" (Button)
  39. IDC_VIEWOPTION, idh_hwwizard_display_components, // "&Display device components" (Button)
  40. IDC_DEVICETREE, IDH_hwwizard_devices_list, // "" (SysTreeView32)
  41. IDCLOSE, idh_hwwizard_close,
  42. IDC_HDWDEVICES, NO_HELP,
  43. IDC_NOHELP1, NO_HELP,
  44. IDC_NOHELP2, NO_HELP,
  45. IDC_NOHELP3, NO_HELP,
  46. IDC_DEVICEDESC, NO_HELP,
  47. 0,0
  48. };
  49. void
  50. OnRemoveDevice(
  51. HWND hDlg,
  52. PDEVICETREE DeviceTree
  53. )
  54. {
  55. PDEVTREENODE DeviceTreeNode;
  56. DeviceTreeNode = DeviceTree->ChildRemovalList;
  57. if (!DeviceTreeNode) {
  58. return;
  59. }
  60. //
  61. // Confirm with the user that they really want
  62. // to remove this device and all of its attached devices.
  63. // The dialog returns standard IDOK, IDCANCEL etc. for results.
  64. // if anything besides IDOK don't do anything.
  65. //
  66. DialogBoxParam(hHotPlug,
  67. MAKEINTRESOURCE(DLG_CONFIRMREMOVE),
  68. hDlg,
  69. RemoveConfirmDlgProc,
  70. (LPARAM)DeviceTree
  71. );
  72. return;
  73. }
  74. void
  75. OnTvnSelChanged(
  76. PDEVICETREE DeviceTree,
  77. NM_TREEVIEW *nmTreeView
  78. )
  79. {
  80. PDEVTREENODE DeviceTreeNode = (PDEVTREENODE)(nmTreeView->itemNew.lParam);
  81. PTCHAR DeviceName;
  82. ULONG DevNodeStatus, Problem;
  83. CONFIGRET ConfigRet;
  84. TCHAR Buffer[MAX_PATH*2];
  85. if (DeviceTree->RedrawWait) {
  86. return;
  87. }
  88. //
  89. // Clear Removal list for previously selected Node
  90. //
  91. ClearRemovalList(DeviceTree);
  92. //
  93. // Save the selected treenode.
  94. //
  95. DeviceTree->SelectedTreeNode = DeviceTreeNode;
  96. //
  97. // No device is selected
  98. //
  99. if (!DeviceTreeNode) {
  100. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_STOPDEVICE), FALSE);
  101. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_PROPERTIES), FALSE);
  102. SetDlgItemText(DeviceTree->hDlg, IDC_DEVICEDESC, TEXT(""));
  103. return;
  104. }
  105. //
  106. // reset the text for the selected item
  107. //
  108. DeviceName = FetchDeviceName(DeviceTreeNode);
  109. if (!DeviceName) {
  110. DeviceName = szUnknown;
  111. }
  112. StringCchPrintf(Buffer,
  113. SIZECHARS(Buffer),
  114. TEXT("%s %s"),
  115. DeviceName,
  116. DeviceTreeNode->Location ? DeviceTreeNode->Location : TEXT("")
  117. );
  118. SetDlgItemText(DeviceTree->hDlg, IDC_DEVICEDESC, Buffer);
  119. //
  120. // Turn on the stop\eject button, and set text accordingly.
  121. //
  122. ConfigRet = CM_Get_DevNode_Status_Ex(&DevNodeStatus,
  123. &Problem,
  124. DeviceTreeNode->DevInst,
  125. 0,
  126. NULL
  127. );
  128. if (ConfigRet != CR_SUCCESS) {
  129. DevNodeStatus = 0;
  130. Problem = 0;
  131. }
  132. //
  133. // Any removable (but not surprise removable) device is OK, except
  134. // if the user already removed it.
  135. //
  136. if (Problem != CM_PROB_HELD_FOR_EJECT) {
  137. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_STOPDEVICE), TRUE);
  138. } else {
  139. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_STOPDEVICE), FALSE);
  140. }
  141. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_PROPERTIES), TRUE);
  142. //
  143. // reset the overlay icons if device state has changed
  144. //
  145. if (DeviceTreeNode->Problem != Problem || DeviceTreeNode->DevNodeStatus != DevNodeStatus) {
  146. TV_ITEM tv;
  147. tv.mask = TVIF_STATE;
  148. tv.stateMask = TVIS_OVERLAYMASK;
  149. tv.hItem = DeviceTreeNode->hTreeItem;
  150. if (DeviceTreeNode->Problem == CM_PROB_DISABLED) {
  151. tv.state = INDEXTOOVERLAYMASK(IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
  152. } else if (DeviceTreeNode->Problem) {
  153. tv.state = INDEXTOOVERLAYMASK(IDI_PROBLEM_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
  154. } else {
  155. tv.state = INDEXTOOVERLAYMASK(0);
  156. }
  157. TreeView_SetItem(DeviceTree->hwndTree, &tv);
  158. }
  159. //
  160. // Starting from the TopLevel removal node, build up the removal lists
  161. //
  162. DeviceTreeNode = TopLevelRemovalNode(DeviceTree, DeviceTreeNode);
  163. //
  164. // Add devices to ChildRemoval list
  165. //
  166. DeviceTree->ChildRemovalList = DeviceTreeNode;
  167. DeviceTreeNode->NextChildRemoval = DeviceTreeNode;
  168. InvalidateTreeItemRect(DeviceTree->hwndTree, DeviceTreeNode->hTreeItem);
  169. AddChildRemoval(DeviceTree, &DeviceTreeNode->ChildSiblingList);
  170. //
  171. // Add eject amd removal relations
  172. //
  173. AddEjectToRemoval(DeviceTree);
  174. }
  175. int
  176. OnCustomDraw(
  177. HWND hDlg,
  178. PDEVICETREE DeviceTree,
  179. LPNMTVCUSTOMDRAW nmtvCustomDraw
  180. )
  181. {
  182. PDEVTREENODE DeviceTreeNode = (PDEVTREENODE)(nmtvCustomDraw->nmcd.lItemlParam);
  183. UNREFERENCED_PARAMETER(hDlg);
  184. if (nmtvCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) {
  185. return CDRF_NOTIFYITEMDRAW;
  186. }
  187. //
  188. // If this node is in the Removal list, then do special
  189. // highlighting.
  190. //
  191. if (DeviceTreeNode->NextChildRemoval) {
  192. //
  193. // set text color if its not the selected item
  194. //
  195. if (DeviceTree->SelectedTreeNode != DeviceTreeNode) {
  196. nmtvCustomDraw->clrText = RemovalTextColor;
  197. }
  198. //
  199. // Highlight the image-icon background
  200. //
  201. ImageList_SetBkColor(DeviceTree->ClassImageList.ImageList,
  202. RemovalImageBkColor
  203. );
  204. } else {
  205. //
  206. // Normal image-icon background
  207. //
  208. ImageList_SetBkColor(DeviceTree->ClassImageList.ImageList,
  209. NormalImageBkColor
  210. );
  211. }
  212. return CDRF_DODEFAULT;
  213. }
  214. void
  215. OnSysColorChange(
  216. HWND hDlg,
  217. PDEVICETREE DeviceTree
  218. )
  219. {
  220. COLORREF ColorWindow, ColorHighlight;
  221. BYTE Red, Green, Blue;
  222. UNREFERENCED_PARAMETER(hDlg);
  223. //
  224. // Fetch the colors used for removal highlighting
  225. //
  226. ColorWindow = GetSysColor(COLOR_WINDOW);
  227. ColorHighlight = GetSysColor(COLOR_HIGHLIGHT);
  228. Red = (BYTE)(((WORD)GetRValue(ColorWindow) + (WORD)GetRValue(ColorHighlight)) >> 1);
  229. Green = (BYTE)(((WORD)GetGValue(ColorWindow) + (WORD)GetGValue(ColorHighlight)) >> 1);
  230. Blue = (BYTE)(((WORD)GetBValue(ColorWindow) + (WORD)GetBValue(ColorHighlight)) >> 1);
  231. RemovalImageBkColor = RGB(Red, Green, Blue);
  232. RemovalTextColor = ColorHighlight;
  233. NormalImageBkColor = ColorWindow;
  234. //
  235. // Update the ImageList Background color
  236. //
  237. if (DeviceTree->ClassImageList.cbSize) {
  238. ImageList_SetBkColor(DeviceTree->ClassImageList.ImageList,
  239. ColorWindow
  240. );
  241. }
  242. }
  243. void
  244. OnTvnItemExpanding(
  245. HWND hDlg,
  246. NM_TREEVIEW *nmTreeView
  247. )
  248. {
  249. PDEVTREENODE DeviceTreeNode = (PDEVTREENODE)(nmTreeView->itemNew.lParam);
  250. //
  251. // don't allow collapse of root items with children
  252. //
  253. if (!DeviceTreeNode->ParentNode &&
  254. (nmTreeView->action == TVE_COLLAPSE ||
  255. nmTreeView->action == TVE_COLLAPSERESET ||
  256. (nmTreeView->action == TVE_TOGGLE &&
  257. (nmTreeView->itemNew.state & TVIS_EXPANDED))) ) {
  258. SetDlgMsgResult(hDlg, WM_NOTIFY, TRUE);
  259. } else {
  260. SetDlgMsgResult(hDlg, WM_NOTIFY, FALSE);
  261. }
  262. }
  263. void
  264. OnContextMenu(
  265. HWND hDlg,
  266. PDEVICETREE DeviceTree
  267. )
  268. {
  269. int IdCmd;
  270. POINT ptPopup;
  271. RECT rect;
  272. HMENU hMenu;
  273. PDEVTREENODE DeviceTreeNode;
  274. TCHAR Buffer[MAX_PATH];
  275. DeviceTreeNode = DeviceTree->SelectedTreeNode;
  276. if (!DeviceTreeNode) {
  277. return;
  278. }
  279. TreeView_GetItemRect(DeviceTree->hwndTree,
  280. DeviceTreeNode->hTreeItem,
  281. &rect,
  282. TRUE
  283. );
  284. ptPopup.x = (rect.left+rect.right)/2;
  285. ptPopup.y = (rect.top+rect.bottom)/2;
  286. ClientToScreen(DeviceTree->hwndTree, &ptPopup);
  287. hMenu = CreatePopupMenu();
  288. if (!hMenu) {
  289. return;
  290. }
  291. //
  292. // if device is running add stop item
  293. //
  294. if (DeviceTreeNode->DevNodeStatus & DN_STARTED) {
  295. LoadString(hHotPlug,
  296. IDS_STOP,
  297. Buffer,
  298. SIZECHARS(Buffer)
  299. );
  300. AppendMenu(hMenu, MF_STRING, IDC_STOPDEVICE, Buffer);
  301. }
  302. //
  303. // add Properties item (link to device mgr).
  304. //
  305. LoadString(hHotPlug,
  306. IDS_PROPERTIES,
  307. Buffer,
  308. SIZECHARS(Buffer)
  309. );
  310. AppendMenu(hMenu, MF_STRING, IDC_PROPERTIES, Buffer);
  311. IdCmd = TrackPopupMenu(hMenu,
  312. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_NONOTIFY,
  313. ptPopup.x,
  314. ptPopup.y,
  315. 0,
  316. hDlg,
  317. NULL
  318. );
  319. DestroyMenu(hMenu);
  320. if (!IdCmd) {
  321. return;
  322. }
  323. switch (IdCmd) {
  324. case IDC_STOPDEVICE:
  325. OnRemoveDevice(hDlg, DeviceTree);
  326. break;
  327. case IDC_PROPERTIES: {
  328. if (pDeviceProperties) {
  329. (*pDeviceProperties)(
  330. hDlg,
  331. NULL,
  332. DeviceTreeNode->InstanceId,
  333. FALSE
  334. );
  335. }
  336. }
  337. break;
  338. }
  339. return;
  340. }
  341. void
  342. OnRightClick(
  343. HWND hDlg,
  344. PDEVICETREE DeviceTree,
  345. NMHDR * nmhdr
  346. )
  347. {
  348. DWORD dwPos;
  349. TV_ITEM tvi;
  350. TV_HITTESTINFO tvht;
  351. PDEVTREENODE DeviceTreeNode;
  352. UNREFERENCED_PARAMETER(hDlg);
  353. if (nmhdr->hwndFrom != DeviceTree->hwndTree) {
  354. return;
  355. }
  356. dwPos = GetMessagePos();
  357. tvht.pt.x = LOWORD(dwPos);
  358. tvht.pt.y = HIWORD(dwPos);
  359. ScreenToClient(DeviceTree->hwndTree, &tvht.pt);
  360. tvi.hItem = TreeView_HitTest(DeviceTree->hwndTree, &tvht);
  361. if (!tvi.hItem) {
  362. return;
  363. }
  364. tvi.mask = TVIF_PARAM;
  365. if (!TreeView_GetItem(DeviceTree->hwndTree, &tvi)) {
  366. return;
  367. }
  368. DeviceTreeNode = (PDEVTREENODE)tvi.lParam;
  369. if (!DeviceTreeNode) {
  370. return;
  371. }
  372. //
  373. // Make the current right click item, the selected item
  374. //
  375. if (DeviceTreeNode != DeviceTree->SelectedTreeNode) {
  376. TreeView_SelectItem(DeviceTree->hwndTree, DeviceTreeNode->hTreeItem);
  377. }
  378. }
  379. void
  380. OnViewOptionClicked(
  381. HWND hDlg,
  382. PDEVICETREE DeviceTree
  383. )
  384. {
  385. BOOL bChecked;
  386. DWORD HotPlugFlags, NewFlags;
  387. HKEY hKey = NULL;
  388. //
  389. // checked means "show complex view"
  390. //
  391. bChecked = IsDlgButtonChecked(hDlg, IDC_VIEWOPTION);
  392. //
  393. // Update HotPlugs registry if needed.
  394. //
  395. NewFlags = HotPlugFlags = GetHotPlugFlags(&hKey);
  396. if (hKey) {
  397. if (bChecked) {
  398. NewFlags |= HOTPLUG_REGFLAG_VIEWALL;
  399. } else {
  400. NewFlags &= ~HOTPLUG_REGFLAG_VIEWALL;
  401. }
  402. if (NewFlags != HotPlugFlags) {
  403. RegSetValueEx(hKey,
  404. szHotPlugFlags,
  405. 0,
  406. REG_DWORD,
  407. (LPBYTE)&NewFlags,
  408. sizeof(NewFlags)
  409. );
  410. }
  411. if (hKey) {
  412. RegCloseKey(hKey);
  413. }
  414. }
  415. if (!DeviceTree->ComplexView && bChecked) {
  416. DeviceTree->ComplexView = TRUE;
  417. } else if (DeviceTree->ComplexView && !bChecked) {
  418. DeviceTree->ComplexView = FALSE;
  419. } else {
  420. // we are in the correct state, nothing to do.
  421. return;
  422. }
  423. //
  424. // redraw the entire tree.
  425. //
  426. RefreshTree(DeviceTree);
  427. return;
  428. }
  429. LRESULT
  430. hotplugNotifyWndProc(
  431. HWND hWnd,
  432. UINT uMsg,
  433. WPARAM wParam,
  434. LPARAM lParam
  435. )
  436. {
  437. HWND hMainWnd;
  438. hMainWnd = (HWND)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  439. switch (uMsg) {
  440. case WM_CREATE:
  441. hMainWnd = (HWND)((CREATESTRUCT*)lParam)->lpCreateParams;
  442. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)hMainWnd);
  443. break;
  444. case WM_DEVICECHANGE:
  445. if (DBT_DEVNODES_CHANGED == wParam) {
  446. //
  447. // While we are in WM_DEVICECHANGE context,
  448. // no CM apis can be called because it would
  449. // deadlock. Here, we schedule a timer so that
  450. // we can handle the message later on.
  451. //
  452. SetTimer(hMainWnd, TIMERID_DEVICECHANGE, 1000, NULL);
  453. }
  454. break;
  455. default:
  456. break;
  457. }
  458. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  459. }
  460. BOOL
  461. CreateNotifyWindow(
  462. HWND hWnd
  463. )
  464. {
  465. WNDCLASS wndClass;
  466. if (!GetClassInfo(hHotPlug, HOTPLUG_NOTIFY_CLASS_NAME, &wndClass)) {
  467. ZeroMemory(&wndClass, sizeof(wndClass));
  468. wndClass.lpfnWndProc = hotplugNotifyWndProc;
  469. wndClass.hInstance = hHotPlug;
  470. wndClass.lpszClassName = HOTPLUG_NOTIFY_CLASS_NAME;
  471. if (!RegisterClass(&wndClass)) {
  472. return FALSE;
  473. }
  474. }
  475. g_hwndNotify = CreateWindowEx(WS_EX_TOOLWINDOW,
  476. HOTPLUG_NOTIFY_CLASS_NAME,
  477. TEXT(""),
  478. WS_DLGFRAME | WS_BORDER | WS_DISABLED,
  479. CW_USEDEFAULT,
  480. CW_USEDEFAULT,
  481. 0,
  482. 0,
  483. NULL,
  484. NULL,
  485. hHotPlug,
  486. (void *)hWnd
  487. );
  488. return(NULL != g_hwndNotify);
  489. }
  490. BOOL
  491. InitDevTreeDlgProc(
  492. HWND hDlg,
  493. PDEVICETREE DeviceTree
  494. )
  495. {
  496. CONFIGRET ConfigRet;
  497. HWND hwndTree;
  498. DWORD HotPlugFlags;
  499. HICON hIcon;
  500. HWND hwndParent;
  501. DeviceTree->AllowRefresh = TRUE;
  502. CreateNotifyWindow(hDlg);
  503. hDevMgr = LoadLibrary(TEXT("devmgr.dll"));
  504. if (hDevMgr) {
  505. pDeviceProperties = (PDEVICEPROPERTIES)GetProcAddress(hDevMgr, "DevicePropertiesW");
  506. }
  507. hIcon = LoadIcon(hHotPlug,MAKEINTRESOURCE(IDI_HOTPLUGICON));
  508. if (hIcon) {
  509. SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
  510. SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
  511. }
  512. hwndParent = GetParent(hDlg);
  513. if (hwndParent) {
  514. SendMessage(hwndParent, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
  515. SendMessage(hwndParent, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
  516. }
  517. DeviceTree->hDlg = hDlg;
  518. DeviceTree->hwndTree = hwndTree = GetDlgItem(hDlg, IDC_DEVICETREE);
  519. LoadString(hHotPlug,
  520. IDS_UNKNOWN,
  521. (PTCHAR)szUnknown,
  522. SIZECHARS(szUnknown)
  523. );
  524. //
  525. // Disable the Stop button, until an item is selected.
  526. //
  527. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_STOPDEVICE), FALSE);
  528. EnableWindow(GetDlgItem(DeviceTree->hDlg, IDC_PROPERTIES), FALSE);
  529. //
  530. // Get the Class Icon Image Lists
  531. //
  532. DeviceTree->ClassImageList.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
  533. if (SetupDiGetClassImageList(&DeviceTree->ClassImageList)) {
  534. TreeView_SetImageList(hwndTree, DeviceTree->ClassImageList.ImageList, TVSIL_NORMAL);
  535. } else {
  536. DeviceTree->ClassImageList.cbSize = 0;
  537. }
  538. OnSysColorChange(hDlg, DeviceTree);
  539. HotPlugFlags = GetHotPlugFlags(NULL);
  540. if (HotPlugFlags & HOTPLUG_REGFLAG_VIEWALL) {
  541. DeviceTree->ComplexView = TRUE;
  542. CheckDlgButton(hDlg, IDC_VIEWOPTION, BST_CHECKED);
  543. } else {
  544. DeviceTree->ComplexView = FALSE;
  545. CheckDlgButton(hDlg, IDC_VIEWOPTION, BST_UNCHECKED);
  546. }
  547. //
  548. // Get the root devnode.
  549. //
  550. ConfigRet = CM_Locate_DevNode_Ex(&DeviceTree->DevInst,
  551. NULL,
  552. CM_LOCATE_DEVNODE_NORMAL,
  553. NULL
  554. );
  555. if (ConfigRet != CR_SUCCESS) {
  556. return FALSE;
  557. }
  558. RefreshTree(DeviceTree);
  559. if (DeviceTree->EjectDeviceInstanceId) {
  560. DEVINST EjectDevInst;
  561. PDEVTREENODE DeviceTreeNode;
  562. //
  563. // we are removing a specific device, find it
  564. // and post a message to trigger device removal.
  565. //
  566. ConfigRet = CM_Locate_DevNode_Ex(&EjectDevInst,
  567. DeviceTree->EjectDeviceInstanceId,
  568. CM_LOCATE_DEVNODE_NORMAL,
  569. NULL
  570. );
  571. if (ConfigRet != CR_SUCCESS) {
  572. return FALSE;
  573. }
  574. DeviceTreeNode = DevTreeNodeByDevInst(EjectDevInst,
  575. &DeviceTree->ChildSiblingList
  576. );
  577. if (!DeviceTreeNode) {
  578. return FALSE;
  579. }
  580. TreeView_SelectItem(hwndTree, DeviceTreeNode->hTreeItem);
  581. PostMessage(hDlg, WUM_EJECTDEVINST, 0, 0);
  582. } else {
  583. ShowWindow(hDlg, SW_SHOW);
  584. }
  585. return TRUE;
  586. }
  587. void
  588. OnContextHelp(
  589. LPHELPINFO HelpInfo,
  590. PDWORD ContextHelpIDs
  591. )
  592. {
  593. //
  594. // Define an array of dword pairs,
  595. // where the first of each pair is the control ID,
  596. // and the second is the context ID for a help topic,
  597. // which is used in the help file.
  598. //
  599. if (HelpInfo->iContextType == HELPINFO_WINDOW) { // must be for a control
  600. WinHelp((HWND)HelpInfo->hItemHandle,
  601. TEXT("hardware.hlp"),
  602. HELP_WM_HELP,
  603. (DWORD_PTR)(void *)ContextHelpIDs
  604. );
  605. }
  606. }
  607. INT_PTR CALLBACK DevTreeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  608. {
  609. PDEVICETREE DeviceTree = NULL;
  610. if (message == WM_INITDIALOG) {
  611. DeviceTree = (PDEVICETREE)lParam;
  612. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)DeviceTree);
  613. if (DeviceTree) {
  614. InitDevTreeDlgProc(hDlg, DeviceTree);
  615. }
  616. return TRUE;
  617. }
  618. DeviceTree = (PDEVICETREE)GetWindowLongPtr(hDlg, DWLP_USER);
  619. switch (message) {
  620. case WM_DESTROY:
  621. //
  622. // Destroy the Notification Window
  623. //
  624. if (g_hwndNotify && IsWindow(g_hwndNotify)) {
  625. DestroyWindow(g_hwndNotify);
  626. g_hwndNotify = NULL;
  627. }
  628. //
  629. // Clear the DeviceTree
  630. //
  631. TreeView_DeleteAllItems(DeviceTree->hwndTree);
  632. //
  633. // Clean up the class image list.
  634. //
  635. if (DeviceTree->ClassImageList.cbSize) {
  636. SetupDiDestroyClassImageList(&DeviceTree->ClassImageList);
  637. DeviceTree->ClassImageList.cbSize = 0;
  638. }
  639. //
  640. // Clean up the device tree
  641. //
  642. ClearRemovalList(DeviceTree);
  643. RemoveChildSiblings(DeviceTree, &DeviceTree->ChildSiblingList);
  644. if (hDevMgr) {
  645. FreeLibrary(hDevMgr);
  646. hDevMgr = NULL;
  647. pDeviceProperties = NULL;
  648. }
  649. break;
  650. case WM_CLOSE:
  651. SendMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
  652. break;
  653. case WM_COMMAND:
  654. {
  655. UINT Control = GET_WM_COMMAND_ID(wParam, lParam);
  656. UINT Cmd = GET_WM_COMMAND_CMD(wParam, lParam);
  657. switch (Control) {
  658. case IDC_VIEWOPTION:
  659. if (Cmd == BN_CLICKED) {
  660. OnViewOptionClicked(hDlg, DeviceTree);
  661. }
  662. break;
  663. case IDC_STOPDEVICE:
  664. OnRemoveDevice(hDlg, DeviceTree);
  665. break;
  666. case IDOK: // enter -> default to expand\collapse the selected tree node
  667. if (DeviceTree->SelectedTreeNode) {
  668. TreeView_Expand(DeviceTree->hwndTree,
  669. DeviceTree->SelectedTreeNode->hTreeItem, TVE_TOGGLE);
  670. }
  671. break;
  672. case IDC_PROPERTIES:
  673. if (DeviceTree->SelectedTreeNode && pDeviceProperties) {
  674. (*pDeviceProperties)(hDlg,
  675. NULL,
  676. DeviceTree->SelectedTreeNode->InstanceId, FALSE);
  677. }
  678. break;
  679. case IDCLOSE:
  680. case IDCANCEL:
  681. EndDialog(hDlg, IDCANCEL);
  682. break;
  683. }
  684. }
  685. break;
  686. // Listen for Tree notifications
  687. case WM_NOTIFY:
  688. switch (((NMHDR *)lParam)->code) {
  689. case TVN_SELCHANGED:
  690. OnTvnSelChanged(DeviceTree, (NM_TREEVIEW *)lParam);
  691. break;
  692. case TVN_ITEMEXPANDING:
  693. OnTvnItemExpanding(hDlg, (NM_TREEVIEW *)lParam);
  694. break;
  695. case TVN_KEYDOWN:
  696. {
  697. TV_KEYDOWN *tvKeyDown = (TV_KEYDOWN *)lParam;
  698. if (tvKeyDown->wVKey == VK_DELETE) {
  699. OnRemoveDevice(hDlg, DeviceTree);
  700. }
  701. }
  702. break;
  703. case NM_CUSTOMDRAW:
  704. if (IDC_DEVICETREE == ((NMHDR *)lParam)->idFrom) {
  705. SetDlgMsgResult(hDlg, WM_NOTIFY, OnCustomDraw(hDlg, DeviceTree, (NMTVCUSTOMDRAW *)lParam));
  706. }
  707. break;
  708. case NM_RETURN:
  709. // we don't get this in a dialog, see IDOK
  710. break;
  711. case NM_DBLCLK:
  712. OnRemoveDevice(hDlg, DeviceTree);
  713. SetDlgMsgResult(hDlg, WM_NOTIFY, TRUE);
  714. break;
  715. case NM_RCLICK:
  716. OnRightClick(hDlg, DeviceTree, (NMHDR *)lParam);
  717. break;
  718. default:
  719. return FALSE;
  720. }
  721. break;
  722. case WUM_EJECTDEVINST:
  723. OnRemoveDevice(hDlg, DeviceTree);
  724. EndDialog(hDlg, IDCANCEL);
  725. break;
  726. case WM_SYSCOLORCHANGE:
  727. HotPlugPropagateMessage(hDlg, message, wParam, lParam);
  728. OnSysColorChange(hDlg,DeviceTree);
  729. break;
  730. case WM_TIMER:
  731. if (TIMERID_DEVICECHANGE == wParam) {
  732. KillTimer(hDlg, TIMERID_DEVICECHANGE);
  733. DeviceTree->RefreshEvent = TRUE;
  734. if (DeviceTree->AllowRefresh) {
  735. OnTimerDeviceChange(DeviceTree);
  736. }
  737. }
  738. break;
  739. case WM_SETCURSOR:
  740. if (DeviceTree->RedrawWait || DeviceTree->RefreshEvent) {
  741. SetCursor(LoadCursor(NULL, IDC_WAIT));
  742. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
  743. break;
  744. }
  745. return FALSE;
  746. case WM_CONTEXTMENU:
  747. //
  748. // handle kbd- shift-F10, mouse rclick is invoked from NM_RCLICK
  749. //
  750. if ((HWND)wParam == DeviceTree->hwndTree) {
  751. OnContextMenu(hDlg, DeviceTree);
  752. break;
  753. } else {
  754. WinHelp((HWND)wParam, TEXT("hardware.hlp"), HELP_CONTEXTMENU,
  755. (DWORD_PTR)(void *)(PDWORD)UnplugtHelpIDs);
  756. }
  757. return FALSE;
  758. case WM_HELP:
  759. OnContextHelp((LPHELPINFO)lParam, (PDWORD)UnplugtHelpIDs);
  760. break;
  761. default:
  762. return FALSE;
  763. }
  764. return TRUE;
  765. }