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
;
52 HDEVINFO CurrentDeviceInfoSet
;
53 SP_DEVINFO_DATA CurrentDeviceInfoData
;
54 DEVINST ParentDevInst
;
56 LPCWSTR lpMachineName
;
60 DWORD PropertySheetType
;
62 HPROPSHEETPAGE
*DevPropSheets
;
64 BOOL FreeDevPropSheets
: 1;
66 BOOL DeviceEnabled
: 1;
67 BOOL DeviceUsageChanged
: 1;
68 BOOL CloseDevInst
: 1;
74 /* struct may be dynamically expanded here! */
75 } DEVADVPROP_INFO
, *PDEVADVPROP_INFO
;
79 InitDevUsageActions(IN HWND hwndDlg
,
81 IN PDEVADVPROP_INFO dap
)
88 DEVENABLEACTION Action
;
91 {IDS_ENABLEDEVICE
, DEA_ENABLE
},
92 {IDS_DISABLEDEVICE
, DEA_DISABLE
},
96 i
!= sizeof(Actions
) / sizeof(Actions
[0]);
99 /* fill in the device usage combo box */
100 if (LoadString(hDllInstance
,
103 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
105 Index
= (INT
)SendMessage(hComboBox
,
108 (LPARAM
)dap
->szTemp
);
111 SendMessage(hComboBox
,
114 (LPARAM
)Actions
[i
].Action
);
116 switch (Actions
[i
].Action
)
119 if (dap
->DeviceEnabled
)
121 SendMessage(hComboBox
,
129 if (!dap
->DeviceEnabled
)
131 SendMessage(hComboBox
,
147 static DEVENABLEACTION
148 GetSelectedUsageAction(IN HWND hComboBox
)
151 DEVENABLEACTION Ret
= DEA_UNKNOWN
;
153 Index
= (INT
)SendMessage(hComboBox
,
159 INT iRet
= SendMessage(hComboBox
,
163 if (iRet
!= CB_ERR
&& iRet
< (INT
)DEA_UNKNOWN
)
165 Ret
= (DEVENABLEACTION
)iRet
;
174 ApplyGeneralSettings(IN HWND hwndDlg
,
175 IN PDEVADVPROP_INFO dap
)
177 if (dap
->DeviceUsageChanged
&& dap
->IsAdmin
)
179 DEVENABLEACTION SelectedUsageAction
;
181 SelectedUsageAction
= GetSelectedUsageAction(GetDlgItem(hwndDlg
,
183 if (SelectedUsageAction
!= DEA_UNKNOWN
)
185 switch (SelectedUsageAction
)
188 if (!dap
->DeviceEnabled
)
190 /* FIXME - enable device */
195 if (dap
->DeviceEnabled
)
197 /* FIXME - disable device */
207 /* disable the apply button */
208 PropSheet_UnChanged(GetParent(hwndDlg
),
210 dap
->DeviceUsageChanged
= FALSE
;
215 UpdateDevInfo(IN HWND hwndDlg
,
216 IN PDEVADVPROP_INFO dap
,
224 HDEVINFO DeviceInfoSet
= NULL
;
225 PSP_DEVINFO_DATA DeviceInfoData
= NULL
;
227 hPropSheetDlg
= GetParent(hwndDlg
);
233 /* switch to the General page */
234 PropSheet_SetCurSelByID(hPropSheetDlg
,
237 /* remove and destroy the existing device property sheet pages */
239 i
!= dap
->nDevPropSheets
;
242 PropSheet_RemovePage(hPropSheetDlg
,
244 dap
->DevPropSheets
[i
]);
247 if (dap
->FreeDevPropSheets
)
249 /* don't free the array if it's the one allocated in
250 DisplayDeviceAdvancedProperties */
251 HeapFree(GetProcessHeap(),
255 dap
->FreeDevPropSheets
= FALSE
;
258 dap
->DevPropSheets
= NULL
;
259 dap
->nDevPropSheets
= 0;
261 /* create a new device info set and re-open the device */
262 if (dap
->CurrentDeviceInfoSet
!= INVALID_HANDLE_VALUE
)
264 SetupDiDestroyDeviceInfoList(dap
->CurrentDeviceInfoSet
);
267 dap
->ParentDevInst
= 0;
268 dap
->CurrentDeviceInfoSet
= SetupDiCreateDeviceInfoListEx(NULL
,
272 if (dap
->CurrentDeviceInfoSet
!= INVALID_HANDLE_VALUE
)
274 if (SetupDiOpenDeviceInfo(dap
->CurrentDeviceInfoSet
,
278 &dap
->CurrentDeviceInfoData
))
280 if (dap
->CloseDevInst
)
282 SetupDiDestroyDeviceInfoList(dap
->DeviceInfoSet
);
285 dap
->CloseDevInst
= TRUE
;
286 dap
->DeviceInfoSet
= dap
->CurrentDeviceInfoSet
;
287 dap
->DeviceInfoData
= dap
->CurrentDeviceInfoData
;
288 dap
->CurrentDeviceInfoSet
= INVALID_HANDLE_VALUE
;
296 /* get the parent node from the initial devinst */
297 CM_Get_Parent_Ex(&dap
->ParentDevInst
,
298 dap
->DeviceInfoData
.DevInst
,
303 if (dap
->CurrentDeviceInfoSet
!= INVALID_HANDLE_VALUE
)
305 DeviceInfoSet
= dap
->CurrentDeviceInfoSet
;
306 DeviceInfoData
= &dap
->CurrentDeviceInfoData
;
310 DeviceInfoSet
= dap
->DeviceInfoSet
;
311 DeviceInfoData
= &dap
->DeviceInfoData
;
314 /* find out how many new device property sheets to add.
315 fake a PROPSHEETHEADER structure, we don't plan to
316 call PropertySheet again!*/
317 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
321 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
325 &dap
->nDevPropSheets
,
326 dap
->PropertySheetType
) &&
327 dap
->nDevPropSheets
!= 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
329 dap
->DevPropSheets
= HeapAlloc(GetProcessHeap(),
331 dap
->nDevPropSheets
* sizeof(HPROPSHEETPAGE
));
332 if (dap
->DevPropSheets
!= NULL
)
334 psh
.phpage
= dap
->DevPropSheets
;
336 /* query the new property sheet pages to add */
337 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
342 dap
->PropertySheetType
))
344 /* add the property sheets */
347 i
!= dap
->nDevPropSheets
;
350 PropSheet_AddPage(hPropSheetDlg
,
351 dap
->DevPropSheets
[i
]);
354 dap
->FreeDevPropSheets
= TRUE
;
358 /* cleanup, we were unable to get the device property sheets */
359 HeapFree(GetProcessHeap(),
363 dap
->nDevPropSheets
= 0;
364 dap
->DevPropSheets
= NULL
;
368 dap
->nDevPropSheets
= 0;
373 if (dap
->CurrentDeviceInfoSet
!= INVALID_HANDLE_VALUE
)
375 DeviceInfoSet
= dap
->CurrentDeviceInfoSet
;
376 DeviceInfoData
= &dap
->CurrentDeviceInfoData
;
380 DeviceInfoSet
= dap
->DeviceInfoSet
;
381 DeviceInfoData
= &dap
->DeviceInfoData
;
385 /* get the device name */
386 if (GetDeviceDescriptionString(DeviceInfoSet
,
389 sizeof(dap
->szDevName
) / sizeof(dap
->szDevName
[0])))
391 PropSheet_SetTitle(GetParent(hwndDlg
),
396 /* set the device image */
397 if (SetupDiLoadClassIcon(&DeviceInfoData
->ClassGuid
,
401 HICON hOldIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
406 if (hOldIcon
!= NULL
)
408 DestroyIcon(hOldIcon
);
412 /* set the device name edit control text */
413 SetDlgItemText(hwndDlg
,
417 /* set the device type edit control text */
418 if (GetDeviceTypeString(DeviceInfoData
,
420 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
422 SetDlgItemText(hwndDlg
,
427 /* set the device manufacturer edit control text */
428 if (GetDeviceManufacturerString(DeviceInfoSet
,
431 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
433 SetDlgItemText(hwndDlg
,
438 /* set the device location edit control text */
439 if (GetDeviceLocationString(DeviceInfoData
->DevInst
,
442 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
444 SetDlgItemText(hwndDlg
,
449 /* set the device status edit control text */
450 if (GetDeviceStatusString(DeviceInfoData
->DevInst
,
453 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
455 SetDlgItemText(hwndDlg
,
460 /* check if the device can be enabled/disabled */
461 hDevUsage
= GetDlgItem(hwndDlg
,
464 dap
->CanDisable
= FALSE
;
465 dap
->DeviceEnabled
= FALSE
;
467 if (CanDisableDevice(DeviceInfoData
->DevInst
,
471 dap
->CanDisable
= bFlag
;
474 if (IsDeviceEnabled(DeviceInfoData
->DevInst
,
478 dap
->DeviceEnabled
= bFlag
;
481 /* enable/disable the device usage controls */
482 EnableWindow(GetDlgItem(hwndDlg
,
484 dap
->CanDisable
&& dap
->IsAdmin
);
485 EnableWindow(hDevUsage
,
486 dap
->CanDisable
&& dap
->IsAdmin
);
488 /* clear the combobox */
489 SendMessage(hDevUsage
,
495 InitDevUsageActions(hwndDlg
,
500 /* finally, disable the apply button */
501 PropSheet_UnChanged(hPropSheetDlg
,
503 dap
->DeviceUsageChanged
= FALSE
;
509 DlgParentSubWndProc(IN HWND hwnd
,
514 PDEVADVPROP_INFO dap
;
516 dap
= (PDEVADVPROP_INFO
)GetProp(hwnd
,
517 L
"DevMgrDevChangeSub");
520 if (uMsg
== WM_DEVICECHANGE
&& !IsWindowVisible(dap
->hWndGeneralPage
))
522 SendMessage(dap
->hWndGeneralPage
,
528 /* pass the message the the old window proc */
529 return CallWindowProc(dap
->ParentOldWndProc
,
537 /* this is not a good idea if the subclassed window was an ansi
538 window, but we failed finding out the previous window proc
539 so we can't use CallWindowProc. This should rarely - if ever -
542 return DefWindowProc(hwnd
,
552 AdvPropGeneralDlgProc(IN HWND hwndDlg
,
557 PDEVADVPROP_INFO dap
;
560 dap
= (PDEVADVPROP_INFO
)GetWindowLongPtr(hwndDlg
,
563 if (dap
!= NULL
|| uMsg
== WM_INITDIALOG
)
569 switch (LOWORD(wParam
))
573 if (HIWORD(wParam
) == CBN_SELCHANGE
)
575 PropSheet_Changed(GetParent(hwndDlg
),
577 dap
->DeviceUsageChanged
= TRUE
;
587 NMHDR
*hdr
= (NMHDR
*)lParam
;
591 ApplyGeneralSettings(hwndDlg
,
600 dap
= (PDEVADVPROP_INFO
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
605 dap
->hWndGeneralPage
= hwndDlg
;
607 SetWindowLongPtr(hwndDlg
,
611 /* subclass the parent window to always receive
612 WM_DEVICECHANGE messages */
613 hWndParent
= GetParent(hwndDlg
);
614 if (hWndParent
!= NULL
)
616 /* subclass the parent window. This is not safe
617 if the parent window belongs to another thread! */
618 dap
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
620 (LONG_PTR
)DlgParentSubWndProc
);
622 if (dap
->ParentOldWndProc
!= NULL
&&
624 L
"DevMgrDevChangeSub",
627 dap
->hWndParent
= hWndParent
;
631 UpdateDevInfo(hwndDlg
,
639 case WM_DEVICECHANGE
:
641 /* FIXME - don't call UpdateDevInfo in all events */
642 UpdateDevInfo(hwndDlg
,
652 /* restore the old window proc of the subclassed parent window */
653 if (dap
->hWndParent
!= NULL
&& dap
->ParentOldWndProc
!= NULL
)
655 SetWindowLongPtr(dap
->hWndParent
,
657 (LONG_PTR
)dap
->ParentOldWndProc
);
660 /* destroy the device icon */
661 hDevIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
666 if (hDevIcon
!= NULL
)
668 DestroyIcon(hDevIcon
);
680 DisplayDeviceAdvancedProperties(IN HWND hWndParent
,
681 IN LPCWSTR lpDeviceID OPTIONAL
,
682 IN HDEVINFO DeviceInfoSet
,
683 IN PSP_DEVINFO_DATA DeviceInfoData
,
684 IN HINSTANCE hComCtl32
,
685 IN LPCWSTR lpMachineName
)
687 PROPSHEETHEADER psh
= {0};
688 PROPSHEETPAGE pspGeneral
= {0};
689 DWORD nPropSheets
= 0;
690 PPROPERTYSHEETW pPropertySheetW
;
691 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW
;
692 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage
;
693 PDEVADVPROP_INFO DevAdvPropInfo
;
694 HMACHINE hMachine
= NULL
;
698 /* we don't want to statically link against comctl32, so find the
699 functions we need dynamically */
701 (PPROPERTYSHEETW
)GetProcAddress(hComCtl32
,
703 pCreatePropertySheetPageW
=
704 (PCREATEPROPERTYSHEETPAGEW
)GetProcAddress(hComCtl32
,
705 "CreatePropertySheetPageW");
706 pDestroyPropertySheetPage
=
707 (PDESTROYPROPERTYSHEETPAGE
)GetProcAddress(hComCtl32
,
708 "DestroyPropertySheetPage");
709 if (pPropertySheetW
== NULL
||
710 pCreatePropertySheetPageW
== NULL
||
711 pDestroyPropertySheetPage
== NULL
)
716 if (lpDeviceID
== NULL
)
718 /* find out how much size is needed for the device id */
719 if (SetupDiGetDeviceInstanceId(DeviceInfoSet
,
725 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
729 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
736 DevIdSize
= (DWORD
)wcslen(lpDeviceID
) + 1;
739 if (lpMachineName
!= NULL
)
741 CONFIGRET cr
= CM_Connect_Machine(lpMachineName
,
743 if (cr
!= CR_SUCCESS
)
749 /* create the internal structure associated with the "General",
750 "Driver", ... pages */
751 DevAdvPropInfo
= HeapAlloc(GetProcessHeap(),
753 FIELD_OFFSET(DEVADVPROP_INFO
,
755 (DevIdSize
* sizeof(WCHAR
)));
756 if (DevAdvPropInfo
== NULL
)
761 if (lpDeviceID
== NULL
)
763 /* read the device instance id */
764 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet
,
766 DevAdvPropInfo
->szDeviceID
,
775 /* copy the device instance id supplied by the caller */
776 wcscpy(DevAdvPropInfo
->szDeviceID
,
780 DevAdvPropInfo
->DeviceInfoSet
= DeviceInfoSet
;
781 DevAdvPropInfo
->DeviceInfoData
= *DeviceInfoData
;
782 DevAdvPropInfo
->CurrentDeviceInfoSet
= INVALID_HANDLE_VALUE
;
783 DevAdvPropInfo
->CurrentDeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
785 DevAdvPropInfo
->hMachine
= hMachine
;
786 DevAdvPropInfo
->lpMachineName
= lpMachineName
;
787 DevAdvPropInfo
->szDevName
[0] = L
'\0';
788 DevAdvPropInfo
->hComCtl32
= hComCtl32
;
790 DevAdvPropInfo
->IsAdmin
= IsUserAdmin();
792 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
793 psh
.dwFlags
= PSH_PROPTITLE
| PSH_NOAPPLYNOW
;
794 psh
.hwndParent
= hWndParent
;
795 psh
.pszCaption
= DevAdvPropInfo
->szDevName
;
797 DevAdvPropInfo
->PropertySheetType
= lpMachineName
!= NULL
?
798 DIGCDP_FLAG_REMOTE_ADVANCED
:
799 DIGCDP_FLAG_ADVANCED
;
801 /* find out how many property sheets we need */
802 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
803 &DevAdvPropInfo
->DeviceInfoData
,
807 DevAdvPropInfo
->PropertySheetType
) &&
810 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
814 if (nPropSheets
!= 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
819 psh
.phpage
= HeapAlloc(GetProcessHeap(),
821 (nPropSheets
+ 1) * sizeof(HPROPSHEETPAGE
));
822 if (psh
.phpage
== NULL
)
827 /* add the "General" property sheet */
828 pspGeneral
.dwSize
= sizeof(PROPSHEETPAGE
);
829 pspGeneral
.dwFlags
= PSP_DEFAULT
;
830 pspGeneral
.hInstance
= hDllInstance
;
831 pspGeneral
.pszTemplate
= (LPCWSTR
)MAKEINTRESOURCE(IDD_DEVICEGENERAL
);
832 pspGeneral
.pfnDlgProc
= AdvPropGeneralDlgProc
;
833 pspGeneral
.lParam
= (LPARAM
)DevAdvPropInfo
;
834 psh
.phpage
[0] = pCreatePropertySheetPageW(&pspGeneral
);
835 if (psh
.phpage
[0] != NULL
)
840 DevAdvPropInfo
->nDevPropSheets
= nPropSheets
;
842 if (nPropSheets
!= 0)
844 DevAdvPropInfo
->DevPropSheets
= psh
.phpage
+ psh
.nPages
;
846 /* create the device property sheets */
847 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
848 &DevAdvPropInfo
->DeviceInfoData
,
850 nPropSheets
+ psh
.nPages
,
852 DevAdvPropInfo
->PropertySheetType
))
858 /* FIXME - add the "Driver" property sheet if necessary */
862 Ret
= pPropertySheetW(&psh
);
864 /* NOTE: no need to destroy the property sheets anymore! */
871 /* in case of failure the property sheets must be destroyed */
872 if (psh
.phpage
!= NULL
)
878 if (psh
.phpage
[i
] != NULL
)
880 pDestroyPropertySheetPage(psh
.phpage
[i
]);
886 if (DevAdvPropInfo
!= NULL
)
888 if (DevAdvPropInfo
->FreeDevPropSheets
)
890 /* don't free the array if it's the one allocated in
891 DisplayDeviceAdvancedProperties */
892 HeapFree(GetProcessHeap(),
894 DevAdvPropInfo
->DevPropSheets
);
897 if (DevAdvPropInfo
->CloseDevInst
)
899 /* close the device info set in case a new one was created */
900 SetupDiDestroyDeviceInfoList(DevAdvPropInfo
->DeviceInfoSet
);
903 if (DevAdvPropInfo
->CurrentDeviceInfoSet
!= INVALID_HANDLE_VALUE
)
905 SetupDiDestroyDeviceInfoList(DevAdvPropInfo
->CurrentDeviceInfoSet
);
908 HeapFree(GetProcessHeap(),
913 if (psh
.phpage
!= NULL
)
915 HeapFree(GetProcessHeap(),
920 if (hMachine
!= NULL
)
922 CM_Disconnect_Machine(hMachine
);
929 /***************************************************************************
931 * DeviceAdvancedPropertiesW
934 * Invokes the device properties dialog, this version may add some property pages
938 * hWndParent: Handle to the parent window
939 * lpMachineName: Machine Name, NULL is the local machine
940 * lpDeviceID: Specifies the device whose properties are to be shown
943 * -1: if errors occured
953 DeviceAdvancedPropertiesW(HWND hWndParent
,
954 LPCWSTR lpMachineName
,
958 SP_DEVINFO_DATA DevInfoData
;
962 /* dynamically load comctl32 */
963 hComCtl32
= LoadAndInitComctl32();
964 if (hComCtl32
!= NULL
)
966 hDevInfo
= SetupDiCreateDeviceInfoListEx(NULL
,
970 if (hDevInfo
!= INVALID_HANDLE_VALUE
)
972 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
973 if (SetupDiOpenDeviceInfo(hDevInfo
,
979 Ret
= DisplayDeviceAdvancedProperties(hWndParent
,
987 SetupDiDestroyDeviceInfoList(hDevInfo
);
990 FreeLibrary(hComCtl32
);
997 /***************************************************************************
999 * DeviceAdvancedPropertiesA
1002 * Invokes the device properties dialog, this version may add some property pages
1006 * hWndParent: Handle to the parent window
1007 * lpMachineName: Machine Name, NULL is the local machine
1008 * lpDeviceID: Specifies the device whose properties are to be shown
1011 * -1: if errors occured
1021 DeviceAdvancedPropertiesA(HWND hWndParent
,
1022 LPCSTR lpMachineName
,
1025 LPWSTR lpMachineNameW
= NULL
;
1026 LPWSTR lpDeviceIDW
= NULL
;
1029 if (lpMachineName
!= NULL
)
1031 if (!(lpMachineNameW
= ConvertMultiByteToUnicode(lpMachineName
,
1037 if (lpDeviceID
!= NULL
)
1039 if (!(lpDeviceIDW
= ConvertMultiByteToUnicode(lpDeviceID
,
1046 Ret
= DeviceAdvancedPropertiesW(hWndParent
,
1051 if (lpMachineNameW
!= NULL
)
1053 HeapFree(GetProcessHeap(),
1057 if (lpDeviceIDW
!= NULL
)
1059 HeapFree(GetProcessHeap(),