5f190615062aadc3185fc1c5c519e2f471fd5060
[reactos.git] / reactos / lib / devmgr / advprop.c
1 /*
2 * ReactOS Device Manager Applet
3 * Copyright (C) 2004 - 2005 ReactOS Team
4 *
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.
9 *
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.
14 *
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
18 */
19 /* $Id: hwpage.c 19599 2005-11-26 02:12:58Z weiden $
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/advprop.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * UPDATE HISTORY:
26 * 04-04-2004 Created
27 */
28 #include <precomp.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 typedef INT_PTR (WINAPI *PPROPERTYSHEETW)(LPCPROPSHEETHEADERW);
34 typedef HPROPSHEETPAGE (WINAPI *PCREATEPROPERTYSHEETPAGEW)(LPCPROPSHEETPAGEW);
35 typedef BOOL (WINAPI *PDESTROYPROPERTYSHEETPAGE)(HPROPSHEETPAGE);
36
37 typedef enum
38 {
39 DEA_DISABLE = 0,
40 DEA_ENABLE,
41 DEA_UNKNOWN
42 } DEVENABLEACTION;
43
44 typedef struct _DEVADVPROP_INFO
45 {
46 HDEVINFO DeviceInfoSet;
47 PSP_DEVINFO_DATA DeviceInfoData;
48 HINSTANCE hComCtl32;
49 HANDLE hMachine;
50 BOOL CanDisable;
51 BOOL DeviceEnabled;
52 WCHAR szDevName[255];
53 WCHAR szTemp[255];
54 WCHAR szDeviceID[1];
55 /* struct may be dynamically expanded here! */
56 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
57
58
59 static VOID
60 InitDevUsageActions(IN HWND hwndDlg,
61 IN HWND hComboBox,
62 IN PDEVADVPROP_INFO dap)
63 {
64 INT Index;
65 UINT i;
66 struct
67 {
68 UINT szId;
69 DEVENABLEACTION Action;
70 } Actions[] =
71 {
72 {IDS_ENABLEDEVICE, DEA_ENABLE},
73 {IDS_DISABLEDEVICE, DEA_DISABLE},
74 };
75
76 for (i = 0;
77 i != sizeof(Actions) / sizeof(Actions[0]);
78 i++)
79 {
80 /* fill in the device usage combo box */
81 if (LoadString(hDllInstance,
82 Actions[i].szId,
83 dap->szTemp,
84 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
85 {
86 Index = (INT)SendMessage(hComboBox,
87 CB_ADDSTRING,
88 0,
89 (LPARAM)dap->szTemp);
90 if (Index != CB_ERR)
91 {
92 SendMessage(hComboBox,
93 CB_SETITEMDATA,
94 (WPARAM)Index,
95 (LPARAM)Actions[i].Action);
96
97 switch (Actions[i].Action)
98 {
99 case DEA_ENABLE:
100 if (dap->DeviceEnabled)
101 {
102 SendMessage(hComboBox,
103 CB_SETCURSEL,
104 (WPARAM)Index,
105 0);
106 }
107 break;
108
109 case DEA_DISABLE:
110 if (!dap->DeviceEnabled)
111 {
112 SendMessage(hComboBox,
113 CB_SETCURSEL,
114 (WPARAM)Index,
115 0);
116 }
117 break;
118
119 default:
120 break;
121 }
122 }
123 }
124 }
125 }
126
127
128 static DEVENABLEACTION
129 GetSelectedUsageAction(IN HWND hComboBox)
130 {
131 INT Index;
132 DEVENABLEACTION Ret = DEA_UNKNOWN;
133
134 Index = (INT)SendMessage(hComboBox,
135 CB_GETCURSEL,
136 0,
137 0);
138 if (Index != CB_ERR)
139 {
140 INT iRet = SendMessage(hComboBox,
141 CB_GETITEMDATA,
142 (WPARAM)Index,
143 0);
144 if (iRet != CB_ERR && iRet < (INT)DEA_UNKNOWN)
145 {
146 Ret = (DEVENABLEACTION)iRet;
147 }
148 }
149
150 return Ret;
151 }
152
153
154 static VOID
155 ApplyGeneralSettings(IN HWND hwndDlg,
156 IN PDEVADVPROP_INFO dap)
157 {
158 DEVENABLEACTION SelectedUsageAction;
159
160 SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
161 IDC_DEVUSAGE));
162 if (SelectedUsageAction != DEA_UNKNOWN)
163 {
164 switch (SelectedUsageAction)
165 {
166 case DEA_ENABLE:
167 if (!dap->DeviceEnabled)
168 {
169 /* FIXME - enable device */
170 }
171 break;
172
173 case DEA_DISABLE:
174 if (dap->DeviceEnabled)
175 {
176 /* FIXME - disable device */
177 }
178 break;
179
180 default:
181 break;
182 }
183
184 /* disable the apply button */
185 PropSheet_UnChanged(GetParent(hwndDlg),
186 hwndDlg);
187 }
188 }
189
190
191 static VOID
192 UpdateDevInfo(IN HWND hwndDlg,
193 IN PDEVADVPROP_INFO dap,
194 IN BOOL ReOpenDevice)
195 {
196 HICON hIcon;
197 HWND hDevUsage;
198
199 if (ReOpenDevice)
200 {
201 /* note, we ignore the fact that SetupDiOpenDeviceInfo could fail here,
202 in case of failure we're still going to query information from it even
203 though those calls are going to fail. But they return readable strings
204 even in that case. */
205 SetupDiOpenDeviceInfo(dap->DeviceInfoSet,
206 dap->szDeviceID,
207 hwndDlg,
208 0,
209 dap->DeviceInfoData);
210 }
211
212 /* get the device name */
213 if (GetDeviceDescriptionString(dap->DeviceInfoSet,
214 dap->DeviceInfoData,
215 dap->szDevName,
216 sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
217 {
218 PropSheet_SetTitle(GetParent(hwndDlg),
219 PSH_PROPTITLE,
220 dap->szDevName);
221 }
222
223 /* set the device image */
224 if (SetupDiLoadClassIcon(&dap->DeviceInfoData->ClassGuid,
225 &hIcon,
226 NULL))
227 {
228 HICON hOldIcon = (HICON)SendDlgItemMessage(hwndDlg,
229 IDC_DEVICON,
230 STM_SETICON,
231 (WPARAM)hIcon,
232 0);
233 if (hOldIcon != NULL)
234 {
235 DestroyIcon(hOldIcon);
236 }
237 }
238
239 /* set the device name edit control text */
240 SetDlgItemText(hwndDlg,
241 IDC_DEVNAME,
242 dap->szDevName);
243
244 /* set the device type edit control text */
245 if (GetDeviceTypeString(dap->DeviceInfoData,
246 dap->szTemp,
247 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
248 {
249 SetDlgItemText(hwndDlg,
250 IDC_DEVTYPE,
251 dap->szTemp);
252 }
253
254 /* set the device manufacturer edit control text */
255 if (GetDeviceManufacturerString(dap->DeviceInfoSet,
256 dap->DeviceInfoData,
257 dap->szTemp,
258 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
259 {
260 SetDlgItemText(hwndDlg,
261 IDC_DEVMANUFACTURER,
262 dap->szTemp);
263 }
264
265 /* set the device location edit control text */
266 if (GetDeviceLocationString(dap->DeviceInfoData->DevInst,
267 dap->szTemp,
268 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
269 {
270 SetDlgItemText(hwndDlg,
271 IDC_DEVLOCATION,
272 dap->szTemp);
273 }
274
275 /* set the device status edit control text */
276 if (GetDeviceStatusString(dap->DeviceInfoData->DevInst,
277 dap->hMachine,
278 dap->szTemp,
279 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
280 {
281 SetDlgItemText(hwndDlg,
282 IDC_DEVSTATUS,
283 dap->szTemp);
284 }
285
286 /* check if the device can be enabled/disabled */
287 hDevUsage = GetDlgItem(hwndDlg,
288 IDC_DEVUSAGE);
289
290 if (!CanDisableDevice(dap->DeviceInfoData->DevInst,
291 dap->hMachine,
292 &dap->CanDisable))
293 {
294 dap->CanDisable = FALSE;
295 }
296
297 if (!IsDeviceEnabled(dap->DeviceInfoData->DevInst,
298 dap->hMachine,
299 &dap->DeviceEnabled))
300 {
301 dap->DeviceEnabled = FALSE;
302 }
303
304 /* enable/disable the device usage controls */
305 EnableWindow(GetDlgItem(hwndDlg,
306 IDC_DEVUSAGELABEL),
307 dap->CanDisable);
308 EnableWindow(hDevUsage,
309 dap->CanDisable);
310
311 /* clear the combobox */
312 SendMessage(hDevUsage,
313 CB_RESETCONTENT,
314 0,
315 0);
316 if (dap->CanDisable)
317 {
318 InitDevUsageActions(hwndDlg,
319 hDevUsage,
320 dap);
321 }
322
323 /* finally, disable the apply button */
324 PropSheet_UnChanged(GetParent(hwndDlg),
325 hwndDlg);
326 }
327
328
329 static INT_PTR
330 CALLBACK
331 AdvPropGeneralDlgProc(IN HWND hwndDlg,
332 IN UINT uMsg,
333 IN WPARAM wParam,
334 IN LPARAM lParam)
335 {
336 PDEVADVPROP_INFO dap;
337 INT_PTR Ret = FALSE;
338
339 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
340 DWL_USER);
341
342 if (dap != NULL || uMsg == WM_INITDIALOG)
343 {
344 switch (uMsg)
345 {
346 case WM_COMMAND:
347 {
348 switch (LOWORD(wParam))
349 {
350 case IDC_DEVUSAGE:
351 {
352 if (HIWORD(wParam) == CBN_SELCHANGE)
353 {
354 PropSheet_Changed(GetParent(hwndDlg),
355 hwndDlg);
356 }
357 break;
358 }
359 }
360 break;
361 }
362
363 case WM_NOTIFY:
364 {
365 NMHDR *hdr = (NMHDR*)lParam;
366 switch (hdr->code)
367 {
368 case PSN_APPLY:
369 ApplyGeneralSettings(hwndDlg,
370 dap);
371 break;
372 }
373 break;
374 }
375
376 case WM_INITDIALOG:
377 {
378 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
379 if (dap != NULL)
380 {
381 SetWindowLongPtr(hwndDlg,
382 DWL_USER,
383 (DWORD_PTR)dap);
384
385 UpdateDevInfo(hwndDlg,
386 dap,
387 FALSE);
388 }
389 Ret = TRUE;
390 break;
391 }
392
393 case WM_DEVICECHANGE:
394 {
395 /* FIXME - don't call UpdateDevInfo in all events */
396 UpdateDevInfo(hwndDlg,
397 dap,
398 TRUE);
399 break;
400 }
401
402 case WM_DESTROY:
403 {
404 HICON hDevIcon;
405
406 /* destroy the device icon */
407 hDevIcon = (HICON)SendDlgItemMessage(hwndDlg,
408 IDC_DEVICON,
409 STM_GETICON,
410 0,
411 0);
412 if (hDevIcon != NULL)
413 {
414 DestroyIcon(hDevIcon);
415 }
416 break;
417 }
418 }
419 }
420
421 return Ret;
422 }
423
424
425 INT_PTR
426 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
427 IN LPCWSTR lpDeviceID OPTIONAL,
428 IN HDEVINFO DeviceInfoSet,
429 IN PSP_DEVINFO_DATA DeviceInfoData,
430 IN HINSTANCE hComCtl32,
431 IN LPCWSTR lpMachineName)
432 {
433 PROPSHEETHEADER psh = {0};
434 PROPSHEETPAGE pspGeneral = {0};
435 DWORD nPropSheets = 0;
436 PPROPERTYSHEETW pPropertySheetW;
437 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
438 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
439 PDEVADVPROP_INFO DevAdvPropInfo;
440 DWORD PropertySheetType;
441 HANDLE hMachine = NULL;
442 DWORD DevIdSize = 0;
443 INT_PTR Ret = -1;
444
445 /* we don't want to statically link against comctl32, so find the
446 functions we need dynamically */
447 pPropertySheetW =
448 (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
449 "PropertySheetW");
450 pCreatePropertySheetPageW =
451 (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
452 "CreatePropertySheetPageW");
453 pDestroyPropertySheetPage =
454 (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
455 "DestroyPropertySheetPage");
456 if (pPropertySheetW == NULL ||
457 pCreatePropertySheetPageW == NULL ||
458 pDestroyPropertySheetPage == NULL)
459 {
460 return -1;
461 }
462
463 if (lpDeviceID == NULL)
464 {
465 /* find out how much size is needed for the device id */
466 if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
467 DeviceInfoData,
468 NULL,
469 0,
470 &DevIdSize))
471 {
472 DPRINT1("SetupDiGetDeviceInterfaceDetail unexpectedly returned TRUE!\n");
473 return -1;
474 }
475
476 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
477 {
478 return -1;
479 }
480 }
481 else
482 {
483 DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
484 }
485
486 if (lpMachineName != NULL)
487 {
488 CONFIGRET cr = CM_Connect_Machine(lpMachineName,
489 &hMachine);
490 if (cr != CR_SUCCESS)
491 {
492 return -1;
493 }
494 }
495
496 /* create the internal structure associated with the "General",
497 "Driver", ... pages */
498 DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
499 0,
500 FIELD_OFFSET(DEVADVPROP_INFO,
501 szDeviceID) +
502 (DevIdSize * sizeof(WCHAR)));
503 if (DevAdvPropInfo == NULL)
504 {
505 goto Cleanup;
506 }
507
508 if (lpDeviceID == NULL)
509 {
510 /* read the device instance id */
511 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
512 DeviceInfoData,
513 DevAdvPropInfo->szDeviceID,
514 DevIdSize,
515 NULL))
516 {
517 goto Cleanup;
518 }
519 }
520
521 DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
522 DevAdvPropInfo->DeviceInfoData = DeviceInfoData;
523 DevAdvPropInfo->hComCtl32 = hComCtl32;
524 DevAdvPropInfo->hMachine = hMachine;
525 DevAdvPropInfo->szDevName[0] = L'\0';
526
527 psh.dwSize = sizeof(PROPSHEETHEADER);
528 psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
529 psh.hwndParent = hWndParent;
530 psh.pszCaption = DevAdvPropInfo->szDevName;
531
532 PropertySheetType = lpMachineName != NULL ?
533 DIGCDP_FLAG_REMOTE_ADVANCED :
534 DIGCDP_FLAG_ADVANCED;
535
536 /* find out how many property sheets we need */
537 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
538 DeviceInfoData,
539 &psh,
540 0,
541 &nPropSheets,
542 PropertySheetType) &&
543 nPropSheets != 0)
544 {
545 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
546 goto Cleanup;
547 }
548
549 if (nPropSheets != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
550 {
551 goto Cleanup;
552 }
553
554 psh.phpage = HeapAlloc(GetProcessHeap(),
555 HEAP_ZERO_MEMORY,
556 (nPropSheets + 1) * sizeof(HPROPSHEETPAGE));
557 if (psh.phpage == NULL)
558 {
559 goto Cleanup;
560 }
561
562 /* add the "General" property sheet */
563 pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
564 pspGeneral.dwFlags = PSP_DEFAULT;
565 pspGeneral.hInstance = hDllInstance;
566 pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
567 pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
568 pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
569 psh.phpage[0] = pCreatePropertySheetPageW(&pspGeneral);
570 if (psh.phpage[0] != NULL)
571 {
572 psh.nPages++;
573 }
574
575 if (nPropSheets != 0)
576 {
577 /* create the device property sheets */
578 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
579 DeviceInfoData,
580 &psh,
581 nPropSheets + psh.nPages,
582 NULL,
583 PropertySheetType))
584 {
585 goto Cleanup;
586 }
587 }
588
589 /* FIXME - add the "Driver" property sheet if necessary */
590
591 if (psh.nPages != 0)
592 {
593 Ret = pPropertySheetW(&psh);
594
595 /* NOTE: no need to destroy the property sheets anymore! */
596 }
597 else
598 {
599 UINT i;
600
601 Cleanup:
602 /* in case of failure the property sheets must be destroyed */
603 for (i = 0;
604 i < psh.nPages;
605 i++)
606 {
607 if (psh.phpage[i] != NULL)
608 {
609 pDestroyPropertySheetPage(psh.phpage[i]);
610 }
611 }
612 }
613
614 HeapFree(GetProcessHeap(),
615 0,
616 psh.phpage);
617
618 HeapFree(GetProcessHeap(),
619 0,
620 DevAdvPropInfo);
621
622 if (hMachine != NULL)
623 {
624 CM_Disconnect_Machine(hMachine);
625 }
626
627 return Ret;
628 }
629
630
631 /***************************************************************************
632 * NAME EXPORTED
633 * DeviceAdvancedPropertiesW
634 *
635 * DESCRIPTION
636 * Invokes the device properties dialog, this version may add some property pages
637 * for some devices
638 *
639 * ARGUMENTS
640 * hWndParent: Handle to the parent window
641 * lpMachineName: Machine Name, NULL is the local machine
642 * lpDeviceID: Specifies the device whose properties are to be shown
643 *
644 * RETURN VALUE
645 * -1: if errors occured
646 *
647 * REVISIONS
648 *
649 * NOTE
650 *
651 * @implemented
652 */
653 INT_PTR
654 WINAPI
655 DeviceAdvancedPropertiesW(HWND hWndParent,
656 LPCWSTR lpMachineName,
657 LPCWSTR lpDeviceID)
658 {
659 HDEVINFO hDevInfo;
660 SP_DEVINFO_DATA DevInfoData;
661 HINSTANCE hComCtl32;
662 INT_PTR Ret = -1;
663
664 /* dynamically load comctl32 */
665 hComCtl32 = LoadAndInitComctl32();
666 if (hComCtl32 != NULL)
667 {
668 if (lpMachineName != NULL)
669 {
670 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
671 hWndParent,
672 lpMachineName,
673 NULL);
674 }
675 else
676 {
677 hDevInfo = SetupDiCreateDeviceInfoList(NULL,
678 hWndParent);
679 }
680
681 if (hDevInfo != INVALID_HANDLE_VALUE)
682 {
683 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
684 if (SetupDiOpenDeviceInfo(hDevInfo,
685 lpDeviceID,
686 hWndParent,
687 0,
688 &DevInfoData))
689 {
690 Ret = DisplayDeviceAdvancedProperties(hWndParent,
691 lpDeviceID,
692 hDevInfo,
693 &DevInfoData,
694 hComCtl32,
695 lpMachineName);
696 }
697
698 SetupDiDestroyDeviceInfoList(hDevInfo);
699 }
700
701 FreeLibrary(hComCtl32);
702 }
703
704 return Ret;
705 }
706
707
708 /***************************************************************************
709 * NAME EXPORTED
710 * DeviceAdvancedPropertiesA
711 *
712 * DESCRIPTION
713 * Invokes the device properties dialog, this version may add some property pages
714 * for some devices
715 *
716 * ARGUMENTS
717 * hWndParent: Handle to the parent window
718 * lpMachineName: Machine Name, NULL is the local machine
719 * lpDeviceID: Specifies the device whose properties are to be shown
720 *
721 * RETURN VALUE
722 * -1: if errors occured
723 *
724 * REVISIONS
725 *
726 * NOTE
727 *
728 * @implemented
729 */
730 INT_PTR
731 WINAPI
732 DeviceAdvancedPropertiesA(HWND hWndParent,
733 LPCSTR lpMachineName,
734 LPCSTR lpDeviceID)
735 {
736 LPWSTR lpMachineNameW = NULL;
737 LPWSTR lpDeviceIDW = NULL;
738 INT_PTR Ret = -1;
739
740 if (lpMachineName != NULL)
741 {
742 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
743 CP_ACP)))
744 {
745 goto Cleanup;
746 }
747 }
748 if (lpDeviceID != NULL)
749 {
750 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
751 CP_ACP)))
752 {
753 goto Cleanup;
754 }
755 }
756
757 Ret = DeviceAdvancedPropertiesW(hWndParent,
758 lpMachineNameW,
759 lpDeviceIDW);
760
761 Cleanup:
762 if (lpMachineNameW != NULL)
763 {
764 HeapFree(GetProcessHeap(),
765 0,
766 lpMachineNameW);
767 }
768 if (lpDeviceIDW != NULL)
769 {
770 HeapFree(GetProcessHeap(),
771 0,
772 lpDeviceIDW);
773 }
774
775 return Ret;
776 }