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 #define DPN_DEVICEUPDATE (WM_USER + 0x1000)
35 typedef INT_PTR (WINAPI
*PPROPERTYSHEETW
)(LPCPROPSHEETHEADERW
);
36 typedef HPROPSHEETPAGE (WINAPI
*PCREATEPROPERTYSHEETPAGEW
)(LPCPROPSHEETPAGEW
);
37 typedef BOOL (WINAPI
*PDESTROYPROPERTYSHEETPAGE
)(HPROPSHEETPAGE
);
46 typedef struct _DEVADVPROP_INFO
50 WNDPROC ParentOldWndProc
;
52 HDEVINFO DeviceInfoSet
;
53 SP_DEVINFO_DATA DeviceInfoData
;
55 LPCWSTR lpMachineName
;
59 DWORD PropertySheetType
;
61 HPROPSHEETPAGE
*DevPropSheets
;
63 BOOL FreeDevPropSheets
: 1;
65 BOOL DeviceEnabled
: 1;
66 BOOL DeviceUsageChanged
: 1;
67 BOOL CreatedDevInfoSet
: 1;
72 /* struct may be dynamically expanded here! */
73 } DEVADVPROP_INFO
, *PDEVADVPROP_INFO
;
77 InitDevUsageActions(IN HWND hwndDlg
,
79 IN PDEVADVPROP_INFO dap
)
86 DEVENABLEACTION Action
;
89 {IDS_ENABLEDEVICE
, DEA_ENABLE
},
90 {IDS_DISABLEDEVICE
, DEA_DISABLE
},
94 i
!= sizeof(Actions
) / sizeof(Actions
[0]);
97 /* fill in the device usage combo box */
98 if (LoadString(hDllInstance
,
101 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
103 Index
= (INT
)SendMessage(hComboBox
,
106 (LPARAM
)dap
->szTemp
);
109 SendMessage(hComboBox
,
112 (LPARAM
)Actions
[i
].Action
);
114 switch (Actions
[i
].Action
)
117 if (dap
->DeviceEnabled
)
119 SendMessage(hComboBox
,
127 if (!dap
->DeviceEnabled
)
129 SendMessage(hComboBox
,
145 static DEVENABLEACTION
146 GetSelectedUsageAction(IN HWND hComboBox
)
149 DEVENABLEACTION Ret
= DEA_UNKNOWN
;
151 Index
= (INT
)SendMessage(hComboBox
,
157 INT iRet
= SendMessage(hComboBox
,
161 if (iRet
!= CB_ERR
&& iRet
< (INT
)DEA_UNKNOWN
)
163 Ret
= (DEVENABLEACTION
)iRet
;
172 ApplyGeneralSettings(IN HWND hwndDlg
,
173 IN PDEVADVPROP_INFO dap
)
175 if (dap
->DeviceUsageChanged
)
177 DEVENABLEACTION SelectedUsageAction
;
179 SelectedUsageAction
= GetSelectedUsageAction(GetDlgItem(hwndDlg
,
181 if (SelectedUsageAction
!= DEA_UNKNOWN
)
183 switch (SelectedUsageAction
)
186 if (!dap
->DeviceEnabled
)
188 /* FIXME - enable device */
193 if (dap
->DeviceEnabled
)
195 /* FIXME - disable device */
205 /* disable the apply button */
206 PropSheet_UnChanged(GetParent(hwndDlg
),
208 dap
->DeviceUsageChanged
= FALSE
;
213 UpdateDevInfo(IN HWND hwndDlg
,
214 IN PDEVADVPROP_INFO dap
,
223 hPropSheetDlg
= GetParent(hwndDlg
);
228 HDEVINFO hOldDevInfo
;
230 /* switch to the General page */
231 PropSheet_SetCurSelByID(hPropSheetDlg
,
234 /* remove and destroy the existing device property sheet pages */
236 i
!= dap
->nDevPropSheets
;
239 PropSheet_RemovePage(hPropSheetDlg
,
241 dap
->DevPropSheets
[i
]);
244 if (dap
->FreeDevPropSheets
)
246 /* don't free the array if it's the one allocated in
247 DisplayDeviceAdvancedProperties */
248 HeapFree(GetProcessHeap(),
252 dap
->FreeDevPropSheets
= FALSE
;
255 dap
->DevPropSheets
= NULL
;
256 dap
->nDevPropSheets
= 0;
258 /* create a new device info set and re-open the device */
259 hOldDevInfo
= dap
->DeviceInfoSet
;
260 dap
->DeviceInfoSet
= SetupDiCreateDeviceInfoListEx(NULL
,
264 if (dap
->DeviceInfoSet
!= INVALID_HANDLE_VALUE
)
266 if (SetupDiOpenDeviceInfo(dap
->DeviceInfoSet
,
270 &dap
->DeviceInfoData
))
272 if (dap
->CreatedDevInfoSet
)
274 SetupDiDestroyDeviceInfoList(hOldDevInfo
);
277 dap
->CreatedDevInfoSet
= TRUE
;
281 SetupDiDestroyDeviceInfoList(dap
->DeviceInfoSet
);
282 dap
->DeviceInfoSet
= INVALID_HANDLE_VALUE
;
283 dap
->CreatedDevInfoSet
= FALSE
;
288 /* oops, something went wrong, restore the old device info set */
289 dap
->DeviceInfoSet
= hOldDevInfo
;
291 if (dap
->DeviceInfoSet
!= INVALID_HANDLE_VALUE
)
293 SetupDiOpenDeviceInfo(dap
->DeviceInfoSet
,
297 &dap
->DeviceInfoData
);
301 /* find out how many new device property sheets to add.
302 fake a PROPSHEETHEADER structure, we don't plan to
303 call PropertySheet again!*/
304 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
308 if (!SetupDiGetClassDevPropertySheets(dap
->DeviceInfoSet
,
309 &dap
->DeviceInfoData
,
312 &dap
->nDevPropSheets
,
313 dap
->PropertySheetType
) &&
314 dap
->nDevPropSheets
!= 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
316 dap
->DevPropSheets
= HeapAlloc(GetProcessHeap(),
318 dap
->nDevPropSheets
* sizeof(HPROPSHEETPAGE
));
319 if (dap
->DevPropSheets
!= NULL
)
321 psh
.phpage
= dap
->DevPropSheets
;
323 /* query the new property sheet pages to add */
324 if (SetupDiGetClassDevPropertySheets(dap
->DeviceInfoSet
,
325 &dap
->DeviceInfoData
,
329 dap
->PropertySheetType
))
331 /* add the property sheets */
334 i
!= dap
->nDevPropSheets
;
337 PropSheet_AddPage(hPropSheetDlg
,
338 dap
->DevPropSheets
[i
]);
341 dap
->FreeDevPropSheets
= TRUE
;
345 /* cleanup, we were unable to get the device property sheets */
346 HeapFree(GetProcessHeap(),
350 dap
->nDevPropSheets
= 0;
351 dap
->DevPropSheets
= NULL
;
355 dap
->nDevPropSheets
= 0;
359 /* get the device name */
360 if (GetDeviceDescriptionString(dap
->DeviceInfoSet
,
361 &dap
->DeviceInfoData
,
363 sizeof(dap
->szDevName
) / sizeof(dap
->szDevName
[0])))
365 PropSheet_SetTitle(GetParent(hwndDlg
),
370 /* set the device image */
371 if (SetupDiLoadClassIcon(&dap
->DeviceInfoData
.ClassGuid
,
375 HICON hOldIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
380 if (hOldIcon
!= NULL
)
382 DestroyIcon(hOldIcon
);
386 /* set the device name edit control text */
387 SetDlgItemText(hwndDlg
,
391 /* set the device type edit control text */
392 if (GetDeviceTypeString(&dap
->DeviceInfoData
,
394 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
396 SetDlgItemText(hwndDlg
,
401 /* set the device manufacturer edit control text */
402 if (GetDeviceManufacturerString(dap
->DeviceInfoSet
,
403 &dap
->DeviceInfoData
,
405 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
407 SetDlgItemText(hwndDlg
,
412 /* set the device location edit control text */
413 if (GetDeviceLocationString(dap
->DeviceInfoData
.DevInst
,
415 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
417 SetDlgItemText(hwndDlg
,
422 /* set the device status edit control text */
423 if (GetDeviceStatusString(dap
->DeviceInfoData
.DevInst
,
426 sizeof(dap
->szTemp
) / sizeof(dap
->szTemp
[0])))
428 SetDlgItemText(hwndDlg
,
433 /* check if the device can be enabled/disabled */
434 hDevUsage
= GetDlgItem(hwndDlg
,
437 dap
->CanDisable
= FALSE
;
438 dap
->DeviceEnabled
= FALSE
;
440 if (dap
->DeviceInfoSet
!= INVALID_HANDLE_VALUE
)
442 if (CanDisableDevice(dap
->DeviceInfoData
.DevInst
,
446 dap
->CanDisable
= bFlag
;
449 if (IsDeviceEnabled(dap
->DeviceInfoData
.DevInst
,
453 dap
->DeviceEnabled
= bFlag
;
457 /* enable/disable the device usage controls */
458 EnableWindow(GetDlgItem(hwndDlg
,
461 EnableWindow(hDevUsage
,
464 /* clear the combobox */
465 SendMessage(hDevUsage
,
471 InitDevUsageActions(hwndDlg
,
476 /* finally, disable the apply button */
477 PropSheet_UnChanged(hPropSheetDlg
,
479 dap
->DeviceUsageChanged
= FALSE
;
485 DlgParentSubWndProc(IN HWND hwnd
,
490 PDEVADVPROP_INFO dap
;
492 dap
= (PDEVADVPROP_INFO
)GetProp(hwnd
,
493 L
"DevMgrDevChangeSub");
496 if (uMsg
== WM_DEVICECHANGE
&& !IsWindowVisible(dap
->hWndGeneralPage
))
498 SendMessage(dap
->hWndGeneralPage
,
504 /* pass the message the the old window proc */
505 return CallWindowProc(dap
->ParentOldWndProc
,
513 /* this is not a good idea if the subclassed window was an ansi
514 window, but we failed finding out the previous window proc
515 so we can't use CallWindowProc. This should rarely - if ever -
518 return DefWindowProc(hwnd
,
528 AdvPropGeneralDlgProc(IN HWND hwndDlg
,
533 PDEVADVPROP_INFO dap
;
536 dap
= (PDEVADVPROP_INFO
)GetWindowLongPtr(hwndDlg
,
539 if (dap
!= NULL
|| uMsg
== WM_INITDIALOG
)
545 switch (LOWORD(wParam
))
549 if (HIWORD(wParam
) == CBN_SELCHANGE
)
551 PropSheet_Changed(GetParent(hwndDlg
),
553 dap
->DeviceUsageChanged
= TRUE
;
563 NMHDR
*hdr
= (NMHDR
*)lParam
;
567 ApplyGeneralSettings(hwndDlg
,
576 dap
= (PDEVADVPROP_INFO
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
581 dap
->hWndGeneralPage
= hwndDlg
;
583 SetWindowLongPtr(hwndDlg
,
587 /* subclass the parent window to always receive
588 WM_DEVICECHANGE messages */
589 hWndParent
= GetParent(hwndDlg
);
590 if (hWndParent
!= NULL
)
592 /* subclass the parent window. This is not safe
593 if the parent window belongs to another thread! */
594 dap
->ParentOldWndProc
= (WNDPROC
)SetWindowLongPtr(hWndParent
,
596 (LONG_PTR
)DlgParentSubWndProc
);
598 if (dap
->ParentOldWndProc
!= NULL
&&
600 L
"DevMgrDevChangeSub",
603 dap
->hWndParent
= hWndParent
;
607 UpdateDevInfo(hwndDlg
,
615 case WM_DEVICECHANGE
:
617 /* FIXME - don't call UpdateDevInfo in all events */
618 UpdateDevInfo(hwndDlg
,
628 /* restore the old window proc of the subclassed parent window */
629 if (dap
->hWndParent
!= NULL
&& dap
->ParentOldWndProc
!= NULL
)
631 SetWindowLongPtr(dap
->hWndParent
,
633 (LONG_PTR
)dap
->ParentOldWndProc
);
636 /* destroy the device icon */
637 hDevIcon
= (HICON
)SendDlgItemMessage(hwndDlg
,
642 if (hDevIcon
!= NULL
)
644 DestroyIcon(hDevIcon
);
656 DisplayDeviceAdvancedProperties(IN HWND hWndParent
,
657 IN LPCWSTR lpDeviceID OPTIONAL
,
658 IN HDEVINFO DeviceInfoSet
,
659 IN PSP_DEVINFO_DATA DeviceInfoData
,
660 IN HINSTANCE hComCtl32
,
661 IN LPCWSTR lpMachineName
)
663 PROPSHEETHEADER psh
= {0};
664 PROPSHEETPAGE pspGeneral
= {0};
665 DWORD nPropSheets
= 0;
666 PPROPERTYSHEETW pPropertySheetW
;
667 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW
;
668 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage
;
669 PDEVADVPROP_INFO DevAdvPropInfo
;
670 HANDLE hMachine
= NULL
;
674 /* we don't want to statically link against comctl32, so find the
675 functions we need dynamically */
677 (PPROPERTYSHEETW
)GetProcAddress(hComCtl32
,
679 pCreatePropertySheetPageW
=
680 (PCREATEPROPERTYSHEETPAGEW
)GetProcAddress(hComCtl32
,
681 "CreatePropertySheetPageW");
682 pDestroyPropertySheetPage
=
683 (PDESTROYPROPERTYSHEETPAGE
)GetProcAddress(hComCtl32
,
684 "DestroyPropertySheetPage");
685 if (pPropertySheetW
== NULL
||
686 pCreatePropertySheetPageW
== NULL
||
687 pDestroyPropertySheetPage
== NULL
)
692 if (lpDeviceID
== NULL
)
694 /* find out how much size is needed for the device id */
695 if (SetupDiGetDeviceInstanceId(DeviceInfoSet
,
701 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
705 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
712 DevIdSize
= (DWORD
)wcslen(lpDeviceID
) + 1;
715 if (lpMachineName
!= NULL
)
717 CONFIGRET cr
= CM_Connect_Machine(lpMachineName
,
719 if (cr
!= CR_SUCCESS
)
725 /* create the internal structure associated with the "General",
726 "Driver", ... pages */
727 DevAdvPropInfo
= HeapAlloc(GetProcessHeap(),
729 FIELD_OFFSET(DEVADVPROP_INFO
,
731 (DevIdSize
* sizeof(WCHAR
)));
732 if (DevAdvPropInfo
== NULL
)
737 if (lpDeviceID
== NULL
)
739 /* read the device instance id */
740 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet
,
742 DevAdvPropInfo
->szDeviceID
,
751 /* copy the device instance id supplied by the caller */
752 wcscpy(DevAdvPropInfo
->szDeviceID
,
756 DevAdvPropInfo
->DeviceInfoSet
= DeviceInfoSet
;
757 DevAdvPropInfo
->DeviceInfoData
= *DeviceInfoData
;
758 DevAdvPropInfo
->hMachine
= hMachine
;
759 DevAdvPropInfo
->lpMachineName
= lpMachineName
;
760 DevAdvPropInfo
->szDevName
[0] = L
'\0';
761 DevAdvPropInfo
->hComCtl32
= hComCtl32
;
763 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
764 psh
.dwFlags
= PSH_PROPTITLE
| PSH_NOAPPLYNOW
;
765 psh
.hwndParent
= hWndParent
;
766 psh
.pszCaption
= DevAdvPropInfo
->szDevName
;
768 DevAdvPropInfo
->PropertySheetType
= lpMachineName
!= NULL
?
769 DIGCDP_FLAG_REMOTE_ADVANCED
:
770 DIGCDP_FLAG_ADVANCED
;
772 /* find out how many property sheets we need */
773 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
774 &DevAdvPropInfo
->DeviceInfoData
,
778 DevAdvPropInfo
->PropertySheetType
) &&
781 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
785 if (nPropSheets
!= 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
790 psh
.phpage
= HeapAlloc(GetProcessHeap(),
792 (nPropSheets
+ 1) * sizeof(HPROPSHEETPAGE
));
793 if (psh
.phpage
== NULL
)
798 /* add the "General" property sheet */
799 pspGeneral
.dwSize
= sizeof(PROPSHEETPAGE
);
800 pspGeneral
.dwFlags
= PSP_DEFAULT
;
801 pspGeneral
.hInstance
= hDllInstance
;
802 pspGeneral
.pszTemplate
= (LPCWSTR
)MAKEINTRESOURCE(IDD_DEVICEGENERAL
);
803 pspGeneral
.pfnDlgProc
= AdvPropGeneralDlgProc
;
804 pspGeneral
.lParam
= (LPARAM
)DevAdvPropInfo
;
805 psh
.phpage
[0] = pCreatePropertySheetPageW(&pspGeneral
);
806 if (psh
.phpage
[0] != NULL
)
811 DevAdvPropInfo
->nDevPropSheets
= nPropSheets
;
813 if (nPropSheets
!= 0)
815 DevAdvPropInfo
->DevPropSheets
= psh
.phpage
+ psh
.nPages
;
817 /* create the device property sheets */
818 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet
,
819 &DevAdvPropInfo
->DeviceInfoData
,
821 nPropSheets
+ psh
.nPages
,
823 DevAdvPropInfo
->PropertySheetType
))
829 /* FIXME - add the "Driver" property sheet if necessary */
833 Ret
= pPropertySheetW(&psh
);
835 /* NOTE: no need to destroy the property sheets anymore! */
842 /* in case of failure the property sheets must be destroyed */
843 if (psh
.phpage
!= NULL
)
849 if (psh
.phpage
[i
] != NULL
)
851 pDestroyPropertySheetPage(psh
.phpage
[i
]);
857 if (DevAdvPropInfo
!= NULL
)
859 if (DevAdvPropInfo
->FreeDevPropSheets
)
861 /* don't free the array if it's the one allocated in
862 DisplayDeviceAdvancedProperties */
863 HeapFree(GetProcessHeap(),
865 DevAdvPropInfo
->DevPropSheets
);
868 if (DevAdvPropInfo
->CreatedDevInfoSet
)
870 /* close the device info set in case a new one was created */
871 SetupDiDestroyDeviceInfoList(DevAdvPropInfo
->DeviceInfoSet
);
874 HeapFree(GetProcessHeap(),
879 if (psh
.phpage
!= NULL
)
881 HeapFree(GetProcessHeap(),
886 if (hMachine
!= NULL
)
888 CM_Disconnect_Machine(hMachine
);
895 /***************************************************************************
897 * DeviceAdvancedPropertiesW
900 * Invokes the device properties dialog, this version may add some property pages
904 * hWndParent: Handle to the parent window
905 * lpMachineName: Machine Name, NULL is the local machine
906 * lpDeviceID: Specifies the device whose properties are to be shown
909 * -1: if errors occured
919 DeviceAdvancedPropertiesW(HWND hWndParent
,
920 LPCWSTR lpMachineName
,
924 SP_DEVINFO_DATA DevInfoData
;
928 /* dynamically load comctl32 */
929 hComCtl32
= LoadAndInitComctl32();
930 if (hComCtl32
!= NULL
)
932 hDevInfo
= SetupDiCreateDeviceInfoListEx(NULL
,
936 if (hDevInfo
!= INVALID_HANDLE_VALUE
)
938 DevInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
939 if (SetupDiOpenDeviceInfo(hDevInfo
,
945 Ret
= DisplayDeviceAdvancedProperties(hWndParent
,
953 SetupDiDestroyDeviceInfoList(hDevInfo
);
956 FreeLibrary(hComCtl32
);
963 /***************************************************************************
965 * DeviceAdvancedPropertiesA
968 * Invokes the device properties dialog, this version may add some property pages
972 * hWndParent: Handle to the parent window
973 * lpMachineName: Machine Name, NULL is the local machine
974 * lpDeviceID: Specifies the device whose properties are to be shown
977 * -1: if errors occured
987 DeviceAdvancedPropertiesA(HWND hWndParent
,
988 LPCSTR lpMachineName
,
991 LPWSTR lpMachineNameW
= NULL
;
992 LPWSTR lpDeviceIDW
= NULL
;
995 if (lpMachineName
!= NULL
)
997 if (!(lpMachineNameW
= ConvertMultiByteToUnicode(lpMachineName
,
1003 if (lpDeviceID
!= NULL
)
1005 if (!(lpDeviceIDW
= ConvertMultiByteToUnicode(lpDeviceID
,
1012 Ret
= DeviceAdvancedPropertiesW(hWndParent
,
1017 if (lpMachineNameW
!= NULL
)
1019 HeapFree(GetProcessHeap(),
1023 if (lpDeviceIDW
!= NULL
)
1025 HeapFree(GetProcessHeap(),