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>
35 HWPD_STANDARDLIST
= 0,
37 HWPD_MAX
= HWPD_LARGELIST
38 } HWPAGE_DISPLAYMODE
, *PHWPAGE_DISPLAYMODE
;
40 typedef struct _HWDEVINFO
42 struct _HWCLASSDEVINFO
*ClassDevInfo
;
43 SP_DEVINFO_DATA DevInfoData
;
44 } HWDEVINFO
, *PHWDEVINFO
;
46 typedef struct _HWCLASSDEVINFO
53 } HWCLASSDEVINFO
, *PHWCLASSDEVINFO
;
55 typedef struct _HARDWARE_PAGE_DATA
59 HINSTANCE hComCtl32
; /* only save this to keep track of the references */
60 INT DevListViewHeight
;
61 SP_CLASSIMAGELIST_DATA ClassImageListData
;
62 HWPAGE_DISPLAYMODE DisplayMode
;
64 /* parent window subclass info */
65 WNDPROC ParentOldWndProc
;
69 HWCLASSDEVINFO ClassDevInfo
[1];
70 /* struct may be dynamically expanded here! */
71 } HARDWARE_PAGE_DATA
, *PHARDWARE_PAGE_DATA
;
73 #define CX_TYPECOLUMN_WIDTH 80
76 InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
83 /* set the list view style */
84 ListView_SetExtendedListViewStyle(hpd
->hWndDevList
,
85 LVS_EX_FULLROWSELECT
);
87 /* set the list view image list */
88 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
90 ListView_SetImageList(hpd
->hWndDevList
,
91 hpd
->ClassImageListData
.ImageList
,
95 GetClientRect(hpd
->hWndDevList
,
98 /* add the list view columns */
99 lvc
.mask
= LVCF_TEXT
| LVCF_WIDTH
;
100 lvc
.fmt
= LVCFMT_LEFT
;
101 lvc
.pszText
= szColName
;
103 if (LoadString(hDllInstance
,
106 sizeof(szColName
) / sizeof(szColName
[0])))
108 lvc
.cx
= rcClient
.right
- CX_TYPECOLUMN_WIDTH
-
109 GetSystemMetrics(SM_CXVSCROLL
);
110 ListView_InsertColumn(hpd
->hWndDevList
,
114 if (LoadString(hDllInstance
,
117 sizeof(szColName
) / sizeof(szColName
[0])))
119 lvc
.cx
= CX_TYPECOLUMN_WIDTH
;
120 ListView_InsertColumn(hpd
->hWndDevList
,
128 DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd
)
130 PHWDEVINFO HwDevInfo
;
133 HwDevInfo
= (PHWDEVINFO
)ListViewGetSelectedItemData(hpd
->hWndDevList
);
134 if (HwDevInfo
!= NULL
)
136 PWSTR szDeviceInstanceId
= NULL
;
137 DWORD DeviceInstanceIdLen
= 0;
139 /* find out how much size is needed for the buffer */
140 if (SetupDiGetDeviceInstanceId(HwDevInfo
->ClassDevInfo
->hDevInfo
,
141 &HwDevInfo
->DevInfoData
,
144 &DeviceInstanceIdLen
))
146 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
150 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
155 szDeviceInstanceId
= HeapAlloc(GetProcessHeap(),
157 DeviceInstanceIdLen
* sizeof(WCHAR
));
158 if (szDeviceInstanceId
== NULL
)
163 /* read the device instance id */
164 if (!SetupDiGetDeviceInstanceId(HwDevInfo
->ClassDevInfo
->hDevInfo
,
165 &HwDevInfo
->DevInfoData
,
168 &DeviceInstanceIdLen
))
173 /* display the properties dialog */
174 Ret
= DeviceAdvancedProperties(hpd
->hWnd
,
176 szDeviceInstanceId
) >= 0;
179 if (szDeviceInstanceId
!= NULL
)
181 HeapFree(GetProcessHeap(),
192 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd
)
194 PHWDEVINFO HwDevInfo
;
195 HWND hBtnTroubleShoot
, hBtnProperties
;
197 hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
199 hBtnProperties
= GetDlgItem(hpd
->hWnd
,
202 HwDevInfo
= (PHWDEVINFO
)ListViewGetSelectedItemData(hpd
->hWndDevList
);
203 if (HwDevInfo
!= NULL
)
205 /* update static controls */
210 LPWSTR szFormatted
= NULL
;
212 /* get the manufacturer string */
213 if (!SetupDiGetDeviceRegistryProperty(HwDevInfo
->ClassDevInfo
->hDevInfo
,
214 &HwDevInfo
->DevInfoData
,
220 RegDataType
!= REG_SZ
)
223 LoadString(hDllInstance
,
226 sizeof(szBuffer
) / sizeof(szBuffer
[0]));
228 /* FIXME - check string for NULL termination! */
229 if (LoadAndFormatString(hDllInstance
,
234 SetDlgItemText(hpd
->hWnd
,
237 LocalFree((HLOCAL
)szFormatted
);
240 /* get the location string */
241 DataSize
= sizeof(szBuffer
);
242 cRet
= CM_Get_DevNode_Registry_Property(HwDevInfo
->DevInfoData
.DevInst
,
243 CM_DRP_LOCATION_INFORMATION
,
248 if (cRet
!= CR_SUCCESS
||
249 RegDataType
!= REG_SZ
)
252 LoadString(hDllInstance
,
255 sizeof(szBuffer
) / sizeof(szBuffer
[0]));
257 /* FIXME - check string for NULL termination! */
259 if (szBuffer
[0] >= L
'0' && szBuffer
[0] <= L
'9')
261 /* convert the string to an integer value and create a
263 ULONG ulLocation
= (ULONG
)wcstoul(szBuffer
,
266 if (LoadAndFormatString(hDllInstance
,
274 (sizeof(szBuffer
) / sizeof(szBuffer
[0])) - 1);
275 szBuffer
[(sizeof(szBuffer
) / sizeof(szBuffer
[0])) - 1] = L
'\0';
276 LocalFree((HLOCAL
)szFormatted
);
280 if (LoadAndFormatString(hDllInstance
,
285 SetDlgItemText(hpd
->hWnd
,
288 LocalFree((HLOCAL
)szFormatted
);
291 /* FIXME - get the device status text */
292 LoadString(hDllInstance
,
295 sizeof(szBuffer
) / sizeof(szBuffer
[0]));
297 if (LoadAndFormatString(hDllInstance
,
302 SetDlgItemText(hpd
->hWnd
,
305 LocalFree((HLOCAL
)szFormatted
);
310 /* clear static controls */
311 SetDlgItemText(hpd
->hWnd
,
314 SetDlgItemText(hpd
->hWnd
,
317 SetDlgItemText(hpd
->hWnd
,
322 EnableWindow(hBtnTroubleShoot
,
324 EnableWindow(hBtnProperties
,
330 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
332 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
334 ClassDevInfo
= hpd
->ClassDevInfo
;
335 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
337 /* free the device info set handles and structures */
338 while (ClassDevInfo
!= LastClassDevInfo
)
340 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
342 SetupDiDestroyDeviceInfoList(ClassDevInfo
->hDevInfo
);
343 ClassDevInfo
->hDevInfo
= INVALID_HANDLE_VALUE
;
346 ClassDevInfo
->ItemCount
= 0;
347 ClassDevInfo
->ImageIndex
= 0;
349 if (ClassDevInfo
->HwDevInfo
!= NULL
)
351 HeapFree(GetProcessHeap(),
353 ClassDevInfo
->HwDevInfo
);
354 ClassDevInfo
->HwDevInfo
= NULL
;
363 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd
)
365 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
366 SP_DEVINFO_DATA DevInfoData
;
368 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
370 ClassDevInfo
= hpd
->ClassDevInfo
;
371 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
373 while (ClassDevInfo
!= LastClassDevInfo
)
375 ClassDevInfo
->ImageIndex
= -1;
377 /* open a class device handle for the GUID we're processing */
378 ClassDevInfo
->hDevInfo
= SetupDiGetClassDevs(&ClassDevInfo
->Guid
,
382 if (ClassDevInfo
->hDevInfo
!= INVALID_HANDLE_VALUE
)
384 DWORD MemberIndex
= 0;
386 SetupDiGetClassImageIndex(&hpd
->ClassImageListData
,
388 &ClassDevInfo
->ImageIndex
);
390 /* enumerate all devices in the class */
391 while (SetupDiEnumDeviceInfo(ClassDevInfo
->hDevInfo
,
395 if (ClassDevInfo
->HwDevInfo
!= NULL
)
397 PHWDEVINFO HwNewDevInfo
= HeapReAlloc(GetProcessHeap(),
399 ClassDevInfo
->HwDevInfo
,
400 (ClassDevInfo
->ItemCount
+ 1) *
402 if (HwNewDevInfo
!= NULL
)
404 ClassDevInfo
->HwDevInfo
= HwNewDevInfo
;
408 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
409 ClassDevInfo
->ItemCount
+ 1);
415 ClassDevInfo
->HwDevInfo
= HeapAlloc(GetProcessHeap(),
418 if (ClassDevInfo
->HwDevInfo
== NULL
)
420 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
425 /* save all information for the current device */
426 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
].ClassDevInfo
= ClassDevInfo
;
427 ClassDevInfo
->HwDevInfo
[ClassDevInfo
->ItemCount
++].DevInfoData
= DevInfoData
;
437 FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd
)
439 PHWCLASSDEVINFO ClassDevInfo
, LastClassDevInfo
;
440 PHWDEVINFO HwDevInfo
, LastHwDevInfo
;
444 BuildDevicesList(hpd
);
446 ClassDevInfo
= hpd
->ClassDevInfo
;
447 LastClassDevInfo
= ClassDevInfo
+ hpd
->NumberOfGuids
;
449 while (ClassDevInfo
!= LastClassDevInfo
)
451 if (ClassDevInfo
->HwDevInfo
!= NULL
)
453 HwDevInfo
= ClassDevInfo
->HwDevInfo
;
454 LastHwDevInfo
= HwDevInfo
+ ClassDevInfo
->ItemCount
;
456 while (HwDevInfo
!= LastHwDevInfo
)
462 /* get the device name */
463 if ((SetupDiGetDeviceRegistryProperty(ClassDevInfo
->hDevInfo
,
464 &HwDevInfo
->DevInfoData
,
470 SetupDiGetDeviceRegistryProperty(ClassDevInfo
->hDevInfo
,
471 &HwDevInfo
->DevInfoData
,
477 RegDataType
== REG_SZ
)
479 /* FIXME - check string for NULL termination! */
481 li
.mask
= LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
| LVIF_IMAGE
;
482 li
.iItem
= ItemCount
;
484 li
.state
= (ItemCount
== 0 ? LVIS_SELECTED
: 0);
485 li
.stateMask
= LVIS_SELECTED
;
486 li
.pszText
= szBuffer
;
487 li
.iImage
= ClassDevInfo
->ImageIndex
;
488 li
.lParam
= (LPARAM
)HwDevInfo
;
490 iItem
= ListView_InsertItem(hpd
->hWndDevList
,
496 /* get the device type for the second column */
497 if (SetupDiGetClassDescription(&ClassDevInfo
->Guid
,
499 sizeof(szBuffer
) / sizeof(szBuffer
[0]),
506 ListView_SetItem(hpd
->hWndDevList
,
519 /* update the controls */
520 UpdateControlStates(hpd
);
526 ParentSubWndProc(IN HWND hwnd
,
531 PHARDWARE_PAGE_DATA hpd
;
533 hpd
= (PHARDWARE_PAGE_DATA
)GetProp(hwnd
,
534 L
"DevMgrSubClassInfo");
539 /* resize the hardware page */
540 SetWindowPos(hpd
->hWnd
,
549 /* pass the message the the old window proc */
550 return CallWindowProc(hpd
->ParentOldWndProc
,
558 /* this is not a good idea if the subclassed window was an ansi
559 window, but we failed finding out the previous window proc
560 so we can't use CallWindowProc. This should rarely - if ever -
563 return DefWindowProc(hwnd
,
572 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd
,
577 HWND hControl
, hButton
;
581 POINT ptMargin
= {0};
582 POINT ptMarginGroup
= {0};
584 /* use left margin of the IDC_DEVICES label as the right
585 margin of all controls outside the group box */
586 hControl
= GetDlgItem(hpd
->hWnd
,
588 GetWindowRect(hControl
,
590 MapWindowPoints(hControl
,
595 Width
= cx
- (2 * ptMargin
.x
);
597 if ((dwp
= BeginDeferWindowPos(8)))
599 /* rc already has the window rect of IDC_DEVICES! */
600 if (!(dwp
= DeferWindowPos(dwp
,
607 SWP_NOMOVE
| SWP_NOZORDER
)))
612 /* resize the devices list view control */
613 GetWindowRect(hpd
->hWndDevList
,
615 MapWindowPoints(hpd
->hWndDevList
,
619 y
= pt
.y
+ hpd
->DevListViewHeight
+ ptMargin
.y
;
620 if (!(dwp
= DeferWindowPos(dwp
,
626 hpd
->DevListViewHeight
,
627 SWP_NOMOVE
| SWP_NOZORDER
)))
632 /* resize the group box control */
633 hControl
= GetDlgItem(hpd
->hWnd
,
634 IDC_PROPERTIESGROUP
);
635 GetWindowRect(hControl
,
637 if (!(dwp
= DeferWindowPos(dwp
,
649 /* use left margin of the IDC_MANUFACTURER label as the right
650 margin of all controls inside the group box */
651 hControl
= GetDlgItem(hpd
->hWnd
,
653 GetWindowRect(hControl
,
655 MapWindowPoints(hControl
,
660 ptMarginGroup
.y
= ptMargin
.y
* 2;
661 Width
= cx
- (2 * ptMarginGroup
.x
);
662 y
+= ptMarginGroup
.y
;
663 if (!(dwp
= DeferWindowPos(dwp
,
674 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
676 /* resize the IDC_LOCATION label */
677 hControl
= GetDlgItem(hpd
->hWnd
,
679 GetWindowRect(hControl
,
681 if (!(dwp
= DeferWindowPos(dwp
,
692 y
+= rc
.bottom
- rc
.top
+ (ptMargin
.y
/ 2);
694 /* measure the size of the buttons */
695 hButton
= GetDlgItem(hpd
->hWnd
,
697 GetWindowRect(hButton
,
700 /* resize the IDC_STATUS label */
701 hControl
= GetDlgItem(hpd
->hWnd
,
703 GetWindowRect(hControl
,
705 if (!(dwp
= DeferWindowPos(dwp
,
711 cy
- y
- (3 * ptMargin
.y
) -
712 (rcButton
.bottom
- rcButton
.top
),
718 /* move the IDC_PROPERTIES button */
719 y
= cy
- (2 * ptMargin
.y
) - (rcButton
.bottom
- rcButton
.top
);
720 x
= cx
- ptMarginGroup
.x
- (rcButton
.right
- rcButton
.left
);
721 if (!(dwp
= DeferWindowPos(dwp
,
728 SWP_NOSIZE
| SWP_NOZORDER
)))
733 /* move the IDC_TROUBLESHOOT button */
734 hButton
= GetDlgItem(hpd
->hWnd
,
736 GetWindowRect(hButton
,
738 x
-= (ptMargin
.x
/ 2) + (rcButton
.right
- rcButton
.left
);
739 if (!(dwp
= DeferWindowPos(dwp
,
746 SWP_NOSIZE
| SWP_NOZORDER
)))
751 EndDeferWindowPos(dwp
);
757 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd
,
760 HWND hBtnTroubleShoot
= GetDlgItem(hpd
->hWnd
,
763 ShowWindow(hBtnTroubleShoot
,
764 Enable
? SW_SHOW
: SW_HIDE
);
770 HardwareDlgProc(IN HWND hwndDlg
,
775 PHARDWARE_PAGE_DATA hpd
;
777 hpd
= (PHARDWARE_PAGE_DATA
)GetWindowLongPtr(hwndDlg
,
780 if (hpd
!= NULL
|| uMsg
== WM_INITDIALOG
)
786 NMHDR
*pnmh
= (NMHDR
*)lParam
;
787 if (pnmh
->hwndFrom
== hpd
->hWndDevList
)
791 case LVN_ITEMCHANGED
:
793 LPNMLISTVIEW pnmv
= (LPNMLISTVIEW
)lParam
;
795 if ((pnmv
->uChanged
& LVIF_STATE
) &&
796 ((pnmv
->uOldState
& (LVIS_FOCUSED
| LVIS_SELECTED
)) ||
797 (pnmv
->uNewState
& (LVIS_FOCUSED
| LVIS_SELECTED
))))
799 UpdateControlStates(hpd
);
810 switch (LOWORD(wParam
))
812 case IDC_TROUBLESHOOT
:
814 /* FIXME - start the help using the command in the window text */
820 DisplaySelectedDeviceProperties(hpd
);
828 HardwareDlgResize(hpd
,
830 (INT
)HIWORD(lParam
));
835 LPCWSTR szWndText
= (LPCWSTR
)lParam
;
836 EnableTroubleShoot(hpd
,
837 (szWndText
!= NULL
&& szWndText
[0] != L
'\0'));
843 hpd
= (PHARDWARE_PAGE_DATA
)lParam
;
849 SetWindowLongPtr(hwndDlg
,
853 hpd
->ClassImageListData
.cbSize
= sizeof(SP_CLASSIMAGELIST_DATA
);
855 SetupDiGetClassImageList(&hpd
->ClassImageListData
);
857 /* calculate the size of the devices list view control */
858 hpd
->hWndDevList
= GetDlgItem(hwndDlg
,
860 if (hpd
->hWndDevList
!= NULL
)
863 GetClientRect(hpd
->hWndDevList
,
865 hpd
->DevListViewHeight
= rcClient
.bottom
;
867 if (hpd
->DisplayMode
== HWPD_LARGELIST
)
869 hpd
->DevListViewHeight
= (hpd
->DevListViewHeight
* 3) / 2;
873 /* subclass the parent window */
874 hWndParent
= GetAncestor(hwndDlg
,
876 if (hWndParent
!= NULL
)
880 if (GetClientRect(hWndParent
,
882 SetWindowPos(hwndDlg
,
890 /* subclass the parent window. This is not safe
891 if the parent window belongs to another thread! */
892 hpd
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
894 (LONG_PTR
)ParentSubWndProc
);
896 if (hpd
->ParentOldWndProc
!= NULL
&&
898 L
"DevMgrSubClassInfo",
901 hpd
->hWndParent
= hWndParent
;
906 /* initialize the devices list view control */
907 InitializeDevicesList(hpd
);
909 /* fill the devices list view control */
910 FillDevicesListViewControl(hpd
);
912 /* decide whether to show or hide the troubleshoot button */
913 EnableTroubleShoot(hpd
,
914 GetWindowTextLength(hwndDlg
) != 0);
921 /* free devices list */
922 FreeDevicesList(hpd
);
924 /* restore the old window proc of the subclassed parent window */
925 if (hpd
->hWndParent
!= NULL
&& hpd
->ParentOldWndProc
!= NULL
)
927 SetWindowLongPtr(hpd
->hWndParent
,
929 (LONG_PTR
)hpd
->ParentOldWndProc
);
932 if (hpd
->ClassImageListData
.ImageList
!= NULL
)
934 SetupDiDestroyClassImageList(&hpd
->ClassImageListData
);
937 /* free the reference to comctl32 */
938 FreeLibrary(hpd
->hComCtl32
);
939 hpd
->hComCtl32
= NULL
;
941 /* free the allocated resources */
942 HeapFree(GetProcessHeap(),
954 /***************************************************************************
956 * DeviceCreateHardwarePageEx
959 * Creates a hardware page
962 * hWndParent: Handle to the parent window
963 * lpGuids: An array of guids of devices that are to be listed
964 * uNumberOfGuids: Numbers of guids in the Guids array
965 * DisplayMode: Sets the size of the device list view control
968 * Returns the handle of the hardware page window that has been created or
975 DeviceCreateHardwarePageEx(IN HWND hWndParent
,
977 IN UINT uNumberOfGuids
,
978 IN HWPAGE_DISPLAYMODE DisplayMode
)
980 PHARDWARE_PAGE_DATA hpd
;
982 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
983 zeroed because the initialization code assumes that in
985 hpd
= HeapAlloc(GetProcessHeap(),
987 FIELD_OFFSET(HARDWARE_PAGE_DATA
,
989 (uNumberOfGuids
* sizeof(HWCLASSDEVINFO
)));
995 hpd
->DisplayMode
= ((DisplayMode
> HWPD_MAX
) ? HWPD_STANDARDLIST
: DisplayMode
);
997 /* initialize the HARDWARE_PAGE_DATA structure */
998 hpd
->NumberOfGuids
= uNumberOfGuids
;
1003 hpd
->ClassDevInfo
[i
].hDevInfo
= INVALID_HANDLE_VALUE
;
1004 hpd
->ClassDevInfo
[i
].Guid
= lpGuids
[i
];
1007 /* load comctl32.dll dynamically */
1008 hpd
->hComCtl32
= LoadAndInitComctl32();
1009 if (hpd
->hComCtl32
== NULL
)
1014 /* create the dialog */
1015 hWnd
= CreateDialogParam(hDllInstance
,
1016 MAKEINTRESOURCE(IDD_HARDWARE
),
1027 /* oops, something went wrong... */
1028 if (hpd
->hComCtl32
!= NULL
)
1030 FreeLibrary(hpd
->hComCtl32
);
1033 HeapFree(GetProcessHeap(),
1043 /***************************************************************************
1045 * DeviceCreateHardwarePage
1048 * Creates a hardware page
1051 * hWndParent: Handle to the parent window
1052 * lpGuid: Guid of the device
1055 * Returns the handle of the hardware page window that has been created or
1056 * NULL if it failed.
1062 DeviceCreateHardwarePage(IN HWND hWndParent
,
1065 return DeviceCreateHardwarePageEx(hWndParent
,