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