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