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.

741 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: getdev.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "hdwwiz.h"
  11. #include <htmlhelp.h>
  12. HMODULE hDevMgr=NULL;
  13. PDEVICEPROBLEMTEXT pDeviceProblemText = NULL;
  14. PTCHAR
  15. DeviceProblemText(
  16. HMACHINE hMachine,
  17. DEVNODE DevNode,
  18. ULONG Status,
  19. ULONG ProblemNumber
  20. )
  21. {
  22. UINT LenChars, ReqLenChars;
  23. PTCHAR Buffer=NULL;
  24. PTCHAR p=NULL;
  25. TCHAR TempBuffer[MAX_PATH];
  26. if (hDevMgr) {
  27. if (!pDeviceProblemText) {
  28. pDeviceProblemText = (PVOID) GetProcAddress(hDevMgr, "DeviceProblemTextW");
  29. }
  30. }
  31. if (pDeviceProblemText) {
  32. LenChars = (pDeviceProblemText)(hMachine,
  33. DevNode,
  34. ProblemNumber,
  35. Buffer,
  36. 0
  37. );
  38. if (!LenChars) {
  39. goto DPTExitCleanup;
  40. }
  41. LenChars++; // one extra for terminating NULL
  42. Buffer = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
  43. if (!Buffer) {
  44. goto DPTExitCleanup;
  45. }
  46. ReqLenChars = (pDeviceProblemText)(hMachine,
  47. DevNode,
  48. ProblemNumber,
  49. Buffer,
  50. LenChars
  51. );
  52. if (!ReqLenChars || ReqLenChars >= LenChars) {
  53. LocalFree(Buffer);
  54. Buffer = NULL;
  55. }
  56. if (Buffer && (Status != 0)) {
  57. if (Status & DN_WILL_BE_REMOVED) {
  58. if (LoadString(hHdwWiz,
  59. IDS_WILL_BE_REMOVED,
  60. TempBuffer,
  61. SIZECHARS(TempBuffer)
  62. )) {
  63. LenChars += lstrlen(TempBuffer) + 1;
  64. p = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
  65. if (p) {
  66. lstrcpy(p, Buffer);
  67. lstrcat(p, TempBuffer);
  68. LocalFree(Buffer);
  69. Buffer = p;
  70. }
  71. }
  72. }
  73. if (Status & DN_NEED_RESTART) {
  74. if (LoadString(hHdwWiz,
  75. IDS_NEED_RESTART,
  76. TempBuffer,
  77. SIZECHARS(TempBuffer)
  78. )) {
  79. LenChars += lstrlen(TempBuffer) + 1;
  80. p = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
  81. if (p) {
  82. lstrcpy(p, Buffer);
  83. lstrcat(p, TempBuffer);
  84. LocalFree(Buffer);
  85. Buffer = p;
  86. }
  87. }
  88. }
  89. }
  90. }
  91. DPTExitCleanup:
  92. return Buffer;
  93. }
  94. int CALLBACK
  95. DeviceListCompare(
  96. LPARAM lParam1,
  97. LPARAM lParam2,
  98. LPARAM lParamSort
  99. )
  100. {
  101. TCHAR ClassName1[MAX_CLASS_NAME_LEN];
  102. TCHAR ClassName2[MAX_CLASS_NAME_LEN];
  103. TCHAR Buffer[MAX_PATH];
  104. GUID ClassGuid1, ClassGuid2;
  105. BOOL bSpecialClass1 = FALSE, bSpecialClass2 = FALSE;
  106. ULONG ulLength;
  107. ULONG Status, Problem1, Problem2;
  108. //
  109. // Return
  110. // -1 if the first item should precede the second
  111. // +1 if the first item should follow the second
  112. // 0 if they are the same
  113. //
  114. //
  115. // First check if lParam1 or lParam2 are 0. A 0 lParam means that this
  116. // is the special 'Add a new hardware device' that goes at the bottom
  117. // of the list.
  118. //
  119. if (lParam1 == 0) {
  120. return 1;
  121. }
  122. if (lParam2 == 0) {
  123. return -1;
  124. }
  125. if (CM_Get_DevNode_Status(&Status, &Problem1, (DEVINST)lParam1, 0) != CR_SUCCESS) {
  126. Problem1 = 0;
  127. }
  128. if (CM_Get_DevNode_Status(&Status, &Problem2, (DEVINST)lParam2, 0) != CR_SUCCESS) {
  129. Problem2 = 0;
  130. }
  131. //
  132. // Devices with problems always go at the top of the list. If both devices
  133. // have problems then we sort by class name.
  134. //
  135. if (Problem1 && !Problem2) {
  136. return -1;
  137. } else if (!Problem1 && Problem2) {
  138. return 1;
  139. }
  140. //
  141. // The next check is to put the special device classes above non-special
  142. // device classes.
  143. //
  144. ulLength = sizeof(Buffer);
  145. if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam1,
  146. CM_DRP_CLASSGUID,
  147. NULL,
  148. Buffer,
  149. &ulLength,
  150. 0) == CR_SUCCESS) &&
  151. (ulLength != 0)) {
  152. pSetupGuidFromString(Buffer, &ClassGuid1);
  153. if (IsEqualGUID(&ClassGuid1, &GUID_DEVCLASS_DISPLAY) ||
  154. IsEqualGUID(&ClassGuid1, &GUID_DEVCLASS_MEDIA)) {
  155. //
  156. // Device 1 is one of the special classes that go at the top of the list.
  157. //
  158. bSpecialClass1 = TRUE;
  159. }
  160. }
  161. ulLength = sizeof(Buffer);
  162. if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam2,
  163. CM_DRP_CLASSGUID,
  164. NULL,
  165. Buffer,
  166. &ulLength,
  167. 0) == CR_SUCCESS) &&
  168. (ulLength != 0)) {
  169. pSetupGuidFromString(Buffer, &ClassGuid2);
  170. if (IsEqualGUID(&ClassGuid2, &GUID_DEVCLASS_DISPLAY) ||
  171. IsEqualGUID(&ClassGuid2, &GUID_DEVCLASS_MEDIA)) {
  172. //
  173. // Device 2 is one of the special classes that go at the top of the list.
  174. //
  175. bSpecialClass2 = TRUE;
  176. }
  177. }
  178. if (bSpecialClass1 && !bSpecialClass2) {
  179. return -1;
  180. } else if (!bSpecialClass1 && bSpecialClass2) {
  181. return 1;
  182. }
  183. //
  184. // The final check is to sort the items by classes
  185. //
  186. ulLength = sizeof(ClassName1);
  187. if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam1,
  188. CM_DRP_CLASS,
  189. NULL,
  190. ClassName1,
  191. &ulLength,
  192. 0) != CR_SUCCESS) ||
  193. (ulLength == 0)) {
  194. //
  195. // If we could not get a class name then set it to all Z's so it will
  196. // get put at the bottom of the list.
  197. //
  198. lstrcpy(ClassName1, TEXT("ZZZZZZZZZZ"));;
  199. }
  200. ulLength = sizeof(ClassName2);
  201. if ((CM_Get_DevNode_Registry_Property((DEVINST)lParam2,
  202. CM_DRP_CLASS,
  203. NULL,
  204. ClassName2,
  205. &ulLength,
  206. 0) != CR_SUCCESS) ||
  207. (ulLength == 0)) {
  208. //
  209. // If we could not get a class name then set it to all Z's so it will
  210. // get put at the bottom of the list.
  211. //
  212. lstrcpy(ClassName2, TEXT("ZZZZZZZZZZ"));;
  213. }
  214. return lstrcmpi(ClassName1, ClassName2);
  215. }
  216. void
  217. InsertNoneOfTheseDevices(
  218. HWND hwndList
  219. )
  220. {
  221. LV_ITEM lviItem;
  222. TCHAR String[MAX_PATH];
  223. LoadString(hHdwWiz, IDS_HDW_NONEDEVICES, String, sizeof(String)/sizeof(TCHAR));
  224. lviItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  225. lviItem.iSubItem = 0;
  226. lviItem.lParam = (LPARAM)0;
  227. lviItem.iItem = 0;
  228. lviItem.iImage = g_BlankIconIndex;
  229. lviItem.pszText = String;
  230. ListView_InsertItem(hwndList, &lviItem);
  231. }
  232. void
  233. InsertProbListView(
  234. PHARDWAREWIZ HardwareWiz,
  235. DEVINST DevInst,
  236. ULONG Problem
  237. )
  238. {
  239. INT Index;
  240. LV_ITEM lviItem;
  241. PTCHAR FriendlyName;
  242. GUID ClassGuid;
  243. ULONG ulSize;
  244. CONFIGRET ConfigRet;
  245. TCHAR szBuffer[MAX_PATH];
  246. lviItem.mask = LVIF_TEXT | LVIF_PARAM;
  247. lviItem.iSubItem = 0;
  248. lviItem.lParam = DevInst;
  249. lviItem.iItem = ListView_GetItemCount(HardwareWiz->hwndProbList);
  250. //
  251. // fetch a name for this device
  252. //
  253. FriendlyName = BuildFriendlyName(DevInst, HardwareWiz->hMachine);
  254. if (FriendlyName) {
  255. lviItem.pszText = FriendlyName;
  256. } else {
  257. lviItem.pszText = szUnknown;
  258. }
  259. //
  260. // Fetch the class icon for this device.
  261. //
  262. ulSize = sizeof(szBuffer);
  263. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  264. CM_DRP_CLASSGUID,
  265. NULL,
  266. szBuffer,
  267. &ulSize,
  268. 0,
  269. HardwareWiz->hMachine
  270. );
  271. if (ConfigRet == CR_SUCCESS) {
  272. pSetupGuidFromString(szBuffer, &ClassGuid);
  273. } else {
  274. ClassGuid = GUID_DEVCLASS_UNKNOWN;
  275. }
  276. if (SetupDiGetClassImageIndex(&HardwareWiz->ClassImageList,
  277. &ClassGuid,
  278. &lviItem.iImage
  279. )) {
  280. lviItem.mask |= (LVIF_IMAGE | LVIF_STATE);
  281. if (Problem) {
  282. lviItem.state = (Problem == CM_PROB_DISABLED) ?
  283. INDEXTOOVERLAYMASK(IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1) :
  284. INDEXTOOVERLAYMASK(IDI_PROBLEM_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
  285. } else {
  286. lviItem.state = INDEXTOOVERLAYMASK(0);
  287. }
  288. lviItem.stateMask = LVIS_OVERLAYMASK;
  289. }
  290. Index = ListView_InsertItem(HardwareWiz->hwndProbList, &lviItem);
  291. if ((Index != -1) && (HardwareWiz->ProblemDevInst == DevInst)) {
  292. ListView_SetItemState(HardwareWiz->hwndProbList,
  293. Index,
  294. LVIS_SELECTED|LVIS_FOCUSED,
  295. LVIS_SELECTED|LVIS_FOCUSED
  296. );
  297. }
  298. if (FriendlyName) {
  299. LocalFree(FriendlyName);
  300. }
  301. return;
  302. }
  303. BOOL
  304. ProblemDeviceListFilter(
  305. PHARDWAREWIZ HardwareWiz,
  306. PSP_DEVINFO_DATA DeviceInfoData
  307. )
  308. /*++
  309. Routine Description:
  310. This function is a callback for the BuildDeviceListView API. It will get called
  311. for every device and can filter which devices end up getting displayed. If it
  312. returns FALSE then the given device won't be displayed. If it returns TRUE then
  313. the device will be displayed.
  314. Currently we will filter out all system devices from the problem devices list since
  315. they cluter up the list view and it would be very rare that a user would come to
  316. Add Hardware to add a system device.
  317. --*/
  318. {
  319. //
  320. // If this is a system class device then filter it out of the list by
  321. // returning FALSE.
  322. //
  323. if (IsEqualGUID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_SYSTEM)) {
  324. return FALSE;
  325. }
  326. return TRUE;
  327. }
  328. INT_PTR CALLBACK
  329. HdwProbListDlgProc(
  330. HWND hDlg,
  331. UINT message,
  332. WPARAM wParam,
  333. LPARAM lParam
  334. )
  335. /*++
  336. Routine Description:
  337. Arguments:
  338. standard stuff.
  339. Return Value:
  340. INT_PTR
  341. --*/
  342. {
  343. PHARDWAREWIZ HardwareWiz;
  344. if (message == WM_INITDIALOG) {
  345. LV_COLUMN lvcCol;
  346. INT Index;
  347. TCHAR Buffer[64];
  348. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  349. HardwareWiz = (PHARDWAREWIZ) lppsp->lParam;
  350. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
  351. HardwareWiz->hwndProbList = GetDlgItem(hDlg, IDC_HDWPROBLIST);
  352. //
  353. // Insert columns for listview.
  354. // 0 == device name
  355. //
  356. lvcCol.mask = LVCF_WIDTH | LVCF_SUBITEM;
  357. lvcCol.iSubItem = 0;
  358. ListView_InsertColumn(HardwareWiz->hwndProbList, 0, &lvcCol);
  359. SendMessage(HardwareWiz->hwndProbList,
  360. LVM_SETEXTENDEDLISTVIEWSTYLE,
  361. LVS_EX_FULLROWSELECT,
  362. LVS_EX_FULLROWSELECT
  363. );
  364. ListView_SetExtendedListViewStyle(HardwareWiz->hwndProbList, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
  365. return TRUE;
  366. }
  367. //
  368. // retrieve private data from window long (stored there during WM_INITDIALOG)
  369. //
  370. HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
  371. switch (message) {
  372. case WM_DESTROY:
  373. break;
  374. case WM_COMMAND:
  375. break;
  376. case WM_NOTIFY: {
  377. NMHDR FAR *pnmhdr = (NMHDR FAR *)lParam;
  378. switch (pnmhdr->code) {
  379. case PSN_SETACTIVE: {
  380. DWORD DevicesDetected;
  381. int nCmdShow;
  382. HWND hwndProbList;
  383. HWND hwndParentDlg;
  384. LVITEM lvItem;
  385. HICON hIcon;
  386. hwndParentDlg = GetParent(hDlg);
  387. HardwareWiz->PrevPage = IDD_ADDDEVICE_PROBLIST;
  388. //
  389. // initialize the list view, we do this on each setactive
  390. // since a new class may have been installed or the problem
  391. // device list may change as we go back and forth between pages.
  392. //
  393. hwndProbList = HardwareWiz->hwndProbList;
  394. SendMessage(hwndProbList, WM_SETREDRAW, FALSE, 0L);
  395. ListView_DeleteAllItems(hwndProbList);
  396. if (HardwareWiz->ClassImageList.cbSize) {
  397. ListView_SetImageList(hwndProbList,
  398. HardwareWiz->ClassImageList.ImageList,
  399. LVSIL_SMALL
  400. );
  401. }
  402. //
  403. // Next put all of the devices into the list
  404. //
  405. DevicesDetected = 0;
  406. BuildDeviceListView(HardwareWiz,
  407. HardwareWiz->hwndProbList,
  408. FALSE,
  409. HardwareWiz->ProblemDevInst,
  410. &DevicesDetected,
  411. ProblemDeviceListFilter
  412. );
  413. InsertNoneOfTheseDevices(HardwareWiz->hwndProbList);
  414. //
  415. // Sort the list
  416. //
  417. ListView_SortItems(HardwareWiz->hwndProbList,
  418. (PFNLVCOMPARE)DeviceListCompare,
  419. NULL
  420. );
  421. lvItem.mask = LVIF_PARAM;
  422. lvItem.iSubItem = 0;
  423. lvItem.iItem = ListView_GetNextItem(HardwareWiz->hwndProbList, -1, LVNI_SELECTED);
  424. //
  425. // select the first item in the list if nothing else was selected
  426. //
  427. if (lvItem.iItem == -1) {
  428. ListView_SetItemState(hwndProbList,
  429. 0,
  430. LVIS_FOCUSED,
  431. LVIS_FOCUSED
  432. );
  433. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK);
  434. } else {
  435. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  436. }
  437. ListView_EnsureVisible(hwndProbList, lvItem.iItem, FALSE);
  438. ListView_SetColumnWidth(hwndProbList, 0, LVSCW_AUTOSIZE_USEHEADER);
  439. SendMessage(hwndProbList, WM_SETREDRAW, TRUE, 0L);
  440. }
  441. break;
  442. case PSN_WIZNEXT: {
  443. LVITEM lvItem;
  444. lvItem.mask = LVIF_PARAM;
  445. lvItem.iSubItem = 0;
  446. lvItem.iItem = ListView_GetNextItem(HardwareWiz->hwndProbList, -1, LVNI_SELECTED);
  447. if (lvItem.iItem != -1) {
  448. ListView_GetItem(HardwareWiz->hwndProbList, &lvItem);
  449. HardwareWiz->ProblemDevInst = (DEVNODE)lvItem.lParam;
  450. } else {
  451. HardwareWiz->ProblemDevInst = 0;
  452. }
  453. //
  454. // If the HardwareWiz->ProblemDevInst is 0 then the user selected none of the items
  455. // so we will move on to detection
  456. //
  457. if (HardwareWiz->ProblemDevInst == 0) {
  458. SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_ASKDETECT);
  459. } else {
  460. SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_PROBLIST_FINISH);
  461. }
  462. }
  463. break;
  464. case PSN_WIZFINISH:
  465. break;
  466. case PSN_WIZBACK:
  467. SetDlgMsgResult(hDlg, WM_NOTIFY, IDD_ADDDEVICE_CONNECTED);
  468. break;
  469. case NM_DBLCLK:
  470. PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
  471. break;
  472. case LVN_ITEMCHANGED:
  473. if (ListView_GetSelectedCount(HardwareWiz->hwndProbList) == 0) {
  474. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  475. } else {
  476. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  477. }
  478. }
  479. }
  480. break;
  481. case WM_SYSCOLORCHANGE:
  482. HdwWizPropagateMessage(hDlg, message, wParam, lParam);
  483. break;
  484. default:
  485. return FALSE;
  486. }
  487. return TRUE;
  488. }
  489. INT_PTR CALLBACK
  490. HdwProbListFinishDlgProc(
  491. HWND hDlg,
  492. UINT wMsg,
  493. WPARAM wParam,
  494. LPARAM lParam
  495. )
  496. /*++
  497. Routine Description:
  498. Arguments:
  499. Return Value:
  500. INT_PTR
  501. --*/
  502. {
  503. PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
  504. if (wMsg == WM_INITDIALOG) {
  505. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  506. HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
  507. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
  508. SetWindowFont(GetDlgItem(hDlg, IDC_HDWNAME), HardwareWiz->hfontTextBigBold, TRUE);
  509. return TRUE;
  510. }
  511. switch (wMsg) {
  512. case WM_DESTROY:
  513. break;
  514. case WM_COMMAND:
  515. break;
  516. case WM_NOTIFY: {
  517. NMHDR FAR *pnmhdr = (NMHDR FAR *)lParam;
  518. switch (pnmhdr->code) {
  519. case PSN_SETACTIVE:
  520. {
  521. PTCHAR FriendlyName;
  522. TCHAR szBuffer[MAX_PATH];
  523. PTCHAR ProblemText;
  524. ULONG Status, Problem;
  525. FriendlyName = BuildFriendlyName(HardwareWiz->ProblemDevInst, NULL);
  526. if (FriendlyName) {
  527. SetDlgItemText(hDlg, IDC_HDW_DESCRIPTION, FriendlyName);
  528. LocalFree(FriendlyName);
  529. }
  530. Status = Problem = 0;
  531. CM_Get_DevNode_Status_Ex(&Status,
  532. &Problem,
  533. HardwareWiz->ProblemDevInst,
  534. 0,
  535. HardwareWiz->hMachine
  536. );
  537. ProblemText = DeviceProblemText(HardwareWiz->hMachine,
  538. HardwareWiz->ProblemDevInst,
  539. Status,
  540. Problem
  541. );
  542. if (ProblemText) {
  543. SetDlgItemText(hDlg, IDC_PROBLEM_DESC, ProblemText);
  544. LocalFree(ProblemText);
  545. }
  546. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
  547. }
  548. break;
  549. case PSN_WIZFINISH:
  550. HardwareWiz->RunTroubleShooter = TRUE;
  551. break;
  552. case PSN_WIZBACK:
  553. SetDlgMsgResult(hDlg, wMsg, IDD_ADDDEVICE_PROBLIST);
  554. break;
  555. }
  556. }
  557. break;
  558. default:
  559. return FALSE;
  560. }
  561. return TRUE;
  562. }