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 VOID (WINAPI
*PINITCOMMONCONTROLS
)(VOID
);
37 HWPD_STANDARDLIST
= 0,
39 HWPD_MAX
= HWPD_LARGELIST
40 } HWPAGE_DISPLAYMODE
, *PHWPAGE_DISPLAYMODE
;
42 typedef struct _HWDEVINFO
44 struct _HWCLASSDEVINFO
*ClassDevInfo
;
45 SP_DEVINFO_DATA DevInfoData
;
46 } HWDEVINFO
, *PHWDEVINFO
;
48 typedef struct _HWCLASSDEVINFO
55 } HWCLASSDEVINFO
, *PHWCLASSDEVINFO
;
57 typedef struct _HARDWARE_PAGE_DATA
61 HINSTANCE hComCtl32
; /* only save this to keep track of the references */
62 INT DevListViewHeight
;
63 SP_CLASSIMAGELIST_DATA ClassImageListData
;
64 HWPAGE_DISPLAYMODE DisplayMode
;
66 /* parent window subclass info */
67 WNDPROC ParentOldWndProc
;
71 HWCLASSDEVINFO ClassDevInfo
[1];
72 /* struct may be dynamically expanded here! */
73 } HARDWARE_PAGE_DATA
, *PHARDWARE_PAGE_DATA
;
75 #define CX_TYPECOLUMN_WIDTH 80
78 InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
85 /* set the list view style */
86 ListView_SetExtendedListViewStyle(hpd
->hWndDevList
,
87 LVS_EX_FULLROWSELECT
);
89 /* set the list view image list */
90 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
92 ListView_SetImageList(hpd
->hWndDevList
,
93 hpd
->ClassImageListData
.ImageList
,
97 GetClientRect(hpd
->hWndDevList
,
100 /* add the list view columns */
101 lvc
.mask
= LVCF_TEXT
| LVCF_WIDTH
;
102 lvc
.fmt
= LVCFMT_LEFT
;
103 lvc
.pszText
= szColName
;
105 if (LoadString(hDllInstance
,
108 sizeof(szColName
) / sizeof(szColName
[0])))
110 lvc
.cx
= rcClient
.right
- CX_TYPECOLUMN_WIDTH
-
111 GetSystemMetrics(SM_CXVSCROLL
);
112 ListView_InsertColumn(hpd
->hWndDevList
,
116 if (LoadString(hDllInstance
,
119 sizeof(szColName
) / sizeof(szColName
[0])))
121 lvc
.cx
= CX_TYPECOLUMN_WIDTH
;
122 ListView_InsertColumn(hpd
->hWndDevList
,
130 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd
)
132 PHWDEVINFO HwDevInfo
;
133 HWND hBtnTroubleShoot
, hBtnProperties
;
135 hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
137 hBtnProperties
= GetDlgItem(hpd
->hWnd
,
140 HwDevInfo
= (PHWDEVINFO
)ListViewGetSelectedItemData(hpd
->hWndDevList
);
141 if (HwDevInfo
!= NULL
)
143 /* update static controls */
148 LPWSTR szFormatted
= NULL
;
150 /* get the manufacturer string */
151 if (!SetupDiGetDeviceRegistryProperty(HwDevInfo
->ClassDevInfo
->hDevInfo
,
152 &HwDevInfo
->DevInfoData
,
158 RegDataType
!= REG_SZ
)
162 /* FIXME - check string for NULL termination! */
163 if (LoadAndFormatString(hDllInstance
,
168 SetDlgItemText(hpd
->hWnd
,
171 LocalFree((HLOCAL
)szFormatted
);
174 /* get the location string */
175 DataSize
= sizeof(szBuffer
);
176 cRet
= CM_Get_DevNode_Registry_Property(HwDevInfo
->DevInfoData
.DevInst
,
177 CM_DRP_LOCATION_INFORMATION
,
182 if (cRet
!= CR_SUCCESS
||
183 RegDataType
!= REG_SZ
)
187 if (cRet
== CR_NO_SUCH_REGISTRY_KEY
||
188 cRet
== CR_NO_SUCH_VALUE
)
190 LoadString(hDllInstance
,
193 sizeof(szBuffer
) / sizeof(szBuffer
[0]));
196 /* FIXME - check string for NULL termination! */
198 if (szBuffer
[0] >= L
'0' && szBuffer
[0] <= L
'9')
200 /* convert the string to an integer value and create a
202 unsigned long ulLocation
= wcstoul(szBuffer
,
205 if (LoadAndFormatString(hDllInstance
,
213 (sizeof(szBuffer
) / sizeof(szBuffer
[0])) - 1);
214 szBuffer
[(sizeof(szBuffer
) / sizeof(szBuffer
[0])) - 1] = L
'\0';
215 LocalFree((HLOCAL
)szFormatted
);
219 if (LoadAndFormatString(hDllInstance
,
224 SetDlgItemText(hpd
->hWnd
,
227 LocalFree((HLOCAL
)szFormatted
);
230 /* FIXME - Display the device status */
234 /* clear static controls */
235 SetDlgItemText(hpd
->hWnd
,
238 SetDlgItemText(hpd
->hWnd
,
241 SetDlgItemText(hpd
->hWnd
,
246 EnableWindow(hBtnTroubleShoot
,
248 EnableWindow(hBtnProperties
,
253 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
255 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
257 ClassDevInfo
= hpd
->ClassDevInfo
;
258 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
260 /* free the device info set handles */
261 while (ClassDevInfo
!= LastClassDevInfo
)
263 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
265 SetupDiDestroyDeviceInfoList(ClassDevInfo
->hDevInfo
);
267 ClassDevInfo
->hDevInfo
= NULL
;
268 ClassDevInfo
->ItemCount
= 0;
269 ClassDevInfo
->ImageIndex
= 0;
271 if (ClassDevInfo
->HwDevInfo
!= NULL
)
273 HeapFree(GetProcessHeap(),
275 ClassDevInfo
->HwDevInfo
);
276 ClassDevInfo
->HwDevInfo
= NULL
;
285 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
287 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
288 SP_DEVINFO_DATA DevInfoData
;
290 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
292 ClassDevInfo
= hpd
->ClassDevInfo
;
293 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
295 while (ClassDevInfo
!= LastClassDevInfo
)
297 ClassDevInfo
->ImageIndex
= -1;
298 ClassDevInfo
->hDevInfo
= SetupDiGetClassDevs(&ClassDevInfo
->Guid
,
302 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
304 DWORD MemberIndex
= 0;
306 SetupDiGetClassImageIndex(&hpd
->ClassImageListData
,
308 &ClassDevInfo
->ImageIndex
);
310 while (SetupDiEnumDeviceInfo(ClassDevInfo
->hDevInfo
,
314 if (ClassDevInfo
->HwDevInfo
!= NULL
)
316 PHWDEVINFO HwNewDevInfo
= HeapReAlloc(GetProcessHeap(),
318 ClassDevInfo
->HwDevInfo
,
319 (ClassDevInfo
->ItemCount
+ 1) *
321 if (HwNewDevInfo
!= NULL
)
323 ClassDevInfo
->HwDevInfo
= HwNewDevInfo
;
327 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
328 ClassDevInfo
->ItemCount
+ 1);
334 ClassDevInfo
->HwDevInfo
= HeapAlloc(GetProcessHeap(),
337 if (ClassDevInfo
->HwDevInfo
== NULL
)
339 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
344 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
].ClassDevInfo
= ClassDevInfo
;
345 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
++].DevInfoData
= DevInfoData
;
355 FillDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
357 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
358 PHWDEVINFO HwDevInfo
, LastHwDevInfo
;
362 BuildDevicesList(hpd
);
364 ClassDevInfo
= hpd
->ClassDevInfo
;
365 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
367 while (ClassDevInfo
!= LastClassDevInfo
)
369 if (ClassDevInfo
->HwDevInfo
!= NULL
)
371 HwDevInfo
= ClassDevInfo
->HwDevInfo
;
372 LastHwDevInfo
= HwDevInfo
+ ClassDevInfo
->ItemCount
;
374 while (HwDevInfo
!= LastHwDevInfo
)
380 if ((SetupDiGetDeviceRegistryProperty(ClassDevInfo
->hDevInfo
,
381 &HwDevInfo
->DevInfoData
,
387 SetupDiGetDeviceRegistryProperty(ClassDevInfo
->hDevInfo
,
388 &HwDevInfo
->DevInfoData
,
394 RegDataType
== REG_SZ
)
396 /* FIXME - check string for NULL termination! */
398 li
.mask
= LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
| LVIF_IMAGE
;
399 li
.iItem
= ItemCount
;
401 li
.state
= (ItemCount
== 0 ? LVIS_SELECTED
: 0);
402 li
.stateMask
= LVIS_SELECTED
;
403 li
.pszText
= szBuffer
;
404 li
.iImage
= ClassDevInfo
->ImageIndex
;
405 li
.lParam
= (LPARAM
)HwDevInfo
;
407 iItem
= ListView_InsertItem(hpd
->hWndDevList
,
413 if (SetupDiGetClassDescription(&ClassDevInfo
->Guid
,
415 sizeof(szBuffer
) / sizeof(szBuffer
[0]),
422 ListView_SetItem(hpd
->hWndDevList
,
435 /* update the controls */
436 UpdateControlStates(hpd
);
442 ParentSubWndProc(IN HWND hwnd
,
447 PHARDWARE_PAGE_DATA hpd
;
449 hpd
= (PHARDWARE_PAGE_DATA
)GetProp(hwnd
,
450 L
"DevMgrSubClassInfo");
455 /* resize the hardware page */
456 SetWindowPos(hpd
->hWnd
,
465 /* pass the message the the old window proc */
466 return CallWindowProc(hpd
->ParentOldWndProc
,
474 /* this is not a good idea if the subclassed window was an ansi
475 window, but we failed finding out the previous window proc
476 so we can't use CallWindowProc. This should rarely - if ever -
479 return DefWindowProc(hwnd
,
488 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd
,
493 HWND hControl
, hButton
;
497 POINT ptMargin
= {0};
498 POINT ptMarginGroup
= {0};
500 /* use left margin of the IDC_DEVICES label as the right
501 margin of all controls outside the group box */
502 hControl
= GetDlgItem(hpd
->hWnd
,
504 GetWindowRect(hControl
,
506 MapWindowPoints(hControl
,
511 Width
= cx
- (2 * ptMargin
.x
);
513 if ((dwp
= BeginDeferWindowPos(8)))
515 /* rc already has the window rect of IDC_DEVICES! */
516 if (!(dwp
= DeferWindowPos(dwp
,
523 SWP_NOMOVE
| SWP_NOZORDER
)))
528 /* resize the devices list view control */
529 GetWindowRect(hpd
->hWndDevList
,
531 MapWindowPoints(hpd
->hWndDevList
,
535 y
= pt
.y
+ hpd
->DevListViewHeight
+ ptMargin
.y
;
536 if (!(dwp
= DeferWindowPos(dwp
,
542 hpd
->DevListViewHeight
,
543 SWP_NOMOVE
| SWP_NOZORDER
)))
548 /* resize the group box control */
549 hControl
= GetDlgItem(hpd
->hWnd
,
550 IDC_PROPERTIESGROUP
);
551 GetWindowRect(hControl
,
553 if (!(dwp
= DeferWindowPos(dwp
,
565 /* use left margin of the IDC_MANUFACTURER label as the right
566 margin of all controls inside the group box */
567 hControl
= GetDlgItem(hpd
->hWnd
,
569 GetWindowRect(hControl
,
571 MapWindowPoints(hControl
,
576 ptMarginGroup
.y
= ptMargin
.y
* 2;
577 Width
= cx
- (2 * ptMarginGroup
.x
);
578 y
+= ptMarginGroup
.y
;
579 if (!(dwp
= DeferWindowPos(dwp
,
590 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
592 /* resize the IDC_LOCATION label */
593 hControl
= GetDlgItem(hpd
->hWnd
,
595 GetWindowRect(hControl
,
597 if (!(dwp
= DeferWindowPos(dwp
,
608 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
610 /* measure the size of the buttons */
611 hButton
= GetDlgItem(hpd
->hWnd
,
613 GetWindowRect(hButton
,
616 /* resize the IDC_STATUS label */
617 hControl
= GetDlgItem(hpd
->hWnd
,
619 GetWindowRect(hControl
,
621 if (!(dwp
= DeferWindowPos(dwp
,
627 cy
- y
- (3 * ptMargin
.y
) -
628 (rcButton
.bottom
- rcButton
.top
),
634 /* move the IDC_PROPERTIES button */
635 y
= cy
- (2 * ptMargin
.y
) - (rcButton
.bottom
- rcButton
.top
);
636 x
= cx
- ptMarginGroup
.x
- (rcButton
.right
- rcButton
.left
);
637 if (!(dwp
= DeferWindowPos(dwp
,
644 SWP_NOSIZE
| SWP_NOZORDER
)))
649 /* move the IDC_TROUBLESHOOT button */
650 hButton
= GetDlgItem(hpd
->hWnd
,
652 GetWindowRect(hButton
,
654 x
-= (ptMargin
.x
/ 2) + (rcButton
.right
- rcButton
.left
);
655 if (!(dwp
= DeferWindowPos(dwp
,
662 SWP_NOSIZE
| SWP_NOZORDER
)))
667 EndDeferWindowPos(dwp
);
673 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd
,
676 HWND hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
679 ShowWindow(hBtnTroubleShoot
,
680 Enable
? SW_SHOW
: SW_HIDE
);
686 HardwareDlgProc(IN HWND hwndDlg
,
691 PHARDWARE_PAGE_DATA hpd
;
693 hpd
= (PHARDWARE_PAGE_DATA
)GetWindowLongPtr(hwndDlg
,
696 if (hpd
!= NULL
|| uMsg
== WM_INITDIALOG
)
702 NMHDR
*pnmh
= (NMHDR
*)lParam
;
703 if (pnmh
->hwndFrom
== hpd
->hWndDevList
)
707 case LVN_ITEMCHANGED
:
709 LPNMLISTVIEW pnmv
= (LPNMLISTVIEW
)lParam
;
711 if ((pnmv
->uChanged
& LVIF_STATE
) &&
712 ((pnmv
->uOldState
& (LVIS_FOCUSED
| LVIS_SELECTED
)) ||
713 (pnmv
->uNewState
& (LVIS_FOCUSED
| LVIS_SELECTED
))))
715 UpdateControlStates(hpd
);
725 HardwareDlgResize(hpd
,
727 (INT
)HIWORD(lParam
));
732 LPCWSTR szWndText
= (LPCWSTR
)lParam
;
733 EnableTroubleShoot(hpd
,
734 (szWndText
!= NULL
&& szWndText
[0] != L
'\0'));
740 hpd
= (PHARDWARE_PAGE_DATA
)lParam
;
746 SetWindowLongPtr(hwndDlg
,
750 hpd
->ClassImageListData
.cbSize
= sizeof(SP_CLASSIMAGELIST_DATA
);
752 SetupDiGetClassImageList(&hpd
->ClassImageListData
);
754 /* calculate the size of the devices list view control */
755 hpd
->hWndDevList
= GetDlgItem(hwndDlg
,
757 if (hpd
->hWndDevList
!= NULL
)
760 GetClientRect(hpd
->hWndDevList
,
762 hpd
->DevListViewHeight
= rcClient
.bottom
;
764 if (hpd
->DisplayMode
== HWPD_LARGELIST
)
766 hpd
->DevListViewHeight
= (hpd
->DevListViewHeight
* 3) / 2;
770 /* subclass the parent window */
771 hWndParent
= GetAncestor(hwndDlg
,
773 if (hWndParent
!= NULL
)
777 if (GetClientRect(hWndParent
,
779 SetWindowPos(hwndDlg
,
787 /* subclass the parent window. This is not safe
788 if the parent window belongs to another thread! */
789 hpd
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
791 (LONG_PTR
)ParentSubWndProc
);
793 if (hpd
->ParentOldWndProc
!= NULL
&&
795 L
"DevMgrSubClassInfo",
798 hpd
->hWndParent
= hWndParent
;
803 /* initialize the devices list view control */
804 InitializeDevicesList(hpd
);
806 /* fill the devices list view control */
807 FillDevicesList(hpd
);
809 /* decide whether to show or hide the troubleshoot button */
810 EnableTroubleShoot(hpd
,
811 GetWindowTextLength(hwndDlg
) != 0);
818 /* free devices list */
819 FreeDevicesList(hpd
);
821 /* restore the old window proc of the subclassed parent window */
822 if (hpd
->hWndParent
!= NULL
&& hpd
->ParentOldWndProc
!= NULL
)
824 SetWindowLongPtr(hpd
->hWndParent
,
826 (LONG_PTR
)hpd
->ParentOldWndProc
);
829 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
831 SetupDiDestroyClassImageList(&hpd
->ClassImageListData
);
834 /* free the reference to comctl32 */
835 FreeLibrary(hpd
->hComCtl32
);
836 hpd
->hComCtl32
= NULL
;
838 /* free the allocated resources */
839 HeapFree(GetProcessHeap(),
851 /***************************************************************************
853 * DeviceCreateHardwarePageEx
856 * Creates a hardware page
859 * hWndParent: Handle to the parent window
860 * lpGuids: An array of guids of devices that are to be listed
861 * uNumberOfGuids: Numbers of guids in the Guids array
862 * Unknown: Unknown parameter, see NOTEs
865 * Returns the handle of the hardware page window that has been created or
869 * 13-05-2005 first working version (Sebastian Gasiorek <zebasoftis@gmail.com>)
872 * missing: device icon in list view, Troubleshoot button, device properties,
873 * status description,
874 * devices should be visible afer PSN_SETACTIVE message
879 DeviceCreateHardwarePageEx(IN HWND hWndParent
,
881 IN UINT uNumberOfGuids
,
882 IN HWPAGE_DISPLAYMODE DisplayMode
)
884 PHARDWARE_PAGE_DATA hpd
;
885 PINITCOMMONCONTROLS pInitCommonControls
;
887 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
888 zeroed because the initialization code assumes that in
890 hpd
= HeapAlloc(GetProcessHeap(),
892 FIELD_OFFSET(HARDWARE_PAGE_DATA
,
894 (uNumberOfGuids
* sizeof(HWCLASSDEVINFO
)));
900 hpd
->DisplayMode
= ((DisplayMode
> HWPD_MAX
) ? HWPD_STANDARDLIST
: DisplayMode
);
902 /* initialize the HARDWARE_PAGE_DATA structure */
903 hpd
->NumberOfGuids
= uNumberOfGuids
;
908 hpd
->ClassDevInfo
[i
].Guid
= lpGuids
[i
];
911 /* load comctl32.dll dynamically */
912 hpd
->hComCtl32
= LoadLibrary(TEXT("comctl32.dll"));
913 if (hpd
->hComCtl32
== NULL
)
918 /* initialize the common controls */
919 pInitCommonControls
= (PINITCOMMONCONTROLS
)GetProcAddress(hpd
->hComCtl32
,
920 "InitCommonControls");
921 if (pInitCommonControls
== NULL
)
925 pInitCommonControls();
927 /* create the dialog */
928 hWnd
= CreateDialogParam(hDllInstance
,
929 MAKEINTRESOURCE(IDD_HARDWARE
),
940 /* oops, something went wrong... */
941 if (hpd
->hComCtl32
!= NULL
)
943 FreeLibrary(hpd
->hComCtl32
);
946 HeapFree(GetProcessHeap(),
956 /***************************************************************************
958 * DeviceCreateHardwarePage
961 * Creates a hardware page
964 * hWndParent: Handle to the parent window
965 * lpGuid: Guid of the device
968 * Returns the handle of the hardware page window that has been created or
978 DeviceCreateHardwarePage(IN HWND hWndParent
,
981 return DeviceCreateHardwarePageEx(hWndParent
,