- if the device cannot be opened display information about the parent node
[reactos.git] / reactos / lib / devmgr / hwpage.c
1 /*
2 * ReactOS Device Manager Applet
3 * Copyright (C) 2004 - 2005 ReactOS Team
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/hwpage.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * UPDATE HISTORY:
26 * 04-04-2004 Created
27 */
28 #include <precomp.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 typedef enum
34 {
35 HWPD_STANDARDLIST = 0,
36 HWPD_LARGELIST,
37 HWPD_MAX = HWPD_LARGELIST
38 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
39
40 typedef struct _HWDEVINFO
41 {
42 struct _HWCLASSDEVINFO *ClassDevInfo;
43 SP_DEVINFO_DATA DevInfoData;
44 BOOL HideDevice;
45 } HWDEVINFO, *PHWDEVINFO;
46
47 typedef struct _HWCLASSDEVINFO
48 {
49 GUID Guid;
50 HDEVINFO hDevInfo;
51 INT ImageIndex;
52 INT ItemCount;
53 PHWDEVINFO HwDevInfo;
54 } HWCLASSDEVINFO, *PHWCLASSDEVINFO;
55
56 typedef struct _HARDWARE_PAGE_DATA
57 {
58 HWND hWnd;
59 HWND hWndDevList;
60 HINSTANCE hComCtl32; /* only save this to keep track of the references */
61 INT DevListViewHeight;
62 SP_CLASSIMAGELIST_DATA ClassImageListData;
63 HWPAGE_DISPLAYMODE DisplayMode;
64
65 /* parent window subclass info */
66 WNDPROC ParentOldWndProc;
67 HWND hWndParent;
68
69 UINT NumberOfGuids;
70 HWCLASSDEVINFO ClassDevInfo[1];
71 /* struct may be dynamically expanded here! */
72 } HARDWARE_PAGE_DATA, *PHARDWARE_PAGE_DATA;
73
74 #define CX_TYPECOLUMN_WIDTH 80
75
76 static VOID
77 InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
78 {
79 LVCOLUMN lvc;
80 RECT rcClient;
81 WCHAR szColName[255];
82 int iCol = 0;
83
84 /* set the list view style */
85 ListView_SetExtendedListViewStyle(hpd->hWndDevList,
86 LVS_EX_FULLROWSELECT);
87
88 /* set the list view image list */
89 if (hpd->ClassImageListData.ImageList != NULL)
90 {
91 ListView_SetImageList(hpd->hWndDevList,
92 hpd->ClassImageListData.ImageList,
93 LVSIL_SMALL);
94 }
95
96 GetClientRect(hpd->hWndDevList,
97 &rcClient);
98
99 /* add the list view columns */
100 lvc.mask = LVCF_TEXT | LVCF_WIDTH;
101 lvc.fmt = LVCFMT_LEFT;
102 lvc.pszText = szColName;
103
104 if (LoadString(hDllInstance,
105 IDS_NAME,
106 szColName,
107 sizeof(szColName) / sizeof(szColName[0])))
108 {
109 lvc.cx = rcClient.right - CX_TYPECOLUMN_WIDTH -
110 GetSystemMetrics(SM_CXVSCROLL);
111 ListView_InsertColumn(hpd->hWndDevList,
112 iCol++,
113 &lvc);
114 }
115 if (LoadString(hDllInstance,
116 IDS_TYPE,
117 szColName,
118 sizeof(szColName) / sizeof(szColName[0])))
119 {
120 lvc.cx = CX_TYPECOLUMN_WIDTH;
121 ListView_InsertColumn(hpd->hWndDevList,
122 iCol++,
123 &lvc);
124 }
125 }
126
127
128 static BOOL
129 DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd)
130 {
131 PHWDEVINFO HwDevInfo;
132 BOOL Ret = FALSE;
133
134 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
135 if (HwDevInfo != NULL)
136 {
137 Ret = DisplayDeviceAdvancedProperties(hpd->hWnd,
138 NULL,
139 HwDevInfo->ClassDevInfo->hDevInfo,
140 &HwDevInfo->DevInfoData,
141 hpd->hComCtl32,
142 NULL) != -1;
143 }
144
145 return Ret;
146 }
147
148
149 static VOID
150 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)
151 {
152 PHWDEVINFO HwDevInfo;
153 HWND hBtnTroubleShoot, hBtnProperties;
154
155 hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
156 IDC_TROUBLESHOOT);
157 hBtnProperties = GetDlgItem(hpd->hWnd,
158 IDC_PROPERTIES);
159
160 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
161 if (HwDevInfo != NULL)
162 {
163 /* update static controls */
164 WCHAR szBuffer[256];
165 LPWSTR szFormatted = NULL;
166
167 /* get the manufacturer string */
168 if (GetDeviceManufacturerString(HwDevInfo->ClassDevInfo->hDevInfo,
169 &HwDevInfo->DevInfoData,
170 szBuffer,
171 sizeof(szBuffer) / sizeof(szBuffer[0])) &&
172 LoadAndFormatString(hDllInstance,
173 IDS_MANUFACTURER,
174 &szFormatted,
175 szBuffer) != 0)
176 {
177 SetDlgItemText(hpd->hWnd,
178 IDC_MANUFACTURER,
179 szFormatted);
180 LocalFree((HLOCAL)szFormatted);
181 }
182
183 /* get the location string */
184 if (GetDeviceLocationString(HwDevInfo->DevInfoData.DevInst,
185 0,
186 szBuffer,
187 sizeof(szBuffer) / sizeof(szBuffer[0])) &&
188 LoadAndFormatString(hDllInstance,
189 IDS_LOCATION,
190 &szFormatted,
191 szBuffer) != 0)
192 {
193 SetDlgItemText(hpd->hWnd,
194 IDC_LOCATION,
195 szFormatted);
196 LocalFree((HLOCAL)szFormatted);
197 }
198
199 if (GetDeviceStatusString(HwDevInfo->DevInfoData.DevInst,
200 NULL,
201 szBuffer,
202 sizeof(szBuffer) / sizeof(szBuffer[0])) &&
203 LoadAndFormatString(hDllInstance,
204 IDS_STATUS,
205 &szFormatted,
206 szBuffer) != 0)
207 {
208 SetDlgItemText(hpd->hWnd,
209 IDC_STATUS,
210 szFormatted);
211 LocalFree((HLOCAL)szFormatted);
212 }
213 }
214 else
215 {
216 /* clear static controls */
217 SetDlgItemText(hpd->hWnd,
218 IDC_MANUFACTURER,
219 NULL);
220 SetDlgItemText(hpd->hWnd,
221 IDC_LOCATION,
222 NULL);
223 SetDlgItemText(hpd->hWnd,
224 IDC_STATUS,
225 NULL);
226 }
227
228 EnableWindow(hBtnTroubleShoot,
229 HwDevInfo != NULL);
230 EnableWindow(hBtnProperties,
231 HwDevInfo != NULL);
232 }
233
234
235 static VOID
236 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
237 {
238 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
239
240 ClassDevInfo = hpd->ClassDevInfo;
241 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
242
243 /* free the device info set handles and structures */
244 while (ClassDevInfo != LastClassDevInfo)
245 {
246 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
247 {
248 SetupDiDestroyDeviceInfoList(ClassDevInfo->hDevInfo);
249 ClassDevInfo->hDevInfo = INVALID_HANDLE_VALUE;
250 }
251
252 ClassDevInfo->ItemCount = 0;
253 ClassDevInfo->ImageIndex = 0;
254
255 if (ClassDevInfo->HwDevInfo != NULL)
256 {
257 HeapFree(GetProcessHeap(),
258 0,
259 ClassDevInfo->HwDevInfo);
260 ClassDevInfo->HwDevInfo = NULL;
261 }
262
263 ClassDevInfo++;
264 }
265 }
266
267
268 static VOID
269 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)
270 {
271 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
272 SP_DEVINFO_DATA DevInfoData;
273
274 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
275
276 ClassDevInfo = hpd->ClassDevInfo;
277 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
278
279 while (ClassDevInfo != LastClassDevInfo)
280 {
281 ClassDevInfo->ImageIndex = -1;
282
283 /* open a class device handle for the GUID we're processing */
284 ClassDevInfo->hDevInfo = SetupDiGetClassDevs(&ClassDevInfo->Guid,
285 NULL,
286 hpd->hWnd,
287 DIGCF_PRESENT | DIGCF_PROFILE);
288 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
289 {
290 DWORD MemberIndex = 0;
291
292 SetupDiGetClassImageIndex(&hpd->ClassImageListData,
293 &ClassDevInfo->Guid,
294 &ClassDevInfo->ImageIndex);
295
296 /* enumerate all devices in the class */
297 while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo,
298 MemberIndex++,
299 &DevInfoData))
300 {
301 BOOL HideDevice = FALSE;
302
303 if (ClassDevInfo->HwDevInfo != NULL)
304 {
305 PHWDEVINFO HwNewDevInfo = HeapReAlloc(GetProcessHeap(),
306 0,
307 ClassDevInfo->HwDevInfo,
308 (ClassDevInfo->ItemCount + 1) *
309 sizeof(HWDEVINFO));
310 if (HwNewDevInfo != NULL)
311 {
312 ClassDevInfo->HwDevInfo = HwNewDevInfo;
313 }
314 else
315 {
316 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
317 ClassDevInfo->ItemCount + 1);
318 break;
319 }
320 }
321 else
322 {
323 ClassDevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
324 0,
325 sizeof(HWDEVINFO));
326 if (ClassDevInfo->HwDevInfo == NULL)
327 {
328 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
329 break;
330 }
331 }
332
333 /* Find out if the device should be hidden by default */
334 IsDeviceHidden(DevInfoData.DevInst,
335 NULL,
336 &HideDevice);
337
338 /* save all information for the current device */
339 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo;
340 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].DevInfoData = DevInfoData;
341 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].HideDevice = HideDevice;
342 }
343 }
344
345 ClassDevInfo++;
346 }
347 }
348
349
350 static VOID
351 FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd)
352 {
353 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
354 PHWDEVINFO HwDevInfo, LastHwDevInfo;
355 WCHAR szBuffer[255];
356 INT ItemCount = 0;
357
358 BuildDevicesList(hpd);
359
360 ClassDevInfo = hpd->ClassDevInfo;
361 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
362
363 while (ClassDevInfo != LastClassDevInfo)
364 {
365 if (ClassDevInfo->HwDevInfo != NULL)
366 {
367 HwDevInfo = ClassDevInfo->HwDevInfo;
368 LastHwDevInfo = HwDevInfo + ClassDevInfo->ItemCount;
369
370 while (HwDevInfo != LastHwDevInfo)
371 {
372 INT iItem;
373 LVITEM li;
374
375 /* get the device name */
376 if (!HwDevInfo->HideDevice &&
377 GetDeviceDescriptionString(ClassDevInfo->hDevInfo,
378 &HwDevInfo->DevInfoData,
379 szBuffer,
380 sizeof(szBuffer) / sizeof(szBuffer[0])))
381 {
382 li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE;
383 li.iItem = ItemCount;
384 li.iSubItem = 0;
385 li.state = (ItemCount == 0 ? LVIS_SELECTED : 0);
386 li.stateMask = LVIS_SELECTED;
387 li.pszText = szBuffer;
388 li.iImage = ClassDevInfo->ImageIndex;
389 li.lParam = (LPARAM)HwDevInfo;
390
391 iItem = ListView_InsertItem(hpd->hWndDevList,
392 &li);
393 if (iItem != -1)
394 {
395 ItemCount++;
396
397 /* get the device type for the second column */
398 if (GetDeviceTypeString(&HwDevInfo->DevInfoData,
399 szBuffer,
400 sizeof(szBuffer) / sizeof(szBuffer[0])))
401 {
402 li.mask = LVIF_TEXT;
403 li.iItem = iItem;
404 li.iSubItem = 1;
405
406 ListView_SetItem(hpd->hWndDevList,
407 &li);
408 }
409 }
410 }
411
412 HwDevInfo++;
413 }
414 }
415
416 ClassDevInfo++;
417 }
418
419 /* update the controls */
420 UpdateControlStates(hpd);
421 }
422
423
424 static LRESULT
425 CALLBACK
426 ParentSubWndProc(IN HWND hwnd,
427 IN UINT uMsg,
428 IN WPARAM wParam,
429 IN LPARAM lParam)
430 {
431 PHARDWARE_PAGE_DATA hpd;
432
433 hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd,
434 L"DevMgrSubClassInfo");
435 if (hpd != NULL)
436 {
437 if (uMsg == WM_SIZE)
438 {
439 /* resize the hardware page */
440 SetWindowPos(hpd->hWnd,
441 NULL,
442 0,
443 0,
444 LOWORD(lParam),
445 HIWORD(lParam),
446 SWP_NOZORDER);
447 }
448
449 /* pass the message the the old window proc */
450 return CallWindowProc(hpd->ParentOldWndProc,
451 hwnd,
452 uMsg,
453 wParam,
454 lParam);
455 }
456 else
457 {
458 /* this is not a good idea if the subclassed window was an ansi
459 window, but we failed finding out the previous window proc
460 so we can't use CallWindowProc. This should rarely - if ever -
461 happen. */
462
463 return DefWindowProc(hwnd,
464 uMsg,
465 wParam,
466 lParam);
467 }
468 }
469
470
471 static VOID
472 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
473 IN INT cx,
474 IN INT cy)
475 {
476 HDWP dwp;
477 HWND hControl, hButton;
478 INT Width, x, y;
479 RECT rc, rcButton;
480 POINT pt = {0};
481 POINT ptMargin = {0};
482 POINT ptMarginGroup = {0};
483
484 /* use left margin of the IDC_DEVICES label as the right
485 margin of all controls outside the group box */
486 hControl = GetDlgItem(hpd->hWnd,
487 IDC_DEVICES);
488 GetWindowRect(hControl,
489 &rc);
490 MapWindowPoints(hControl,
491 hpd->hWnd,
492 &ptMargin,
493 1);
494
495 Width = cx - (2 * ptMargin.x);
496
497 if ((dwp = BeginDeferWindowPos(8)))
498 {
499 /* rc already has the window rect of IDC_DEVICES! */
500 if (!(dwp = DeferWindowPos(dwp,
501 hControl,
502 NULL,
503 0,
504 0,
505 Width,
506 rc.bottom - rc.top,
507 SWP_NOMOVE | SWP_NOZORDER)))
508 {
509 return;
510 }
511
512 /* resize the devices list view control */
513 GetWindowRect(hpd->hWndDevList,
514 &rc);
515 MapWindowPoints(hpd->hWndDevList,
516 hpd->hWnd,
517 &pt,
518 1);
519 y = pt.y + hpd->DevListViewHeight + ptMargin.y;
520 if (!(dwp = DeferWindowPos(dwp,
521 hpd->hWndDevList,
522 NULL,
523 0,
524 0,
525 Width,
526 hpd->DevListViewHeight,
527 SWP_NOMOVE | SWP_NOZORDER)))
528 {
529 return;
530 }
531
532 /* resize the group box control */
533 hControl = GetDlgItem(hpd->hWnd,
534 IDC_PROPERTIESGROUP);
535 GetWindowRect(hControl,
536 &rc);
537 if (!(dwp = DeferWindowPos(dwp,
538 hControl,
539 NULL,
540 ptMargin.x,
541 y,
542 Width,
543 cy - y - ptMargin.y,
544 SWP_NOZORDER)))
545 {
546 return;
547 }
548
549 /* use left margin of the IDC_MANUFACTURER label as the right
550 margin of all controls inside the group box */
551 hControl = GetDlgItem(hpd->hWnd,
552 IDC_MANUFACTURER);
553 GetWindowRect(hControl,
554 &rc);
555 MapWindowPoints(hControl,
556 hpd->hWnd,
557 &ptMarginGroup,
558 1);
559
560 ptMarginGroup.y = ptMargin.y * 2;
561 Width = cx - (2 * ptMarginGroup.x);
562 y += ptMarginGroup.y;
563 if (!(dwp = DeferWindowPos(dwp,
564 hControl,
565 NULL,
566 ptMarginGroup.x,
567 y,
568 Width,
569 rc.bottom - rc.top,
570 SWP_NOZORDER)))
571 {
572 return;
573 }
574 y += rc.bottom - rc.top + (ptMargin.y / 2);
575
576 /* resize the IDC_LOCATION label */
577 hControl = GetDlgItem(hpd->hWnd,
578 IDC_LOCATION);
579 GetWindowRect(hControl,
580 &rc);
581 if (!(dwp = DeferWindowPos(dwp,
582 hControl,
583 NULL,
584 ptMarginGroup.x,
585 y,
586 Width,
587 rc.bottom - rc.top,
588 SWP_NOZORDER)))
589 {
590 return;
591 }
592 y += rc.bottom - rc.top + (ptMargin.y / 2);
593
594 /* measure the size of the buttons */
595 hButton = GetDlgItem(hpd->hWnd,
596 IDC_PROPERTIES);
597 GetWindowRect(hButton,
598 &rcButton);
599
600 /* resize the IDC_STATUS label */
601 hControl = GetDlgItem(hpd->hWnd,
602 IDC_STATUS);
603 GetWindowRect(hControl,
604 &rc);
605 if (!(dwp = DeferWindowPos(dwp,
606 hControl,
607 NULL,
608 ptMarginGroup.x,
609 y,
610 Width,
611 cy - y - (3 * ptMargin.y) -
612 (rcButton.bottom - rcButton.top),
613 SWP_NOZORDER)))
614 {
615 return;
616 }
617
618 /* move the IDC_PROPERTIES button */
619 y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top);
620 x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left);
621 if (!(dwp = DeferWindowPos(dwp,
622 hButton,
623 NULL,
624 x,
625 y,
626 0,
627 0,
628 SWP_NOSIZE | SWP_NOZORDER)))
629 {
630 return;
631 }
632
633 /* move the IDC_TROUBLESHOOT button */
634 hButton = GetDlgItem(hpd->hWnd,
635 IDC_TROUBLESHOOT);
636 GetWindowRect(hButton,
637 &rcButton);
638 x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left);
639 if (!(dwp = DeferWindowPos(dwp,
640 hButton,
641 NULL,
642 x,
643 y,
644 0,
645 0,
646 SWP_NOSIZE | SWP_NOZORDER)))
647 {
648 return;
649 }
650
651 EndDeferWindowPos(dwp);
652 }
653 }
654
655
656 static VOID
657 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd,
658 BOOL Enable)
659 {
660 HWND hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
661 IDC_TROUBLESHOOT);
662
663 ShowWindow(hBtnTroubleShoot,
664 Enable ? SW_SHOW : SW_HIDE);
665 }
666
667
668 static INT_PTR
669 CALLBACK
670 HardwareDlgProc(IN HWND hwndDlg,
671 IN UINT uMsg,
672 IN WPARAM wParam,
673 IN LPARAM lParam)
674 {
675 PHARDWARE_PAGE_DATA hpd;
676 INT_PTR Ret = FALSE;
677
678 hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg,
679 DWL_USER);
680
681 if (hpd != NULL || uMsg == WM_INITDIALOG)
682 {
683 switch (uMsg)
684 {
685 case WM_NOTIFY:
686 {
687 NMHDR *pnmh = (NMHDR*)lParam;
688 if (pnmh->hwndFrom == hpd->hWndDevList)
689 {
690 switch (pnmh->code)
691 {
692 case LVN_ITEMCHANGED:
693 {
694 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
695
696 if ((pnmv->uChanged & LVIF_STATE) &&
697 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
698 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
699 {
700 UpdateControlStates(hpd);
701 }
702 break;
703 }
704
705 case NM_DBLCLK:
706 {
707 DisplaySelectedDeviceProperties(hpd);
708 break;
709 }
710 }
711 }
712 break;
713 }
714
715 case WM_COMMAND:
716 {
717 switch (LOWORD(wParam))
718 {
719 case IDC_TROUBLESHOOT:
720 {
721 /* FIXME - start the help using the command in the window text */
722 break;
723 }
724
725 case IDC_PROPERTIES:
726 {
727 DisplaySelectedDeviceProperties(hpd);
728 break;
729 }
730 }
731 break;
732 }
733
734 case WM_SIZE:
735 HardwareDlgResize(hpd,
736 (INT)LOWORD(lParam),
737 (INT)HIWORD(lParam));
738 break;
739
740 case WM_SETTEXT:
741 {
742 LPCWSTR szWndText = (LPCWSTR)lParam;
743 EnableTroubleShoot(hpd,
744 (szWndText != NULL && szWndText[0] != L'\0'));
745 break;
746 }
747
748 case WM_INITDIALOG:
749 {
750 hpd = (PHARDWARE_PAGE_DATA)lParam;
751 if (hpd != NULL)
752 {
753 HWND hWndParent;
754
755 hpd->hWnd = hwndDlg;
756 SetWindowLongPtr(hwndDlg,
757 DWL_USER,
758 (DWORD_PTR)hpd);
759
760 hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
761
762 SetupDiGetClassImageList(&hpd->ClassImageListData);
763
764 /* calculate the size of the devices list view control */
765 hpd->hWndDevList = GetDlgItem(hwndDlg,
766 IDC_LV_DEVICES);
767 if (hpd->hWndDevList != NULL)
768 {
769 RECT rcClient;
770 GetClientRect(hpd->hWndDevList,
771 &rcClient);
772 hpd->DevListViewHeight = rcClient.bottom;
773
774 if (hpd->DisplayMode == HWPD_LARGELIST)
775 {
776 hpd->DevListViewHeight = (hpd->DevListViewHeight * 3) / 2;
777 }
778 }
779
780 /* subclass the parent window */
781 hWndParent = GetAncestor(hwndDlg,
782 GA_PARENT);
783 if (hWndParent != NULL)
784 {
785 RECT rcClient;
786
787 if (GetClientRect(hWndParent,
788 &rcClient) &&
789 SetWindowPos(hwndDlg,
790 NULL,
791 0,
792 0,
793 rcClient.right,
794 rcClient.bottom,
795 SWP_NOZORDER))
796 {
797 /* subclass the parent window. This is not safe
798 if the parent window belongs to another thread! */
799 hpd->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
800 GWLP_WNDPROC,
801 (LONG_PTR)ParentSubWndProc);
802
803 if (hpd->ParentOldWndProc != NULL &&
804 SetProp(hWndParent,
805 L"DevMgrSubClassInfo",
806 (HANDLE)hpd))
807 {
808 hpd->hWndParent = hWndParent;
809 }
810 }
811 }
812
813 /* initialize the devices list view control */
814 InitializeDevicesList(hpd);
815
816 /* fill the devices list view control */
817 FillDevicesListViewControl(hpd);
818
819 /* decide whether to show or hide the troubleshoot button */
820 EnableTroubleShoot(hpd,
821 GetWindowTextLength(hwndDlg) != 0);
822 }
823 Ret = TRUE;
824 break;
825 }
826
827 case WM_DESTROY:
828 {
829 /* free devices list */
830 FreeDevicesList(hpd);
831
832 /* restore the old window proc of the subclassed parent window */
833 if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL)
834 {
835 SetWindowLongPtr(hpd->hWndParent,
836 GWLP_WNDPROC,
837 (LONG_PTR)hpd->ParentOldWndProc);
838 }
839
840 if (hpd->ClassImageListData.ImageList != NULL)
841 {
842 SetupDiDestroyClassImageList(&hpd->ClassImageListData);
843 }
844
845 /* free the reference to comctl32 */
846 FreeLibrary(hpd->hComCtl32);
847 hpd->hComCtl32 = NULL;
848
849 /* free the allocated resources */
850 HeapFree(GetProcessHeap(),
851 0,
852 hpd);
853 break;
854 }
855 }
856 }
857
858 return Ret;
859 }
860
861
862 /***************************************************************************
863 * NAME EXPORTED
864 * DeviceCreateHardwarePageEx
865 *
866 * DESCRIPTION
867 * Creates a hardware page
868 *
869 * ARGUMENTS
870 * hWndParent: Handle to the parent window
871 * lpGuids: An array of guids of devices that are to be listed
872 * uNumberOfGuids: Numbers of guids in the Guids array
873 * DisplayMode: Sets the size of the device list view control
874 *
875 * RETURN VALUE
876 * Returns the handle of the hardware page window that has been created or
877 * NULL if it failed.
878 *
879 * @implemented
880 */
881 HWND
882 WINAPI
883 DeviceCreateHardwarePageEx(IN HWND hWndParent,
884 IN LPGUID lpGuids,
885 IN UINT uNumberOfGuids,
886 IN HWPAGE_DISPLAYMODE DisplayMode)
887 {
888 PHARDWARE_PAGE_DATA hpd;
889
890 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
891 zeroed because the initialization code assumes that in
892 failure cases! */
893 hpd = HeapAlloc(GetProcessHeap(),
894 HEAP_ZERO_MEMORY,
895 FIELD_OFFSET(HARDWARE_PAGE_DATA,
896 ClassDevInfo) +
897 (uNumberOfGuids * sizeof(HWCLASSDEVINFO)));
898 if (hpd != NULL)
899 {
900 HWND hWnd;
901 UINT i;
902
903 hpd->DisplayMode = ((DisplayMode > HWPD_MAX) ? HWPD_STANDARDLIST : DisplayMode);
904
905 /* initialize the HARDWARE_PAGE_DATA structure */
906 hpd->NumberOfGuids = uNumberOfGuids;
907 for (i = 0;
908 i < uNumberOfGuids;
909 i++)
910 {
911 hpd->ClassDevInfo[i].hDevInfo = INVALID_HANDLE_VALUE;
912 hpd->ClassDevInfo[i].Guid = lpGuids[i];
913 }
914
915 /* load comctl32.dll dynamically */
916 hpd->hComCtl32 = LoadAndInitComctl32();
917 if (hpd->hComCtl32 == NULL)
918 {
919 goto Cleanup;
920 }
921
922 /* create the dialog */
923 hWnd = CreateDialogParam(hDllInstance,
924 MAKEINTRESOURCE(IDD_HARDWARE),
925 hWndParent,
926 HardwareDlgProc,
927 (LPARAM)hpd);
928 if (hWnd != NULL)
929 {
930 return hWnd;
931 }
932 else
933 {
934 Cleanup:
935 /* oops, something went wrong... */
936 if (hpd->hComCtl32 != NULL)
937 {
938 FreeLibrary(hpd->hComCtl32);
939 }
940
941 HeapFree(GetProcessHeap(),
942 0,
943 hpd);
944 }
945 }
946
947 return NULL;
948 }
949
950
951 /***************************************************************************
952 * NAME EXPORTED
953 * DeviceCreateHardwarePage
954 *
955 * DESCRIPTION
956 * Creates a hardware page
957 *
958 * ARGUMENTS
959 * hWndParent: Handle to the parent window
960 * lpGuid: Guid of the device
961 *
962 * RETURN VALUE
963 * Returns the handle of the hardware page window that has been created or
964 * NULL if it failed.
965 *
966 * @implemented
967 */
968 HWND
969 WINAPI
970 DeviceCreateHardwarePage(IN HWND hWndParent,
971 IN LPGUID lpGuid)
972 {
973 return DeviceCreateHardwarePageEx(hWndParent,
974 lpGuid,
975 1,
976 HWPD_LARGELIST);
977 }