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