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 
30 #include "precomp.h"
31 #include "properties.h"
32 #include "resource.h"
33 
34 #include <winver.h>
35 
36 #define PDCAP_D0_SUPPORTED                       0x00000001
37 #define PDCAP_D1_SUPPORTED                       0x00000002
38 #define PDCAP_D2_SUPPORTED                       0x00000004
39 #define PDCAP_D3_SUPPORTED                       0x00000008
40 #define PDCAP_WAKE_FROM_D0_SUPPORTED             0x00000010
41 #define PDCAP_WAKE_FROM_D1_SUPPORTED             0x00000020
42 #define PDCAP_WAKE_FROM_D2_SUPPORTED             0x00000040
43 #define PDCAP_WAKE_FROM_D3_SUPPORTED             0x00000080
44 #define PDCAP_WARM_EJECT_SUPPORTED               0x00000100
45 
46 typedef struct CM_Power_Data_s
47 {
48     ULONG PD_Size;
49     DEVICE_POWER_STATE PD_MostRecentPowerState;
50     ULONG PD_Capabilities;
51     ULONG PD_D1Latency;
52     ULONG PD_D2Latency;
53     ULONG PD_D3Latency;
54     DEVICE_POWER_STATE PD_PowerStateMapping[PowerSystemMaximum];
55     SYSTEM_POWER_STATE PD_DeepestSystemWake;
56 } CM_POWER_DATA, *PCM_POWER_DATA;
57 
58 
59 static UINT WINAPI
60 EnumDeviceDriverFilesCallback(IN PVOID Context,
61                               IN UINT Notification,
62                               IN UINT_PTR Param1,
63                               IN UINT_PTR Param2)
64 {
65     LVITEM li;
66     PENUMDRIVERFILES_CONTEXT EnumDriverFilesContext = (PENUMDRIVERFILES_CONTEXT)Context;
67 
68     li.mask = LVIF_TEXT | LVIF_STATE;
69     li.iItem = EnumDriverFilesContext->nCount++;
70     li.iSubItem = 0;
71     li.state = (li.iItem == 0 ? LVIS_SELECTED : 0);
72     li.stateMask = LVIS_SELECTED;
73     li.pszText = (LPWSTR)Param1;
74     (void)ListView_InsertItem(EnumDriverFilesContext->hDriversListView,
75                               &li);
76     return NO_ERROR;
77 }
78 
79 
80 static VOID
81 UpdateDriverDetailsDlg(IN HWND hwndDlg,
82                        IN HWND hDriversListView,
83                        IN PDEVADVPROP_INFO dap)
84 {
85     HDEVINFO DeviceInfoSet;
86     PSP_DEVINFO_DATA DeviceInfoData;
87     SP_DRVINFO_DATA DriverInfoData;
88     ENUMDRIVERFILES_CONTEXT EnumDriverFilesContext;
89 
90     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
91     {
92         DeviceInfoSet = dap->CurrentDeviceInfoSet;
93         DeviceInfoData = &dap->CurrentDeviceInfoData;
94     }
95     else
96     {
97         DeviceInfoSet = dap->DeviceInfoSet;
98         DeviceInfoData = &dap->DeviceInfoData;
99     }
100 
101     /* set the device image */
102     SendDlgItemMessage(hwndDlg,
103                        IDC_DEVICON,
104                        STM_SETICON,
105                        (WPARAM)dap->hDevIcon,
106                        0);
107 
108     /* set the device name edit control text */
109     SetDlgItemText(hwndDlg,
110                    IDC_DEVNAME,
111                    dap->szDevName);
112 
113     /* fill the driver files list view */
114     EnumDriverFilesContext.hDriversListView = hDriversListView;
115     EnumDriverFilesContext.nCount = 0;
116 
117     (void)ListView_DeleteAllItems(EnumDriverFilesContext.hDriversListView);
118     DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
119     if (FindCurrentDriver(DeviceInfoSet,
120                           DeviceInfoData,
121                           &DriverInfoData) &&
122         SetupDiSetSelectedDriver(DeviceInfoSet,
123                                  DeviceInfoData,
124                                  &DriverInfoData))
125     {
126         HSPFILEQ queueHandle;
127 
128         queueHandle = SetupOpenFileQueue();
129         if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
130         {
131             SP_DEVINSTALL_PARAMS DeviceInstallParams = {0};
132             DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
133             if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
134                                               DeviceInfoData,
135                                               &DeviceInstallParams))
136             {
137                 DeviceInstallParams.FileQueue = queueHandle;
138                 DeviceInstallParams.Flags |= DI_NOVCP;
139 
140                 if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
141                                                   DeviceInfoData,
142                                                   &DeviceInstallParams) &&
143                     SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
144                                               DeviceInfoSet,
145                                               DeviceInfoData))
146                 {
147                     DWORD scanResult;
148                     RECT rcClient;
149                     LVCOLUMN lvc;
150 
151                     /* enumerate the driver files */
152                     SetupScanFileQueue(queueHandle,
153                                        SPQ_SCAN_USE_CALLBACK,
154                                        NULL,
155                                        EnumDeviceDriverFilesCallback,
156                                        &EnumDriverFilesContext,
157                                        &scanResult);
158 
159                     /* update the list view column width */
160                     GetClientRect(hDriversListView,
161                                   &rcClient);
162                     lvc.mask = LVCF_WIDTH;
163                     lvc.cx = rcClient.right;
164                     (void)ListView_SetColumn(hDriversListView,
165                                              0,
166                                              &lvc);
167 
168                     /* highlight the first item from list */
169                     if (ListView_GetSelectedCount(hDriversListView) != 0)
170                     {
171                         ListView_SetItemState(hDriversListView,
172                                               0,
173                                               LVIS_FOCUSED | LVIS_SELECTED,
174                                               LVIS_FOCUSED | LVIS_SELECTED);
175                     }
176                 }
177             }
178 
179             SetupCloseFileQueue(queueHandle);
180         }
181     }
182 }
183 
184 
185 static VOID
186 UpdateDriverVersionInfoDetails(IN HWND hwndDlg,
187                                IN LPCWSTR lpszDriverPath)
188 {
189     DWORD dwHandle;
190     DWORD dwVerInfoSize;
191     LPVOID lpData = NULL;
192     LPVOID lpInfo;
193     UINT uInfoLen;
194     DWORD dwLangId;
195     WCHAR szLangInfo[255];
196     WCHAR szLangPath[MAX_PATH];
197     LPWSTR lpCompanyName = NULL;
198     LPWSTR lpFileVersion = NULL;
199     LPWSTR lpLegalCopyright = NULL;
200     LPWSTR lpDigitalSigner = NULL;
201     UINT uBufLen;
202     WCHAR szNotAvailable[255];
203 
204     /* extract version info from selected file */
205     dwVerInfoSize = GetFileVersionInfoSize(lpszDriverPath,
206                                            &dwHandle);
207     if (!dwVerInfoSize)
208         goto done;
209 
210     lpData = HeapAlloc(GetProcessHeap(),
211                        HEAP_ZERO_MEMORY,
212                        dwVerInfoSize);
213     if (!lpData)
214         goto done;
215 
216     if (!GetFileVersionInfo(lpszDriverPath,
217                             dwHandle,
218                             dwVerInfoSize,
219                             lpData))
220         goto done;
221 
222     if (!VerQueryValue(lpData,
223                        L"\\VarFileInfo\\Translation",
224                        &lpInfo,
225                        &uInfoLen))
226         goto done;
227 
228     dwLangId = *(LPDWORD)lpInfo;
229     swprintf(szLangInfo, L"\\StringFileInfo\\%04x%04x\\",
230              LOWORD(dwLangId), HIWORD(dwLangId));
231 
232     /* read CompanyName */
233     wcscpy(szLangPath, szLangInfo);
234     wcscat(szLangPath, L"CompanyName");
235 
236     VerQueryValue(lpData,
237                   szLangPath,
238                   (void **)&lpCompanyName,
239                   (PUINT)&uBufLen);
240 
241     /* read FileVersion */
242     wcscpy(szLangPath, szLangInfo);
243     wcscat(szLangPath, L"FileVersion");
244 
245     VerQueryValue(lpData,
246                   szLangPath,
247                   (void **)&lpFileVersion,
248                   (PUINT)&uBufLen);
249 
250     /* read LegalTrademarks */
251     wcscpy(szLangPath, szLangInfo);
252     wcscat(szLangPath, L"LegalCopyright");
253 
254     VerQueryValue(lpData,
255                   szLangPath,
256                   (void **)&lpLegalCopyright,
257                   (PUINT)&uBufLen);
258 
259     /* TODO: read digital signer info */
260 
261 done:
262     if (!LoadString(hDllInstance,
263                     IDS_NOTAVAILABLE,
264                     szNotAvailable,
265                     sizeof(szNotAvailable) / sizeof(WCHAR)))
266     {
267         wcscpy(szNotAvailable, L"n/a");
268     }
269 
270     /* update labels */
271     if (!lpCompanyName)
272         lpCompanyName = szNotAvailable;
273     SetDlgItemText(hwndDlg,
274                    IDC_FILEPROVIDER,
275                    lpCompanyName);
276 
277     if (!lpFileVersion)
278         lpFileVersion = szNotAvailable;
279     SetDlgItemText(hwndDlg,
280                    IDC_FILEVERSION,
281                    lpFileVersion);
282 
283     if (!lpLegalCopyright)
284         lpLegalCopyright = szNotAvailable;
285     SetDlgItemText(hwndDlg,
286                    IDC_FILECOPYRIGHT,
287                    lpLegalCopyright);
288 
289     if (!lpDigitalSigner)
290         lpDigitalSigner = szNotAvailable;
291     SetDlgItemText(hwndDlg,
292                    IDC_DIGITALSIGNER,
293                    lpDigitalSigner);
294 
295     /* release version info */
296     if (lpData)
297         HeapFree(GetProcessHeap(),
298                  0,
299                  lpData);
300 }
301 
302 
303 static INT_PTR
304 CALLBACK
305 DriverDetailsDlgProc(IN HWND hwndDlg,
306                      IN UINT uMsg,
307                      IN WPARAM wParam,
308                      IN LPARAM lParam)
309 {
310     PDEVADVPROP_INFO dap;
311     INT_PTR Ret = FALSE;
312 
313     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
314 
315     if (dap != NULL || uMsg == WM_INITDIALOG)
316     {
317         switch (uMsg)
318         {
319             case WM_COMMAND:
320             {
321                 switch (LOWORD(wParam))
322                 {
323                     case IDOK:
324                     case IDCANCEL:
325                     {
326                         EndDialog(hwndDlg,
327                                   IDOK);
328                         break;
329                     }
330                 }
331                 break;
332             }
333 
334             case WM_CLOSE:
335             {
336                 EndDialog(hwndDlg,
337                           IDCANCEL);
338                 break;
339             }
340 
341             case WM_INITDIALOG:
342             {
343                 LV_COLUMN lvc;
344                 HWND hDriversListView;
345                 WCHAR szBuffer[260];
346 
347                 dap = (PDEVADVPROP_INFO)lParam;
348                 if (dap != NULL)
349                 {
350                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
351 
352                     hDriversListView = GetDlgItem(hwndDlg,
353                                                   IDC_DRIVERFILES);
354 
355                     /* add a column to the list view control */
356                     lvc.mask = LVCF_FMT | LVCF_WIDTH;
357                     lvc.fmt = LVCFMT_LEFT;
358                     lvc.cx = 0;
359                     (void)ListView_InsertColumn(hDriversListView,
360                                                 0,
361                                                 &lvc);
362 
363                     UpdateDriverDetailsDlg(hwndDlg,
364                                            hDriversListView,
365                                            dap);
366 
367                     if (ListView_GetItemCount(hDriversListView) == 0)
368                     {
369                         if (LoadStringW(hDllInstance, IDS_NODRIVERS, szBuffer, _countof(szBuffer)))
370                             MessageBoxW(hwndDlg, szBuffer, dap->szDevName, MB_OK);
371                         EndDialog(hwndDlg, IDCANCEL);
372                     }
373                 }
374 
375                 Ret = TRUE;
376                 break;
377             }
378 
379             case WM_NOTIFY:
380             {
381                 LPNMHDR pnmhdr = (LPNMHDR)lParam;
382 
383                 switch (pnmhdr->code)
384                 {
385                 case LVN_ITEMCHANGED:
386                     {
387                         LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
388                         HWND hDriversListView = GetDlgItem(hwndDlg,
389                                                            IDC_DRIVERFILES);
390 
391                         if (ListView_GetSelectedCount(hDriversListView) == 0)
392                         {
393                             /* nothing is selected - empty the labels */
394                             SetDlgItemText(hwndDlg,
395                                            IDC_FILEPROVIDER,
396                                            NULL);
397                             SetDlgItemText(hwndDlg,
398                                            IDC_FILEVERSION,
399                                            NULL);
400                             SetDlgItemText(hwndDlg,
401                                            IDC_FILECOPYRIGHT,
402                                            NULL);
403                             SetDlgItemText(hwndDlg,
404                                            IDC_DIGITALSIGNER,
405                                            NULL);
406                         }
407                         else if (pnmv->uNewState != 0)
408                         {
409                             /* extract version info and update the labels */
410                             WCHAR szDriverPath[MAX_PATH];
411 
412                             ListView_GetItemText(hDriversListView,
413                                                  pnmv->iItem,
414                                                  pnmv->iSubItem,
415                                                  szDriverPath,
416                                                  MAX_PATH);
417 
418                             UpdateDriverVersionInfoDetails(hwndDlg,
419                                                            szDriverPath);
420                         }
421                     }
422                 }
423                 break;
424             }
425         }
426     }
427 
428     return Ret;
429 }
430 
431 
432 static
433 INT_PTR
434 CALLBACK
435 UninstallDriverDlgProc(IN HWND hwndDlg,
436                        IN UINT uMsg,
437                        IN WPARAM wParam,
438                        IN LPARAM lParam)
439 {
440     PDEVADVPROP_INFO dap;
441     INT_PTR Ret = FALSE;
442 
443     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
444 
445     if (dap != NULL || uMsg == WM_INITDIALOG)
446     {
447         switch (uMsg)
448         {
449             case WM_INITDIALOG:
450                 dap = (PDEVADVPROP_INFO)lParam;
451                 if (dap != NULL)
452                 {
453                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
454 
455                     /* Set the device image */
456                     SendDlgItemMessage(hwndDlg,
457                                        IDC_DEVICON,
458                                        STM_SETICON,
459                                        (WPARAM)dap->hDevIcon,
460                                        0);
461 
462                     /* Set the device name */
463                     SetDlgItemText(hwndDlg,
464                                    IDC_DEVNAME,
465                                    dap->szDevName);
466                 }
467 
468                 Ret = TRUE;
469                 break;
470 
471             case WM_COMMAND:
472                 switch (LOWORD(wParam))
473                 {
474                     case IDOK:
475                         EndDialog(hwndDlg, IDOK);
476                         break;
477 
478                     case IDCANCEL:
479                         EndDialog(hwndDlg,  IDCANCEL);
480                         break;
481                 }
482                 break;
483 
484             case WM_CLOSE:
485                 EndDialog(hwndDlg, IDCANCEL);
486                 break;
487         }
488     }
489 
490     return Ret;
491 }
492 
493 
494 static
495 VOID
496 UninstallDriver(
497     _In_ HWND hwndDlg,
498     _In_ PDEVADVPROP_INFO dap)
499 {
500     SP_REMOVEDEVICE_PARAMS RemoveDevParams;
501 
502     if (DialogBoxParam(hDllInstance,
503                        MAKEINTRESOURCE(IDD_UNINSTALLDRIVER),
504                        hwndDlg,
505                        UninstallDriverDlgProc,
506                        (ULONG_PTR)dap) == IDCANCEL)
507         return;
508 
509     RemoveDevParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
510     RemoveDevParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
511     RemoveDevParams.Scope = DI_REMOVEDEVICE_GLOBAL;
512     RemoveDevParams.HwProfile = 0;
513 
514     SetupDiSetClassInstallParamsW(dap->DeviceInfoSet,
515                                   &dap->DeviceInfoData,
516                                   &RemoveDevParams.ClassInstallHeader,
517                                   sizeof(SP_REMOVEDEVICE_PARAMS));
518 
519     SetupDiCallClassInstaller(DIF_REMOVE,
520                               dap->DeviceInfoSet,
521                               &dap->DeviceInfoData);
522 
523     SetupDiSetClassInstallParamsW(dap->DeviceInfoSet,
524                                   &dap->DeviceInfoData,
525                                   NULL,
526                                   0);
527 }
528 
529 
530 static
531 VOID
532 UpdateDriver(
533     IN HWND hwndDlg,
534     IN PDEVADVPROP_INFO dap)
535 {
536     TOKEN_PRIVILEGES Privileges;
537     HANDLE hToken;
538     DWORD dwReboot;
539     BOOL NeedReboot = FALSE;
540 
541     // Better use InstallDevInst:
542     //     BOOL
543     //     WINAPI
544     //     InstallDevInst(
545     //         HWND hWnd,
546     //         LPWSTR wszDeviceId,
547     //         BOOL bUpdate,
548     //         DWORD *dwReboot);
549     // See: http://comp.os.ms-windows.programmer.win32.narkive.com/J8FTd4KK/signature-of-undocumented-installdevinstex
550 
551     if (!InstallDevInst(hwndDlg, dap->szDeviceID, TRUE, &dwReboot))
552         return;
553 
554     if (NeedReboot == FALSE)
555         return;
556 
557     //FIXME: load text from resource file
558     if (MessageBoxW(hwndDlg, L"Reboot now?", L"Reboot required", MB_YESNO | MB_ICONQUESTION) != IDYES)
559         return;
560 
561     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
562     {
563         ERR("OpenProcessToken failed\n");
564         return;
565     }
566 
567     /* Get the LUID for the Shutdown privilege */
568     if (!LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &Privileges.Privileges[0].Luid))
569     {
570         ERR("LookupPrivilegeValue failed\n");
571         CloseHandle(hToken);
572         return;
573     }
574 
575     /* Assign the Shutdown privilege to our process */
576     Privileges.PrivilegeCount = 1;
577     Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
578 
579     if (!AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL))
580     {
581         ERR("AdjustTokenPrivileges failed\n");
582         CloseHandle(hToken);
583         return;
584     }
585 
586     /* Finally shut down the system */
587     if (!ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED))
588     {
589         ERR("ExitWindowsEx failed\n");
590         CloseHandle(hToken);
591     }
592 }
593 
594 
595 static VOID
596 UpdateDriverDlg(IN HWND hwndDlg,
597                 IN PDEVADVPROP_INFO dap)
598 {
599     HDEVINFO DeviceInfoSet;
600     PSP_DEVINFO_DATA DeviceInfoData;
601     DWORD dwStatus = 0;
602     DWORD dwProblem = 0;
603     CONFIGRET cr;
604 
605     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
606     {
607         DeviceInfoSet = dap->CurrentDeviceInfoSet;
608         DeviceInfoData = &dap->CurrentDeviceInfoData;
609     }
610     else
611     {
612         DeviceInfoSet = dap->DeviceInfoSet;
613         DeviceInfoData = &dap->DeviceInfoData;
614     }
615 
616     /* set the device image */
617     SendDlgItemMessage(hwndDlg,
618                        IDC_DEVICON,
619                        STM_SETICON,
620                        (WPARAM)dap->hDevIcon,
621                        0);
622 
623     /* set the device name edit control text */
624     SetDlgItemText(hwndDlg,
625                    IDC_DEVNAME,
626                    dap->szDevName);
627 
628     /* query the driver provider */
629     if (GetDriverProviderString(DeviceInfoSet,
630                                 DeviceInfoData,
631                                 dap->szTemp,
632                                 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
633     {
634         SetDlgItemText(hwndDlg,
635                        IDC_DRVPROVIDER,
636                        dap->szTemp);
637     }
638 
639     /* query the driver date */
640     if (GetDriverDateString(DeviceInfoSet,
641                             DeviceInfoData,
642                             dap->szTemp,
643                             sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
644     {
645         SetDlgItemText(hwndDlg,
646                        IDC_DRVDATE,
647                        dap->szTemp);
648     }
649 
650     /* query the driver version */
651     if (GetDriverVersionString(DeviceInfoSet,
652                                DeviceInfoData,
653                                dap->szTemp,
654                                sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
655     {
656         SetDlgItemText(hwndDlg,
657                        IDC_DRVVERSION,
658                        dap->szTemp);
659     }
660 
661     /* Disable the Uninstall button if the driver cannot be removed */
662     cr = CM_Get_DevNode_Status_Ex(&dwStatus,
663                                   &dwProblem,
664                                   dap->DeviceInfoData.DevInst,
665                                   0,
666                                   dap->hMachine);
667     if (cr == CR_SUCCESS)
668     {
669         if ((dwStatus & DN_ROOT_ENUMERATED) != 0 &&
670             (dwStatus & DN_DISABLEABLE) == 0)
671             EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTALLDRIVER), FALSE);
672     }
673 }
674 
675 
676 static INT_PTR
677 CALLBACK
678 AdvProcDriverDlgProc(IN HWND hwndDlg,
679                      IN UINT uMsg,
680                      IN WPARAM wParam,
681                      IN LPARAM lParam)
682 {
683     PDEVADVPROP_INFO dap;
684     INT_PTR Ret = FALSE;
685 
686     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
687 
688     if (dap != NULL || uMsg == WM_INITDIALOG)
689     {
690         switch (uMsg)
691         {
692             case WM_COMMAND:
693             {
694                 switch (LOWORD(wParam))
695                 {
696                     case IDC_DRIVERDETAILS:
697                         DialogBoxParam(hDllInstance,
698                                        MAKEINTRESOURCE(IDD_DRIVERDETAILS),
699                                        hwndDlg,
700                                        DriverDetailsDlgProc,
701                                        (ULONG_PTR)dap);
702                         break;
703 
704                     case IDC_UPDATEDRIVER:
705                         UpdateDriver(hwndDlg, dap);
706                         break;
707 
708                     case IDC_ROLLBACKDRIVER:
709                         // FIXME
710                         break;
711 
712                     case IDC_UNINSTALLDRIVER:
713                         UninstallDriver(hwndDlg, dap);
714                         break;
715                 }
716                 break;
717             }
718 
719             case WM_NOTIFY:
720             {
721                 NMHDR *hdr = (NMHDR*)lParam;
722                 switch (hdr->code)
723                 {
724                     case PSN_APPLY:
725                         break;
726                 }
727                 break;
728             }
729 
730             case WM_INITDIALOG:
731             {
732                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
733                 if (dap != NULL)
734                 {
735                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
736 
737                     UpdateDriverDlg(hwndDlg,
738                                     dap);
739                 }
740                 EnableWindow(GetDlgItem(hwndDlg, IDC_ROLLBACKDRIVER), FALSE);
741                 Ret = TRUE;
742                 break;
743             }
744         }
745     }
746 
747     return Ret;
748 }
749 
750 
751 static VOID
752 SetListViewText(HWND hwnd,
753                 INT iItem,
754                 LPCWSTR lpText)
755 {
756     LVITEM li;
757 
758     li.mask = LVIF_TEXT | LVIF_STATE;
759     li.iItem = iItem;
760     li.iSubItem = 0;
761     li.state = 0; //(li.iItem == 0 ? LVIS_SELECTED : 0);
762     li.stateMask = LVIS_SELECTED;
763     li.pszText = (LPWSTR)lpText;
764     (void)ListView_InsertItem(hwnd,
765                               &li);
766 }
767 
768 
769 static VOID
770 UpdateDetailsDlg(IN HWND hwndDlg,
771                  IN PDEVADVPROP_INFO dap)
772 {
773     HWND hwndComboBox;
774     HWND hwndListView;
775     LV_COLUMN lvc;
776     RECT rcClient;
777 
778     UINT i;
779     UINT Properties[] =
780     {
781         IDS_PROP_DEVICEID,
782         IDS_PROP_HARDWAREIDS,
783         IDS_PROP_COMPATIBLEIDS,
784         IDS_PROP_MATCHINGDEVICEID,
785         IDS_PROP_SERVICE,
786         IDS_PROP_ENUMERATOR,
787         IDS_PROP_CAPABILITIES,
788         IDS_PROP_DEVNODEFLAGS,
789         IDS_PROP_CONFIGFLAGS,
790         IDS_PROP_CSCONFIGFLAGS,
791         IDS_PROP_EJECTIONRELATIONS,
792         IDS_PROP_REMOVALRELATIONS,
793         IDS_PROP_BUSRELATIONS,
794         IDS_PROP_DEVUPPERFILTERS,
795         IDS_PROP_DEVLOWERFILTERS,
796         IDS_PROP_CLASSUPPERFILTERS,
797         IDS_PROP_CLASSLOWERFILTERS,
798         IDS_PROP_CLASSINSTALLER,
799         IDS_PROP_CLASSCOINSTALLER,
800         IDS_PROP_DEVICECOINSTALLER,
801         IDS_PROP_FIRMWAREREVISION,
802         IDS_PROP_CURRENTPOWERSTATE,
803         IDS_PROP_POWERCAPABILITIES,
804         IDS_PROP_POWERSTATEMAPPINGS
805     };
806 
807 
808     /* set the device image */
809     SendDlgItemMessage(hwndDlg,
810                        IDC_DEVICON,
811                        STM_SETICON,
812                        (WPARAM)dap->hDevIcon,
813                        0);
814 
815     /* set the device name edit control text */
816     SetDlgItemText(hwndDlg,
817                    IDC_DEVNAME,
818                    dap->szDevName);
819 
820 
821     hwndComboBox = GetDlgItem(hwndDlg,
822                               IDC_DETAILSPROPNAME);
823 
824     hwndListView = GetDlgItem(hwndDlg,
825                               IDC_DETAILSPROPVALUE);
826 
827     for (i = 0; i != sizeof(Properties) / sizeof(Properties[0]); i++)
828     {
829         /* fill in the device usage combo box */
830         if (LoadString(hDllInstance,
831                        Properties[i],
832                        dap->szTemp,
833                        sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
834         {
835             SendMessage(hwndComboBox,
836                         CB_ADDSTRING,
837                         0,
838                         (LPARAM)dap->szTemp);
839         }
840     }
841 
842 
843     GetClientRect(hwndListView,
844                   &rcClient);
845 
846     /* add a column to the list view control */
847     lvc.mask = LVCF_FMT | LVCF_WIDTH;
848     lvc.fmt = LVCFMT_LEFT;
849     lvc.cx = rcClient.right;
850     (void)ListView_InsertColumn(hwndListView,
851                                 0,
852                                 &lvc);
853 
854     SendMessage(hwndComboBox,
855                 CB_SETCURSEL,
856                 0,
857                 0);
858 
859     SetListViewText(hwndListView, 0, dap->szDeviceID);
860 
861     SetFocus(hwndComboBox);
862 }
863 
864 
865 static VOID
866 DisplayDevicePropertyText(IN PDEVADVPROP_INFO dap,
867                           IN HWND hwndListView,
868                           IN DWORD dwProperty)
869 {
870     HDEVINFO DeviceInfoSet;
871     PSP_DEVINFO_DATA DeviceInfoData;
872     DWORD dwType;
873     DWORD dwSize;
874     DWORD dwValue;
875     LPBYTE lpBuffer;
876     LPWSTR lpStr;
877     INT len;
878     INT index;
879 
880     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
881     {
882         DeviceInfoSet = dap->CurrentDeviceInfoSet;
883         DeviceInfoData = &dap->CurrentDeviceInfoData;
884     }
885     else
886     {
887         DeviceInfoSet = dap->DeviceInfoSet;
888         DeviceInfoData = &dap->DeviceInfoData;
889     }
890 
891     dwSize = 0;
892     SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
893                                      DeviceInfoData,
894                                      dwProperty,
895                                      &dwType,
896                                      NULL,
897                                      0,
898                                      &dwSize);
899     if (dwSize == 0)
900     {
901         if (GetLastError() != ERROR_FILE_NOT_FOUND)
902         {
903             swprintf(dap->szTemp, L"Error: Getting the size failed! (Error: %ld)", GetLastError());
904             SetListViewText(hwndListView, 0, dap->szTemp);
905         }
906         return;
907     }
908 
909     if (dwType == REG_SZ)
910         dwSize += sizeof(WCHAR);
911 
912     lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
913                                  HEAP_ZERO_MEMORY,
914                                  dwSize);
915     if (lpBuffer == NULL)
916     {
917         SetListViewText(hwndListView, 0, L"Error: Allocating the buffer failed!");
918         return;
919     }
920 
921     if (SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
922                                          DeviceInfoData,
923                                          dwProperty,
924                                          &dwType,
925                                          lpBuffer,
926                                          dwSize,
927                                          &dwSize))
928     {
929         if (dwType == REG_SZ)
930         {
931             SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
932         }
933         else if (dwType == REG_MULTI_SZ)
934         {
935             lpStr = (LPWSTR)lpBuffer;
936             index = 0;
937             while (*lpStr != 0)
938             {
939                 len = wcslen(lpStr) + 1;
940 
941                 SetListViewText(hwndListView, index, lpStr);
942 
943                 lpStr += len;
944                 index++;
945             }
946         }
947         else if (dwType == REG_DWORD)
948         {
949             dwValue = *(DWORD *) lpBuffer;
950 
951             switch (dwProperty)
952             {
953                 case SPDRP_CAPABILITIES:
954                     index = 0;
955                     swprintf(dap->szTemp, L"%08lx", dwValue);
956                     SetListViewText(hwndListView, index++, dap->szTemp);
957                     if (dwValue & CM_DEVCAP_LOCKSUPPORTED)
958                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_LOCKSUPPORTED");
959                     if (dwValue & CM_DEVCAP_EJECTSUPPORTED)
960                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_EJECTSUPPORTED");
961                     if (dwValue & CM_DEVCAP_REMOVABLE)
962                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_REMOVABLE");
963                     if (dwValue & CM_DEVCAP_DOCKDEVICE)
964                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_DOCKDEVICE");
965                     if (dwValue & CM_DEVCAP_UNIQUEID)
966                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_UNIQUEID");
967                     if (dwValue & CM_DEVCAP_SILENTINSTALL)
968                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_SILENTINSTALL");
969                     if (dwValue & CM_DEVCAP_RAWDEVICEOK)
970                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_RAWDEVICEOK");
971                     if (dwValue & CM_DEVCAP_SURPRISEREMOVALOK)
972                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_SURPRISEREMOVALOK");
973                     if (dwValue & CM_DEVCAP_HARDWAREDISABLED)
974                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_HARDWAREDISABLED");
975                     if (dwValue & CM_DEVCAP_NONDYNAMIC)
976                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_NONDYNAMIC");
977                     break;
978 
979                 case SPDRP_CONFIGFLAGS:
980                     index = 0;
981                     swprintf(dap->szTemp, L"%08lx", dwValue);
982                     SetListViewText(hwndListView, index++, dap->szTemp);
983                     if (dwValue & CONFIGFLAG_DISABLED)
984                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_DISABLED");
985                     if (dwValue & CONFIGFLAG_REMOVED)
986                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_REMOVED");
987                     if (dwValue & CONFIGFLAG_MANUAL_INSTALL)
988                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_MANUAL_INSTALL");
989                     if (dwValue & CONFIGFLAG_IGNORE_BOOT_LC)
990                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_IGNORE_BOOT_LC");
991                     if (dwValue & CONFIGFLAG_NET_BOOT)
992                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_NET_BOOT");
993                     if (dwValue & CONFIGFLAG_REINSTALL)
994                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_REINSTALL");
995                     if (dwValue & CONFIGFLAG_FAILEDINSTALL)
996                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_FAILEDINSTALL");
997                     if (dwValue & CONFIGFLAG_CANTSTOPACHILD)
998                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_CANTSTOPACHILD");
999                     if (dwValue & CONFIGFLAG_OKREMOVEROM)
1000                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_OKREMOVEROM");
1001                     if (dwValue & CONFIGFLAG_NOREMOVEEXIT)
1002                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_NOREMOVEEXIT");
1003                     break;
1004 
1005                 default:
1006                     swprintf(dap->szTemp, L"0x%08lx", dwValue);
1007                     SetListViewText(hwndListView, 0, dap->szTemp);
1008                     break;
1009             }
1010         }
1011         else
1012         {
1013             SetListViewText(hwndListView, 0, L"Error: Unsupported value type!");
1014 
1015         }
1016     }
1017     else
1018     {
1019         SetListViewText(hwndListView, 0, L"Error: Retrieving the value failed!");
1020     }
1021 
1022     HeapFree(GetProcessHeap(),
1023              0,
1024              lpBuffer);
1025 }
1026 
1027 static VOID
1028 DisplayDevNodeFlags(IN PDEVADVPROP_INFO dap,
1029                     IN HWND hwndListView)
1030 {
1031     DWORD dwStatus = 0;
1032     DWORD dwProblem = 0;
1033     INT index;
1034 
1035     CM_Get_DevNode_Status_Ex(&dwStatus,
1036                              &dwProblem,
1037                              dap->DeviceInfoData.DevInst,
1038                              0,
1039                              dap->hMachine);
1040 
1041     index = 0;
1042     swprintf(dap->szTemp, L"%08lx", dwStatus);
1043     SetListViewText(hwndListView, index++, dap->szTemp);
1044     if (dwStatus & DN_ROOT_ENUMERATED)
1045         SetListViewText(hwndListView, index++, L"DN_ROOT_ENUMERATED");
1046     if (dwStatus & DN_DRIVER_LOADED)
1047         SetListViewText(hwndListView, index++, L"DN_DRIVER_LOADED");
1048     if (dwStatus & DN_ENUM_LOADED)
1049         SetListViewText(hwndListView, index++, L"DN_ENUM_LOADED");
1050     if (dwStatus & DN_STARTED)
1051         SetListViewText(hwndListView, index++, L"DN_STARTED");
1052     if (dwStatus & DN_MANUAL)
1053         SetListViewText(hwndListView, index++, L"DN_MANUAL");
1054     if (dwStatus & DN_NEED_TO_ENUM)
1055         SetListViewText(hwndListView, index++, L"DN_NEED_TO_ENUM");
1056     if (dwStatus & DN_DRIVER_BLOCKED)
1057         SetListViewText(hwndListView, index++, L"DN_DRIVER_BLOCKED");
1058     if (dwStatus & DN_HARDWARE_ENUM)
1059         SetListViewText(hwndListView, index++, L"DN_HARDWARE_ENUM");
1060     if (dwStatus & DN_NEED_RESTART)
1061         SetListViewText(hwndListView, index++, L"DN_NEED_RESTART");
1062     if (dwStatus & DN_CHILD_WITH_INVALID_ID)
1063         SetListViewText(hwndListView, index++, L"DN_CHILD_WITH_INVALID_ID");
1064     if (dwStatus & DN_HAS_PROBLEM)
1065         SetListViewText(hwndListView, index++, L"DN_HAS_PROBLEM");
1066     if (dwStatus & DN_FILTERED)
1067         SetListViewText(hwndListView, index++, L"DN_FILTERED");
1068     if (dwStatus & DN_LEGACY_DRIVER)
1069         SetListViewText(hwndListView, index++, L"DN_LEGACY_DRIVER");
1070     if (dwStatus & DN_DISABLEABLE)
1071         SetListViewText(hwndListView, index++, L"DN_DISABLEABLE");
1072     if (dwStatus & DN_REMOVABLE)
1073         SetListViewText(hwndListView, index++, L"DN_REMOVABLE");
1074     if (dwStatus & DN_PRIVATE_PROBLEM)
1075         SetListViewText(hwndListView, index++, L"DN_PRIVATE_PROBLEM");
1076     if (dwStatus & DN_MF_PARENT)
1077         SetListViewText(hwndListView, index++, L"DN_MF_PARENT");
1078     if (dwStatus & DN_MF_CHILD)
1079         SetListViewText(hwndListView, index++, L"DN_MF_CHILD");
1080     if (dwStatus & DN_WILL_BE_REMOVED)
1081         SetListViewText(hwndListView, index++, L"DN_WILL_BE_REMOVED");
1082 
1083     if (dwStatus & DN_NOT_FIRST_TIMEE)
1084         SetListViewText(hwndListView, index++, L"DN_NOT_FIRST_TIMEE");
1085     if (dwStatus & DN_STOP_FREE_RES)
1086         SetListViewText(hwndListView, index++, L"DN_STOP_FREE_RES");
1087     if (dwStatus & DN_REBAL_CANDIDATE)
1088         SetListViewText(hwndListView, index++, L"DN_REBAL_CANDIDATE");
1089     if (dwStatus & DN_BAD_PARTIAL)
1090         SetListViewText(hwndListView, index++, L"DN_BAD_PARTIAL");
1091     if (dwStatus & DN_NT_ENUMERATOR)
1092         SetListViewText(hwndListView, index++, L"DN_NT_ENUMERATOR");
1093     if (dwStatus & DN_NT_DRIVER)
1094         SetListViewText(hwndListView, index++, L"DN_NT_DRIVER");
1095 
1096     if (dwStatus & DN_NEEDS_LOCKING)
1097         SetListViewText(hwndListView, index++, L"DN_NEEDS_LOCKING");
1098     if (dwStatus & DN_ARM_WAKEUP)
1099         SetListViewText(hwndListView, index++, L"DN_ARM_WAKEUP");
1100     if (dwStatus & DN_APM_ENUMERATOR)
1101         SetListViewText(hwndListView, index++, L"DN_APM_ENUMERATOR");
1102     if (dwStatus & DN_APM_DRIVER)
1103         SetListViewText(hwndListView, index++, L"DN_APM_DRIVER");
1104     if (dwStatus & DN_SILENT_INSTALL)
1105         SetListViewText(hwndListView, index++, L"DN_SILENT_INSTALL");
1106     if (dwStatus & DN_NO_SHOW_IN_DM)
1107         SetListViewText(hwndListView, index++, L"DN_NO_SHOW_IN_DM");
1108     if (dwStatus & DN_BOOT_LOG_PROB)
1109         SetListViewText(hwndListView, index++, L"DN_BOOT_LOG_PROB");
1110 }
1111 
1112 
1113 static VOID
1114 DisplayDevNodeEnumerator(IN PDEVADVPROP_INFO dap,
1115                          IN HWND hwndListView)
1116 {
1117     PSP_DEVINFO_DATA DeviceInfoData;
1118 
1119     DWORD dwType = 0;
1120     WCHAR szBuffer[256];
1121     DWORD dwSize = 256 * sizeof(WCHAR);
1122 
1123     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1124     {
1125         DeviceInfoData = &dap->CurrentDeviceInfoData;
1126     }
1127     else
1128     {
1129         DeviceInfoData = &dap->DeviceInfoData;
1130     }
1131 
1132     CM_Get_DevNode_Registry_Property_ExW(DeviceInfoData->DevInst,
1133                                          CM_DRP_ENUMERATOR_NAME,
1134                                          &dwType,
1135                                          &szBuffer,
1136                                          &dwSize,
1137                                          0,
1138                                          dap->hMachine);
1139 
1140     SetListViewText(hwndListView, 0, szBuffer);
1141 }
1142 
1143 
1144 static VOID
1145 DisplayCsFlags(IN PDEVADVPROP_INFO dap,
1146                IN HWND hwndListView)
1147 {
1148     DWORD dwValue = 0;
1149     INT index;
1150 
1151     CM_Get_HW_Prof_Flags_Ex(dap->szDevName,
1152                             0, /* current hardware profile */
1153                             &dwValue,
1154                             0,
1155                             dap->hMachine);
1156 
1157     index = 0;
1158     swprintf(dap->szTemp, L"%08lx", dwValue);
1159     SetListViewText(hwndListView, index++, dap->szTemp);
1160 
1161     if (dwValue & CSCONFIGFLAG_DISABLED)
1162         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DISABLED");
1163 
1164     if (dwValue & CSCONFIGFLAG_DO_NOT_CREATE)
1165         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_CREATE");
1166 
1167     if (dwValue & CSCONFIGFLAG_DO_NOT_START)
1168         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_START");
1169 }
1170 
1171 
1172 static VOID
1173 DisplayMatchingDeviceId(IN PDEVADVPROP_INFO dap,
1174                         IN HWND hwndListView)
1175 {
1176     HDEVINFO DeviceInfoSet;
1177     PSP_DEVINFO_DATA DeviceInfoData;
1178     WCHAR szBuffer[256];
1179     HKEY hKey;
1180     DWORD dwSize;
1181     DWORD dwType;
1182 
1183     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1184     {
1185         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1186         DeviceInfoData = &dap->CurrentDeviceInfoData;
1187     }
1188     else
1189     {
1190         DeviceInfoSet = dap->DeviceInfoSet;
1191         DeviceInfoData = &dap->DeviceInfoData;
1192     }
1193 
1194     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
1195                                 DeviceInfoData,
1196                                 DICS_FLAG_GLOBAL,
1197                                 0,
1198                                 DIREG_DRV,
1199                                 KEY_QUERY_VALUE);
1200     if (hKey != INVALID_HANDLE_VALUE)
1201     {
1202         dwSize = 256 * sizeof(WCHAR);
1203         if (RegQueryValueEx(hKey,
1204                             L"MatchingDeviceId",
1205                             NULL,
1206                             &dwType,
1207                             (LPBYTE)szBuffer,
1208                             &dwSize) == ERROR_SUCCESS)
1209         {
1210             SetListViewText(hwndListView, 0, szBuffer);
1211         }
1212 
1213         RegCloseKey(hKey);
1214     }
1215 }
1216 
1217 
1218 static VOID
1219 DisplayClassCoinstallers(IN PDEVADVPROP_INFO dap,
1220                           IN HWND hwndListView)
1221 {
1222     HDEVINFO DeviceInfoSet;
1223     PSP_DEVINFO_DATA DeviceInfoData;
1224     WCHAR szClassGuid[45];
1225     HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
1226     DWORD dwSize;
1227     DWORD dwType;
1228     LPBYTE lpBuffer = NULL;
1229     LPWSTR lpStr;
1230     INT index;
1231     INT len;
1232     LONG lError;
1233 
1234     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1235     {
1236         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1237         DeviceInfoData = &dap->CurrentDeviceInfoData;
1238     }
1239     else
1240     {
1241         DeviceInfoSet = dap->DeviceInfoSet;
1242         DeviceInfoData = &dap->DeviceInfoData;
1243     }
1244 
1245     dwSize = 45 * sizeof(WCHAR);
1246     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1247                                           DeviceInfoData,
1248                                           SPDRP_CLASSGUID,
1249                                           &dwType,
1250                                           (LPBYTE)szClassGuid,
1251                                           dwSize,
1252                                           &dwSize))
1253         return;
1254 
1255     lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1256                            L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
1257                            0,
1258                            GENERIC_READ,
1259                            &hKey);
1260     if (lError != ERROR_SUCCESS)
1261         return;
1262 
1263     dwSize = 0;
1264     lError = RegQueryValueEx(hKey,
1265                              szClassGuid,
1266                              NULL,
1267                              &dwType,
1268                              NULL,
1269                              &dwSize);
1270     if (lError != ERROR_SUCCESS)
1271         goto done;
1272 
1273     if (dwSize == 0)
1274         goto done;
1275 
1276     lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1277                                  HEAP_ZERO_MEMORY,
1278                                  dwSize);
1279 
1280     RegQueryValueEx(hKey,
1281                     szClassGuid,
1282                     NULL,
1283                     &dwType,
1284                     lpBuffer,
1285                     &dwSize);
1286 
1287     lpStr = (LPWSTR)lpBuffer;
1288     index = 0;
1289     while (*lpStr != 0)
1290     {
1291         len = wcslen(lpStr) + 1;
1292 
1293         SetListViewText(hwndListView, index, lpStr);
1294 
1295         lpStr += len;
1296         index++;
1297     }
1298 
1299 done:
1300     if (lpBuffer != NULL)
1301         HeapFree(GetProcessHeap(), 0, lpBuffer);
1302 
1303     if (hKey != INVALID_HANDLE_VALUE)
1304         RegCloseKey(hKey);
1305 }
1306 
1307 
1308 static VOID
1309 DisplayDeviceCoinstallers(IN PDEVADVPROP_INFO dap,
1310                           IN HWND hwndListView)
1311 {
1312     HDEVINFO DeviceInfoSet;
1313     PSP_DEVINFO_DATA DeviceInfoData;
1314     HKEY hKey;
1315     DWORD dwSize;
1316     DWORD dwType;
1317     LPBYTE lpBuffer;
1318     LPWSTR lpStr;
1319     INT index;
1320     INT len;
1321 
1322     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1323     {
1324         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1325         DeviceInfoData = &dap->CurrentDeviceInfoData;
1326     }
1327     else
1328     {
1329         DeviceInfoSet = dap->DeviceInfoSet;
1330         DeviceInfoData = &dap->DeviceInfoData;
1331     }
1332 
1333     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
1334                                 DeviceInfoData,
1335                                 DICS_FLAG_GLOBAL,
1336                                 0,
1337                                 DIREG_DRV,
1338                                 KEY_QUERY_VALUE);
1339     if (hKey != INVALID_HANDLE_VALUE)
1340     {
1341         dwSize = 0;
1342         if (RegQueryValueEx(hKey,
1343                             L"CoInstallers32",
1344                             NULL,
1345                             &dwType,
1346                             NULL,
1347                             &dwSize) == ERROR_SUCCESS &&
1348             dwSize > 0)
1349         {
1350 
1351             lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1352                                          HEAP_ZERO_MEMORY,
1353                                          dwSize);
1354 
1355             RegQueryValueEx(hKey,
1356                             L"CoInstallers32",
1357                             NULL,
1358                             &dwType,
1359                             lpBuffer,
1360                             &dwSize);
1361 
1362             lpStr = (LPWSTR)lpBuffer;
1363             index = 0;
1364             while (*lpStr != 0)
1365             {
1366                 len = wcslen(lpStr) + 1;
1367 
1368                 SetListViewText(hwndListView, index, lpStr);
1369 
1370                 lpStr += len;
1371                 index++;
1372             }
1373 
1374             HeapFree(GetProcessHeap(),
1375                      0,
1376                      lpBuffer);
1377         }
1378 
1379         RegCloseKey(hKey);
1380     }
1381 }
1382 
1383 
1384 static VOID
1385 DisplayClassProperties(IN PDEVADVPROP_INFO dap,
1386                        IN HWND hwndListView,
1387                        IN LPCWSTR lpProperty)
1388 {
1389     HDEVINFO DeviceInfoSet;
1390     PSP_DEVINFO_DATA DeviceInfoData;
1391     WCHAR szClassGuid[45];
1392     DWORD dwSize;
1393     DWORD dwType;
1394     HKEY hKey;
1395     GUID ClassGuid;
1396     LPBYTE lpBuffer;
1397     LPWSTR lpStr;
1398     INT index = 0;
1399     INT len;
1400 
1401     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1402     {
1403         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1404         DeviceInfoData = &dap->CurrentDeviceInfoData;
1405     }
1406     else
1407     {
1408         DeviceInfoSet = dap->DeviceInfoSet;
1409         DeviceInfoData = &dap->DeviceInfoData;
1410     }
1411 
1412     dwSize = 45 * sizeof(WCHAR);
1413     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1414                                           DeviceInfoData,
1415                                           SPDRP_CLASSGUID,
1416                                           &dwType,
1417                                           (LPBYTE)szClassGuid,
1418                                           dwSize,
1419                                           &dwSize))
1420         return;
1421 
1422     pSetupGuidFromString(szClassGuid,
1423                          &ClassGuid);
1424 
1425     hKey = SetupDiOpenClassRegKey(&ClassGuid,
1426                                   KEY_QUERY_VALUE);
1427     if (hKey != INVALID_HANDLE_VALUE)
1428     {
1429         dwSize = 0;
1430         if (RegQueryValueEx(hKey,
1431                             lpProperty,
1432                             NULL,
1433                             &dwType,
1434                             NULL,
1435                             &dwSize) == ERROR_SUCCESS &&
1436             dwSize > 0)
1437         {
1438             lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1439                                          HEAP_ZERO_MEMORY,
1440                                          dwSize);
1441 
1442             RegQueryValueEx(hKey,
1443                             lpProperty,
1444                             NULL,
1445                             &dwType,
1446                             lpBuffer,
1447                             &dwSize);
1448 
1449             if (dwType == REG_SZ)
1450             {
1451                 SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
1452             }
1453             else if (dwType == REG_MULTI_SZ)
1454             {
1455                 lpStr = (LPWSTR)lpBuffer;
1456                 index = 0;
1457                 while (*lpStr != 0)
1458                 {
1459                     len = wcslen(lpStr) + 1;
1460 
1461                     SetListViewText(hwndListView, index, lpStr);
1462 
1463                     lpStr += len;
1464                     index++;
1465                 }
1466             }
1467 
1468             HeapFree(GetProcessHeap(),
1469                      0,
1470                      lpBuffer);
1471         }
1472 
1473         RegCloseKey(hKey);
1474     }
1475 }
1476 
1477 
1478 static VOID
1479 DisplayDeviceRelations(
1480     IN PDEVADVPROP_INFO dap,
1481     IN HWND hwndListView,
1482     IN ULONG ulFlags)
1483 {
1484     ULONG ulLength = 0;
1485     LPWSTR pszBuffer = NULL, pszStr;
1486     INT index = 0, len;
1487     CONFIGRET ret;
1488 
1489     ret = CM_Get_Device_ID_List_Size_ExW(&ulLength,
1490                                          dap->szDeviceID,
1491                                          ulFlags,
1492                                          NULL);
1493     if (ret != CR_SUCCESS)
1494         return;
1495 
1496     pszBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(),
1497                                   HEAP_ZERO_MEMORY,
1498                                   ulLength * sizeof(WCHAR));
1499     if (pszBuffer == NULL)
1500         return;
1501 
1502     ret = CM_Get_Device_ID_List_ExW(dap->szDeviceID,
1503                                     pszBuffer,
1504                                     ulLength,
1505                                     ulFlags,
1506                                     NULL);
1507     if (ret != CR_SUCCESS)
1508     {
1509         HeapFree(GetProcessHeap(), 0, pszBuffer);
1510         return;
1511     }
1512 
1513     pszStr = pszBuffer;
1514     index = 0;
1515     while (*pszStr != 0)
1516     {
1517         len = wcslen(pszStr) + 1;
1518 
1519         SetListViewText(hwndListView, index, pszStr);
1520 
1521         pszStr += len;
1522         index++;
1523     }
1524 
1525     HeapFree(GetProcessHeap(), 0, pszBuffer);
1526 }
1527 
1528 
1529 static VOID
1530 DisplayCurrentPowerState(
1531     IN PDEVADVPROP_INFO dap,
1532     IN HWND hwndListView)
1533 {
1534     HDEVINFO DeviceInfoSet;
1535     PSP_DEVINFO_DATA DeviceInfoData;
1536     CM_POWER_DATA PowerData;
1537     DWORD dwSize, dwType;
1538     PCWSTR lpText = NULL;
1539 
1540     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1541     {
1542         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1543         DeviceInfoData = &dap->CurrentDeviceInfoData;
1544     }
1545     else
1546     {
1547         DeviceInfoSet = dap->DeviceInfoSet;
1548         DeviceInfoData = &dap->DeviceInfoData;
1549     }
1550 
1551     dwSize = sizeof(CM_POWER_DATA);
1552     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1553                                           DeviceInfoData,
1554                                           SPDRP_DEVICE_POWER_DATA,
1555                                           &dwType,
1556                                           (LPBYTE)&PowerData,
1557                                           dwSize,
1558                                           &dwSize))
1559         return;
1560 
1561     switch (PowerData.PD_MostRecentPowerState)
1562     {
1563 //        case PowerDeviceUnspecified:
1564 
1565         case PowerDeviceD0:
1566             lpText = L"D0";
1567             break;
1568 
1569         case PowerDeviceD1:
1570             lpText = L"D1";
1571             break;
1572 
1573         case PowerDeviceD2:
1574             lpText = L"D2";
1575             break;
1576 
1577         case PowerDeviceD3:
1578             lpText = L"D3";
1579             break;
1580 
1581         default:
1582             break;
1583     }
1584 
1585     if (lpText != NULL)
1586         SetListViewText(hwndListView, 0, lpText);
1587 }
1588 
1589 
1590 static VOID
1591 DisplayPowerCapabilities(
1592     IN PDEVADVPROP_INFO dap,
1593     IN HWND hwndListView)
1594 {
1595     HDEVINFO DeviceInfoSet;
1596     PSP_DEVINFO_DATA DeviceInfoData;
1597     CM_POWER_DATA PowerData;
1598     DWORD dwSize, dwType;
1599     INT index = 0;
1600 
1601     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1602     {
1603         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1604         DeviceInfoData = &dap->CurrentDeviceInfoData;
1605     }
1606     else
1607     {
1608         DeviceInfoSet = dap->DeviceInfoSet;
1609         DeviceInfoData = &dap->DeviceInfoData;
1610     }
1611 
1612     dwSize = sizeof(CM_POWER_DATA);
1613     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1614                                           DeviceInfoData,
1615                                           SPDRP_DEVICE_POWER_DATA,
1616                                           &dwType,
1617                                           (LPBYTE)&PowerData,
1618                                           dwSize,
1619                                           &dwSize))
1620         return;
1621 
1622     if (PowerData.PD_Capabilities & PDCAP_D0_SUPPORTED)
1623         SetListViewText(hwndListView, index++, L"PDCAP_D0_SUPPORTED");
1624 
1625     if (PowerData.PD_Capabilities & PDCAP_D1_SUPPORTED)
1626         SetListViewText(hwndListView, index++, L"PDCAP_D1_SUPPORTED");
1627 
1628     if (PowerData.PD_Capabilities & PDCAP_D2_SUPPORTED)
1629         SetListViewText(hwndListView, index++, L"PDCAP_D2_SUPPORTED");
1630 
1631     if (PowerData.PD_Capabilities & PDCAP_D3_SUPPORTED)
1632         SetListViewText(hwndListView, index++, L"PDCAP_D3_SUPPORTED");
1633 
1634     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D0_SUPPORTED)
1635         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D0_SUPPORTED");
1636 
1637     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D1_SUPPORTED)
1638         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D1_SUPPORTED");
1639 
1640     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D2_SUPPORTED)
1641         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D2_SUPPORTED");
1642 
1643     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D3_SUPPORTED)
1644         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D3_SUPPORTED");
1645 
1646     if (PowerData.PD_Capabilities & PDCAP_WARM_EJECT_SUPPORTED)
1647         SetListViewText(hwndListView, index++, L"PDCAP_WARM_EJECT_SUPPORTED");
1648 }
1649 
1650 
1651 static VOID
1652 DisplayPowerStateMappings(
1653     IN PDEVADVPROP_INFO dap,
1654     IN HWND hwndListView)
1655 {
1656     HDEVINFO DeviceInfoSet;
1657     PSP_DEVINFO_DATA DeviceInfoData;
1658     CM_POWER_DATA PowerData;
1659     DWORD dwSize, dwType;
1660     INT i;
1661     DEVICE_POWER_STATE PowerState;
1662     WCHAR szSystemStateBuffer[40];
1663     WCHAR szDeviceStateBuffer[40];
1664     WCHAR szOutBuffer[100];
1665 
1666     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1667     {
1668         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1669         DeviceInfoData = &dap->CurrentDeviceInfoData;
1670     }
1671     else
1672     {
1673         DeviceInfoSet = dap->DeviceInfoSet;
1674         DeviceInfoData = &dap->DeviceInfoData;
1675     }
1676 
1677     dwSize = sizeof(CM_POWER_DATA);
1678     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1679                                           DeviceInfoData,
1680                                           SPDRP_DEVICE_POWER_DATA,
1681                                           &dwType,
1682                                           (LPBYTE)&PowerData,
1683                                           dwSize,
1684                                           &dwSize))
1685         return;
1686 
1687     for (i = PowerSystemWorking; i < PowerSystemMaximum; i++)
1688     {
1689         PowerState = PowerData.PD_PowerStateMapping[i];
1690         if ((PowerState >= PowerDeviceUnspecified) && (PowerState <= PowerDeviceD3))
1691         {
1692             swprintf(szSystemStateBuffer, L"S%u", i - 1);
1693 
1694             switch (PowerState)
1695             {
1696                 case PowerDeviceUnspecified:
1697                     wcscpy(szDeviceStateBuffer, L"Not specified");
1698                     break;
1699 
1700                 case PowerDeviceD0:
1701                     wcscpy(szDeviceStateBuffer, L"D0");
1702                     break;
1703 
1704                 case PowerDeviceD1:
1705                     wcscpy(szDeviceStateBuffer, L"D1");
1706                     break;
1707 
1708                 case PowerDeviceD2:
1709                     wcscpy(szDeviceStateBuffer, L"D2");
1710                     break;
1711 
1712                 case PowerDeviceD3:
1713                     wcscpy(szDeviceStateBuffer, L"D3");
1714                     break;
1715 
1716                 default:
1717                     break;
1718             }
1719 
1720             swprintf(szOutBuffer, L"%s -> %s", szSystemStateBuffer, szDeviceStateBuffer);
1721             SetListViewText(hwndListView, i, szOutBuffer);
1722         }
1723     }
1724 }
1725 
1726 
1727 static VOID
1728 DisplayDeviceProperties(IN PDEVADVPROP_INFO dap,
1729                         IN HWND hwndComboBox,
1730                         IN HWND hwndListView)
1731 {
1732     INT Index;
1733 
1734     Index = (INT)SendMessage(hwndComboBox,
1735                              CB_GETCURSEL,
1736                              0,
1737                              0);
1738     if (Index == CB_ERR)
1739         return;
1740 
1741     (void)ListView_DeleteAllItems(hwndListView);
1742 
1743     switch (Index)
1744     {
1745         case 0: /* Device ID */
1746             SetListViewText(hwndListView, 0, dap->szDeviceID);
1747             break;
1748 
1749         case 1: /* Hardware ID */
1750             DisplayDevicePropertyText(dap,
1751                                       hwndListView,
1752                                       SPDRP_HARDWAREID);
1753             break;
1754 
1755         case 2: /* Compatible IDs */
1756             DisplayDevicePropertyText(dap,
1757                                       hwndListView,
1758                                       SPDRP_COMPATIBLEIDS);
1759             break;
1760 
1761         case 3: /* Matching ID */
1762             DisplayMatchingDeviceId(dap,
1763                                     hwndListView);
1764             break;
1765 
1766         case 4: /* Service */
1767             DisplayDevicePropertyText(dap,
1768                                       hwndListView,
1769                                       SPDRP_SERVICE);
1770             break;
1771 
1772         case 5: /* Enumerator */
1773             DisplayDevNodeEnumerator(dap,
1774                                      hwndListView);
1775             break;
1776 
1777         case 6: /* Capabilities */
1778             DisplayDevicePropertyText(dap,
1779                                       hwndListView,
1780                                       SPDRP_CAPABILITIES);
1781             break;
1782 
1783         case 7: /* Devnode Flags */
1784             DisplayDevNodeFlags(dap,
1785                                 hwndListView);
1786             break;
1787 
1788         case 8: /* Config Flags */
1789             DisplayDevicePropertyText(dap,
1790                                       hwndListView,
1791                                       SPDRP_CONFIGFLAGS);
1792             break;
1793 
1794         case 9: /* CSConfig Flags */
1795             DisplayCsFlags(dap,
1796                            hwndListView);
1797             break;
1798 
1799         case 10: /* Ejection relation */
1800             DisplayDeviceRelations(dap,
1801                                    hwndListView,
1802                                    CM_GETIDLIST_FILTER_EJECTRELATIONS);
1803             break;
1804 
1805         case 11: /* Removal relations */
1806             DisplayDeviceRelations(dap,
1807                                    hwndListView,
1808                                    CM_GETIDLIST_FILTER_REMOVALRELATIONS);
1809             break;
1810 
1811         case 12: /* Bus relation */
1812             DisplayDeviceRelations(dap,
1813                                    hwndListView,
1814                                    CM_GETIDLIST_FILTER_BUSRELATIONS);
1815             break;
1816 
1817         case 13: /* Device Upper Filters */
1818             DisplayDevicePropertyText(dap,
1819                                       hwndListView,
1820                                       SPDRP_UPPERFILTERS);
1821             break;
1822 
1823         case 14: /* Device Lower Filters */
1824             DisplayDevicePropertyText(dap,
1825                                       hwndListView,
1826                                       SPDRP_LOWERFILTERS);
1827             break;
1828 
1829         case 15: /* Class Upper Filters */
1830             DisplayClassProperties(dap,
1831                                    hwndListView,
1832                                    L"UpperFilters");
1833             break;
1834 
1835         case 16: /* Class Lower Filters */
1836             DisplayClassProperties(dap,
1837                                    hwndListView,
1838                                    L"LowerFilters");
1839             break;
1840 
1841         case 17: /* Class Installer */
1842             DisplayClassProperties(dap,
1843                                    hwndListView,
1844                                    L"Installer32");
1845             break;
1846 
1847         case 18: /* Class Coinstaller */
1848             DisplayClassCoinstallers(dap,
1849                                      hwndListView);
1850             break;
1851 
1852         case 19: /* Device Coinstaller */
1853             DisplayDeviceCoinstallers(dap,
1854                                       hwndListView);
1855             break;
1856 
1857 #if 0
1858         case 20: /* Firmware Revision */
1859             break;
1860 #endif
1861 
1862         case 21: /* Current Power State */
1863             DisplayCurrentPowerState(dap,
1864                                      hwndListView);
1865             break;
1866 
1867         case 22: /* Power Capabilities */
1868             DisplayPowerCapabilities(dap,
1869                                      hwndListView);
1870             break;
1871 
1872         case 23: /* Power State Mappings */
1873             DisplayPowerStateMappings(dap,
1874                                       hwndListView);
1875             break;
1876 
1877         default:
1878             SetListViewText(hwndListView, 0, L"<Not implemented yet>");
1879             break;
1880     }
1881 }
1882 
1883 
1884 static INT_PTR
1885 CALLBACK
1886 AdvProcDetailsDlgProc(IN HWND hwndDlg,
1887                       IN UINT uMsg,
1888                       IN WPARAM wParam,
1889                       IN LPARAM lParam)
1890 {
1891     PDEVADVPROP_INFO dap;
1892     INT_PTR Ret = FALSE;
1893 
1894     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
1895 
1896     if (dap != NULL || uMsg == WM_INITDIALOG)
1897     {
1898         switch (uMsg)
1899         {
1900             case WM_COMMAND:
1901             {
1902                 switch (LOWORD(wParam))
1903                 {
1904                     case IDC_DETAILSPROPNAME:
1905                         if (HIWORD(wParam) == CBN_SELCHANGE)
1906                         {
1907                             DisplayDeviceProperties(dap,
1908                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPNAME),
1909                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE));
1910                         }
1911                         break;
1912                 }
1913                 break;
1914             }
1915 
1916             case WM_NOTIFY:
1917             {
1918                 NMHDR *hdr = (NMHDR*)lParam;
1919                 switch (hdr->code)
1920                 {
1921                     case PSN_APPLY:
1922                         break;
1923                 }
1924                 break;
1925             }
1926 
1927             case WM_INITDIALOG:
1928             {
1929                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
1930                 if (dap != NULL)
1931                 {
1932                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
1933 
1934                     UpdateDetailsDlg(hwndDlg,
1935                                      dap);
1936                 }
1937                 Ret = TRUE;
1938                 break;
1939             }
1940         }
1941     }
1942 
1943     return Ret;
1944 }
1945 
1946 
1947 static VOID
1948 InitDevUsageActions(IN HWND hwndDlg,
1949                     IN HWND hComboBox,
1950                     IN PDEVADVPROP_INFO dap)
1951 {
1952     INT Index;
1953     UINT i;
1954     UINT Actions[] =
1955     {
1956         IDS_ENABLEDEVICE,
1957         IDS_DISABLEDEVICE,
1958     };
1959 
1960     for (i = 0;
1961          i != sizeof(Actions) / sizeof(Actions[0]);
1962          i++)
1963     {
1964         /* fill in the device usage combo box */
1965         if (LoadString(hDllInstance,
1966                        Actions[i],
1967                        dap->szTemp,
1968                        sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
1969         {
1970             Index = (INT)SendMessage(hComboBox,
1971                                      CB_ADDSTRING,
1972                                      0,
1973                                      (LPARAM)dap->szTemp);
1974             if (Index != CB_ERR)
1975             {
1976                 SendMessage(hComboBox,
1977                             CB_SETITEMDATA,
1978                             (WPARAM)Index,
1979                             (LPARAM)Actions[i]);
1980 
1981                 switch (Actions[i])
1982                 {
1983                     case IDS_ENABLEDEVICE:
1984                         if (dap->DeviceStarted)
1985                         {
1986                             SendMessage(hComboBox,
1987                                         CB_SETCURSEL,
1988                                         (WPARAM)Index,
1989                                         0);
1990                         }
1991                         break;
1992 
1993                     case IDS_DISABLEDEVICE:
1994                         if (!dap->DeviceStarted)
1995                         {
1996                             SendMessage(hComboBox,
1997                                         CB_SETCURSEL,
1998                                         (WPARAM)Index,
1999                                         0);
2000                         }
2001                         break;
2002 
2003                     default:
2004                         break;
2005                 }
2006             }
2007         }
2008     }
2009 }
2010 
2011 
2012 static UINT
2013 GetSelectedUsageAction(IN HWND hComboBox)
2014 {
2015     INT Index;
2016     UINT Ret = 0;
2017 
2018     Index = (INT)SendMessage(hComboBox,
2019                              CB_GETCURSEL,
2020                              0,
2021                              0);
2022     if (Index != CB_ERR)
2023     {
2024         INT iRet = (INT) SendMessage(hComboBox,
2025                                CB_GETITEMDATA,
2026                                (WPARAM)Index,
2027                                0);
2028         if (iRet != CB_ERR)
2029         {
2030             Ret = (UINT)iRet;
2031         }
2032     }
2033 
2034     return Ret;
2035 }
2036 
2037 
2038 static BOOL
2039 ApplyGeneralSettings(IN HWND hwndDlg,
2040                      IN PDEVADVPROP_INFO dap)
2041 {
2042     BOOL Ret = FALSE;
2043 
2044     if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
2045     {
2046         UINT SelectedUsageAction;
2047         BOOL NeedReboot = FALSE;
2048 
2049         SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
2050                                                                 IDC_DEVUSAGE));
2051         switch (SelectedUsageAction)
2052         {
2053             case IDS_ENABLEDEVICE:
2054                 if (!dap->DeviceStarted)
2055                 {
2056                     Ret = EnableDevice(dap->DeviceInfoSet,
2057                                        &dap->DeviceInfoData,
2058                                        TRUE,
2059                                        0,
2060                                        &NeedReboot);
2061                 }
2062                 break;
2063 
2064             case IDS_DISABLEDEVICE:
2065                 if (dap->DeviceStarted)
2066                 {
2067                     Ret = EnableDevice(dap->DeviceInfoSet,
2068                                        &dap->DeviceInfoData,
2069                                        FALSE,
2070                                        0,
2071                                        &NeedReboot);
2072                 }
2073                 break;
2074 
2075             default:
2076                 break;
2077         }
2078 
2079         if (Ret)
2080         {
2081             if (NeedReboot)
2082             {
2083                 /* make PropertySheet() return PSM_REBOOTSYSTEM */
2084                 PropSheet_RebootSystem(hwndDlg);
2085             }
2086         }
2087         else
2088         {
2089             /* FIXME - display an error message */
2090             FIXME("Failed to enable/disable device! LastError: %d\n",
2091                   GetLastError());
2092         }
2093     }
2094     else
2095         Ret = !dap->DeviceUsageChanged;
2096 
2097     /* disable the apply button */
2098     PropSheet_UnChanged(GetParent(hwndDlg),
2099                         hwndDlg);
2100     dap->DeviceUsageChanged = FALSE;
2101     return Ret;
2102 }
2103 
2104 
2105 static VOID
2106 UpdateDevInfo(IN HWND hwndDlg,
2107               IN PDEVADVPROP_INFO dap,
2108               IN BOOL ReOpen)
2109 {
2110     HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
2111     CONFIGRET cr;
2112     ULONG Status, ProblemNumber;
2113     SP_DEVINSTALL_PARAMS_W InstallParams;
2114     UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
2115     BOOL bFlag, bDevActionAvailable = TRUE;
2116     BOOL bDrvInstalled = FALSE;
2117     DWORD iPage;
2118     HDEVINFO DeviceInfoSet = NULL;
2119     PSP_DEVINFO_DATA DeviceInfoData = NULL;
2120     PROPSHEETHEADER psh;
2121     DWORD nDriverPages = 0;
2122     BOOL RecalcPages = FALSE;
2123 
2124     hPropSheetDlg = GetParent(hwndDlg);
2125 
2126     if (dap->PageInitialized)
2127     {
2128         /* switch to the General page */
2129         PropSheet_SetCurSelByID(hPropSheetDlg,
2130                                 IDD_DEVICEGENERAL);
2131 
2132         /* remove and destroy the existing device property sheet pages */
2133         if (dap->DevPropSheets != NULL)
2134         {
2135             for (iPage = 0;
2136                  iPage != dap->nDevPropSheets;
2137                  iPage++)
2138             {
2139                 if (dap->DevPropSheets[iPage] != NULL)
2140                 {
2141                     PropSheet_RemovePage(hPropSheetDlg,
2142                                          (WPARAM) -1,
2143                                          dap->DevPropSheets[iPage]);
2144                     RecalcPages = TRUE;
2145                 }
2146             }
2147         }
2148     }
2149 
2150     iPage = 0;
2151 
2152     if (dap->FreeDevPropSheets)
2153     {
2154         /* don't free the array if it's the one allocated in
2155            DisplayDeviceAdvancedProperties */
2156         HeapFree(GetProcessHeap(),
2157                  0,
2158                  dap->DevPropSheets);
2159 
2160         dap->FreeDevPropSheets = FALSE;
2161     }
2162 
2163     dap->DevPropSheets = NULL;
2164     dap->nDevPropSheets = 0;
2165 
2166     if (ReOpen)
2167     {
2168         /* create a new device info set and re-open the device */
2169         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2170         {
2171             SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
2172         }
2173 
2174         dap->ParentDevInst = 0;
2175         dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
2176                                                                   hwndDlg,
2177                                                                   dap->lpMachineName,
2178                                                                   NULL);
2179         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2180         {
2181             if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
2182                                       dap->szDeviceID,
2183                                       hwndDlg,
2184                                       0,
2185                                       &dap->CurrentDeviceInfoData))
2186             {
2187                 if (dap->CloseDevInst)
2188                 {
2189                     SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
2190                 }
2191 
2192                 dap->CloseDevInst = TRUE;
2193                 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
2194                 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
2195                 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
2196             }
2197             else
2198                 goto GetParentNode;
2199         }
2200         else
2201         {
2202 GetParentNode:
2203             /* get the parent node from the initial devinst */
2204             CM_Get_Parent_Ex(&dap->ParentDevInst,
2205                              dap->DeviceInfoData.DevInst,
2206                              0,
2207                              dap->hMachine);
2208         }
2209 
2210         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2211         {
2212             DeviceInfoSet = dap->CurrentDeviceInfoSet;
2213             DeviceInfoData = &dap->CurrentDeviceInfoData;
2214         }
2215         else
2216         {
2217             DeviceInfoSet = dap->DeviceInfoSet;
2218             DeviceInfoData = &dap->DeviceInfoData;
2219         }
2220     }
2221     else
2222     {
2223         DeviceInfoSet = dap->DeviceInfoSet;
2224         DeviceInfoData = &dap->DeviceInfoData;
2225     }
2226 
2227     dap->HasDriverPage = TRUE;
2228     dap->HasResourcePage = TRUE;
2229     dap->HasPowerPage = TRUE;
2230     if (IsDriverInstalled(DeviceInfoData->DevInst,
2231                           dap->hMachine,
2232                           &bDrvInstalled) &&
2233         bDrvInstalled)
2234     {
2235         if (SetupDiCallClassInstaller((dap->ShowRemotePages ?
2236                                            DIF_ADDREMOTEPROPERTYPAGE_ADVANCED :
2237                                            DIF_ADDPROPERTYPAGE_ADVANCED),
2238                                       DeviceInfoSet,
2239                                       DeviceInfoData))
2240         {
2241             /* get install params */
2242             InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2243             if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
2244                                                 DeviceInfoData,
2245                                                 &InstallParams))
2246             {
2247                 /* zero the flags */
2248                 InstallParams.Flags = 0;
2249                 InstallParams.FlagsEx = 0;
2250             }
2251 
2252             dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
2253             dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
2254             dap->HasPowerPage = !(InstallParams.FlagsEx & DI_FLAGSEX_POWERPAGE_ADDED);
2255         }
2256     }
2257 
2258     /* get the device icon */
2259     if (dap->hDevIcon != NULL)
2260     {
2261         DestroyIcon(dap->hDevIcon);
2262         dap->hDevIcon = NULL;
2263     }
2264     if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
2265                               &dap->hDevIcon,
2266                               NULL))
2267     {
2268         dap->hDevIcon = NULL;
2269     }
2270 
2271     /* get the device name */
2272     if (GetDeviceDescriptionString(DeviceInfoSet,
2273                                    DeviceInfoData,
2274                                    dap->szDevName,
2275                                    sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
2276     {
2277         PropSheet_SetTitle(hPropSheetDlg,
2278                            PSH_PROPTITLE,
2279                            dap->szDevName);
2280     }
2281 
2282     /* set the device image */
2283     SendDlgItemMessage(hwndDlg,
2284                        IDC_DEVICON,
2285                        STM_SETICON,
2286                        (WPARAM)dap->hDevIcon,
2287                        0);
2288 
2289     /* set the device name edit control text */
2290     SetDlgItemText(hwndDlg,
2291                    IDC_DEVNAME,
2292                    dap->szDevName);
2293 
2294     /* set the device type edit control text */
2295     if (GetDeviceTypeString(DeviceInfoData,
2296                             dap->szTemp,
2297                             sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2298     {
2299         SetDlgItemText(hwndDlg,
2300                        IDC_DEVTYPE,
2301                        dap->szTemp);
2302     }
2303 
2304     /* set the device manufacturer edit control text */
2305     if (GetDeviceManufacturerString(DeviceInfoSet,
2306                                     DeviceInfoData,
2307                                     dap->szTemp,
2308                                     sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2309     {
2310         SetDlgItemText(hwndDlg,
2311                        IDC_DEVMANUFACTURER,
2312                        dap->szTemp);
2313     }
2314 
2315     /* set the device location edit control text */
2316     if (GetDeviceLocationString(DeviceInfoSet,
2317                                 DeviceInfoData,
2318                                 dap->ParentDevInst,
2319                                 dap->szTemp,
2320                                 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2321     {
2322         SetDlgItemText(hwndDlg,
2323                        IDC_DEVLOCATION,
2324                        dap->szTemp);
2325     }
2326 
2327     /* set the device status edit control text */
2328     if (GetDeviceStatusString(DeviceInfoData->DevInst,
2329                               dap->hMachine,
2330                               dap->szTemp,
2331                               sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2332     {
2333         SetDlgItemText(hwndDlg,
2334                        IDC_DEVSTATUS,
2335                        dap->szTemp);
2336     }
2337 
2338     /* set the device troubleshoot button text and disable it if necessary */
2339     hDevProbBtn = GetDlgItem(hwndDlg,
2340                              IDC_DEVPROBLEM);
2341     cr = CM_Get_DevNode_Status_Ex(&Status,
2342                                   &ProblemNumber,
2343                                   DeviceInfoData->DevInst,
2344                                   0,
2345                                   dap->hMachine);
2346     if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
2347     {
2348         switch (ProblemNumber)
2349         {
2350             case CM_PROB_DEVLOADER_FAILED:
2351             {
2352                 /* FIXME - only if it's not a root bus devloader,
2353                            disable the button otherwise */
2354                 TroubleShootStrId = IDS_UPDATEDRV;
2355                 break;
2356             }
2357 
2358             case CM_PROB_OUT_OF_MEMORY:
2359             case CM_PROB_ENTRY_IS_WRONG_TYPE:
2360             case CM_PROB_LACKED_ARBITRATOR:
2361             case CM_PROB_FAILED_START:
2362             case CM_PROB_LIAR:
2363             case CM_PROB_UNKNOWN_RESOURCE:
2364             {
2365                 TroubleShootStrId = IDS_UPDATEDRV;
2366                 break;
2367             }
2368 
2369             case CM_PROB_BOOT_CONFIG_CONFLICT:
2370             case CM_PROB_NORMAL_CONFLICT:
2371             case CM_PROB_REENUMERATION:
2372             {
2373                 /* FIXME - Troubleshoot conflict */
2374                 break;
2375             }
2376 
2377             case CM_PROB_FAILED_FILTER:
2378             case CM_PROB_REINSTALL:
2379             case CM_PROB_FAILED_INSTALL:
2380             {
2381                 TroubleShootStrId = IDS_REINSTALLDRV;
2382                 break;
2383             }
2384 
2385             case CM_PROB_DEVLOADER_NOT_FOUND:
2386             {
2387                 /* FIXME - 4 cases:
2388                    1) if it's a missing system devloader:
2389                       - disable the button (Reinstall Driver)
2390                    2) if it's not a system devloader but still missing:
2391                       - Reinstall Driver
2392                    3) if it's not a system devloader but the file can be found:
2393                       - Update Driver
2394                    4) if it's a missing or empty software key
2395                       - Update Driver
2396                  */
2397                 break;
2398             }
2399 
2400             case CM_PROB_INVALID_DATA:
2401             case CM_PROB_PARTIAL_LOG_CONF:
2402             case CM_PROB_NO_VALID_LOG_CONF:
2403             case CM_PROB_HARDWARE_DISABLED:
2404             case CM_PROB_CANT_SHARE_IRQ:
2405             case CM_PROB_TRANSLATION_FAILED:
2406             case CM_PROB_SYSTEM_SHUTDOWN:
2407             case CM_PROB_PHANTOM:
2408                 bDevActionAvailable = FALSE;
2409                 break;
2410 
2411             case CM_PROB_NOT_VERIFIED:
2412             case CM_PROB_DEVICE_NOT_THERE:
2413                 /* FIXME - search hardware */
2414                 break;
2415 
2416             case CM_PROB_NEED_RESTART:
2417             case CM_PROB_WILL_BE_REMOVED:
2418             case CM_PROB_MOVED:
2419             case CM_PROB_TOO_EARLY:
2420             case CM_PROB_DISABLED_SERVICE:
2421                 TroubleShootStrId = IDS_REBOOT;
2422                 break;
2423 
2424             case CM_PROB_REGISTRY:
2425                 /* FIXME - check registry? */
2426                 break;
2427 
2428             case CM_PROB_DISABLED:
2429                 /* if device was disabled by the user: */
2430                 TroubleShootStrId = IDS_ENABLEDEV;
2431                 /* FIXME - otherwise disable button because the device was
2432                            disabled by the system*/
2433                 break;
2434 
2435             case CM_PROB_DEVLOADER_NOT_READY:
2436                 /* FIXME - if it's a graphics adapter:
2437                            - if it's a a secondary adapter and the main adapter
2438                              couldn't be found
2439                              - disable  button
2440                            - else
2441                              - Properties
2442                          - else
2443                            - Update driver
2444                  */
2445                 break;
2446 
2447             case CM_PROB_FAILED_ADD:
2448                 TroubleShootStrId = IDS_PROPERTIES;
2449                 break;
2450         }
2451     }
2452 
2453     if (LoadString(hDllInstance,
2454                    TroubleShootStrId,
2455                    dap->szTemp,
2456                    sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
2457     {
2458         SetWindowText(hDevProbBtn,
2459                       dap->szTemp);
2460     }
2461     EnableWindow(hDevProbBtn,
2462                  dap->IsAdmin && bDevActionAvailable);
2463 
2464     /* check if the device can be enabled/disabled */
2465     hDevUsage = GetDlgItem(hwndDlg,
2466                            IDC_DEVUSAGE);
2467 
2468     dap->CanDisable = FALSE;
2469     dap->DeviceStarted = FALSE;
2470 
2471     if (CanDisableDevice(DeviceInfoData->DevInst,
2472                          dap->hMachine,
2473                          &bFlag))
2474     {
2475         dap->CanDisable = bFlag;
2476     }
2477 
2478     if (IsDeviceStarted(DeviceInfoData->DevInst,
2479                         dap->hMachine,
2480                         &bFlag))
2481     {
2482         dap->DeviceStarted = bFlag;
2483     }
2484 
2485     /* enable/disable the device usage controls */
2486     EnableWindow(GetDlgItem(hwndDlg,
2487                             IDC_DEVUSAGELABEL),
2488                  dap->CanDisable && dap->IsAdmin);
2489     EnableWindow(hDevUsage,
2490                  dap->CanDisable && dap->IsAdmin);
2491 
2492     /* clear the combobox */
2493     SendMessage(hDevUsage,
2494                 CB_RESETCONTENT,
2495                 0,
2496                 0);
2497     if (dap->CanDisable)
2498     {
2499         InitDevUsageActions(hwndDlg,
2500                             hDevUsage,
2501                             dap);
2502     }
2503 
2504     /* find out how many new device property sheets to add.
2505        fake a PROPSHEETHEADER structure, we don't plan to
2506        call PropertySheet again!*/
2507     psh.dwSize = sizeof(PROPSHEETHEADER);
2508     psh.dwFlags = 0;
2509     psh.nPages = 0;
2510 
2511     /* get the number of device property sheets for the device */
2512     if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2513                                           DeviceInfoData,
2514                                           &psh,
2515                                           0,
2516                                           &nDriverPages,
2517                                           dap->PropertySheetType) &&
2518         nDriverPages != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2519     {
2520         dap->nDevPropSheets += nDriverPages;
2521     }
2522     else
2523     {
2524         nDriverPages = 0;
2525     }
2526 
2527     dap->pResourceList = GetResourceList(dap->szDeviceID);
2528 
2529     /* include the driver page */
2530     if (dap->HasDriverPage)
2531         dap->nDevPropSheets++;
2532 
2533     /* include the details page */
2534     if (dap->Extended)
2535         dap->nDevPropSheets++;
2536 
2537     if (dap->HasResourcePage && dap->pResourceList != NULL)
2538         dap->nDevPropSheets++;
2539 
2540     /* add the device property sheets */
2541     if (dap->nDevPropSheets != 0)
2542     {
2543         dap->DevPropSheets = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
2544                                                          HEAP_ZERO_MEMORY,
2545                                                          dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
2546         if (dap->DevPropSheets != NULL)
2547         {
2548             if (nDriverPages != 0)
2549             {
2550                 psh.phpage = dap->DevPropSheets;
2551 
2552                 /* query the device property sheet pages to add */
2553                 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2554                                                      DeviceInfoData,
2555                                                      &psh,
2556                                                      dap->nDevPropSheets,
2557                                                      NULL,
2558                                                      dap->PropertySheetType))
2559                 {
2560                     /* add the property sheets */
2561                     for (iPage = 0;
2562                          iPage < nDriverPages;
2563                          iPage++)
2564                     {
2565                         if (PropSheet_AddPage(hPropSheetDlg,
2566                                               dap->DevPropSheets[iPage]))
2567                         {
2568                             RecalcPages = TRUE;
2569                         }
2570                     }
2571 
2572                     dap->FreeDevPropSheets = TRUE;
2573                 }
2574                 else
2575                 {
2576                     /* cleanup, we were unable to get the device property sheets */
2577                     iPage = nDriverPages;
2578                     dap->nDevPropSheets -= nDriverPages;
2579                     nDriverPages = 0;
2580                 }
2581             }
2582             else
2583                 iPage = 0;
2584 
2585             /* add the driver page if necessary */
2586             if (dap->HasDriverPage)
2587             {
2588                 PROPSHEETPAGE pspDriver = {0};
2589                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2590                 pspDriver.dwFlags = PSP_DEFAULT;
2591                 pspDriver.hInstance = hDllInstance;
2592                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDRIVER);
2593                 pspDriver.pfnDlgProc = AdvProcDriverDlgProc;
2594                 pspDriver.lParam = (LPARAM)dap;
2595                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2596                 if (dap->DevPropSheets[iPage] != NULL)
2597                 {
2598                     if (PropSheet_AddPage(hPropSheetDlg,
2599                                           dap->DevPropSheets[iPage]))
2600                     {
2601                         iPage++;
2602                         RecalcPages = TRUE;
2603                     }
2604                     else
2605                     {
2606                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2607                         dap->DevPropSheets[iPage] = NULL;
2608                     }
2609                 }
2610             }
2611 
2612             if (dap->Extended)
2613             {
2614                 /* Add the details page */
2615                 PROPSHEETPAGE pspDetails = {0};
2616                 pspDetails.dwSize = sizeof(PROPSHEETPAGE);
2617                 pspDetails.dwFlags = PSP_DEFAULT;
2618                 pspDetails.hInstance = hDllInstance;
2619                 pspDetails.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDETAILS);
2620                 pspDetails.pfnDlgProc = AdvProcDetailsDlgProc;
2621                 pspDetails.lParam = (LPARAM)dap;
2622                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDetails);
2623                 if (dap->DevPropSheets[iPage] != NULL)
2624                 {
2625                     if (PropSheet_AddPage(hPropSheetDlg,
2626                                           dap->DevPropSheets[iPage]))
2627                     {
2628                         iPage++;
2629                         RecalcPages = TRUE;
2630                     }
2631                     else
2632                     {
2633                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2634                         dap->DevPropSheets[iPage] = NULL;
2635                     }
2636                 }
2637             }
2638 
2639             if (dap->HasResourcePage && dap->pResourceList)
2640             {
2641                 PROPSHEETPAGE pspDriver = {0};
2642                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2643                 pspDriver.dwFlags = PSP_DEFAULT;
2644                 pspDriver.hInstance = hDllInstance;
2645                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICERESOURCES);
2646                 pspDriver.pfnDlgProc = ResourcesProcDriverDlgProc;
2647                 pspDriver.lParam = (LPARAM)dap;
2648                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2649                 if (dap->DevPropSheets[iPage] != NULL)
2650                 {
2651                     if (PropSheet_AddPage(hPropSheetDlg,
2652                                           dap->DevPropSheets[iPage]))
2653                     {
2654                         iPage++;
2655                         RecalcPages = TRUE;
2656                     }
2657                     else
2658                     {
2659                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2660                         dap->DevPropSheets[iPage] = NULL;
2661                     }
2662                 }
2663             }
2664             /* FIXME: Add the power page */
2665         }
2666         else
2667             dap->nDevPropSheets = 0;
2668     }
2669 
2670     if (RecalcPages)
2671     {
2672         PropSheet_RecalcPageSizes(hPropSheetDlg);
2673     }
2674 
2675     /* finally, disable the apply button */
2676     PropSheet_UnChanged(hPropSheetDlg,
2677                         hwndDlg);
2678     dap->DeviceUsageChanged = FALSE;
2679 }
2680 
2681 
2682 static LRESULT
2683 CALLBACK
2684 DlgParentSubWndProc(IN HWND hwnd,
2685                     IN UINT uMsg,
2686                     IN WPARAM wParam,
2687                     IN LPARAM lParam)
2688 {
2689     PDEVADVPROP_INFO dap;
2690 
2691     dap = (PDEVADVPROP_INFO)GetProp(hwnd,
2692                                     L"DevMgrDevChangeSub");
2693     if (dap != NULL)
2694     {
2695         if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
2696         {
2697             SendMessage(dap->hWndGeneralPage,
2698                         WM_DEVICECHANGE,
2699                         wParam,
2700                         lParam);
2701         }
2702 
2703         /* pass the message the the old window proc */
2704         return CallWindowProc(dap->ParentOldWndProc,
2705                               hwnd,
2706                               uMsg,
2707                               wParam,
2708                               lParam);
2709     }
2710     else
2711     {
2712         /* this is not a good idea if the subclassed window was an ansi
2713            window, but we failed finding out the previous window proc
2714            so we can't use CallWindowProc. This should rarely - if ever -
2715            happen. */
2716 
2717         return DefWindowProc(hwnd,
2718                              uMsg,
2719                              wParam,
2720                              lParam);
2721     }
2722 }
2723 
2724 
2725 static INT_PTR
2726 CALLBACK
2727 AdvPropGeneralDlgProc(IN HWND hwndDlg,
2728                       IN UINT uMsg,
2729                       IN WPARAM wParam,
2730                       IN LPARAM lParam)
2731 {
2732     PDEVADVPROP_INFO dap;
2733     INT_PTR Ret = FALSE;
2734 
2735     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
2736 
2737     if (dap != NULL || uMsg == WM_INITDIALOG)
2738     {
2739         switch (uMsg)
2740         {
2741             case WM_COMMAND:
2742             {
2743                 switch (LOWORD(wParam))
2744                 {
2745                     case IDC_DEVUSAGE:
2746                     {
2747                         if (HIWORD(wParam) == CBN_SELCHANGE)
2748                         {
2749                             PropSheet_Changed(GetParent(hwndDlg),
2750                                               hwndDlg);
2751                             dap->DeviceUsageChanged = TRUE;
2752                         }
2753                         break;
2754                     }
2755 
2756                     case IDC_DEVPROBLEM:
2757                     {
2758                         if (dap->IsAdmin)
2759                         {
2760                             /* display the device problem wizard */
2761                             ShowDeviceProblemWizard(hwndDlg,
2762                                                     dap->DeviceInfoSet,
2763                                                     &dap->DeviceInfoData,
2764                                                     dap->hMachine);
2765                         }
2766                         break;
2767                     }
2768                 }
2769                 break;
2770             }
2771 
2772             case WM_NOTIFY:
2773             {
2774                 NMHDR *hdr = (NMHDR*)lParam;
2775                 switch (hdr->code)
2776                 {
2777                     case PSN_APPLY:
2778                         ApplyGeneralSettings(hwndDlg,
2779                                              dap);
2780                         break;
2781                 }
2782                 break;
2783             }
2784 
2785             case WM_INITDIALOG:
2786             {
2787                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
2788                 if (dap != NULL)
2789                 {
2790                     HWND hWndParent;
2791 
2792                     dap->hWndGeneralPage = hwndDlg;
2793 
2794                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
2795 
2796                     /* subclass the parent window to always receive
2797                        WM_DEVICECHANGE messages */
2798                     hWndParent = GetParent(hwndDlg);
2799                     if (hWndParent != NULL)
2800                     {
2801                         /* subclass the parent window. This is not safe
2802                            if the parent window belongs to another thread! */
2803                         dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
2804                                                                           GWLP_WNDPROC,
2805                                                                           (LONG_PTR)DlgParentSubWndProc);
2806 
2807                         if (dap->ParentOldWndProc != NULL &&
2808                             SetProp(hWndParent,
2809                                     L"DevMgrDevChangeSub",
2810                                     (HANDLE)dap))
2811                         {
2812                             dap->hWndParent = hWndParent;
2813                         }
2814                     }
2815 
2816                     /* do not call UpdateDevInfo directly in here because it modifies
2817                        the pages of the property sheet! */
2818                     PostMessage(hwndDlg,
2819                                 PM_INITIALIZE,
2820                                 0,
2821                                 0);
2822                 }
2823                 Ret = TRUE;
2824                 break;
2825             }
2826 
2827             case WM_DEVICECHANGE:
2828             {
2829                 /* FIXME - don't call UpdateDevInfo for all events */
2830                 UpdateDevInfo(hwndDlg,
2831                               dap,
2832                               TRUE);
2833                 Ret = TRUE;
2834                 break;
2835             }
2836 
2837             case PM_INITIALIZE:
2838             {
2839                 UpdateDevInfo(hwndDlg,
2840                               dap,
2841                               FALSE);
2842                 dap->PageInitialized = TRUE;
2843                 break;
2844             }
2845 
2846             case WM_DESTROY:
2847             {
2848                 /* restore the old window proc of the subclassed parent window */
2849                 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
2850                 {
2851                     if (SetWindowLongPtr(dap->hWndParent,
2852                                          GWLP_WNDPROC,
2853                                          (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
2854                     {
2855                         RemoveProp(dap->hWndParent,
2856                                    L"DevMgrDevChangeSub");
2857                     }
2858                 }
2859                 break;
2860             }
2861         }
2862     }
2863 
2864     return Ret;
2865 }
2866 
2867 
2868 INT_PTR
2869 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
2870                                 IN LPCWSTR lpDeviceID  OPTIONAL,
2871                                 IN HDEVINFO DeviceInfoSet,
2872                                 IN PSP_DEVINFO_DATA DeviceInfoData,
2873                                 IN HINSTANCE hComCtl32,
2874                                 IN LPCWSTR lpMachineName,
2875                                 IN DWORD dwFlags)
2876 {
2877     PROPSHEETHEADER psh = {0};
2878     PROPSHEETPAGE pspGeneral = {0};
2879     PPROPERTYSHEETW pPropertySheetW;
2880     PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
2881     PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
2882     PDEVADVPROP_INFO DevAdvPropInfo;
2883     HMACHINE hMachine = NULL;
2884     DWORD DevIdSize = 0;
2885     INT_PTR Ret = -1;
2886 
2887     /* we don't want to statically link against comctl32, so find the
2888        functions we need dynamically */
2889     pPropertySheetW =
2890         (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
2891                                         "PropertySheetW");
2892     pCreatePropertySheetPageW =
2893         (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
2894                                                   "CreatePropertySheetPageW");
2895     pDestroyPropertySheetPage =
2896         (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
2897                                                   "DestroyPropertySheetPage");
2898     if (pPropertySheetW == NULL ||
2899         pCreatePropertySheetPageW == NULL ||
2900         pDestroyPropertySheetPage == NULL)
2901     {
2902         return -1;
2903     }
2904 
2905     if (lpDeviceID == NULL)
2906     {
2907         /* find out how much size is needed for the device id */
2908         if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
2909                                        DeviceInfoData,
2910                                        NULL,
2911                                        0,
2912                                        &DevIdSize))
2913         {
2914             ERR("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
2915             return -1;
2916         }
2917 
2918         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2919         {
2920             return -1;
2921         }
2922     }
2923     else
2924     {
2925         DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
2926     }
2927 
2928     if (lpMachineName != NULL && lpMachineName[0] != L'\0')
2929     {
2930         CONFIGRET cr = CM_Connect_Machine(lpMachineName,
2931                                           &hMachine);
2932         if (cr != CR_SUCCESS)
2933         {
2934             return -1;
2935         }
2936     }
2937 
2938     /* create the internal structure associated with the "General",
2939        "Driver", ... pages */
2940     DevAdvPropInfo = (PDEVADVPROP_INFO)HeapAlloc(GetProcessHeap(),
2941                                                  HEAP_ZERO_MEMORY,
2942                                                  FIELD_OFFSET(DEVADVPROP_INFO,
2943                                                               szDeviceID) +
2944                                                      (DevIdSize * sizeof(WCHAR)));
2945     if (DevAdvPropInfo == NULL)
2946     {
2947         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2948         goto Cleanup;
2949     }
2950 
2951     if (lpDeviceID == NULL)
2952     {
2953         /* read the device instance id */
2954         if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
2955                                         DeviceInfoData,
2956                                         DevAdvPropInfo->szDeviceID,
2957                                         DevIdSize,
2958                                         NULL))
2959         {
2960             goto Cleanup;
2961         }
2962     }
2963     else
2964     {
2965         /* copy the device instance id supplied by the caller */
2966         wcscpy(DevAdvPropInfo->szDeviceID,
2967                lpDeviceID);
2968     }
2969 
2970     DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
2971     DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
2972     DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
2973     DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
2974 
2975     DevAdvPropInfo->ShowRemotePages = (lpMachineName != NULL && lpMachineName[0] != L'\0');
2976     DevAdvPropInfo->hMachine = hMachine;
2977     DevAdvPropInfo->lpMachineName = lpMachineName;
2978     DevAdvPropInfo->szDevName[0] = L'\0';
2979     DevAdvPropInfo->hComCtl32 = hComCtl32;
2980     DevAdvPropInfo->pCreatePropertySheetPageW = pCreatePropertySheetPageW;
2981     DevAdvPropInfo->pDestroyPropertySheetPage = pDestroyPropertySheetPage;
2982 
2983     DevAdvPropInfo->IsAdmin = TRUE;// IsUserAdmin();
2984     DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
2985     DevAdvPropInfo->Extended = ((dwFlags & DPF_EXTENDED) != 0);
2986 
2987     psh.dwSize = sizeof(PROPSHEETHEADER);
2988     psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
2989     psh.hwndParent = hWndParent;
2990     psh.pszCaption = DevAdvPropInfo->szDevName;
2991 
2992     DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
2993                                             DIGCDP_FLAG_REMOTE_ADVANCED :
2994                                             DIGCDP_FLAG_ADVANCED;
2995 
2996     psh.phpage = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
2997                                              HEAP_ZERO_MEMORY,
2998                                              1 * sizeof(HPROPSHEETPAGE));
2999     if (psh.phpage == NULL)
3000     {
3001         goto Cleanup;
3002     }
3003 
3004     /* add the "General" property sheet */
3005     pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
3006     pspGeneral.dwFlags = PSP_DEFAULT;
3007     pspGeneral.hInstance = hDllInstance;
3008     pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
3009     pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
3010     pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
3011     psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
3012     if (psh.phpage[psh.nPages] != NULL)
3013     {
3014         psh.nPages++;
3015     }
3016 
3017     DevAdvPropInfo->nDevPropSheets = psh.nPages;
3018 
3019     if (psh.nPages != 0)
3020     {
3021         Ret = pPropertySheetW(&psh);
3022 
3023         /* NOTE: no need to destroy the property sheets anymore! */
3024     }
3025     else
3026     {
3027         UINT i;
3028 
3029 Cleanup:
3030         /* in case of failure the property sheets must be destroyed */
3031         if (psh.phpage != NULL)
3032         {
3033             for (i = 0;
3034                  i < psh.nPages;
3035                  i++)
3036             {
3037                 if (psh.phpage[i] != NULL)
3038                 {
3039                     pDestroyPropertySheetPage(psh.phpage[i]);
3040                 }
3041             }
3042         }
3043     }
3044 
3045     if (Ret != 1)
3046     {
3047         SP_DEVINSTALL_PARAMS_W DeviceInstallParams;
3048 
3049         DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
3050         if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
3051                                            DeviceInfoData,
3052                                            &DeviceInstallParams))
3053         {
3054             SP_PROPCHANGE_PARAMS PropChangeParams;
3055             PropChangeParams.ClassInstallHeader.cbSize = sizeof(PropChangeParams.ClassInstallHeader);
3056             PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
3057             PropChangeParams.Scope = DICS_FLAG_GLOBAL;
3058             PropChangeParams.StateChange = DICS_PROPCHANGE;
3059 
3060             SetupDiSetClassInstallParamsW(DeviceInfoSet,
3061                                           DeviceInfoData,
3062                                           (PSP_CLASSINSTALL_HEADER)&PropChangeParams,
3063                                           sizeof(PropChangeParams));
3064 
3065             SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
3066                                       DeviceInfoSet,
3067                                       DeviceInfoData);
3068 
3069             DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_PROPCHANGE_PENDING;
3070             SetupDiSetDeviceInstallParamsW(DeviceInfoSet,
3071                                            DeviceInfoData,
3072                                            &DeviceInstallParams);
3073         }
3074     }
3075 
3076     if (DevAdvPropInfo != NULL)
3077     {
3078         if (DevAdvPropInfo->FreeDevPropSheets)
3079         {
3080             /* don't free the array if it's the one allocated in
3081                DisplayDeviceAdvancedProperties */
3082             HeapFree(GetProcessHeap(),
3083                      0,
3084                      DevAdvPropInfo->DevPropSheets);
3085         }
3086 
3087         if (DevAdvPropInfo->CloseDevInst)
3088         {
3089             /* close the device info set in case a new one was created */
3090             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
3091         }
3092 
3093         if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
3094         {
3095             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
3096         }
3097 
3098         if (DevAdvPropInfo->hDevIcon != NULL)
3099         {
3100             DestroyIcon(DevAdvPropInfo->hDevIcon);
3101         }
3102 
3103         if (DevAdvPropInfo->pResourceList != NULL)
3104             HeapFree(GetProcessHeap(), 0, DevAdvPropInfo->pResourceList);
3105 
3106         HeapFree(GetProcessHeap(),
3107                  0,
3108                  DevAdvPropInfo);
3109     }
3110 
3111     if (psh.phpage != NULL)
3112     {
3113         HeapFree(GetProcessHeap(),
3114                  0,
3115                  psh.phpage);
3116     }
3117 
3118     if (hMachine != NULL)
3119     {
3120         CM_Disconnect_Machine(hMachine);
3121     }
3122 
3123     return Ret;
3124 }
3125