rename IsDeviceEnabled to IsDeviceStarted
[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 struct _DEVADVPROP_INFO
38 {
39 HWND hWndGeneralPage;
40 HWND hWndParent;
41 WNDPROC ParentOldWndProc;
42
43 HDEVINFO DeviceInfoSet;
44 SP_DEVINFO_DATA DeviceInfoData;
45 HDEVINFO CurrentDeviceInfoSet;
46 SP_DEVINFO_DATA CurrentDeviceInfoData;
47 DEVINST ParentDevInst;
48 HMACHINE hMachine;
49 LPCWSTR lpMachineName;
50
51 HINSTANCE hComCtl32;
52
53 DWORD PropertySheetType;
54 DWORD nDevPropSheets;
55 HPROPSHEETPAGE *DevPropSheets;
56
57 BOOL FreeDevPropSheets : 1;
58 BOOL CanDisable : 1;
59 BOOL DeviceStarted : 1;
60 BOOL DeviceUsageChanged : 1;
61 BOOL CloseDevInst : 1;
62 BOOL IsAdmin : 1;
63 BOOL DoDefaultDevAction : 1;
64
65 WCHAR szDevName[255];
66 WCHAR szTemp[255];
67 WCHAR szDeviceID[1];
68 /* struct may be dynamically expanded here! */
69 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
70
71
72 static VOID
73 InitDevUsageActions(IN HWND hwndDlg,
74 IN HWND hComboBox,
75 IN PDEVADVPROP_INFO dap)
76 {
77 INT Index;
78 UINT i;
79 UINT Actions[] =
80 {
81 IDS_ENABLEDEVICE,
82 IDS_DISABLEDEVICE,
83 };
84
85 for (i = 0;
86 i != sizeof(Actions) / sizeof(Actions[0]);
87 i++)
88 {
89 /* fill in the device usage combo box */
90 if (LoadString(hDllInstance,
91 Actions[i],
92 dap->szTemp,
93 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
94 {
95 Index = (INT)SendMessage(hComboBox,
96 CB_ADDSTRING,
97 0,
98 (LPARAM)dap->szTemp);
99 if (Index != CB_ERR)
100 {
101 SendMessage(hComboBox,
102 CB_SETITEMDATA,
103 (WPARAM)Index,
104 (LPARAM)Actions[i]);
105
106 switch (Actions[i])
107 {
108 case IDS_ENABLEDEVICE:
109 if (dap->DeviceStarted)
110 {
111 SendMessage(hComboBox,
112 CB_SETCURSEL,
113 (WPARAM)Index,
114 0);
115 }
116 break;
117
118 case IDS_DISABLEDEVICE:
119 if (!dap->DeviceStarted)
120 {
121 SendMessage(hComboBox,
122 CB_SETCURSEL,
123 (WPARAM)Index,
124 0);
125 }
126 break;
127
128 default:
129 break;
130 }
131 }
132 }
133 }
134 }
135
136
137 static UINT
138 GetSelectedUsageAction(IN HWND hComboBox)
139 {
140 INT Index;
141 UINT Ret = 0;
142
143 Index = (INT)SendMessage(hComboBox,
144 CB_GETCURSEL,
145 0,
146 0);
147 if (Index != CB_ERR)
148 {
149 INT iRet = SendMessage(hComboBox,
150 CB_GETITEMDATA,
151 (WPARAM)Index,
152 0);
153 if (iRet != CB_ERR)
154 {
155 Ret = (UINT)iRet;
156 }
157 }
158
159 return Ret;
160 }
161
162
163 static BOOL
164 ApplyGeneralSettings(IN HWND hwndDlg,
165 IN PDEVADVPROP_INFO dap)
166 {
167 BOOL Ret = FALSE;
168
169 if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
170 {
171 UINT SelectedUsageAction;
172 BOOL NeedReboot = FALSE;
173
174 SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
175 IDC_DEVUSAGE));
176 switch (SelectedUsageAction)
177 {
178 case IDS_ENABLEDEVICE:
179 if (!dap->DeviceStarted)
180 {
181 Ret = EnableDevice(dap->DeviceInfoSet,
182 &dap->DeviceInfoData,
183 TRUE,
184 0,
185 &NeedReboot);
186 }
187 break;
188
189 case IDS_DISABLEDEVICE:
190 if (dap->DeviceStarted)
191 {
192 Ret = EnableDevice(dap->DeviceInfoSet,
193 &dap->DeviceInfoData,
194 FALSE,
195 0,
196 &NeedReboot);
197 }
198 break;
199
200 default:
201 break;
202 }
203
204 if (Ret)
205 {
206 if (NeedReboot)
207 {
208 /* make PropertySheet() return PSM_REBOOTSYSTEM */
209 PropSheet_RebootSystem(hwndDlg);
210 }
211 }
212 else
213 {
214 /* FIXME - display an error message */
215 DPRINT1("Failed to enable/disable device! LastError: %d\n",
216 GetLastError());
217 }
218 }
219 else
220 Ret = !dap->DeviceUsageChanged;
221
222 /* disable the apply button */
223 PropSheet_UnChanged(GetParent(hwndDlg),
224 hwndDlg);
225 dap->DeviceUsageChanged = FALSE;
226 return Ret;
227 }
228
229
230 static VOID
231 UpdateDevInfo(IN HWND hwndDlg,
232 IN PDEVADVPROP_INFO dap,
233 IN BOOL ReOpen)
234 {
235 HICON hIcon;
236 HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
237 CONFIGRET cr;
238 ULONG Status, ProblemNumber;
239 UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
240 BOOL bFlag, bDevActionAvailable = TRUE;
241 DWORD i;
242 HDEVINFO DeviceInfoSet = NULL;
243 PSP_DEVINFO_DATA DeviceInfoData = NULL;
244
245 hPropSheetDlg = GetParent(hwndDlg);
246
247 if (ReOpen)
248 {
249 PROPSHEETHEADER psh;
250
251 /* switch to the General page */
252 PropSheet_SetCurSelByID(hPropSheetDlg,
253 IDD_DEVICEGENERAL);
254
255 /* remove and destroy the existing device property sheet pages */
256 for (i = 0;
257 i != dap->nDevPropSheets;
258 i++)
259 {
260 PropSheet_RemovePage(hPropSheetDlg,
261 -1,
262 dap->DevPropSheets[i]);
263 }
264
265 if (dap->FreeDevPropSheets)
266 {
267 /* don't free the array if it's the one allocated in
268 DisplayDeviceAdvancedProperties */
269 HeapFree(GetProcessHeap(),
270 0,
271 dap->DevPropSheets);
272
273 dap->FreeDevPropSheets = FALSE;
274 }
275
276 dap->DevPropSheets = NULL;
277 dap->nDevPropSheets = 0;
278
279 /* create a new device info set and re-open the device */
280 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
281 {
282 SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
283 }
284
285 dap->ParentDevInst = 0;
286 dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
287 hwndDlg,
288 dap->lpMachineName,
289 NULL);
290 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
291 {
292 if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
293 dap->szDeviceID,
294 hwndDlg,
295 0,
296 &dap->CurrentDeviceInfoData))
297 {
298 if (dap->CloseDevInst)
299 {
300 SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
301 }
302
303 dap->CloseDevInst = TRUE;
304 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
305 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
306 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
307 }
308 else
309 goto GetParentNode;
310 }
311 else
312 {
313 GetParentNode:
314 /* get the parent node from the initial devinst */
315 CM_Get_Parent_Ex(&dap->ParentDevInst,
316 dap->DeviceInfoData.DevInst,
317 0,
318 dap->hMachine);
319 }
320
321 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
322 {
323 DeviceInfoSet = dap->CurrentDeviceInfoSet;
324 DeviceInfoData = &dap->CurrentDeviceInfoData;
325 }
326 else
327 {
328 DeviceInfoSet = dap->DeviceInfoSet;
329 DeviceInfoData = &dap->DeviceInfoData;
330 }
331
332 /* find out how many new device property sheets to add.
333 fake a PROPSHEETHEADER structure, we don't plan to
334 call PropertySheet again!*/
335 psh.dwSize = sizeof(PROPSHEETHEADER);
336 psh.dwFlags = 0;
337 psh.nPages = 0;
338
339 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
340 DeviceInfoData,
341 &psh,
342 0,
343 &dap->nDevPropSheets,
344 dap->PropertySheetType) &&
345 dap->nDevPropSheets != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
346 {
347 dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
348 HEAP_ZERO_MEMORY,
349 dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
350 if (dap->DevPropSheets != NULL)
351 {
352 psh.phpage = dap->DevPropSheets;
353
354 /* query the new property sheet pages to add */
355 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
356 DeviceInfoData,
357 &psh,
358 dap->nDevPropSheets,
359 NULL,
360 dap->PropertySheetType))
361 {
362 /* add the property sheets */
363
364 for (i = 0;
365 i != dap->nDevPropSheets;
366 i++)
367 {
368 PropSheet_AddPage(hPropSheetDlg,
369 dap->DevPropSheets[i]);
370 }
371
372 dap->FreeDevPropSheets = TRUE;
373 }
374 else
375 {
376 /* cleanup, we were unable to get the device property sheets */
377 HeapFree(GetProcessHeap(),
378 0,
379 dap->DevPropSheets);
380
381 dap->nDevPropSheets = 0;
382 dap->DevPropSheets = NULL;
383 }
384 }
385 else
386 dap->nDevPropSheets = 0;
387 }
388 }
389 else
390 {
391 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
392 {
393 DeviceInfoSet = dap->CurrentDeviceInfoSet;
394 DeviceInfoData = &dap->CurrentDeviceInfoData;
395 }
396 else
397 {
398 DeviceInfoSet = dap->DeviceInfoSet;
399 DeviceInfoData = &dap->DeviceInfoData;
400 }
401 }
402
403 /* get the device name */
404 if (GetDeviceDescriptionString(DeviceInfoSet,
405 DeviceInfoData,
406 dap->szDevName,
407 sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
408 {
409 PropSheet_SetTitle(GetParent(hwndDlg),
410 PSH_PROPTITLE,
411 dap->szDevName);
412 }
413
414 /* set the device image */
415 if (SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
416 &hIcon,
417 NULL))
418 {
419 HICON hOldIcon = (HICON)SendDlgItemMessage(hwndDlg,
420 IDC_DEVICON,
421 STM_SETICON,
422 (WPARAM)hIcon,
423 0);
424 if (hOldIcon != NULL)
425 {
426 DestroyIcon(hOldIcon);
427 }
428 }
429
430 /* set the device name edit control text */
431 SetDlgItemText(hwndDlg,
432 IDC_DEVNAME,
433 dap->szDevName);
434
435 /* set the device type edit control text */
436 if (GetDeviceTypeString(DeviceInfoData,
437 dap->szTemp,
438 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
439 {
440 SetDlgItemText(hwndDlg,
441 IDC_DEVTYPE,
442 dap->szTemp);
443 }
444
445 /* set the device manufacturer edit control text */
446 if (GetDeviceManufacturerString(DeviceInfoSet,
447 DeviceInfoData,
448 dap->szTemp,
449 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
450 {
451 SetDlgItemText(hwndDlg,
452 IDC_DEVMANUFACTURER,
453 dap->szTemp);
454 }
455
456 /* set the device location edit control text */
457 if (GetDeviceLocationString(DeviceInfoData->DevInst,
458 dap->ParentDevInst,
459 dap->szTemp,
460 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
461 {
462 SetDlgItemText(hwndDlg,
463 IDC_DEVLOCATION,
464 dap->szTemp);
465 }
466
467 /* set the device status edit control text */
468 if (GetDeviceStatusString(DeviceInfoData->DevInst,
469 dap->hMachine,
470 dap->szTemp,
471 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
472 {
473 SetDlgItemText(hwndDlg,
474 IDC_DEVSTATUS,
475 dap->szTemp);
476 }
477
478 /* set the device troubleshoot button text and disable it if necessary */
479 hDevProbBtn = GetDlgItem(hwndDlg,
480 IDC_DEVPROBLEM);
481 cr = CM_Get_DevNode_Status_Ex(&Status,
482 &ProblemNumber,
483 DeviceInfoData->DevInst,
484 0,
485 dap->hMachine);
486 if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
487 {
488 switch (ProblemNumber)
489 {
490 case CM_PROB_DEVLOADER_FAILED:
491 {
492 /* FIXME - only if it's not a root bus devloader,
493 disable the button otherwise */
494 TroubleShootStrId = IDS_UPDATEDRV;
495 break;
496 }
497
498 case CM_PROB_OUT_OF_MEMORY:
499 case CM_PROB_ENTRY_IS_WRONG_TYPE:
500 case CM_PROB_LACKED_ARBITRATOR:
501 case CM_PROB_FAILED_START:
502 case CM_PROB_LIAR:
503 case CM_PROB_UNKNOWN_RESOURCE:
504 {
505 TroubleShootStrId = IDS_UPDATEDRV;
506 break;
507 }
508
509 case CM_PROB_BOOT_CONFIG_CONFLICT:
510 case CM_PROB_NORMAL_CONFLICT:
511 case CM_PROB_REENUMERATION:
512 {
513 /* FIXME - Troubleshoot conflict */
514 break;
515 }
516
517 case CM_PROB_FAILED_FILTER:
518 case CM_PROB_REINSTALL:
519 case CM_PROB_FAILED_INSTALL:
520 {
521 TroubleShootStrId = IDS_REINSTALLDRV;
522 break;
523 }
524
525 case CM_PROB_DEVLOADER_NOT_FOUND:
526 {
527 /* FIXME - 4 cases:
528 1) if it's a missing system devloader:
529 - disable the button (Reinstall Driver)
530 2) if it's not a system devloader but still missing:
531 - Reinstall Driver
532 3) if it's not a system devloader but the file can be found:
533 - Update Driver
534 4) if it's a missing or empty software key
535 - Update Driver
536 */
537 break;
538 }
539
540 case CM_PROB_INVALID_DATA:
541 case CM_PROB_PARTIAL_LOG_CONF:
542 case CM_PROB_NO_VALID_LOG_CONF:
543 case CM_PROB_HARDWARE_DISABLED:
544 case CM_PROB_CANT_SHARE_IRQ:
545 case CM_PROB_TRANSLATION_FAILED:
546 case CM_PROB_SYSTEM_SHUTDOWN:
547 case CM_PROB_PHANTOM:
548 bDevActionAvailable = FALSE;
549 break;
550
551 case CM_PROB_NOT_VERIFIED:
552 case CM_PROB_DEVICE_NOT_THERE:
553 /* FIXME - search hardware */
554 break;
555
556 case CM_PROB_NEED_RESTART:
557 case CM_PROB_WILL_BE_REMOVED:
558 case CM_PROB_MOVED:
559 case CM_PROB_TOO_EARLY:
560 case CM_PROB_DISABLED_SERVICE:
561 TroubleShootStrId = IDS_REBOOT;
562 break;
563
564 case CM_PROB_REGISTRY:
565 /* FIXME - check registry? */
566 break;
567
568 case CM_PROB_DISABLED:
569 /* if device was disabled by the user: */
570 TroubleShootStrId = IDS_ENABLEDEV;
571 /* FIXME - otherwise disable button because the device was
572 disabled by the system*/
573 break;
574
575 case CM_PROB_DEVLOADER_NOT_READY:
576 /* FIXME - if it's a graphics adapter:
577 - if it's a a secondary adapter and the main adapter
578 couldn't be found
579 - disable button
580 - else
581 - Properties
582 - else
583 - Update driver
584 */
585 break;
586
587 case CM_PROB_FAILED_ADD:
588 TroubleShootStrId = IDS_PROPERTIES;
589 break;
590 }
591 }
592
593 if (LoadString(hDllInstance,
594 TroubleShootStrId,
595 dap->szTemp,
596 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
597 {
598 SetWindowText(hDevProbBtn,
599 dap->szTemp);
600 }
601 EnableWindow(hDevProbBtn,
602 dap->IsAdmin && bDevActionAvailable);
603
604 /* check if the device can be enabled/disabled */
605 hDevUsage = GetDlgItem(hwndDlg,
606 IDC_DEVUSAGE);
607
608 dap->CanDisable = FALSE;
609 dap->DeviceStarted = FALSE;
610
611 if (CanDisableDevice(DeviceInfoData->DevInst,
612 dap->hMachine,
613 &bFlag))
614 {
615 dap->CanDisable = bFlag;
616 }
617
618 if (IsDeviceStarted(DeviceInfoData->DevInst,
619 dap->hMachine,
620 &bFlag))
621 {
622 dap->DeviceStarted = bFlag;
623 }
624
625 /* enable/disable the device usage controls */
626 EnableWindow(GetDlgItem(hwndDlg,
627 IDC_DEVUSAGELABEL),
628 dap->CanDisable && dap->IsAdmin);
629 EnableWindow(hDevUsage,
630 dap->CanDisable && dap->IsAdmin);
631
632 /* clear the combobox */
633 SendMessage(hDevUsage,
634 CB_RESETCONTENT,
635 0,
636 0);
637 if (dap->CanDisable)
638 {
639 InitDevUsageActions(hwndDlg,
640 hDevUsage,
641 dap);
642 }
643
644 /* finally, disable the apply button */
645 PropSheet_UnChanged(hPropSheetDlg,
646 hwndDlg);
647 dap->DeviceUsageChanged = FALSE;
648 }
649
650
651 static LRESULT
652 CALLBACK
653 DlgParentSubWndProc(IN HWND hwnd,
654 IN UINT uMsg,
655 IN WPARAM wParam,
656 IN LPARAM lParam)
657 {
658 PDEVADVPROP_INFO dap;
659
660 dap = (PDEVADVPROP_INFO)GetProp(hwnd,
661 L"DevMgrDevChangeSub");
662 if (dap != NULL)
663 {
664 if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
665 {
666 SendMessage(dap->hWndGeneralPage,
667 WM_DEVICECHANGE,
668 wParam,
669 lParam);
670 }
671
672 /* pass the message the the old window proc */
673 return CallWindowProc(dap->ParentOldWndProc,
674 hwnd,
675 uMsg,
676 wParam,
677 lParam);
678 }
679 else
680 {
681 /* this is not a good idea if the subclassed window was an ansi
682 window, but we failed finding out the previous window proc
683 so we can't use CallWindowProc. This should rarely - if ever -
684 happen. */
685
686 return DefWindowProc(hwnd,
687 uMsg,
688 wParam,
689 lParam);
690 }
691 }
692
693
694 static INT_PTR
695 CALLBACK
696 AdvPropGeneralDlgProc(IN HWND hwndDlg,
697 IN UINT uMsg,
698 IN WPARAM wParam,
699 IN LPARAM lParam)
700 {
701 PDEVADVPROP_INFO dap;
702 INT_PTR Ret = FALSE;
703
704 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
705 DWL_USER);
706
707 if (dap != NULL || uMsg == WM_INITDIALOG)
708 {
709 switch (uMsg)
710 {
711 case WM_COMMAND:
712 {
713 switch (LOWORD(wParam))
714 {
715 case IDC_DEVUSAGE:
716 {
717 if (HIWORD(wParam) == CBN_SELCHANGE)
718 {
719 PropSheet_Changed(GetParent(hwndDlg),
720 hwndDlg);
721 dap->DeviceUsageChanged = TRUE;
722 }
723 break;
724 }
725
726 case IDC_DEVPROBLEM:
727 {
728 if (dap->IsAdmin)
729 {
730 /* display the device problem wizard */
731 ShowDeviceProblemWizard(hwndDlg,
732 dap->DeviceInfoSet,
733 &dap->DeviceInfoData,
734 dap->hMachine);
735 }
736 break;
737 }
738 }
739 break;
740 }
741
742 case WM_NOTIFY:
743 {
744 NMHDR *hdr = (NMHDR*)lParam;
745 switch (hdr->code)
746 {
747 case PSN_APPLY:
748 ApplyGeneralSettings(hwndDlg,
749 dap);
750 break;
751 }
752 break;
753 }
754
755 case WM_INITDIALOG:
756 {
757 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
758 if (dap != NULL)
759 {
760 HWND hWndParent;
761
762 dap->hWndGeneralPage = hwndDlg;
763
764 SetWindowLongPtr(hwndDlg,
765 DWL_USER,
766 (DWORD_PTR)dap);
767
768 /* subclass the parent window to always receive
769 WM_DEVICECHANGE messages */
770 hWndParent = GetParent(hwndDlg);
771 if (hWndParent != NULL)
772 {
773 /* subclass the parent window. This is not safe
774 if the parent window belongs to another thread! */
775 dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
776 GWLP_WNDPROC,
777 (LONG_PTR)DlgParentSubWndProc);
778
779 if (dap->ParentOldWndProc != NULL &&
780 SetProp(hWndParent,
781 L"DevMgrDevChangeSub",
782 (HANDLE)dap))
783 {
784 dap->hWndParent = hWndParent;
785 }
786 }
787
788 UpdateDevInfo(hwndDlg,
789 dap,
790 FALSE);
791 }
792 Ret = TRUE;
793 break;
794 }
795
796 case WM_DEVICECHANGE:
797 {
798 /* FIXME - don't call UpdateDevInfo for all events */
799 UpdateDevInfo(hwndDlg,
800 dap,
801 TRUE);
802 Ret = TRUE;
803 break;
804 }
805
806 case WM_DESTROY:
807 {
808 HICON hDevIcon;
809
810 /* restore the old window proc of the subclassed parent window */
811 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
812 {
813 SetWindowLongPtr(dap->hWndParent,
814 GWLP_WNDPROC,
815 (LONG_PTR)dap->ParentOldWndProc);
816 }
817
818 /* destroy the device icon */
819 hDevIcon = (HICON)SendDlgItemMessage(hwndDlg,
820 IDC_DEVICON,
821 STM_GETICON,
822 0,
823 0);
824 if (hDevIcon != NULL)
825 {
826 DestroyIcon(hDevIcon);
827 }
828 break;
829 }
830 }
831 }
832
833 return Ret;
834 }
835
836
837 INT_PTR
838 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
839 IN LPCWSTR lpDeviceID OPTIONAL,
840 IN HDEVINFO DeviceInfoSet,
841 IN PSP_DEVINFO_DATA DeviceInfoData,
842 IN HINSTANCE hComCtl32,
843 IN LPCWSTR lpMachineName,
844 IN DWORD dwFlags)
845 {
846 PROPSHEETHEADER psh = {0};
847 PROPSHEETPAGE pspGeneral = {0};
848 DWORD nPropSheets = 0;
849 PPROPERTYSHEETW pPropertySheetW;
850 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
851 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
852 PDEVADVPROP_INFO DevAdvPropInfo;
853 HMACHINE hMachine = NULL;
854 DWORD DevIdSize = 0;
855 INT_PTR Ret = -1;
856
857 /* we don't want to statically link against comctl32, so find the
858 functions we need dynamically */
859 pPropertySheetW =
860 (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
861 "PropertySheetW");
862 pCreatePropertySheetPageW =
863 (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
864 "CreatePropertySheetPageW");
865 pDestroyPropertySheetPage =
866 (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
867 "DestroyPropertySheetPage");
868 if (pPropertySheetW == NULL ||
869 pCreatePropertySheetPageW == NULL ||
870 pDestroyPropertySheetPage == NULL)
871 {
872 return -1;
873 }
874
875 if (lpDeviceID == NULL)
876 {
877 /* find out how much size is needed for the device id */
878 if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
879 DeviceInfoData,
880 NULL,
881 0,
882 &DevIdSize))
883 {
884 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
885 return -1;
886 }
887
888 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
889 {
890 return -1;
891 }
892 }
893 else
894 {
895 DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
896 }
897
898 if (lpMachineName != NULL)
899 {
900 CONFIGRET cr = CM_Connect_Machine(lpMachineName,
901 &hMachine);
902 if (cr != CR_SUCCESS)
903 {
904 return -1;
905 }
906 }
907
908 /* create the internal structure associated with the "General",
909 "Driver", ... pages */
910 DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
911 HEAP_ZERO_MEMORY,
912 FIELD_OFFSET(DEVADVPROP_INFO,
913 szDeviceID) +
914 (DevIdSize * sizeof(WCHAR)));
915 if (DevAdvPropInfo == NULL)
916 {
917 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
918 goto Cleanup;
919 }
920
921 if (lpDeviceID == NULL)
922 {
923 /* read the device instance id */
924 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
925 DeviceInfoData,
926 DevAdvPropInfo->szDeviceID,
927 DevIdSize,
928 NULL))
929 {
930 goto Cleanup;
931 }
932 }
933 else
934 {
935 /* copy the device instance id supplied by the caller */
936 wcscpy(DevAdvPropInfo->szDeviceID,
937 lpDeviceID);
938 }
939
940 DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
941 DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
942 DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
943 DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
944
945 DevAdvPropInfo->hMachine = hMachine;
946 DevAdvPropInfo->lpMachineName = lpMachineName;
947 DevAdvPropInfo->szDevName[0] = L'\0';
948 DevAdvPropInfo->hComCtl32 = hComCtl32;
949
950 DevAdvPropInfo->IsAdmin = IsUserAdmin();
951 DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
952
953 psh.dwSize = sizeof(PROPSHEETHEADER);
954 psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
955 psh.hwndParent = hWndParent;
956 psh.pszCaption = DevAdvPropInfo->szDevName;
957
958 DevAdvPropInfo->PropertySheetType = lpMachineName != NULL ?
959 DIGCDP_FLAG_REMOTE_ADVANCED :
960 DIGCDP_FLAG_ADVANCED;
961
962 /* find out how many property sheets we need */
963 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
964 &DevAdvPropInfo->DeviceInfoData,
965 &psh,
966 0,
967 &nPropSheets,
968 DevAdvPropInfo->PropertySheetType) &&
969 nPropSheets != 0)
970 {
971 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
972 goto Cleanup;
973 }
974
975 if (nPropSheets != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
976 {
977 goto Cleanup;
978 }
979
980 psh.phpage = HeapAlloc(GetProcessHeap(),
981 HEAP_ZERO_MEMORY,
982 (nPropSheets + 1) * sizeof(HPROPSHEETPAGE));
983 if (psh.phpage == NULL)
984 {
985 goto Cleanup;
986 }
987
988 /* add the "General" property sheet */
989 pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
990 pspGeneral.dwFlags = PSP_DEFAULT;
991 pspGeneral.hInstance = hDllInstance;
992 pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
993 pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
994 pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
995 psh.phpage[0] = pCreatePropertySheetPageW(&pspGeneral);
996 if (psh.phpage[0] != NULL)
997 {
998 psh.nPages++;
999 }
1000
1001 DevAdvPropInfo->nDevPropSheets = nPropSheets;
1002
1003 if (nPropSheets != 0)
1004 {
1005 DevAdvPropInfo->DevPropSheets = psh.phpage + psh.nPages;
1006
1007 /* create the device property sheets */
1008 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
1009 &DevAdvPropInfo->DeviceInfoData,
1010 &psh,
1011 nPropSheets + psh.nPages,
1012 NULL,
1013 DevAdvPropInfo->PropertySheetType))
1014 {
1015 goto Cleanup;
1016 }
1017 }
1018
1019 /* FIXME - add the "Driver" property sheet if necessary */
1020
1021 if (psh.nPages != 0)
1022 {
1023 Ret = pPropertySheetW(&psh);
1024
1025 /* NOTE: no need to destroy the property sheets anymore! */
1026 }
1027 else
1028 {
1029 UINT i;
1030
1031 Cleanup:
1032 /* in case of failure the property sheets must be destroyed */
1033 if (psh.phpage != NULL)
1034 {
1035 for (i = 0;
1036 i < psh.nPages;
1037 i++)
1038 {
1039 if (psh.phpage[i] != NULL)
1040 {
1041 pDestroyPropertySheetPage(psh.phpage[i]);
1042 }
1043 }
1044 }
1045 }
1046
1047 if (DevAdvPropInfo != NULL)
1048 {
1049 if (DevAdvPropInfo->FreeDevPropSheets)
1050 {
1051 /* don't free the array if it's the one allocated in
1052 DisplayDeviceAdvancedProperties */
1053 HeapFree(GetProcessHeap(),
1054 0,
1055 DevAdvPropInfo->DevPropSheets);
1056 }
1057
1058 if (DevAdvPropInfo->CloseDevInst)
1059 {
1060 /* close the device info set in case a new one was created */
1061 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
1062 }
1063
1064 if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1065 {
1066 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
1067 }
1068
1069 HeapFree(GetProcessHeap(),
1070 0,
1071 DevAdvPropInfo);
1072 }
1073
1074 if (psh.phpage != NULL)
1075 {
1076 HeapFree(GetProcessHeap(),
1077 0,
1078 psh.phpage);
1079 }
1080
1081 if (hMachine != NULL)
1082 {
1083 CM_Disconnect_Machine(hMachine);
1084 }
1085
1086 return Ret;
1087 }
1088
1089
1090 /***************************************************************************
1091 * NAME EXPORTED
1092 * DeviceAdvancedPropertiesW
1093 *
1094 * DESCRIPTION
1095 * Invokes the device properties dialog, this version may add some property pages
1096 * for some devices
1097 *
1098 * ARGUMENTS
1099 * hWndParent: Handle to the parent window
1100 * lpMachineName: Machine Name, NULL is the local machine
1101 * lpDeviceID: Specifies the device whose properties are to be shown
1102 *
1103 * RETURN VALUE
1104 * Always returns -1, a call to GetLastError returns 0 if successful
1105 *
1106 * @implemented
1107 */
1108 INT_PTR
1109 WINAPI
1110 DeviceAdvancedPropertiesW(IN HWND hWndParent OPTIONAL,
1111 IN LPCWSTR lpMachineName OPTIONAL,
1112 IN LPCWSTR lpDeviceID)
1113 {
1114 HDEVINFO hDevInfo;
1115 SP_DEVINFO_DATA DevInfoData;
1116 HINSTANCE hComCtl32;
1117 INT_PTR Ret = -1;
1118
1119 if (lpDeviceID == NULL)
1120 {
1121 SetLastError(ERROR_INVALID_PARAMETER);
1122 return FALSE;
1123 }
1124
1125 /* dynamically load comctl32 */
1126 hComCtl32 = LoadAndInitComctl32();
1127 if (hComCtl32 != NULL)
1128 {
1129 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1130 hWndParent,
1131 lpMachineName,
1132 NULL);
1133 if (hDevInfo != INVALID_HANDLE_VALUE)
1134 {
1135 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1136 if (SetupDiOpenDeviceInfo(hDevInfo,
1137 lpDeviceID,
1138 hWndParent,
1139 0,
1140 &DevInfoData))
1141 {
1142 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1143 lpDeviceID,
1144 hDevInfo,
1145 &DevInfoData,
1146 hComCtl32,
1147 lpMachineName,
1148 0);
1149 }
1150
1151 SetupDiDestroyDeviceInfoList(hDevInfo);
1152 }
1153
1154 FreeLibrary(hComCtl32);
1155 }
1156
1157 return Ret;
1158 }
1159
1160
1161 /***************************************************************************
1162 * NAME EXPORTED
1163 * DeviceAdvancedPropertiesA
1164 *
1165 * DESCRIPTION
1166 * Invokes the device properties dialog, this version may add some property pages
1167 * for some devices
1168 *
1169 * ARGUMENTS
1170 * hWndParent: Handle to the parent window
1171 * lpMachineName: Machine Name, NULL is the local machine
1172 * lpDeviceID: Specifies the device whose properties are to be shown
1173 *
1174 * RETURN VALUE
1175 * Always returns -1, a call to GetLastError returns 0 if successful
1176 *
1177 * @implemented
1178 */
1179 INT_PTR
1180 WINAPI
1181 DeviceAdvancedPropertiesA(IN HWND hWndParent OPTIONAL,
1182 IN LPCSTR lpMachineName OPTIONAL,
1183 IN LPCSTR lpDeviceID)
1184 {
1185 LPWSTR lpMachineNameW = NULL;
1186 LPWSTR lpDeviceIDW = NULL;
1187 INT_PTR Ret = -1;
1188
1189 if (lpMachineName != NULL)
1190 {
1191 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1192 CP_ACP)))
1193 {
1194 goto Cleanup;
1195 }
1196 }
1197 if (lpDeviceID != NULL)
1198 {
1199 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1200 CP_ACP)))
1201 {
1202 goto Cleanup;
1203 }
1204 }
1205
1206 Ret = DeviceAdvancedPropertiesW(hWndParent,
1207 lpMachineNameW,
1208 lpDeviceIDW);
1209
1210 Cleanup:
1211 if (lpMachineNameW != NULL)
1212 {
1213 HeapFree(GetProcessHeap(),
1214 0,
1215 lpMachineNameW);
1216 }
1217 if (lpDeviceIDW != NULL)
1218 {
1219 HeapFree(GetProcessHeap(),
1220 0,
1221 lpDeviceIDW);
1222 }
1223
1224 return Ret;
1225 }
1226
1227
1228 /***************************************************************************
1229 * NAME EXPORTED
1230 * DevicePropertiesExA
1231 *
1232 * DESCRIPTION
1233 * Invokes the extended device properties dialog
1234 *
1235 * ARGUMENTS
1236 * hWndParent: Handle to the parent window
1237 * lpMachineName: Machine Name, NULL is the local machine
1238 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1239 * bShowDevMgr is nonzero
1240 * dwFlags: This parameter can be a combination of the following flags:
1241 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1242 * the default device status action button
1243 * to be clicked (Troubleshoot, Enable
1244 * Device, etc)
1245 * bShowDevMgr: If non-zero it displays the device manager instead of
1246 * the advanced device property dialog
1247 *
1248 * RETURN VALUE
1249 * 1: if bShowDevMgr is non-zero and no error occured
1250 * -1: a call to GetLastError returns 0 if successful
1251 *
1252 * @implemented
1253 */
1254 INT_PTR
1255 WINAPI
1256 DevicePropertiesExA(IN HWND hWndParent OPTIONAL,
1257 IN LPCSTR lpMachineName OPTIONAL,
1258 IN LPCSTR lpDeviceID OPTIONAL,
1259 IN DWORD dwFlags OPTIONAL,
1260 IN BOOL bShowDevMgr)
1261 {
1262 LPWSTR lpMachineNameW = NULL;
1263 LPWSTR lpDeviceIDW = NULL;
1264 INT_PTR Ret = -1;
1265
1266 if (lpMachineName != NULL)
1267 {
1268 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1269 CP_ACP)))
1270 {
1271 goto Cleanup;
1272 }
1273 }
1274 if (lpDeviceID != NULL)
1275 {
1276 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1277 CP_ACP)))
1278 {
1279 goto Cleanup;
1280 }
1281 }
1282
1283 Ret = DevicePropertiesExW(hWndParent,
1284 lpMachineNameW,
1285 lpDeviceIDW,
1286 dwFlags,
1287 bShowDevMgr);
1288
1289 Cleanup:
1290 if (lpMachineNameW != NULL)
1291 {
1292 HeapFree(GetProcessHeap(),
1293 0,
1294 lpMachineNameW);
1295 }
1296 if (lpDeviceIDW != NULL)
1297 {
1298 HeapFree(GetProcessHeap(),
1299 0,
1300 lpDeviceIDW);
1301 }
1302
1303 return Ret;
1304 }
1305
1306
1307 /***************************************************************************
1308 * NAME EXPORTED
1309 * DevicePropertiesExW
1310 *
1311 * DESCRIPTION
1312 * Invokes the extended device properties dialog
1313 *
1314 * ARGUMENTS
1315 * hWndParent: Handle to the parent window
1316 * lpMachineName: Machine Name, NULL is the local machine
1317 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1318 * bShowDevMgr is nonzero
1319 * dwFlags: This parameter can be a combination of the following flags:
1320 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1321 * the default device status action button
1322 * to be clicked (Troubleshoot, Enable
1323 * Device, etc)
1324 * bShowDevMgr: If non-zero it displays the device manager instead of
1325 * the advanced device property dialog
1326 *
1327 * RETURN VALUE
1328 * 1: if bShowDevMgr is non-zero and no error occured
1329 * -1: a call to GetLastError returns 0 if successful
1330 *
1331 * @unimplemented
1332 */
1333 INT_PTR
1334 WINAPI
1335 DevicePropertiesExW(IN HWND hWndParent OPTIONAL,
1336 IN LPCWSTR lpMachineName OPTIONAL,
1337 IN LPCWSTR lpDeviceID OPTIONAL,
1338 IN DWORD dwFlags OPTIONAL,
1339 IN BOOL bShowDevMgr)
1340 {
1341 INT_PTR Ret = -1;
1342
1343 if (dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION))
1344 {
1345 DPRINT1("DevPropertiesExW: Invalid flags: 0x%x\n",
1346 dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION));
1347 SetLastError(ERROR_INVALID_FLAGS);
1348 return -1;
1349 }
1350
1351 if (bShowDevMgr)
1352 {
1353 DPRINT("DevPropertiesExW doesn't support bShowDevMgr!\n");
1354 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1355 }
1356 else
1357 {
1358 HDEVINFO hDevInfo;
1359 SP_DEVINFO_DATA DevInfoData;
1360 HINSTANCE hComCtl32;
1361
1362 if (lpDeviceID == NULL)
1363 {
1364 SetLastError(ERROR_INVALID_PARAMETER);
1365 return -1;
1366 }
1367
1368 /* dynamically load comctl32 */
1369 hComCtl32 = LoadAndInitComctl32();
1370 if (hComCtl32 != NULL)
1371 {
1372 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1373 hWndParent,
1374 lpMachineName,
1375 NULL);
1376 if (hDevInfo != INVALID_HANDLE_VALUE)
1377 {
1378 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1379 if (SetupDiOpenDeviceInfo(hDevInfo,
1380 lpDeviceID,
1381 hWndParent,
1382 0,
1383 &DevInfoData))
1384 {
1385 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1386 lpDeviceID,
1387 hDevInfo,
1388 &DevInfoData,
1389 hComCtl32,
1390 lpMachineName,
1391 dwFlags);
1392 }
1393
1394 SetupDiDestroyDeviceInfoList(hDevInfo);
1395 }
1396
1397 FreeLibrary(hComCtl32);
1398 }
1399 }
1400
1401 return Ret;
1402 }