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