2 * ReactOS Device Manager Applet
3 * Copyright (C) 2004 - 2005 ReactOS Team
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.
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.
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
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/hwpage.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
33 typedef struct _HWDEVINFO
35 struct _HWCLASSDEVINFO
*ClassDevInfo
;
36 SP_DEVINFO_DATA DevInfoData
;
38 } HWDEVINFO
, *PHWDEVINFO
;
40 typedef struct _HWCLASSDEVINFO
47 } HWCLASSDEVINFO
, *PHWCLASSDEVINFO
;
49 typedef struct _HARDWARE_PAGE_DATA
53 HINSTANCE hComCtl32
; /* only save this to keep track of the references */
54 INT DevListViewHeight
;
55 SP_CLASSIMAGELIST_DATA ClassImageListData
;
56 HWPAGE_DISPLAYMODE DisplayMode
;
58 /* parent window subclass info */
59 WNDPROC ParentOldWndProc
;
63 HWCLASSDEVINFO ClassDevInfo
[1];
64 /* struct may be dynamically expanded here! */
65 } HARDWARE_PAGE_DATA
, *PHARDWARE_PAGE_DATA
;
67 #define CX_TYPECOLUMN_WIDTH 80
70 InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
77 /* set the list view style */
78 ListView_SetExtendedListViewStyle(hpd
->hWndDevList
,
79 LVS_EX_FULLROWSELECT
);
81 /* set the list view image list */
82 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
84 ListView_SetImageList(hpd
->hWndDevList
,
85 hpd
->ClassImageListData
.ImageList
,
89 GetClientRect(hpd
->hWndDevList
,
92 /* add the list view columns */
93 lvc
.mask
= LVCF_TEXT
| LVCF_WIDTH
;
94 lvc
.fmt
= LVCFMT_LEFT
;
95 lvc
.pszText
= szColName
;
97 if (LoadString(hDllInstance
,
100 sizeof(szColName
) / sizeof(szColName
[0])))
102 lvc
.cx
= rcClient
.right
- CX_TYPECOLUMN_WIDTH
-
103 GetSystemMetrics(SM_CXVSCROLL
);
104 ListView_InsertColumn(hpd
->hWndDevList
,
108 if (LoadString(hDllInstance
,
111 sizeof(szColName
) / sizeof(szColName
[0])))
113 lvc
.cx
= CX_TYPECOLUMN_WIDTH
;
114 ListView_InsertColumn(hpd
->hWndDevList
,
122 DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd
)
124 PHWDEVINFO HwDevInfo
;
127 HwDevInfo
= (PHWDEVINFO
)ListViewGetSelectedItemData(hpd
->hWndDevList
);
128 if (HwDevInfo
!= NULL
)
130 Ret
= DisplayDeviceAdvancedProperties(hpd
->hWnd
,
132 HwDevInfo
->ClassDevInfo
->hDevInfo
,
133 &HwDevInfo
->DevInfoData
,
144 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd
)
146 PHWDEVINFO HwDevInfo
;
147 HWND hBtnTroubleShoot
, hBtnProperties
;
149 hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
151 hBtnProperties
= GetDlgItem(hpd
->hWnd
,
154 HwDevInfo
= (PHWDEVINFO
)ListViewGetSelectedItemData(hpd
->hWndDevList
);
155 if (HwDevInfo
!= NULL
)
157 /* update static controls */
159 LPWSTR szFormatted
= NULL
;
161 /* get the manufacturer string */
162 if (GetDeviceManufacturerString(HwDevInfo
->ClassDevInfo
->hDevInfo
,
163 &HwDevInfo
->DevInfoData
,
165 sizeof(szBuffer
) / sizeof(szBuffer
[0])) &&
166 LoadAndFormatString(hDllInstance
,
171 SetDlgItemText(hpd
->hWnd
,
174 LocalFree((HLOCAL
)szFormatted
);
177 /* get the location string */
178 if (GetDeviceLocationString(HwDevInfo
->DevInfoData
.DevInst
,
181 sizeof(szBuffer
) / sizeof(szBuffer
[0])) &&
182 LoadAndFormatString(hDllInstance
,
187 SetDlgItemText(hpd
->hWnd
,
190 LocalFree((HLOCAL
)szFormatted
);
193 if (GetDeviceStatusString(HwDevInfo
->DevInfoData
.DevInst
,
196 sizeof(szBuffer
) / sizeof(szBuffer
[0])) &&
197 LoadAndFormatString(hDllInstance
,
202 SetDlgItemText(hpd
->hWnd
,
205 LocalFree((HLOCAL
)szFormatted
);
210 /* clear static controls */
211 SetDlgItemText(hpd
->hWnd
,
214 SetDlgItemText(hpd
->hWnd
,
217 SetDlgItemText(hpd
->hWnd
,
222 EnableWindow(hBtnTroubleShoot
,
224 EnableWindow(hBtnProperties
,
230 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
232 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
234 ClassDevInfo
= hpd
->ClassDevInfo
;
235 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
237 /* free the device info set handles and structures */
238 while (ClassDevInfo
!= LastClassDevInfo
)
240 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
242 SetupDiDestroyDeviceInfoList(ClassDevInfo
->hDevInfo
);
243 ClassDevInfo
->hDevInfo
= INVALID_HANDLE_VALUE
;
246 ClassDevInfo
->ItemCount
= 0;
247 ClassDevInfo
->ImageIndex
= 0;
249 if (ClassDevInfo
->HwDevInfo
!= NULL
)
251 HeapFree(GetProcessHeap(),
253 ClassDevInfo
->HwDevInfo
);
254 ClassDevInfo
->HwDevInfo
= NULL
;
263 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
265 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
266 SP_DEVINFO_DATA DevInfoData
;
268 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
270 ClassDevInfo
= hpd
->ClassDevInfo
;
271 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
273 while (ClassDevInfo
!= LastClassDevInfo
)
275 ClassDevInfo
->ImageIndex
= -1;
277 /* open a class device handle for the GUID we're processing */
278 ClassDevInfo
->hDevInfo
= SetupDiGetClassDevs(&ClassDevInfo
->Guid
,
281 DIGCF_PRESENT
| DIGCF_PROFILE
);
282 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
284 DWORD MemberIndex
= 0;
286 SetupDiGetClassImageIndex(&hpd
->ClassImageListData
,
288 &ClassDevInfo
->ImageIndex
);
290 /* enumerate all devices in the class */
291 while (SetupDiEnumDeviceInfo(ClassDevInfo
->hDevInfo
,
295 BOOL HideDevice
= FALSE
;
297 if (ClassDevInfo
->HwDevInfo
!= NULL
)
299 PHWDEVINFO HwNewDevInfo
= HeapReAlloc(GetProcessHeap(),
301 ClassDevInfo
->HwDevInfo
,
302 (ClassDevInfo
->ItemCount
+ 1) *
304 if (HwNewDevInfo
!= NULL
)
306 ClassDevInfo
->HwDevInfo
= HwNewDevInfo
;
310 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
311 ClassDevInfo
->ItemCount
+ 1);
317 ClassDevInfo
->HwDevInfo
= HeapAlloc(GetProcessHeap(),
320 if (ClassDevInfo
->HwDevInfo
== NULL
)
322 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
327 /* Find out if the device should be hidden by default */
328 IsDeviceHidden(DevInfoData
.DevInst
,
332 /* save all information for the current device */
333 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
].ClassDevInfo
= ClassDevInfo
;
334 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
].DevInfoData
= DevInfoData
;
335 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
++].HideDevice
= HideDevice
;
345 FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd
)
347 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
348 PHWDEVINFO HwDevInfo
, LastHwDevInfo
;
352 BuildDevicesList(hpd
);
354 ClassDevInfo
= hpd
->ClassDevInfo
;
355 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
357 while (ClassDevInfo
!= LastClassDevInfo
)
359 if (ClassDevInfo
->HwDevInfo
!= NULL
)
361 HwDevInfo
= ClassDevInfo
->HwDevInfo
;
362 LastHwDevInfo
= HwDevInfo
+ ClassDevInfo
->ItemCount
;
364 while (HwDevInfo
!= LastHwDevInfo
)
369 /* get the device name */
370 if (!HwDevInfo
->HideDevice
&&
371 GetDeviceDescriptionString(ClassDevInfo
->hDevInfo
,
372 &HwDevInfo
->DevInfoData
,
374 sizeof(szBuffer
) / sizeof(szBuffer
[0])))
376 li
.mask
= LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
| LVIF_IMAGE
;
377 li
.iItem
= ItemCount
;
379 li
.state
= (ItemCount
== 0 ? LVIS_SELECTED
: 0);
380 li
.stateMask
= LVIS_SELECTED
;
381 li
.pszText
= szBuffer
;
382 li
.iImage
= ClassDevInfo
->ImageIndex
;
383 li
.lParam
= (LPARAM
)HwDevInfo
;
385 iItem
= ListView_InsertItem(hpd
->hWndDevList
,
391 /* get the device type for the second column */
392 if (GetDeviceTypeString(&HwDevInfo
->DevInfoData
,
394 sizeof(szBuffer
) / sizeof(szBuffer
[0])))
400 ListView_SetItem(hpd
->hWndDevList
,
413 /* update the controls */
414 UpdateControlStates(hpd
);
420 ParentSubWndProc(IN HWND hwnd
,
425 PHARDWARE_PAGE_DATA hpd
;
427 hpd
= (PHARDWARE_PAGE_DATA
)GetProp(hwnd
,
428 L
"DevMgrSubClassInfo");
433 /* resize the hardware page */
434 SetWindowPos(hpd
->hWnd
,
443 /* pass the message the the old window proc */
444 return CallWindowProc(hpd
->ParentOldWndProc
,
452 /* this is not a good idea if the subclassed window was an ansi
453 window, but we failed finding out the previous window proc
454 so we can't use CallWindowProc. This should rarely - if ever -
457 return DefWindowProc(hwnd
,
466 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd
,
471 HWND hControl
, hButton
;
475 POINT ptMargin
= {0};
476 POINT ptMarginGroup
= {0};
478 /* use left margin of the IDC_DEVICES label as the right
479 margin of all controls outside the group box */
480 hControl
= GetDlgItem(hpd
->hWnd
,
482 GetWindowRect(hControl
,
484 MapWindowPoints(hControl
,
489 Width
= cx
- (2 * ptMargin
.x
);
491 if ((dwp
= BeginDeferWindowPos(8)))
493 /* rc already has the window rect of IDC_DEVICES! */
494 if (!(dwp
= DeferWindowPos(dwp
,
501 SWP_NOMOVE
| SWP_NOZORDER
)))
506 /* resize the devices list view control */
507 GetWindowRect(hpd
->hWndDevList
,
509 MapWindowPoints(hpd
->hWndDevList
,
513 y
= pt
.y
+ hpd
->DevListViewHeight
+ ptMargin
.y
;
514 if (!(dwp
= DeferWindowPos(dwp
,
520 hpd
->DevListViewHeight
,
521 SWP_NOMOVE
| SWP_NOZORDER
)))
526 /* resize the group box control */
527 hControl
= GetDlgItem(hpd
->hWnd
,
528 IDC_PROPERTIESGROUP
);
529 GetWindowRect(hControl
,
531 if (!(dwp
= DeferWindowPos(dwp
,
543 /* use left margin of the IDC_MANUFACTURER label as the right
544 margin of all controls inside the group box */
545 hControl
= GetDlgItem(hpd
->hWnd
,
547 GetWindowRect(hControl
,
549 MapWindowPoints(hControl
,
554 ptMarginGroup
.y
= ptMargin
.y
* 2;
555 Width
= cx
- (2 * ptMarginGroup
.x
);
556 y
+= ptMarginGroup
.y
;
557 if (!(dwp
= DeferWindowPos(dwp
,
568 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
570 /* resize the IDC_LOCATION label */
571 hControl
= GetDlgItem(hpd
->hWnd
,
573 GetWindowRect(hControl
,
575 if (!(dwp
= DeferWindowPos(dwp
,
586 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
588 /* measure the size of the buttons */
589 hButton
= GetDlgItem(hpd
->hWnd
,
591 GetWindowRect(hButton
,
594 /* resize the IDC_STATUS label */
595 hControl
= GetDlgItem(hpd
->hWnd
,
597 GetWindowRect(hControl
,
599 if (!(dwp
= DeferWindowPos(dwp
,
605 cy
- y
- (3 * ptMargin
.y
) -
606 (rcButton
.bottom
- rcButton
.top
),
612 /* move the IDC_PROPERTIES button */
613 y
= cy
- (2 * ptMargin
.y
) - (rcButton
.bottom
- rcButton
.top
);
614 x
= cx
- ptMarginGroup
.x
- (rcButton
.right
- rcButton
.left
);
615 if (!(dwp
= DeferWindowPos(dwp
,
622 SWP_NOSIZE
| SWP_NOZORDER
)))
627 /* move the IDC_TROUBLESHOOT button */
628 hButton
= GetDlgItem(hpd
->hWnd
,
630 GetWindowRect(hButton
,
632 x
-= (ptMargin
.x
/ 2) + (rcButton
.right
- rcButton
.left
);
633 if (!(dwp
= DeferWindowPos(dwp
,
640 SWP_NOSIZE
| SWP_NOZORDER
)))
645 EndDeferWindowPos(dwp
);
651 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd
,
654 HWND hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
657 ShowWindow(hBtnTroubleShoot
,
658 Enable
? SW_SHOW
: SW_HIDE
);
664 HardwareDlgProc(IN HWND hwndDlg
,
669 PHARDWARE_PAGE_DATA hpd
;
672 hpd
= (PHARDWARE_PAGE_DATA
)GetWindowLongPtr(hwndDlg
,
675 if (hpd
!= NULL
|| uMsg
== WM_INITDIALOG
)
681 NMHDR
*pnmh
= (NMHDR
*)lParam
;
682 if (pnmh
->hwndFrom
== hpd
->hWndDevList
)
686 case LVN_ITEMCHANGED
:
688 LPNMLISTVIEW pnmv
= (LPNMLISTVIEW
)lParam
;
690 if ((pnmv
->uChanged
& LVIF_STATE
) &&
691 ((pnmv
->uOldState
& (LVIS_FOCUSED
| LVIS_SELECTED
)) ||
692 (pnmv
->uNewState
& (LVIS_FOCUSED
| LVIS_SELECTED
))))
694 UpdateControlStates(hpd
);
701 DisplaySelectedDeviceProperties(hpd
);
711 switch (LOWORD(wParam
))
713 case IDC_TROUBLESHOOT
:
715 /* FIXME - start the help using the command in the window text */
721 DisplaySelectedDeviceProperties(hpd
);
729 HardwareDlgResize(hpd
,
731 (INT
)HIWORD(lParam
));
736 LPCWSTR szWndText
= (LPCWSTR
)lParam
;
737 EnableTroubleShoot(hpd
,
738 (szWndText
!= NULL
&& szWndText
[0] != L
'\0'));
744 hpd
= (PHARDWARE_PAGE_DATA
)lParam
;
750 SetWindowLongPtr(hwndDlg
,
754 hpd
->ClassImageListData
.cbSize
= sizeof(SP_CLASSIMAGELIST_DATA
);
756 SetupDiGetClassImageList(&hpd
->ClassImageListData
);
758 /* calculate the size of the devices list view control */
759 hpd
->hWndDevList
= GetDlgItem(hwndDlg
,
761 if (hpd
->hWndDevList
!= NULL
)
764 GetClientRect(hpd
->hWndDevList
,
766 hpd
->DevListViewHeight
= rcClient
.bottom
;
768 if (hpd
->DisplayMode
== HWPD_LARGELIST
)
770 hpd
->DevListViewHeight
= (hpd
->DevListViewHeight
* 3) / 2;
774 /* subclass the parent window */
775 hWndParent
= GetAncestor(hwndDlg
,
777 if (hWndParent
!= NULL
)
781 if (GetClientRect(hWndParent
,
783 SetWindowPos(hwndDlg
,
791 /* subclass the parent window. This is not safe
792 if the parent window belongs to another thread! */
793 hpd
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
795 (LONG_PTR
)ParentSubWndProc
);
797 if (hpd
->ParentOldWndProc
!= NULL
&&
799 L
"DevMgrSubClassInfo",
802 hpd
->hWndParent
= hWndParent
;
807 /* initialize the devices list view control */
808 InitializeDevicesList(hpd
);
810 /* fill the devices list view control */
811 FillDevicesListViewControl(hpd
);
813 /* decide whether to show or hide the troubleshoot button */
814 EnableTroubleShoot(hpd
,
815 GetWindowTextLength(hwndDlg
) != 0);
823 /* free devices list */
824 FreeDevicesList(hpd
);
826 /* restore the old window proc of the subclassed parent window */
827 if (hpd
->hWndParent
!= NULL
&& hpd
->ParentOldWndProc
!= NULL
)
829 SetWindowLongPtr(hpd
->hWndParent
,
831 (LONG_PTR
)hpd
->ParentOldWndProc
);
834 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
836 SetupDiDestroyClassImageList(&hpd
->ClassImageListData
);
839 /* free the reference to comctl32 */
840 FreeLibrary(hpd
->hComCtl32
);
841 hpd
->hComCtl32
= NULL
;
843 /* free the allocated resources */
844 HeapFree(GetProcessHeap(),
856 /***************************************************************************
858 * DeviceCreateHardwarePageEx
861 * Creates a hardware page
864 * hWndParent: Handle to the parent window
865 * lpGuids: An array of guids of devices that are to be listed
866 * uNumberOfGuids: Numbers of guids in the Guids array
867 * DisplayMode: Sets the size of the device list view control
870 * Returns the handle of the hardware page window that has been created or
877 DeviceCreateHardwarePageEx(IN HWND hWndParent
,
879 IN UINT uNumberOfGuids
,
880 IN HWPAGE_DISPLAYMODE DisplayMode
)
882 PHARDWARE_PAGE_DATA hpd
;
884 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
885 zeroed because the initialization code assumes that in
887 hpd
= HeapAlloc(GetProcessHeap(),
889 FIELD_OFFSET(HARDWARE_PAGE_DATA
,
891 (uNumberOfGuids
* sizeof(HWCLASSDEVINFO
)));
897 hpd
->DisplayMode
= ((DisplayMode
> HWPD_MAX
) ? HWPD_STANDARDLIST
: DisplayMode
);
899 /* initialize the HARDWARE_PAGE_DATA structure */
900 hpd
->NumberOfGuids
= uNumberOfGuids
;
905 hpd
->ClassDevInfo
[i
].hDevInfo
= INVALID_HANDLE_VALUE
;
906 hpd
->ClassDevInfo
[i
].Guid
= lpGuids
[i
];
909 /* load comctl32.dll dynamically */
910 hpd
->hComCtl32
= LoadAndInitComctl32();
911 if (hpd
->hComCtl32
== NULL
)
916 /* create the dialog */
917 hWnd
= CreateDialogParam(hDllInstance
,
918 MAKEINTRESOURCE(IDD_HARDWARE
),
929 /* oops, something went wrong... */
930 if (hpd
->hComCtl32
!= NULL
)
932 FreeLibrary(hpd
->hComCtl32
);
935 HeapFree(GetProcessHeap(),
945 /***************************************************************************
947 * DeviceCreateHardwarePage
950 * Creates a hardware page
953 * hWndParent: Handle to the parent window
954 * lpGuid: Guid of the device
957 * Returns the handle of the hardware page window that has been created or
964 DeviceCreateHardwarePage(IN HWND hWndParent
,
967 return DeviceCreateHardwarePageEx(hWndParent
,