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