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