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