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