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
19 /* $Id: hwpage.c 19599 2005-11-26 02:12:58Z weiden $
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/advprop.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
33 typedef INT_PTR (WINAPI
*PPROPERTYSHEETW
)(LPCPROPSHEETHEADERW
);
34 typedef HPROPSHEETPAGE (WINAPI
*PCREATEPROPERTYSHEETPAGEW
)(LPCPROPSHEETPAGEW
);
35 typedef BOOL (WINAPI
*PDESTROYPROPERTYSHEETPAGE
)(HPROPSHEETPAGE
);
44 typedef struct _DEVADVPROP_INFO
48 WNDPROC ParentOldWndProc
;
50 HDEVINFO DeviceInfoSet
;
51 SP_DEVINFO_DATA DeviceInfoData
;
53 LPCWSTR lpMachineName
;
57 DWORD PropertySheetType
;
59 HPROPSHEETPAGE
*DevPropSheets
;
61 BOOL FreeDevPropSheets
: 1;
63 BOOL DeviceEnabled
: 1;
64 BOOL DeviceUsageChanged
: 1;
65 BOOL CreatedDevInfoSet
: 1;
70 /* struct may be dynamically expanded here! */
71 } DEVADVPROP_INFO
, *PDEVADVPROP_INFO
;
75 InitDevUsageActions(IN HWND hwndDlg
,
77 IN PDEVADVPROP_INFO dap
)
84 DEVENABLEACTION Action
;
87 {IDS_ENABLEDEVICE
, DEA_ENABLE
},
88 {IDS_DISABLEDEVICE
, DEA_DISABLE
},
92 i
!= sizeof(Actions
) / sizeof(Actions
[0]);
95 /* fill in the device usage combo box */
96 if (LoadString(hDllInstance
,
99 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
101 Index
= (INT
)SendMessage(hComboBox
,
104 (LPARAM
)dap
->szTemp
);
107 SendMessage(hComboBox
,
110 (LPARAM
)Actions
[i
].Action
);
112 switch (Actions
[i
].Action
)
115 if (dap
->DeviceEnabled
)
117 SendMessage(hComboBox
,
125 if (!dap
->DeviceEnabled
)
127 SendMessage(hComboBox
,
143 static DEVENABLEACTION
144 GetSelectedUsageAction(IN HWND hComboBox
)
147 DEVENABLEACTION Ret
= DEA_UNKNOWN
;
149 Index
= (INT
)SendMessage(hComboBox
,
155 INT iRet
= SendMessage(hComboBox
,
159 if (iRet
!= CB_ERR
&& iRet
< (INT
)DEA_UNKNOWN
)
161 Ret
= (DEVENABLEACTION
)iRet
;
170 ApplyGeneralSettings(IN HWND hwndDlg
,
171 IN PDEVADVPROP_INFO dap
)
173 if (dap
->DeviceUsageChanged
)
175 DEVENABLEACTION SelectedUsageAction
;
177 SelectedUsageAction
= GetSelectedUsageAction(GetDlgItem(hwndDlg
,
179 if (SelectedUsageAction
!= DEA_UNKNOWN
)
181 switch (SelectedUsageAction
)
184 if (!dap
->DeviceEnabled
)
186 /* FIXME - enable device */
191 if (dap
->DeviceEnabled
)
193 /* FIXME - disable device */
203 /* disable the apply button */
204 PropSheet_UnChanged(GetParent(hwndDlg
),
206 dap
->DeviceUsageChanged
= FALSE
;
211 UpdateDevInfo(IN HWND hwndDlg
,
212 IN PDEVADVPROP_INFO dap
,
221 hPropSheetDlg
= GetParent(hwndDlg
);
226 HDEVINFO hOldDevInfo
;
228 /* switch to the General page */
229 PropSheet_SetCurSelByID(hPropSheetDlg
,
232 /* remove and destroy the existing device property sheet pages */
234 i
!= dap
->nDevPropSheets
;
237 PropSheet_RemovePage(hPropSheetDlg
,
239 dap
->DevPropSheets
[i
]);
242 if (dap
->FreeDevPropSheets
)
244 /* don't free the array if it's the one allocated in
245 DisplayDeviceAdvancedProperties */
246 HeapFree(GetProcessHeap(),
250 dap
->FreeDevPropSheets
= FALSE
;
253 dap
->DevPropSheets
= NULL
;
254 dap
->nDevPropSheets
= 0;
256 /* create a new device info set and re-open the device */
257 hOldDevInfo
= dap
->DeviceInfoSet
;
258 dap
->DeviceInfoSet
= SetupDiCreateDeviceInfoListEx(NULL
,
262 if (dap
->DeviceInfoSet
!= INVALID_HANDLE_VALUE
)
264 if (SetupDiOpenDeviceInfo(dap
->DeviceInfoSet
,
268 &dap
->DeviceInfoData
))
270 if (dap
->CreatedDevInfoSet
)
272 SetupDiDestroyDeviceInfoList(hOldDevInfo
);
275 dap
->CreatedDevInfoSet
= TRUE
;
279 SetupDiDestroyDeviceInfoList(dap
->DeviceInfoSet
);
280 dap
->DeviceInfoSet
= INVALID_HANDLE_VALUE
;
281 dap
->CreatedDevInfoSet
= FALSE
;
286 /* oops, something went wrong, restore the old device info set */
287 dap
->DeviceInfoSet
= hOldDevInfo
;
289 if (dap
->DeviceInfoSet
!= INVALID_HANDLE_VALUE
)
291 SetupDiOpenDeviceInfo(dap
->DeviceInfoSet
,
295 &dap
->DeviceInfoData
);
299 /* find out how many new device property sheets to add.
300 fake a PROPSHEETHEADER structure, we don't plan to
301 call PropertySheet again!*/
302 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
306 if (!SetupDiGetClassDevPropertySheets(dap
->DeviceInfoSet
,
307 &dap
->DeviceInfoData
,
310 &dap
->nDevPropSheets
,
311 dap
->PropertySheetType
) &&
312 dap
->nDevPropSheets
!= 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
314 dap
->DevPropSheets
= HeapAlloc(GetProcessHeap(),
316 dap
->nDevPropSheets
* sizeof(HPROPSHEETPAGE
));
317 if (dap
->DevPropSheets
!= NULL
)
319 psh
.phpage
= dap
->DevPropSheets
;
321 /* query the new property sheet pages to add */
322 if (SetupDiGetClassDevPropertySheets(dap
->DeviceInfoSet
,
323 &dap
->DeviceInfoData
,
327 dap
->PropertySheetType
))
329 /* add the property sheets */
332 i
!= dap
->nDevPropSheets
;
335 PropSheet_AddPage(hPropSheetDlg
,
336 dap
->DevPropSheets
[i
]);
339 dap
->FreeDevPropSheets
= TRUE
;
343 /* cleanup, we were unable to get the device property sheets */
344 HeapFree(GetProcessHeap(),
348 dap
->nDevPropSheets
= 0;
349 dap
->DevPropSheets
= NULL
;
353 dap
->nDevPropSheets
= 0;
357 /* get the device name */
358 if (GetDeviceDescriptionString(dap
->DeviceInfoSet
,
359 &dap
->DeviceInfoData
,
361 sizeof(dap
->szDevName
) / sizeof(dap
->szDevName
[0])))
363 PropSheet_SetTitle(GetParent(hwndDlg
),
368 /* set the device image */
369 if (SetupDiLoadClassIcon(&dap
->DeviceInfoData
.ClassGuid
,
373 HICON hOldIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
378 if (hOldIcon
!= NULL
)
380 DestroyIcon(hOldIcon
);
384 /* set the device name edit control text */
385 SetDlgItemText(hwndDlg
,
389 /* set the device type edit control text */
390 if (GetDeviceTypeString(&dap
->DeviceInfoData
,
392 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
394 SetDlgItemText(hwndDlg
,
399 /* set the device manufacturer edit control text */
400 if (GetDeviceManufacturerString(dap
->DeviceInfoSet
,
401 &dap
->DeviceInfoData
,
403 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
405 SetDlgItemText(hwndDlg
,
410 /* set the device location edit control text */
411 if (GetDeviceLocationString(dap
->DeviceInfoData
.DevInst
,
413 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
415 SetDlgItemText(hwndDlg
,
420 /* set the device status edit control text */
421 if (GetDeviceStatusString(dap
->DeviceInfoData
.DevInst
,
424 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
426 SetDlgItemText(hwndDlg
,
431 /* check if the device can be enabled/disabled */
432 hDevUsage
= GetDlgItem(hwndDlg
,
435 dap
->CanDisable
= FALSE
;
436 dap
->DeviceEnabled
= FALSE
;
438 if (CanDisableDevice(dap
->DeviceInfoData
.DevInst
,
442 dap
->CanDisable
= bFlag
;
445 if (IsDeviceEnabled(dap
->DeviceInfoData
.DevInst
,
449 dap
->DeviceEnabled
= bFlag
;
452 /* enable/disable the device usage controls */
453 EnableWindow(GetDlgItem(hwndDlg
,
456 EnableWindow(hDevUsage
,
459 /* clear the combobox */
460 SendMessage(hDevUsage
,
466 InitDevUsageActions(hwndDlg
,
471 /* finally, disable the apply button */
472 PropSheet_UnChanged(hPropSheetDlg
,
474 dap
->DeviceUsageChanged
= FALSE
;
480 DlgParentSubWndProc(IN HWND hwnd
,
485 PDEVADVPROP_INFO dap
;
487 dap
= (PDEVADVPROP_INFO
)GetProp(hwnd
,
488 L
"DevMgrDevChangeSub");
491 if (uMsg
== WM_DEVICECHANGE
&& !IsWindowVisible(dap
->hWndGeneralPage
))
493 SendMessage(dap
->hWndGeneralPage
,
499 /* pass the message the the old window proc */
500 return CallWindowProc(dap
->ParentOldWndProc
,
508 /* this is not a good idea if the subclassed window was an ansi
509 window, but we failed finding out the previous window proc
510 so we can't use CallWindowProc. This should rarely - if ever -
513 return DefWindowProc(hwnd
,
523 AdvPropGeneralDlgProc(IN HWND hwndDlg
,
528 PDEVADVPROP_INFO dap
;
531 dap
= (PDEVADVPROP_INFO
)GetWindowLongPtr(hwndDlg
,
534 if (dap
!= NULL
|| uMsg
== WM_INITDIALOG
)
540 switch (LOWORD(wParam
))
544 if (HIWORD(wParam
) == CBN_SELCHANGE
)
546 PropSheet_Changed(GetParent(hwndDlg
),
548 dap
->DeviceUsageChanged
= TRUE
;
558 NMHDR
*hdr
= (NMHDR
*)lParam
;
562 ApplyGeneralSettings(hwndDlg
,
571 dap
= (PDEVADVPROP_INFO
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
576 dap
->hWndGeneralPage
= hwndDlg
;
578 SetWindowLongPtr(hwndDlg
,
582 /* subclass the parent window to always receive
583 WM_DEVICECHANGE messages */
584 hWndParent
= GetParent(hwndDlg
);
585 if (hWndParent
!= NULL
)
587 /* subclass the parent window. This is not safe
588 if the parent window belongs to another thread! */
589 dap
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
591 (LONG_PTR
)DlgParentSubWndProc
);
593 if (dap
->ParentOldWndProc
!= NULL
&&
595 L
"DevMgrDevChangeSub",
598 dap
->hWndParent
= hWndParent
;
602 UpdateDevInfo(hwndDlg
,
610 case WM_DEVICECHANGE
:
612 /* FIXME - don't call UpdateDevInfo in all events */
613 UpdateDevInfo(hwndDlg
,
623 /* restore the old window proc of the subclassed parent window */
624 if (dap
->hWndParent
!= NULL
&& dap
->ParentOldWndProc
!= NULL
)
626 SetWindowLongPtr(dap
->hWndParent
,
628 (LONG_PTR
)dap
->ParentOldWndProc
);
631 /* destroy the device icon */
632 hDevIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
637 if (hDevIcon
!= NULL
)
639 DestroyIcon(hDevIcon
);
651 DisplayDeviceAdvancedProperties(IN HWND hWndParent
,
652 IN LPCWSTR lpDeviceID OPTIONAL
,
653 IN HDEVINFO DeviceInfoSet
,
654 IN PSP_DEVINFO_DATA DeviceInfoData
,
655 IN HINSTANCE hComCtl32
,
656 IN LPCWSTR lpMachineName
)
658 PROPSHEETHEADER psh
= {0};
659 PROPSHEETPAGE pspGeneral
= {0};
660 DWORD nPropSheets
= 0;
661 PPROPERTYSHEETW pPropertySheetW
;
662 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW
;
663 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage
;
664 PDEVADVPROP_INFO DevAdvPropInfo
;
665 HANDLE hMachine
= NULL
;
669 /* we don't want to statically link against comctl32, so find the
670 functions we need dynamically */
672 (PPROPERTYSHEETW
)GetProcAddress(hComCtl32
,
674 pCreatePropertySheetPageW
=
675 (PCREATEPROPERTYSHEETPAGEW
)GetProcAddress(hComCtl32
,
676 "CreatePropertySheetPageW");
677 pDestroyPropertySheetPage
=
678 (PDESTROYPROPERTYSHEETPAGE
)GetProcAddress(hComCtl32
,
679 "DestroyPropertySheetPage");
680 if (pPropertySheetW
== NULL
||
681 pCreatePropertySheetPageW
== NULL
||
682 pDestroyPropertySheetPage
== NULL
)
687 if (lpDeviceID
== NULL
)
689 /* find out how much size is needed for the device id */
690 if (SetupDiGetDeviceInstanceId(DeviceInfoSet
,
696 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
700 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
707 DevIdSize
= (DWORD
)wcslen(lpDeviceID
) + 1;
710 if (lpMachineName
!= NULL
)
712 CONFIGRET cr
= CM_Connect_Machine(lpMachineName
,
714 if (cr
!= CR_SUCCESS
)
720 /* create the internal structure associated with the "General",
721 "Driver", ... pages */
722 DevAdvPropInfo
= HeapAlloc(GetProcessHeap(),
724 FIELD_OFFSET(DEVADVPROP_INFO
,
726 (DevIdSize
* sizeof(WCHAR
)));
727 if (DevAdvPropInfo
== NULL
)
732 if (lpDeviceID
== NULL
)
734 /* read the device instance id */
735 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet
,
737 DevAdvPropInfo
->szDeviceID
,
746 /* copy the device instance id supplied by the caller */
747 wcscpy(DevAdvPropInfo
->szDeviceID
,
751 DevAdvPropInfo
->DeviceInfoSet
= DeviceInfoSet
;
752 DevAdvPropInfo
->DeviceInfoData
= *DeviceInfoData
;
753 DevAdvPropInfo
->hMachine
= hMachine
;
754 DevAdvPropInfo
->lpMachineName
= lpMachineName
;
755 DevAdvPropInfo
->szDevName
[0] = L
'\0';
756 DevAdvPropInfo
->hComCtl32
= hComCtl32
;
758 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
759 psh
.dwFlags
= PSH_PROPTITLE
| PSH_NOAPPLYNOW
;
760 psh
.hwndParent
= hWndParent
;
761 psh
.pszCaption
= DevAdvPropInfo
->szDevName
;
763 DevAdvPropInfo
->PropertySheetType
= lpMachineName
!= NULL
?
764 DIGCDP_FLAG_REMOTE_ADVANCED
:
765 DIGCDP_FLAG_ADVANCED
;
767 /* find out how many property sheets we need */
768 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
769 &DevAdvPropInfo
->DeviceInfoData
,
773 DevAdvPropInfo
->PropertySheetType
) &&
776 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
780 if (nPropSheets
!= 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
785 psh
.phpage
= HeapAlloc(GetProcessHeap(),
787 (nPropSheets
+ 1) * sizeof(HPROPSHEETPAGE
));
788 if (psh
.phpage
== NULL
)
793 /* add the "General" property sheet */
794 pspGeneral
.dwSize
= sizeof(PROPSHEETPAGE
);
795 pspGeneral
.dwFlags
= PSP_DEFAULT
;
796 pspGeneral
.hInstance
= hDllInstance
;
797 pspGeneral
.pszTemplate
= (LPCWSTR
)MAKEINTRESOURCE(IDD_DEVICEGENERAL
);
798 pspGeneral
.pfnDlgProc
= AdvPropGeneralDlgProc
;
799 pspGeneral
.lParam
= (LPARAM
)DevAdvPropInfo
;
800 psh
.phpage
[0] = pCreatePropertySheetPageW(&pspGeneral
);
801 if (psh
.phpage
[0] != NULL
)
806 DevAdvPropInfo
->nDevPropSheets
= nPropSheets
;
808 if (nPropSheets
!= 0)
810 DevAdvPropInfo
->DevPropSheets
= psh
.phpage
+ psh
.nPages
;
812 /* create the device property sheets */
813 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
814 &DevAdvPropInfo
->DeviceInfoData
,
816 nPropSheets
+ psh
.nPages
,
818 DevAdvPropInfo
->PropertySheetType
))
824 /* FIXME - add the "Driver" property sheet if necessary */
828 Ret
= pPropertySheetW(&psh
);
830 /* NOTE: no need to destroy the property sheets anymore! */
837 /* in case of failure the property sheets must be destroyed */
838 if (psh
.phpage
!= NULL
)
844 if (psh
.phpage
[i
] != NULL
)
846 pDestroyPropertySheetPage(psh
.phpage
[i
]);
852 if (DevAdvPropInfo
!= NULL
)
854 if (DevAdvPropInfo
->FreeDevPropSheets
)
856 /* don't free the array if it's the one allocated in
857 DisplayDeviceAdvancedProperties */
858 HeapFree(GetProcessHeap(),
860 DevAdvPropInfo
->DevPropSheets
);
863 if (DevAdvPropInfo
->CreatedDevInfoSet
)
865 /* close the device info set in case a new one was created */
866 SetupDiDestroyDeviceInfoList(DevAdvPropInfo
->DeviceInfoSet
);
869 HeapFree(GetProcessHeap(),
874 if (psh
.phpage
!= NULL
)
876 HeapFree(GetProcessHeap(),
881 if (hMachine
!= NULL
)
883 CM_Disconnect_Machine(hMachine
);
890 /***************************************************************************
892 * DeviceAdvancedPropertiesW
895 * Invokes the device properties dialog, this version may add some property pages
899 * hWndParent: Handle to the parent window
900 * lpMachineName: Machine Name, NULL is the local machine
901 * lpDeviceID: Specifies the device whose properties are to be shown
904 * -1: if errors occured
914 DeviceAdvancedPropertiesW(HWND hWndParent
,
915 LPCWSTR lpMachineName
,
919 SP_DEVINFO_DATA DevInfoData
;
923 /* dynamically load comctl32 */
924 hComCtl32
= LoadAndInitComctl32();
925 if (hComCtl32
!= NULL
)
927 hDevInfo
= SetupDiCreateDeviceInfoListEx(NULL
,
931 if (hDevInfo
!= INVALID_HANDLE_VALUE
)
933 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
934 if (SetupDiOpenDeviceInfo(hDevInfo
,
940 Ret
= DisplayDeviceAdvancedProperties(hWndParent
,
948 SetupDiDestroyDeviceInfoList(hDevInfo
);
951 FreeLibrary(hComCtl32
);
958 /***************************************************************************
960 * DeviceAdvancedPropertiesA
963 * Invokes the device properties dialog, this version may add some property pages
967 * hWndParent: Handle to the parent window
968 * lpMachineName: Machine Name, NULL is the local machine
969 * lpDeviceID: Specifies the device whose properties are to be shown
972 * -1: if errors occured
982 DeviceAdvancedPropertiesA(HWND hWndParent
,
983 LPCSTR lpMachineName
,
986 LPWSTR lpMachineNameW
= NULL
;
987 LPWSTR lpDeviceIDW
= NULL
;
990 if (lpMachineName
!= NULL
)
992 if (!(lpMachineNameW
= ConvertMultiByteToUnicode(lpMachineName
,
998 if (lpDeviceID
!= NULL
)
1000 if (!(lpDeviceIDW
= ConvertMultiByteToUnicode(lpDeviceID
,
1007 Ret
= DeviceAdvancedPropertiesW(hWndParent
,
1012 if (lpMachineNameW
!= NULL
)
1014 HeapFree(GetProcessHeap(),
1018 if (lpDeviceIDW
!= NULL
)
1020 HeapFree(GetProcessHeap(),