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