Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[reactos.git] / dll / win32 / 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 /*
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 * Ged Murphy <gedmurphy@reactos.org>
26 * UPDATE HISTORY:
27 * 04-04-2004 Created
28 */
29 #include <precomp.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 typedef INT_PTR (WINAPI *PPROPERTYSHEETW)(LPCPROPSHEETHEADERW);
35 typedef HPROPSHEETPAGE (WINAPI *PCREATEPROPERTYSHEETPAGEW)(LPCPROPSHEETPAGEW);
36 typedef BOOL (WINAPI *PDESTROYPROPERTYSHEETPAGE)(HPROPSHEETPAGE);
37
38 typedef struct _DEVADVPROP_INFO
39 {
40 HWND hWndGeneralPage;
41 HWND hWndParent;
42 WNDPROC ParentOldWndProc;
43 HICON hDevIcon;
44
45 HDEVINFO DeviceInfoSet;
46 SP_DEVINFO_DATA DeviceInfoData;
47 HDEVINFO CurrentDeviceInfoSet;
48 SP_DEVINFO_DATA CurrentDeviceInfoData;
49 DEVINST ParentDevInst;
50 HMACHINE hMachine;
51 LPCWSTR lpMachineName;
52
53 HINSTANCE hComCtl32;
54 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
55 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
56
57 DWORD PropertySheetType;
58 DWORD nDevPropSheets;
59 HPROPSHEETPAGE *DevPropSheets;
60
61 union
62 {
63 UINT Flags;
64 struct
65 {
66 UINT FreeDevPropSheets : 1;
67 UINT CanDisable : 1;
68 UINT DeviceStarted : 1;
69 UINT DeviceUsageChanged : 1;
70 UINT CloseDevInst : 1;
71 UINT IsAdmin : 1;
72 UINT DoDefaultDevAction : 1;
73 UINT PageInitialized : 1;
74 UINT ShowRemotePages : 1;
75 UINT HasDriverPage : 1;
76 UINT HasResourcePage : 1;
77 UINT HasPowerPage : 1;
78 };
79 };
80
81 WCHAR szDevName[255];
82 WCHAR szTemp[255];
83 WCHAR szDeviceID[1];
84 /* struct may be dynamically expanded here! */
85 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
86
87
88 typedef struct _ENUMDRIVERFILES_CONTEXT
89 {
90 HWND hDriversListView;
91 UINT nCount;
92 } ENUMDRIVERFILES_CONTEXT, *PENUMDRIVERFILES_CONTEXT;
93
94 #define PM_INITIALIZE (WM_APP + 0x101)
95
96
97 static UINT WINAPI
98 EnumDeviceDriverFilesCallback(IN PVOID Context,
99 IN UINT Notification,
100 IN UINT_PTR Param1,
101 IN UINT_PTR Param2)
102 {
103 LVITEM li;
104 PENUMDRIVERFILES_CONTEXT EnumDriverFilesContext = (PENUMDRIVERFILES_CONTEXT)Context;
105
106 li.mask = LVIF_TEXT | LVIF_STATE;
107 li.iItem = EnumDriverFilesContext->nCount++;
108 li.iSubItem = 0;
109 li.state = (li.iItem == 0 ? LVIS_SELECTED : 0);
110 li.stateMask = LVIS_SELECTED;
111 li.pszText = (LPWSTR)Param1;
112 (void)ListView_InsertItem(EnumDriverFilesContext->hDriversListView,
113 &li);
114 return NO_ERROR;
115 }
116
117
118 static VOID
119 UpdateDriverDetailsDlg(IN HWND hwndDlg,
120 IN HWND hDriversListView,
121 IN PDEVADVPROP_INFO dap)
122 {
123 HDEVINFO DeviceInfoSet;
124 PSP_DEVINFO_DATA DeviceInfoData;
125 SP_DRVINFO_DATA DriverInfoData;
126 ENUMDRIVERFILES_CONTEXT EnumDriverFilesContext;
127
128 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
129 {
130 DeviceInfoSet = dap->CurrentDeviceInfoSet;
131 DeviceInfoData = &dap->CurrentDeviceInfoData;
132 }
133 else
134 {
135 DeviceInfoSet = dap->DeviceInfoSet;
136 DeviceInfoData = &dap->DeviceInfoData;
137 }
138
139 /* set the device image */
140 SendDlgItemMessage(hwndDlg,
141 IDC_DEVICON,
142 STM_SETICON,
143 (WPARAM)dap->hDevIcon,
144 0);
145
146 /* set the device name edit control text */
147 SetDlgItemText(hwndDlg,
148 IDC_DEVNAME,
149 dap->szDevName);
150
151 /* fill the driver files list view */
152 EnumDriverFilesContext.hDriversListView = hDriversListView;
153 EnumDriverFilesContext.nCount = 0;
154
155 (void)ListView_DeleteAllItems(EnumDriverFilesContext.hDriversListView);
156 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
157 if (FindCurrentDriver(DeviceInfoSet,
158 DeviceInfoData,
159 &DriverInfoData) &&
160 SetupDiSetSelectedDriver(DeviceInfoSet,
161 DeviceInfoData,
162 &DriverInfoData))
163 {
164 HSPFILEQ queueHandle;
165
166 queueHandle = SetupOpenFileQueue();
167 if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
168 {
169 SP_DEVINSTALL_PARAMS DeviceInstallParams = {0};
170 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
171 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
172 DeviceInfoData,
173 &DeviceInstallParams))
174 {
175 DeviceInstallParams.FileQueue = queueHandle;
176 DeviceInstallParams.Flags |= DI_NOVCP;
177
178 if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
179 DeviceInfoData,
180 &DeviceInstallParams) &&
181 SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
182 DeviceInfoSet,
183 DeviceInfoData))
184 {
185 DWORD scanResult;
186 RECT rcClient;
187 LVCOLUMN lvc;
188
189 /* enumerate the driver files */
190 SetupScanFileQueue(queueHandle,
191 SPQ_SCAN_USE_CALLBACK,
192 NULL,
193 EnumDeviceDriverFilesCallback,
194 &EnumDriverFilesContext,
195 &scanResult);
196
197 /* update the list view column width */
198 GetClientRect(hDriversListView,
199 &rcClient);
200 lvc.mask = LVCF_WIDTH;
201 lvc.cx = rcClient.right;
202 (void)ListView_SetColumn(hDriversListView,
203 0,
204 &lvc);
205 }
206 }
207
208 SetupCloseFileQueue(queueHandle);
209 }
210 }
211 }
212
213
214 static INT_PTR
215 CALLBACK
216 DriverDetailsDlgProc(IN HWND hwndDlg,
217 IN UINT uMsg,
218 IN WPARAM wParam,
219 IN LPARAM lParam)
220 {
221 PDEVADVPROP_INFO dap;
222 INT_PTR Ret = FALSE;
223
224 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
225 DWL_USER);
226
227 if (dap != NULL || uMsg == WM_INITDIALOG)
228 {
229 switch (uMsg)
230 {
231 case WM_COMMAND:
232 {
233 switch (LOWORD(wParam))
234 {
235 case IDOK:
236 {
237 EndDialog(hwndDlg,
238 IDOK);
239 break;
240 }
241 }
242 break;
243 }
244
245 case WM_CLOSE:
246 {
247 EndDialog(hwndDlg,
248 IDCANCEL);
249 break;
250 }
251
252 case WM_INITDIALOG:
253 {
254 LV_COLUMN lvc;
255 HWND hDriversListView;
256
257 dap = (PDEVADVPROP_INFO)lParam;
258 if (dap != NULL)
259 {
260 SetWindowLongPtr(hwndDlg,
261 DWL_USER,
262 (DWORD_PTR)dap);
263
264 hDriversListView = GetDlgItem(hwndDlg,
265 IDC_DRIVERFILES);
266
267 /* add a column to the list view control */
268 lvc.mask = LVCF_FMT | LVCF_WIDTH;
269 lvc.fmt = LVCFMT_LEFT;
270 lvc.cx = 0;
271 (void)ListView_InsertColumn(hDriversListView,
272 0,
273 &lvc);
274
275 UpdateDriverDetailsDlg(hwndDlg,
276 hDriversListView,
277 dap);
278 }
279
280 Ret = TRUE;
281 break;
282 }
283 }
284 }
285
286 return Ret;
287 }
288
289
290 static VOID
291 UpdateDriverDlg(IN HWND hwndDlg,
292 IN PDEVADVPROP_INFO dap)
293 {
294 HDEVINFO DeviceInfoSet;
295 PSP_DEVINFO_DATA DeviceInfoData;
296
297 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
298 {
299 DeviceInfoSet = dap->CurrentDeviceInfoSet;
300 DeviceInfoData = &dap->CurrentDeviceInfoData;
301 }
302 else
303 {
304 DeviceInfoSet = dap->DeviceInfoSet;
305 DeviceInfoData = &dap->DeviceInfoData;
306 }
307
308 /* set the device image */
309 SendDlgItemMessage(hwndDlg,
310 IDC_DEVICON,
311 STM_SETICON,
312 (WPARAM)dap->hDevIcon,
313 0);
314
315 /* set the device name edit control text */
316 SetDlgItemText(hwndDlg,
317 IDC_DEVNAME,
318 dap->szDevName);
319
320 /* query the driver provider */
321 if (GetDriverProviderString(DeviceInfoSet,
322 DeviceInfoData,
323 dap->szTemp,
324 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
325 {
326 SetDlgItemText(hwndDlg,
327 IDC_DRVPROVIDER,
328 dap->szTemp);
329 }
330
331 /* query the driver date */
332 if (GetDriverDateString(DeviceInfoSet,
333 DeviceInfoData,
334 dap->szTemp,
335 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
336 {
337 SetDlgItemText(hwndDlg,
338 IDC_DRVDATE,
339 dap->szTemp);
340 }
341
342 /* query the driver version */
343 if (GetDriverVersionString(DeviceInfoSet,
344 DeviceInfoData,
345 dap->szTemp,
346 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
347 {
348 SetDlgItemText(hwndDlg,
349 IDC_DRVVERSION,
350 dap->szTemp);
351 }
352 }
353
354
355 static INT_PTR
356 CALLBACK
357 AdvProcDriverDlgProc(IN HWND hwndDlg,
358 IN UINT uMsg,
359 IN WPARAM wParam,
360 IN LPARAM lParam)
361 {
362 PDEVADVPROP_INFO dap;
363 INT_PTR Ret = FALSE;
364
365 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
366 DWL_USER);
367
368 if (dap != NULL || uMsg == WM_INITDIALOG)
369 {
370 switch (uMsg)
371 {
372 case WM_COMMAND:
373 {
374 switch (LOWORD(wParam))
375 {
376 case IDC_DRIVERDETAILS:
377 {
378 DialogBoxParam(hDllInstance,
379 MAKEINTRESOURCE(IDD_DRIVERDETAILS),
380 hwndDlg,
381 DriverDetailsDlgProc,
382 (ULONG_PTR)dap);
383 break;
384 }
385 }
386 break;
387 }
388
389 case WM_NOTIFY:
390 {
391 NMHDR *hdr = (NMHDR*)lParam;
392 switch (hdr->code)
393 {
394 case PSN_APPLY:
395 break;
396 }
397 break;
398 }
399
400 case WM_INITDIALOG:
401 {
402 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
403 if (dap != NULL)
404 {
405 SetWindowLongPtr(hwndDlg,
406 DWL_USER,
407 (DWORD_PTR)dap);
408
409 UpdateDriverDlg(hwndDlg,
410 dap);
411 }
412 Ret = TRUE;
413 break;
414 }
415 }
416 }
417
418 return Ret;
419 }
420
421
422 static VOID
423 InitDevUsageActions(IN HWND hwndDlg,
424 IN HWND hComboBox,
425 IN PDEVADVPROP_INFO dap)
426 {
427 INT Index;
428 UINT i;
429 UINT Actions[] =
430 {
431 IDS_ENABLEDEVICE,
432 IDS_DISABLEDEVICE,
433 };
434
435 for (i = 0;
436 i != sizeof(Actions) / sizeof(Actions[0]);
437 i++)
438 {
439 /* fill in the device usage combo box */
440 if (LoadString(hDllInstance,
441 Actions[i],
442 dap->szTemp,
443 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
444 {
445 Index = (INT)SendMessage(hComboBox,
446 CB_ADDSTRING,
447 0,
448 (LPARAM)dap->szTemp);
449 if (Index != CB_ERR)
450 {
451 SendMessage(hComboBox,
452 CB_SETITEMDATA,
453 (WPARAM)Index,
454 (LPARAM)Actions[i]);
455
456 switch (Actions[i])
457 {
458 case IDS_ENABLEDEVICE:
459 if (dap->DeviceStarted)
460 {
461 SendMessage(hComboBox,
462 CB_SETCURSEL,
463 (WPARAM)Index,
464 0);
465 }
466 break;
467
468 case IDS_DISABLEDEVICE:
469 if (!dap->DeviceStarted)
470 {
471 SendMessage(hComboBox,
472 CB_SETCURSEL,
473 (WPARAM)Index,
474 0);
475 }
476 break;
477
478 default:
479 break;
480 }
481 }
482 }
483 }
484 }
485
486
487 static UINT
488 GetSelectedUsageAction(IN HWND hComboBox)
489 {
490 INT Index;
491 UINT Ret = 0;
492
493 Index = (INT)SendMessage(hComboBox,
494 CB_GETCURSEL,
495 0,
496 0);
497 if (Index != CB_ERR)
498 {
499 INT iRet = (INT) SendMessage(hComboBox,
500 CB_GETITEMDATA,
501 (WPARAM)Index,
502 0);
503 if (iRet != CB_ERR)
504 {
505 Ret = (UINT)iRet;
506 }
507 }
508
509 return Ret;
510 }
511
512
513 static BOOL
514 ApplyGeneralSettings(IN HWND hwndDlg,
515 IN PDEVADVPROP_INFO dap)
516 {
517 BOOL Ret = FALSE;
518
519 if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
520 {
521 UINT SelectedUsageAction;
522 BOOL NeedReboot = FALSE;
523
524 SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
525 IDC_DEVUSAGE));
526 switch (SelectedUsageAction)
527 {
528 case IDS_ENABLEDEVICE:
529 if (!dap->DeviceStarted)
530 {
531 Ret = EnableDevice(dap->DeviceInfoSet,
532 &dap->DeviceInfoData,
533 TRUE,
534 0,
535 &NeedReboot);
536 }
537 break;
538
539 case IDS_DISABLEDEVICE:
540 if (dap->DeviceStarted)
541 {
542 Ret = EnableDevice(dap->DeviceInfoSet,
543 &dap->DeviceInfoData,
544 FALSE,
545 0,
546 &NeedReboot);
547 }
548 break;
549
550 default:
551 break;
552 }
553
554 if (Ret)
555 {
556 if (NeedReboot)
557 {
558 /* make PropertySheet() return PSM_REBOOTSYSTEM */
559 PropSheet_RebootSystem(hwndDlg);
560 }
561 }
562 else
563 {
564 /* FIXME - display an error message */
565 DPRINT1("Failed to enable/disable device! LastError: %d\n",
566 GetLastError());
567 }
568 }
569 else
570 Ret = !dap->DeviceUsageChanged;
571
572 /* disable the apply button */
573 PropSheet_UnChanged(GetParent(hwndDlg),
574 hwndDlg);
575 dap->DeviceUsageChanged = FALSE;
576 return Ret;
577 }
578
579
580 static VOID
581 UpdateDevInfo(IN HWND hwndDlg,
582 IN PDEVADVPROP_INFO dap,
583 IN BOOL ReOpen)
584 {
585 HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
586 CONFIGRET cr;
587 ULONG Status, ProblemNumber;
588 SP_DEVINSTALL_PARAMS_W InstallParams;
589 UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
590 BOOL bFlag, bDevActionAvailable = TRUE;
591 BOOL bDrvInstalled = FALSE;
592 DWORD iPage;
593 HDEVINFO DeviceInfoSet = NULL;
594 PSP_DEVINFO_DATA DeviceInfoData = NULL;
595 PROPSHEETHEADER psh;
596 DWORD nDriverPages = 0;
597 BOOL RecalcPages = FALSE;
598
599 hPropSheetDlg = GetParent(hwndDlg);
600
601 if (dap->PageInitialized)
602 {
603 /* switch to the General page */
604 PropSheet_SetCurSelByID(hPropSheetDlg,
605 IDD_DEVICEGENERAL);
606
607 /* remove and destroy the existing device property sheet pages */
608 if (dap->DevPropSheets != NULL)
609 {
610 for (iPage = 0;
611 iPage != dap->nDevPropSheets;
612 iPage++)
613 {
614 if (dap->DevPropSheets[iPage] != NULL)
615 {
616 PropSheet_RemovePage(hPropSheetDlg,
617 (WPARAM) -1,
618 dap->DevPropSheets[iPage]);
619 RecalcPages = TRUE;
620 }
621 }
622 }
623 }
624
625 iPage = 0;
626
627 if (dap->FreeDevPropSheets)
628 {
629 /* don't free the array if it's the one allocated in
630 DisplayDeviceAdvancedProperties */
631 HeapFree(GetProcessHeap(),
632 0,
633 dap->DevPropSheets);
634
635 dap->FreeDevPropSheets = FALSE;
636 }
637
638 dap->DevPropSheets = NULL;
639 dap->nDevPropSheets = 0;
640
641 if (ReOpen)
642 {
643 /* create a new device info set and re-open the device */
644 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
645 {
646 SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
647 }
648
649 dap->ParentDevInst = 0;
650 dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
651 hwndDlg,
652 dap->lpMachineName,
653 NULL);
654 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
655 {
656 if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
657 dap->szDeviceID,
658 hwndDlg,
659 0,
660 &dap->CurrentDeviceInfoData))
661 {
662 if (dap->CloseDevInst)
663 {
664 SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
665 }
666
667 dap->CloseDevInst = TRUE;
668 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
669 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
670 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
671 }
672 else
673 goto GetParentNode;
674 }
675 else
676 {
677 GetParentNode:
678 /* get the parent node from the initial devinst */
679 CM_Get_Parent_Ex(&dap->ParentDevInst,
680 dap->DeviceInfoData.DevInst,
681 0,
682 dap->hMachine);
683 }
684
685 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
686 {
687 DeviceInfoSet = dap->CurrentDeviceInfoSet;
688 DeviceInfoData = &dap->CurrentDeviceInfoData;
689 }
690 else
691 {
692 DeviceInfoSet = dap->DeviceInfoSet;
693 DeviceInfoData = &dap->DeviceInfoData;
694 }
695 }
696 else
697 {
698 DeviceInfoSet = dap->DeviceInfoSet;
699 DeviceInfoData = &dap->DeviceInfoData;
700 }
701
702 dap->HasDriverPage = FALSE;
703 dap->HasResourcePage = FALSE;
704 dap->HasPowerPage = FALSE;
705 if (IsDriverInstalled(DeviceInfoData->DevInst,
706 dap->hMachine,
707 &bDrvInstalled) &&
708 bDrvInstalled)
709 {
710 if (SetupDiCallClassInstaller((dap->ShowRemotePages ?
711 DIF_ADDREMOTEPROPERTYPAGE_ADVANCED :
712 DIF_ADDPROPERTYPAGE_ADVANCED),
713 DeviceInfoSet,
714 DeviceInfoData))
715 {
716 /* get install params */
717 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
718 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
719 DeviceInfoData,
720 &InstallParams))
721 {
722 /* zero the flags */
723 InstallParams.Flags = 0;
724 }
725
726 dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
727 dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
728 dap->HasPowerPage = !(InstallParams.Flags & DI_FLAGSEX_POWERPAGE_ADDED);
729 }
730 }
731
732 /* get the device icon */
733 if (dap->hDevIcon != NULL)
734 {
735 DestroyIcon(dap->hDevIcon);
736 dap->hDevIcon = NULL;
737 }
738 if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
739 &dap->hDevIcon,
740 NULL))
741 {
742 dap->hDevIcon = NULL;
743 }
744
745 /* get the device name */
746 if (GetDeviceDescriptionString(DeviceInfoSet,
747 DeviceInfoData,
748 dap->szDevName,
749 sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
750 {
751 PropSheet_SetTitle(hPropSheetDlg,
752 PSH_PROPTITLE,
753 dap->szDevName);
754 }
755
756 /* set the device image */
757 SendDlgItemMessage(hwndDlg,
758 IDC_DEVICON,
759 STM_SETICON,
760 (WPARAM)dap->hDevIcon,
761 0);
762
763 /* set the device name edit control text */
764 SetDlgItemText(hwndDlg,
765 IDC_DEVNAME,
766 dap->szDevName);
767
768 /* set the device type edit control text */
769 if (GetDeviceTypeString(DeviceInfoData,
770 dap->szTemp,
771 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
772 {
773 SetDlgItemText(hwndDlg,
774 IDC_DEVTYPE,
775 dap->szTemp);
776 }
777
778 /* set the device manufacturer edit control text */
779 if (GetDeviceManufacturerString(DeviceInfoSet,
780 DeviceInfoData,
781 dap->szTemp,
782 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
783 {
784 SetDlgItemText(hwndDlg,
785 IDC_DEVMANUFACTURER,
786 dap->szTemp);
787 }
788
789 /* set the device location edit control text */
790 if (GetDeviceLocationString(DeviceInfoData->DevInst,
791 dap->ParentDevInst,
792 dap->szTemp,
793 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
794 {
795 SetDlgItemText(hwndDlg,
796 IDC_DEVLOCATION,
797 dap->szTemp);
798 }
799
800 /* set the device status edit control text */
801 if (GetDeviceStatusString(DeviceInfoData->DevInst,
802 dap->hMachine,
803 dap->szTemp,
804 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
805 {
806 SetDlgItemText(hwndDlg,
807 IDC_DEVSTATUS,
808 dap->szTemp);
809 }
810
811 /* set the device troubleshoot button text and disable it if necessary */
812 hDevProbBtn = GetDlgItem(hwndDlg,
813 IDC_DEVPROBLEM);
814 cr = CM_Get_DevNode_Status_Ex(&Status,
815 &ProblemNumber,
816 DeviceInfoData->DevInst,
817 0,
818 dap->hMachine);
819 if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
820 {
821 switch (ProblemNumber)
822 {
823 case CM_PROB_DEVLOADER_FAILED:
824 {
825 /* FIXME - only if it's not a root bus devloader,
826 disable the button otherwise */
827 TroubleShootStrId = IDS_UPDATEDRV;
828 break;
829 }
830
831 case CM_PROB_OUT_OF_MEMORY:
832 case CM_PROB_ENTRY_IS_WRONG_TYPE:
833 case CM_PROB_LACKED_ARBITRATOR:
834 case CM_PROB_FAILED_START:
835 case CM_PROB_LIAR:
836 case CM_PROB_UNKNOWN_RESOURCE:
837 {
838 TroubleShootStrId = IDS_UPDATEDRV;
839 break;
840 }
841
842 case CM_PROB_BOOT_CONFIG_CONFLICT:
843 case CM_PROB_NORMAL_CONFLICT:
844 case CM_PROB_REENUMERATION:
845 {
846 /* FIXME - Troubleshoot conflict */
847 break;
848 }
849
850 case CM_PROB_FAILED_FILTER:
851 case CM_PROB_REINSTALL:
852 case CM_PROB_FAILED_INSTALL:
853 {
854 TroubleShootStrId = IDS_REINSTALLDRV;
855 break;
856 }
857
858 case CM_PROB_DEVLOADER_NOT_FOUND:
859 {
860 /* FIXME - 4 cases:
861 1) if it's a missing system devloader:
862 - disable the button (Reinstall Driver)
863 2) if it's not a system devloader but still missing:
864 - Reinstall Driver
865 3) if it's not a system devloader but the file can be found:
866 - Update Driver
867 4) if it's a missing or empty software key
868 - Update Driver
869 */
870 break;
871 }
872
873 case CM_PROB_INVALID_DATA:
874 case CM_PROB_PARTIAL_LOG_CONF:
875 case CM_PROB_NO_VALID_LOG_CONF:
876 case CM_PROB_HARDWARE_DISABLED:
877 case CM_PROB_CANT_SHARE_IRQ:
878 case CM_PROB_TRANSLATION_FAILED:
879 case CM_PROB_SYSTEM_SHUTDOWN:
880 case CM_PROB_PHANTOM:
881 bDevActionAvailable = FALSE;
882 break;
883
884 case CM_PROB_NOT_VERIFIED:
885 case CM_PROB_DEVICE_NOT_THERE:
886 /* FIXME - search hardware */
887 break;
888
889 case CM_PROB_NEED_RESTART:
890 case CM_PROB_WILL_BE_REMOVED:
891 case CM_PROB_MOVED:
892 case CM_PROB_TOO_EARLY:
893 case CM_PROB_DISABLED_SERVICE:
894 TroubleShootStrId = IDS_REBOOT;
895 break;
896
897 case CM_PROB_REGISTRY:
898 /* FIXME - check registry? */
899 break;
900
901 case CM_PROB_DISABLED:
902 /* if device was disabled by the user: */
903 TroubleShootStrId = IDS_ENABLEDEV;
904 /* FIXME - otherwise disable button because the device was
905 disabled by the system*/
906 break;
907
908 case CM_PROB_DEVLOADER_NOT_READY:
909 /* FIXME - if it's a graphics adapter:
910 - if it's a a secondary adapter and the main adapter
911 couldn't be found
912 - disable button
913 - else
914 - Properties
915 - else
916 - Update driver
917 */
918 break;
919
920 case CM_PROB_FAILED_ADD:
921 TroubleShootStrId = IDS_PROPERTIES;
922 break;
923 }
924 }
925
926 if (LoadString(hDllInstance,
927 TroubleShootStrId,
928 dap->szTemp,
929 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
930 {
931 SetWindowText(hDevProbBtn,
932 dap->szTemp);
933 }
934 EnableWindow(hDevProbBtn,
935 dap->IsAdmin && bDevActionAvailable);
936
937 /* check if the device can be enabled/disabled */
938 hDevUsage = GetDlgItem(hwndDlg,
939 IDC_DEVUSAGE);
940
941 dap->CanDisable = FALSE;
942 dap->DeviceStarted = FALSE;
943
944 if (CanDisableDevice(DeviceInfoData->DevInst,
945 dap->hMachine,
946 &bFlag))
947 {
948 dap->CanDisable = bFlag;
949 }
950
951 if (IsDeviceStarted(DeviceInfoData->DevInst,
952 dap->hMachine,
953 &bFlag))
954 {
955 dap->DeviceStarted = bFlag;
956 }
957
958 /* enable/disable the device usage controls */
959 EnableWindow(GetDlgItem(hwndDlg,
960 IDC_DEVUSAGELABEL),
961 dap->CanDisable && dap->IsAdmin);
962 EnableWindow(hDevUsage,
963 dap->CanDisable && dap->IsAdmin);
964
965 /* clear the combobox */
966 SendMessage(hDevUsage,
967 CB_RESETCONTENT,
968 0,
969 0);
970 if (dap->CanDisable)
971 {
972 InitDevUsageActions(hwndDlg,
973 hDevUsage,
974 dap);
975 }
976
977 /* find out how many new device property sheets to add.
978 fake a PROPSHEETHEADER structure, we don't plan to
979 call PropertySheet again!*/
980 psh.dwSize = sizeof(PROPSHEETHEADER);
981 psh.dwFlags = 0;
982 psh.nPages = 0;
983
984 /* get the number of device property sheets for the device */
985 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
986 DeviceInfoData,
987 &psh,
988 0,
989 &nDriverPages,
990 dap->PropertySheetType) &&
991 nDriverPages != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
992 {
993 dap->nDevPropSheets += nDriverPages;
994 }
995 else
996 {
997 nDriverPages = 0;
998 }
999
1000 /* include the driver page */
1001 if (dap->HasDriverPage)
1002 dap->nDevPropSheets++;
1003
1004 /* add the device property sheets */
1005 if (dap->nDevPropSheets != 0)
1006 {
1007 dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
1008 HEAP_ZERO_MEMORY,
1009 dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
1010 if (dap->DevPropSheets != NULL)
1011 {
1012 if (nDriverPages != 0)
1013 {
1014 psh.phpage = dap->DevPropSheets;
1015
1016 /* query the device property sheet pages to add */
1017 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
1018 DeviceInfoData,
1019 &psh,
1020 dap->nDevPropSheets,
1021 NULL,
1022 dap->PropertySheetType))
1023 {
1024 /* add the property sheets */
1025 for (iPage = 0;
1026 iPage != nDriverPages;
1027 iPage++)
1028 {
1029 if (PropSheet_AddPage(hPropSheetDlg,
1030 dap->DevPropSheets[iPage]))
1031 {
1032 RecalcPages = TRUE;
1033 }
1034 }
1035
1036 dap->FreeDevPropSheets = TRUE;
1037 }
1038 else
1039 {
1040 /* cleanup, we were unable to get the device property sheets */
1041 iPage = nDriverPages;
1042 dap->nDevPropSheets -= nDriverPages;
1043 nDriverPages = 0;
1044 }
1045 }
1046 else
1047 iPage = 0;
1048
1049 /* add the driver page if necessary */
1050 if (dap->HasDriverPage)
1051 {
1052 PROPSHEETPAGE pspDriver = {0};
1053 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
1054 pspDriver.dwFlags = PSP_DEFAULT;
1055 pspDriver.hInstance = hDllInstance;
1056 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDRIVER);
1057 pspDriver.pfnDlgProc = AdvProcDriverDlgProc;
1058 pspDriver.lParam = (LPARAM)dap;
1059 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
1060 if (dap->DevPropSheets[iPage] != NULL)
1061 {
1062 if (PropSheet_AddPage(hPropSheetDlg,
1063 dap->DevPropSheets[iPage]))
1064 {
1065 iPage++;
1066 RecalcPages = TRUE;
1067 }
1068 else
1069 {
1070 dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
1071 dap->DevPropSheets[iPage] = NULL;
1072 }
1073 }
1074 }
1075 }
1076 else
1077 dap->nDevPropSheets = 0;
1078 }
1079
1080 if (RecalcPages)
1081 {
1082 PropSheet_RecalcPageSizes(hPropSheetDlg);
1083 }
1084
1085 /* finally, disable the apply button */
1086 PropSheet_UnChanged(hPropSheetDlg,
1087 hwndDlg);
1088 dap->DeviceUsageChanged = FALSE;
1089 }
1090
1091
1092 static LRESULT
1093 CALLBACK
1094 DlgParentSubWndProc(IN HWND hwnd,
1095 IN UINT uMsg,
1096 IN WPARAM wParam,
1097 IN LPARAM lParam)
1098 {
1099 PDEVADVPROP_INFO dap;
1100
1101 dap = (PDEVADVPROP_INFO)GetProp(hwnd,
1102 L"DevMgrDevChangeSub");
1103 if (dap != NULL)
1104 {
1105 if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
1106 {
1107 SendMessage(dap->hWndGeneralPage,
1108 WM_DEVICECHANGE,
1109 wParam,
1110 lParam);
1111 }
1112
1113 /* pass the message the the old window proc */
1114 return CallWindowProc(dap->ParentOldWndProc,
1115 hwnd,
1116 uMsg,
1117 wParam,
1118 lParam);
1119 }
1120 else
1121 {
1122 /* this is not a good idea if the subclassed window was an ansi
1123 window, but we failed finding out the previous window proc
1124 so we can't use CallWindowProc. This should rarely - if ever -
1125 happen. */
1126
1127 return DefWindowProc(hwnd,
1128 uMsg,
1129 wParam,
1130 lParam);
1131 }
1132 }
1133
1134
1135 static INT_PTR
1136 CALLBACK
1137 AdvPropGeneralDlgProc(IN HWND hwndDlg,
1138 IN UINT uMsg,
1139 IN WPARAM wParam,
1140 IN LPARAM lParam)
1141 {
1142 PDEVADVPROP_INFO dap;
1143 INT_PTR Ret = FALSE;
1144
1145 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
1146 DWL_USER);
1147
1148 if (dap != NULL || uMsg == WM_INITDIALOG)
1149 {
1150 switch (uMsg)
1151 {
1152 case WM_COMMAND:
1153 {
1154 switch (LOWORD(wParam))
1155 {
1156 case IDC_DEVUSAGE:
1157 {
1158 if (HIWORD(wParam) == CBN_SELCHANGE)
1159 {
1160 PropSheet_Changed(GetParent(hwndDlg),
1161 hwndDlg);
1162 dap->DeviceUsageChanged = TRUE;
1163 }
1164 break;
1165 }
1166
1167 case IDC_DEVPROBLEM:
1168 {
1169 if (dap->IsAdmin)
1170 {
1171 /* display the device problem wizard */
1172 ShowDeviceProblemWizard(hwndDlg,
1173 dap->DeviceInfoSet,
1174 &dap->DeviceInfoData,
1175 dap->hMachine);
1176 }
1177 break;
1178 }
1179 }
1180 break;
1181 }
1182
1183 case WM_NOTIFY:
1184 {
1185 NMHDR *hdr = (NMHDR*)lParam;
1186 switch (hdr->code)
1187 {
1188 case PSN_APPLY:
1189 ApplyGeneralSettings(hwndDlg,
1190 dap);
1191 break;
1192 }
1193 break;
1194 }
1195
1196 case WM_INITDIALOG:
1197 {
1198 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
1199 if (dap != NULL)
1200 {
1201 HWND hWndParent;
1202
1203 dap->hWndGeneralPage = hwndDlg;
1204
1205 SetWindowLongPtr(hwndDlg,
1206 DWL_USER,
1207 (DWORD_PTR)dap);
1208
1209 /* subclass the parent window to always receive
1210 WM_DEVICECHANGE messages */
1211 hWndParent = GetParent(hwndDlg);
1212 if (hWndParent != NULL)
1213 {
1214 /* subclass the parent window. This is not safe
1215 if the parent window belongs to another thread! */
1216 dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
1217 GWLP_WNDPROC,
1218 (LONG_PTR)DlgParentSubWndProc);
1219
1220 if (dap->ParentOldWndProc != NULL &&
1221 SetProp(hWndParent,
1222 L"DevMgrDevChangeSub",
1223 (HANDLE)dap))
1224 {
1225 dap->hWndParent = hWndParent;
1226 }
1227 }
1228
1229 /* do not call UpdateDevInfo directly in here because it modifies
1230 the pages of the property sheet! */
1231 PostMessage(hwndDlg,
1232 PM_INITIALIZE,
1233 0,
1234 0);
1235 }
1236 Ret = TRUE;
1237 break;
1238 }
1239
1240 case WM_DEVICECHANGE:
1241 {
1242 /* FIXME - don't call UpdateDevInfo for all events */
1243 UpdateDevInfo(hwndDlg,
1244 dap,
1245 TRUE);
1246 Ret = TRUE;
1247 break;
1248 }
1249
1250 case PM_INITIALIZE:
1251 {
1252 UpdateDevInfo(hwndDlg,
1253 dap,
1254 FALSE);
1255 dap->PageInitialized = TRUE;
1256 break;
1257 }
1258
1259 case WM_DESTROY:
1260 {
1261 /* restore the old window proc of the subclassed parent window */
1262 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
1263 {
1264 if (SetWindowLongPtr(dap->hWndParent,
1265 GWLP_WNDPROC,
1266 (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
1267 {
1268 RemoveProp(dap->hWndParent,
1269 L"DevMgrDevChangeSub");
1270 }
1271 }
1272 break;
1273 }
1274 }
1275 }
1276
1277 return Ret;
1278 }
1279
1280
1281 INT_PTR
1282 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
1283 IN LPCWSTR lpDeviceID OPTIONAL,
1284 IN HDEVINFO DeviceInfoSet,
1285 IN PSP_DEVINFO_DATA DeviceInfoData,
1286 IN HINSTANCE hComCtl32,
1287 IN LPCWSTR lpMachineName,
1288 IN DWORD dwFlags)
1289 {
1290 PROPSHEETHEADER psh = {0};
1291 PROPSHEETPAGE pspGeneral = {0};
1292 PPROPERTYSHEETW pPropertySheetW;
1293 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
1294 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
1295 PDEVADVPROP_INFO DevAdvPropInfo;
1296 HMACHINE hMachine = NULL;
1297 DWORD DevIdSize = 0;
1298 INT_PTR Ret = -1;
1299
1300 /* we don't want to statically link against comctl32, so find the
1301 functions we need dynamically */
1302 pPropertySheetW =
1303 (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
1304 "PropertySheetW");
1305 pCreatePropertySheetPageW =
1306 (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
1307 "CreatePropertySheetPageW");
1308 pDestroyPropertySheetPage =
1309 (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
1310 "DestroyPropertySheetPage");
1311 if (pPropertySheetW == NULL ||
1312 pCreatePropertySheetPageW == NULL ||
1313 pDestroyPropertySheetPage == NULL)
1314 {
1315 return -1;
1316 }
1317
1318 if (lpDeviceID == NULL)
1319 {
1320 /* find out how much size is needed for the device id */
1321 if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
1322 DeviceInfoData,
1323 NULL,
1324 0,
1325 &DevIdSize))
1326 {
1327 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
1328 return -1;
1329 }
1330
1331 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1332 {
1333 return -1;
1334 }
1335 }
1336 else
1337 {
1338 DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
1339 }
1340
1341 if (lpMachineName != NULL && lpMachineName[0] != L'\0')
1342 {
1343 CONFIGRET cr = CM_Connect_Machine(lpMachineName,
1344 &hMachine);
1345 if (cr != CR_SUCCESS)
1346 {
1347 return -1;
1348 }
1349 }
1350
1351 /* create the internal structure associated with the "General",
1352 "Driver", ... pages */
1353 DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
1354 HEAP_ZERO_MEMORY,
1355 FIELD_OFFSET(DEVADVPROP_INFO,
1356 szDeviceID) +
1357 (DevIdSize * sizeof(WCHAR)));
1358 if (DevAdvPropInfo == NULL)
1359 {
1360 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1361 goto Cleanup;
1362 }
1363
1364 if (lpDeviceID == NULL)
1365 {
1366 /* read the device instance id */
1367 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
1368 DeviceInfoData,
1369 DevAdvPropInfo->szDeviceID,
1370 DevIdSize,
1371 NULL))
1372 {
1373 goto Cleanup;
1374 }
1375 }
1376 else
1377 {
1378 /* copy the device instance id supplied by the caller */
1379 wcscpy(DevAdvPropInfo->szDeviceID,
1380 lpDeviceID);
1381 }
1382
1383 DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
1384 DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
1385 DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
1386 DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1387
1388 DevAdvPropInfo->ShowRemotePages = (lpMachineName != NULL && lpMachineName[0] != L'\0');
1389 DevAdvPropInfo->hMachine = hMachine;
1390 DevAdvPropInfo->lpMachineName = lpMachineName;
1391 DevAdvPropInfo->szDevName[0] = L'\0';
1392 DevAdvPropInfo->hComCtl32 = hComCtl32;
1393 DevAdvPropInfo->pCreatePropertySheetPageW = pCreatePropertySheetPageW;
1394 DevAdvPropInfo->pDestroyPropertySheetPage = pDestroyPropertySheetPage;
1395
1396 DevAdvPropInfo->IsAdmin = IsUserAdmin();
1397 DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
1398
1399 psh.dwSize = sizeof(PROPSHEETHEADER);
1400 psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
1401 psh.hwndParent = hWndParent;
1402 psh.pszCaption = DevAdvPropInfo->szDevName;
1403
1404 DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
1405 DIGCDP_FLAG_REMOTE_ADVANCED :
1406 DIGCDP_FLAG_ADVANCED;
1407
1408 psh.phpage = HeapAlloc(GetProcessHeap(),
1409 HEAP_ZERO_MEMORY,
1410 1 * sizeof(HPROPSHEETPAGE));
1411 if (psh.phpage == NULL)
1412 {
1413 goto Cleanup;
1414 }
1415
1416 /* add the "General" property sheet */
1417 pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
1418 pspGeneral.dwFlags = PSP_DEFAULT;
1419 pspGeneral.hInstance = hDllInstance;
1420 pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
1421 pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
1422 pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
1423 psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
1424 if (psh.phpage[psh.nPages] != NULL)
1425 {
1426 psh.nPages++;
1427 }
1428
1429 DevAdvPropInfo->nDevPropSheets = psh.nPages;
1430
1431 if (psh.nPages != 0)
1432 {
1433 Ret = pPropertySheetW(&psh);
1434
1435 /* NOTE: no need to destroy the property sheets anymore! */
1436 }
1437 else
1438 {
1439 UINT i;
1440
1441 Cleanup:
1442 /* in case of failure the property sheets must be destroyed */
1443 if (psh.phpage != NULL)
1444 {
1445 for (i = 0;
1446 i < psh.nPages;
1447 i++)
1448 {
1449 if (psh.phpage[i] != NULL)
1450 {
1451 pDestroyPropertySheetPage(psh.phpage[i]);
1452 }
1453 }
1454 }
1455 }
1456
1457 if (DevAdvPropInfo != NULL)
1458 {
1459 if (DevAdvPropInfo->FreeDevPropSheets)
1460 {
1461 /* don't free the array if it's the one allocated in
1462 DisplayDeviceAdvancedProperties */
1463 HeapFree(GetProcessHeap(),
1464 0,
1465 DevAdvPropInfo->DevPropSheets);
1466 }
1467
1468 if (DevAdvPropInfo->CloseDevInst)
1469 {
1470 /* close the device info set in case a new one was created */
1471 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
1472 }
1473
1474 if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1475 {
1476 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
1477 }
1478
1479 if (DevAdvPropInfo->hDevIcon != NULL)
1480 {
1481 DestroyIcon(DevAdvPropInfo->hDevIcon);
1482 }
1483
1484 HeapFree(GetProcessHeap(),
1485 0,
1486 DevAdvPropInfo);
1487 }
1488
1489 if (psh.phpage != NULL)
1490 {
1491 HeapFree(GetProcessHeap(),
1492 0,
1493 psh.phpage);
1494 }
1495
1496 if (hMachine != NULL)
1497 {
1498 CM_Disconnect_Machine(hMachine);
1499 }
1500
1501 return Ret;
1502 }
1503
1504
1505 static BOOL
1506 GetDeviceAndComputerName(LPWSTR lpString,
1507 WCHAR szDeviceID[],
1508 WCHAR szMachineName[])
1509 {
1510 BOOL ret = FALSE;
1511
1512 szDeviceID[0] = L'\0';
1513 szMachineName[0] = L'\0';
1514
1515 while (*lpString != L'\0')
1516 {
1517 if (*lpString == L'/')
1518 {
1519 lpString++;
1520 if(!wcsnicmp(lpString, L"DeviceID", 8))
1521 {
1522 lpString += 9;
1523 if (*lpString != L'\0')
1524 {
1525 int i = 0;
1526 while ((*lpString != L' ') &&
1527 (*lpString != L'\0') &&
1528 (i <= MAX_DEVICE_ID_LEN))
1529 {
1530 szDeviceID[i++] = *lpString++;
1531 }
1532 szDeviceID[i] = L'\0';
1533 ret = TRUE;
1534 }
1535 }
1536 else if (!wcsnicmp(lpString, L"MachineName", 11))
1537 {
1538 lpString += 12;
1539 if (*lpString != L'\0')
1540 {
1541 int i = 0;
1542 while ((*lpString != L' ') &&
1543 (*lpString != L'\0') &&
1544 (i <= MAX_COMPUTERNAME_LENGTH))
1545 {
1546 szMachineName[i++] = *lpString++;
1547 }
1548 szMachineName[i] = L'\0';
1549 }
1550 }
1551 /* knock the pointer back one and let the next
1552 * pointer deal with incrementing, otherwise we
1553 * go past the end of the string */
1554 lpString--;
1555 }
1556 lpString++;
1557 }
1558
1559 return ret;
1560 }
1561
1562
1563 /***************************************************************************
1564 * NAME EXPORTED
1565 * DeviceAdvancedPropertiesW
1566 *
1567 * DESCRIPTION
1568 * Invokes the device properties dialog, this version may add some property pages
1569 * for some devices
1570 *
1571 * ARGUMENTS
1572 * hWndParent: Handle to the parent window
1573 * lpMachineName: Machine Name, NULL is the local machine
1574 * lpDeviceID: Specifies the device whose properties are to be shown
1575 *
1576 * RETURN VALUE
1577 * Always returns -1, a call to GetLastError returns 0 if successful
1578 *
1579 * @implemented
1580 */
1581 INT_PTR
1582 WINAPI
1583 DeviceAdvancedPropertiesW(IN HWND hWndParent OPTIONAL,
1584 IN LPCWSTR lpMachineName OPTIONAL,
1585 IN LPCWSTR lpDeviceID)
1586 {
1587 HDEVINFO hDevInfo;
1588 SP_DEVINFO_DATA DevInfoData;
1589 HINSTANCE hComCtl32;
1590 INT_PTR Ret = -1;
1591
1592 if (lpDeviceID == NULL)
1593 {
1594 SetLastError(ERROR_INVALID_PARAMETER);
1595 return FALSE;
1596 }
1597
1598 /* dynamically load comctl32 */
1599 hComCtl32 = LoadAndInitComctl32();
1600 if (hComCtl32 != NULL)
1601 {
1602 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1603 hWndParent,
1604 lpMachineName,
1605 NULL);
1606 if (hDevInfo != INVALID_HANDLE_VALUE)
1607 {
1608 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1609 if (SetupDiOpenDeviceInfo(hDevInfo,
1610 lpDeviceID,
1611 hWndParent,
1612 0,
1613 &DevInfoData))
1614 {
1615 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1616 lpDeviceID,
1617 hDevInfo,
1618 &DevInfoData,
1619 hComCtl32,
1620 lpMachineName,
1621 0);
1622 }
1623
1624 SetupDiDestroyDeviceInfoList(hDevInfo);
1625 }
1626
1627 FreeLibrary(hComCtl32);
1628 }
1629
1630 return Ret;
1631 }
1632
1633
1634 /***************************************************************************
1635 * NAME EXPORTED
1636 * DeviceAdvancedPropertiesA
1637 *
1638 * DESCRIPTION
1639 * Invokes the device properties dialog, this version may add some property pages
1640 * for some devices
1641 *
1642 * ARGUMENTS
1643 * hWndParent: Handle to the parent window
1644 * lpMachineName: Machine Name, NULL is the local machine
1645 * lpDeviceID: Specifies the device whose properties are to be shown
1646 *
1647 * RETURN VALUE
1648 * Always returns -1, a call to GetLastError returns 0 if successful
1649 *
1650 * @implemented
1651 */
1652 INT_PTR
1653 WINAPI
1654 DeviceAdvancedPropertiesA(IN HWND hWndParent OPTIONAL,
1655 IN LPCSTR lpMachineName OPTIONAL,
1656 IN LPCSTR lpDeviceID)
1657 {
1658 LPWSTR lpMachineNameW = NULL;
1659 LPWSTR lpDeviceIDW = NULL;
1660 INT_PTR Ret = -1;
1661
1662 if (lpMachineName != NULL)
1663 {
1664 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1665 CP_ACP)))
1666 {
1667 goto Cleanup;
1668 }
1669 }
1670 if (lpDeviceID != NULL)
1671 {
1672 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1673 CP_ACP)))
1674 {
1675 goto Cleanup;
1676 }
1677 }
1678
1679 Ret = DeviceAdvancedPropertiesW(hWndParent,
1680 lpMachineNameW,
1681 lpDeviceIDW);
1682
1683 Cleanup:
1684 if (lpMachineNameW != NULL)
1685 {
1686 HeapFree(GetProcessHeap(),
1687 0,
1688 lpMachineNameW);
1689 }
1690 if (lpDeviceIDW != NULL)
1691 {
1692 HeapFree(GetProcessHeap(),
1693 0,
1694 lpDeviceIDW);
1695 }
1696
1697 return Ret;
1698 }
1699
1700
1701 /***************************************************************************
1702 * NAME EXPORTED
1703 * DevicePropertiesExA
1704 *
1705 * DESCRIPTION
1706 * Invokes the extended device properties dialog
1707 *
1708 * ARGUMENTS
1709 * hWndParent: Handle to the parent window
1710 * lpMachineName: Machine Name, NULL is the local machine
1711 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1712 * bShowDevMgr is nonzero
1713 * dwFlags: This parameter can be a combination of the following flags:
1714 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1715 * the default device status action button
1716 * to be clicked (Troubleshoot, Enable
1717 * Device, etc)
1718 * bShowDevMgr: If non-zero it displays the device manager instead of
1719 * the advanced device property dialog
1720 *
1721 * RETURN VALUE
1722 * 1: if bShowDevMgr is non-zero and no error occured
1723 * -1: a call to GetLastError returns 0 if successful
1724 *
1725 * @implemented
1726 */
1727 INT_PTR
1728 WINAPI
1729 DevicePropertiesExA(IN HWND hWndParent OPTIONAL,
1730 IN LPCSTR lpMachineName OPTIONAL,
1731 IN LPCSTR lpDeviceID OPTIONAL,
1732 IN DWORD dwFlags OPTIONAL,
1733 IN BOOL bShowDevMgr)
1734 {
1735 LPWSTR lpMachineNameW = NULL;
1736 LPWSTR lpDeviceIDW = NULL;
1737 INT_PTR Ret = -1;
1738
1739 if (lpMachineName != NULL)
1740 {
1741 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1742 CP_ACP)))
1743 {
1744 goto Cleanup;
1745 }
1746 }
1747 if (lpDeviceID != NULL)
1748 {
1749 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1750 CP_ACP)))
1751 {
1752 goto Cleanup;
1753 }
1754 }
1755
1756 Ret = DevicePropertiesExW(hWndParent,
1757 lpMachineNameW,
1758 lpDeviceIDW,
1759 dwFlags,
1760 bShowDevMgr);
1761
1762 Cleanup:
1763 if (lpMachineNameW != NULL)
1764 {
1765 HeapFree(GetProcessHeap(),
1766 0,
1767 lpMachineNameW);
1768 }
1769 if (lpDeviceIDW != NULL)
1770 {
1771 HeapFree(GetProcessHeap(),
1772 0,
1773 lpDeviceIDW);
1774 }
1775
1776 return Ret;
1777 }
1778
1779
1780 /***************************************************************************
1781 * NAME EXPORTED
1782 * DevicePropertiesExW
1783 *
1784 * DESCRIPTION
1785 * Invokes the extended device properties dialog
1786 *
1787 * ARGUMENTS
1788 * hWndParent: Handle to the parent window
1789 * lpMachineName: Machine Name, NULL is the local machine
1790 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1791 * bShowDevMgr is nonzero
1792 * dwFlags: This parameter can be a combination of the following flags:
1793 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1794 * the default device status action button
1795 * to be clicked (Troubleshoot, Enable
1796 * Device, etc)
1797 * bShowDevMgr: If non-zero it displays the device manager instead of
1798 * the advanced device property dialog
1799 *
1800 * RETURN VALUE
1801 * 1: if bShowDevMgr is non-zero and no error occured
1802 * -1: a call to GetLastError returns 0 if successful
1803 *
1804 * @implemented
1805 */
1806 INT_PTR
1807 WINAPI
1808 DevicePropertiesExW(IN HWND hWndParent OPTIONAL,
1809 IN LPCWSTR lpMachineName OPTIONAL,
1810 IN LPCWSTR lpDeviceID OPTIONAL,
1811 IN DWORD dwFlags OPTIONAL,
1812 IN BOOL bShowDevMgr)
1813 {
1814 INT_PTR Ret = -1;
1815
1816 if (dwFlags & ~(DPF_EXTENDED | DPF_DEVICE_STATUS_ACTION))
1817 {
1818 DPRINT1("DevPropertiesExW: Invalid flags: 0x%x\n",
1819 dwFlags & ~(DPF_EXTENDED | DPF_DEVICE_STATUS_ACTION));
1820 SetLastError(ERROR_INVALID_FLAGS);
1821 return -1;
1822 }
1823
1824 if (bShowDevMgr)
1825 {
1826 DPRINT("DevPropertiesExW doesn't support bShowDevMgr!\n");
1827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1828 }
1829 else
1830 {
1831 HDEVINFO hDevInfo;
1832 SP_DEVINFO_DATA DevInfoData;
1833 HINSTANCE hComCtl32;
1834
1835 if (lpDeviceID == NULL)
1836 {
1837 SetLastError(ERROR_INVALID_PARAMETER);
1838 return -1;
1839 }
1840
1841 /* dynamically load comctl32 */
1842 hComCtl32 = LoadAndInitComctl32();
1843 if (hComCtl32 != NULL)
1844 {
1845 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1846 hWndParent,
1847 lpMachineName,
1848 NULL);
1849 if (hDevInfo != INVALID_HANDLE_VALUE)
1850 {
1851 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1852 if (SetupDiOpenDeviceInfo(hDevInfo,
1853 lpDeviceID,
1854 hWndParent,
1855 0,
1856 &DevInfoData))
1857 {
1858 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1859 lpDeviceID,
1860 hDevInfo,
1861 &DevInfoData,
1862 hComCtl32,
1863 lpMachineName,
1864 dwFlags);
1865 }
1866
1867 SetupDiDestroyDeviceInfoList(hDevInfo);
1868 }
1869
1870 FreeLibrary(hComCtl32);
1871 }
1872 }
1873
1874 return Ret;
1875 }
1876
1877
1878 /***************************************************************************
1879 * NAME EXPORTED
1880 * DevicePropertiesA
1881 *
1882 * DESCRIPTION
1883 * Invokes the device properties dialog directly
1884 *
1885 * ARGUMENTS
1886 * hWndParent: Handle to the parent window
1887 * lpMachineName: Machine Name, NULL is the local machine
1888 * lpDeviceID: Specifies the device whose properties are to be shown
1889 * bShowDevMgr: If non-zero it displays the device manager instead of
1890 * the device property dialog
1891 *
1892 * RETURN VALUE
1893 * >=0: if no errors occured
1894 * -1: if errors occured
1895 *
1896 * REVISIONS
1897 *
1898 * @implemented
1899 */
1900 int
1901 WINAPI
1902 DevicePropertiesA(HWND hWndParent,
1903 LPCSTR lpMachineName,
1904 LPCSTR lpDeviceID,
1905 BOOL bShowDevMgr)
1906 {
1907 return DevicePropertiesExA(hWndParent,
1908 lpMachineName,
1909 lpDeviceID,
1910 DPF_EXTENDED,
1911 bShowDevMgr);
1912 }
1913
1914
1915 /***************************************************************************
1916 * NAME EXPORTED
1917 * DevicePropertiesW
1918 *
1919 * DESCRIPTION
1920 * Invokes the device properties dialog directly
1921 *
1922 * ARGUMENTS
1923 * hWndParent: Handle to the parent window
1924 * lpMachineName: Machine Name, NULL is the local machine
1925 * lpDeviceID: Specifies the device whose properties are to be shown
1926 * bShowDevMgr: If non-zero it displays the device manager instead of
1927 * the device property dialog
1928 *
1929 * RETURN VALUE
1930 * >=0: if no errors occured
1931 * -1: if errors occured
1932 *
1933 * REVISIONS
1934 *
1935 * @implemented
1936 */
1937 int
1938 WINAPI
1939 DevicePropertiesW(HWND hWndParent,
1940 LPCWSTR lpMachineName,
1941 LPCWSTR lpDeviceID,
1942 BOOL bShowDevMgr)
1943 {
1944 return DevicePropertiesExW(hWndParent,
1945 lpMachineName,
1946 lpDeviceID,
1947 DPF_EXTENDED,
1948 bShowDevMgr);
1949 }
1950
1951
1952 /***************************************************************************
1953 * NAME EXPORTED
1954 * DeviceProperties_RunDLLA
1955 *
1956 * DESCRIPTION
1957 * Invokes the device properties dialog
1958 *
1959 * ARGUMENTS
1960 * hWndParent: Handle to the parent window
1961 * hInst: Handle to the application instance
1962 * lpDeviceCmd: A command that includes the DeviceID of the properties to be shown,
1963 * also see NOTEs
1964 * nCmdShow: Specifies how the window should be shown
1965 *
1966 * RETURN VALUE
1967 *
1968 * REVISIONS
1969 *
1970 * NOTE
1971 * - lpDeviceCmd is a string in the form of "/MachineName MACHINE /DeviceID DEVICEPATH"
1972 * (/MachineName is optional). This function only parses this string and eventually
1973 * calls DeviceProperties().
1974 *
1975 * @implemented
1976 */
1977 VOID
1978 WINAPI
1979 DeviceProperties_RunDLLA(HWND hWndParent,
1980 HINSTANCE hInst,
1981 LPCSTR lpDeviceCmd,
1982 int nCmdShow)
1983 {
1984 LPWSTR lpDeviceCmdW = NULL;
1985
1986 if (lpDeviceCmd != NULL)
1987 {
1988 if ((lpDeviceCmdW = ConvertMultiByteToUnicode(lpDeviceCmd,
1989 CP_ACP)))
1990 {
1991 DeviceProperties_RunDLLW(hWndParent,
1992 hInst,
1993 lpDeviceCmdW,
1994 nCmdShow);
1995 }
1996 }
1997
1998 if (lpDeviceCmdW != NULL)
1999 {
2000 HeapFree(GetProcessHeap(),
2001 0,
2002 lpDeviceCmdW);
2003 }
2004 }
2005
2006
2007 /***************************************************************************
2008 * NAME EXPORTED
2009 * DeviceProperties_RunDLLW
2010 *
2011 * DESCRIPTION
2012 * Invokes the device properties dialog
2013 *
2014 * ARGUMENTS
2015 * hWndParent: Handle to the parent window
2016 * hInst: Handle to the application instance
2017 * lpDeviceCmd: A command that includes the DeviceID of the properties to be shown,
2018 * also see NOTEs
2019 * nCmdShow: Specifies how the window should be shown
2020 *
2021 * RETURN VALUE
2022 *
2023 * REVISIONS
2024 *
2025 * NOTE
2026 * - lpDeviceCmd is a string in the form of "/MachineName MACHINE /DeviceID DEVICEPATH"
2027 * (/MachineName is optional). This function only parses this string and eventually
2028 * calls DeviceProperties().
2029 *
2030 * @implemented
2031 */
2032 VOID
2033 WINAPI
2034 DeviceProperties_RunDLLW(HWND hWndParent,
2035 HINSTANCE hInst,
2036 LPCWSTR lpDeviceCmd,
2037 int nCmdShow)
2038 {
2039 WCHAR szDeviceID[MAX_DEVICE_ID_LEN+1];
2040 WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH+1];
2041 LPWSTR lpString = (LPWSTR)lpDeviceCmd;
2042
2043 if (!GetDeviceAndComputerName(lpString,
2044 szDeviceID,
2045 szMachineName))
2046 {
2047 DPRINT1("DeviceProperties_RunDLLW DeviceID: %S, MachineName: %S\n", szDeviceID, szMachineName);
2048 return;
2049 }
2050
2051 DevicePropertiesW(hWndParent,
2052 szMachineName,
2053 szDeviceID,
2054 FALSE);
2055 }