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                                                  _countof(szDriverPath));
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_CONTEXTMENU:
1901             {
1902                 if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE))
1903                 {
1904                     WCHAR szColName[255];
1905 
1906                     if (!LoadStringW(hDllInstance, IDS_COPY, szColName, _countof(szColName)))
1907                         break;
1908 
1909                     INT nSelectedItems = ListView_GetSelectedCount((HWND)wParam);
1910                     POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1911                     HMENU hPopup = CreatePopupMenu();
1912 
1913                     AppendMenuW(hPopup, MF_STRING, IDS_MENU_COPY, szColName);
1914 
1915                     if (nSelectedItems <= 0)
1916                         EnableMenuItem(hPopup, IDS_MENU_COPY, MF_BYCOMMAND | MF_GRAYED);
1917 
1918                     TrackPopupMenu(hPopup, TPM_LEFTALIGN, pt.x, pt.y, 0, hwndDlg, NULL);
1919                     DestroyMenu(hPopup);
1920                     Ret = TRUE;
1921                 }
1922                 break;
1923             }
1924 
1925             case WM_COMMAND:
1926             {
1927                 switch (LOWORD(wParam))
1928                 {
1929                     case IDC_DETAILSPROPNAME:
1930                         if (HIWORD(wParam) == CBN_SELCHANGE)
1931                         {
1932                             DisplayDeviceProperties(dap,
1933                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPNAME),
1934                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE));
1935                         }
1936                         break;
1937 
1938                     case IDS_MENU_COPY:
1939                     {
1940                         HWND hwndListView = GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE);
1941                         INT nSelectedItems = ListView_GetSelectedCount(hwndListView);
1942                         INT nSelectedId = ListView_GetSelectionMark(hwndListView);
1943 
1944                         if (nSelectedId < 0 || nSelectedItems <= 0)
1945                             break;
1946 
1947                         HGLOBAL hGlobal;
1948                         LPWSTR pszBuffer;
1949                         SIZE_T cchSize = MAX_PATH + 1;
1950 
1951                         hGlobal = GlobalAlloc(GHND, cchSize * sizeof(WCHAR));
1952                         if (!hGlobal)
1953                             break;
1954                         pszBuffer = (LPWSTR)GlobalLock(hGlobal);
1955                         if (!pszBuffer)
1956                         {
1957                             GlobalFree(hGlobal);
1958                             break;
1959                         }
1960 
1961                         ListView_GetItemText(hwndListView,
1962                                              nSelectedId, 0,
1963                                              pszBuffer,
1964                                              cchSize);
1965                         /* Ensure NULL-termination */
1966                         pszBuffer[cchSize - 1] = UNICODE_NULL;
1967 
1968                         GlobalUnlock(hGlobal);
1969 
1970                         if (OpenClipboard(NULL))
1971                         {
1972                             EmptyClipboard();
1973                             SetClipboardData(CF_UNICODETEXT, hGlobal);
1974                             CloseClipboard();
1975                             Ret = TRUE;
1976                         }
1977                         else
1978                         {
1979                             GlobalFree(hGlobal);
1980                         }
1981                         break;
1982                     }
1983                 }
1984                 break;
1985             }
1986 
1987             case WM_NOTIFY:
1988             {
1989                 NMHDR *hdr = (NMHDR*)lParam;
1990                 switch (hdr->code)
1991                 {
1992                     case PSN_APPLY:
1993                         break;
1994                 }
1995                 break;
1996             }
1997 
1998             case WM_INITDIALOG:
1999             {
2000                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
2001                 if (dap != NULL)
2002                 {
2003                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
2004 
2005                     UpdateDetailsDlg(hwndDlg,
2006                                      dap);
2007                 }
2008                 Ret = TRUE;
2009                 break;
2010             }
2011         }
2012     }
2013 
2014     return Ret;
2015 }
2016 
2017 
2018 static VOID
2019 InitDevUsageActions(IN HWND hwndDlg,
2020                     IN HWND hComboBox,
2021                     IN PDEVADVPROP_INFO dap)
2022 {
2023     INT Index;
2024     UINT i;
2025     UINT Actions[] =
2026     {
2027         IDS_ENABLEDEVICE,
2028         IDS_DISABLEDEVICE,
2029     };
2030 
2031     for (i = 0;
2032          i != sizeof(Actions) / sizeof(Actions[0]);
2033          i++)
2034     {
2035         /* fill in the device usage combo box */
2036         if (LoadString(hDllInstance,
2037                        Actions[i],
2038                        dap->szTemp,
2039                        sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2040         {
2041             Index = (INT)SendMessage(hComboBox,
2042                                      CB_ADDSTRING,
2043                                      0,
2044                                      (LPARAM)dap->szTemp);
2045             if (Index != CB_ERR)
2046             {
2047                 SendMessage(hComboBox,
2048                             CB_SETITEMDATA,
2049                             (WPARAM)Index,
2050                             (LPARAM)Actions[i]);
2051 
2052                 switch (Actions[i])
2053                 {
2054                     case IDS_ENABLEDEVICE:
2055                         if (dap->DeviceStarted)
2056                         {
2057                             SendMessage(hComboBox,
2058                                         CB_SETCURSEL,
2059                                         (WPARAM)Index,
2060                                         0);
2061                         }
2062                         break;
2063 
2064                     case IDS_DISABLEDEVICE:
2065                         if (!dap->DeviceStarted)
2066                         {
2067                             SendMessage(hComboBox,
2068                                         CB_SETCURSEL,
2069                                         (WPARAM)Index,
2070                                         0);
2071                         }
2072                         break;
2073 
2074                     default:
2075                         break;
2076                 }
2077             }
2078         }
2079     }
2080 }
2081 
2082 
2083 static UINT
2084 GetSelectedUsageAction(IN HWND hComboBox)
2085 {
2086     INT Index;
2087     UINT Ret = 0;
2088 
2089     Index = (INT)SendMessage(hComboBox,
2090                              CB_GETCURSEL,
2091                              0,
2092                              0);
2093     if (Index != CB_ERR)
2094     {
2095         INT iRet = (INT) SendMessage(hComboBox,
2096                                CB_GETITEMDATA,
2097                                (WPARAM)Index,
2098                                0);
2099         if (iRet != CB_ERR)
2100         {
2101             Ret = (UINT)iRet;
2102         }
2103     }
2104 
2105     return Ret;
2106 }
2107 
2108 
2109 static BOOL
2110 ApplyGeneralSettings(IN HWND hwndDlg,
2111                      IN PDEVADVPROP_INFO dap)
2112 {
2113     BOOL Ret = FALSE;
2114 
2115     if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
2116     {
2117         UINT SelectedUsageAction;
2118         BOOL NeedReboot = FALSE;
2119 
2120         SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
2121                                                                 IDC_DEVUSAGE));
2122         switch (SelectedUsageAction)
2123         {
2124             case IDS_ENABLEDEVICE:
2125                 if (!dap->DeviceStarted)
2126                 {
2127                     Ret = EnableDevice(dap->DeviceInfoSet,
2128                                        &dap->DeviceInfoData,
2129                                        TRUE,
2130                                        0,
2131                                        &NeedReboot);
2132                 }
2133                 break;
2134 
2135             case IDS_DISABLEDEVICE:
2136                 if (dap->DeviceStarted)
2137                 {
2138                     Ret = EnableDevice(dap->DeviceInfoSet,
2139                                        &dap->DeviceInfoData,
2140                                        FALSE,
2141                                        0,
2142                                        &NeedReboot);
2143                 }
2144                 break;
2145 
2146             default:
2147                 break;
2148         }
2149 
2150         if (Ret)
2151         {
2152             if (NeedReboot)
2153             {
2154                 /* make PropertySheet() return PSM_REBOOTSYSTEM */
2155                 PropSheet_RebootSystem(hwndDlg);
2156             }
2157         }
2158         else
2159         {
2160             /* FIXME - display an error message */
2161             FIXME("Failed to enable/disable device! LastError: %d\n",
2162                   GetLastError());
2163         }
2164     }
2165     else
2166         Ret = !dap->DeviceUsageChanged;
2167 
2168     /* disable the apply button */
2169     PropSheet_UnChanged(GetParent(hwndDlg),
2170                         hwndDlg);
2171     dap->DeviceUsageChanged = FALSE;
2172     return Ret;
2173 }
2174 
2175 
2176 static VOID
2177 UpdateDevInfo(IN HWND hwndDlg,
2178               IN PDEVADVPROP_INFO dap,
2179               IN BOOL ReOpen)
2180 {
2181     HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
2182     CONFIGRET cr;
2183     ULONG Status, ProblemNumber;
2184     SP_DEVINSTALL_PARAMS_W InstallParams;
2185     UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
2186     BOOL bFlag, bDevActionAvailable = TRUE;
2187     BOOL bDrvInstalled = FALSE;
2188     DWORD iPage;
2189     HDEVINFO DeviceInfoSet = NULL;
2190     PSP_DEVINFO_DATA DeviceInfoData = NULL;
2191     PROPSHEETHEADER psh;
2192     DWORD nDriverPages = 0;
2193     BOOL RecalcPages = FALSE;
2194 
2195     hPropSheetDlg = GetParent(hwndDlg);
2196 
2197     if (dap->PageInitialized)
2198     {
2199         /* switch to the General page */
2200         PropSheet_SetCurSelByID(hPropSheetDlg,
2201                                 IDD_DEVICEGENERAL);
2202 
2203         /* remove and destroy the existing device property sheet pages */
2204         if (dap->DevPropSheets != NULL)
2205         {
2206             for (iPage = 0;
2207                  iPage != dap->nDevPropSheets;
2208                  iPage++)
2209             {
2210                 if (dap->DevPropSheets[iPage] != NULL)
2211                 {
2212                     PropSheet_RemovePage(hPropSheetDlg,
2213                                          (WPARAM) -1,
2214                                          dap->DevPropSheets[iPage]);
2215                     RecalcPages = TRUE;
2216                 }
2217             }
2218         }
2219     }
2220 
2221     iPage = 0;
2222 
2223     if (dap->FreeDevPropSheets)
2224     {
2225         /* don't free the array if it's the one allocated in
2226            DisplayDeviceAdvancedProperties */
2227         HeapFree(GetProcessHeap(),
2228                  0,
2229                  dap->DevPropSheets);
2230 
2231         dap->FreeDevPropSheets = FALSE;
2232     }
2233 
2234     dap->DevPropSheets = NULL;
2235     dap->nDevPropSheets = 0;
2236 
2237     if (ReOpen)
2238     {
2239         /* create a new device info set and re-open the device */
2240         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2241         {
2242             SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
2243         }
2244 
2245         dap->ParentDevInst = 0;
2246         dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
2247                                                                   hwndDlg,
2248                                                                   dap->lpMachineName,
2249                                                                   NULL);
2250         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2251         {
2252             if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
2253                                       dap->szDeviceID,
2254                                       hwndDlg,
2255                                       0,
2256                                       &dap->CurrentDeviceInfoData))
2257             {
2258                 if (dap->CloseDevInst)
2259                 {
2260                     SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
2261                 }
2262 
2263                 dap->CloseDevInst = TRUE;
2264                 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
2265                 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
2266                 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
2267             }
2268             else
2269                 goto GetParentNode;
2270         }
2271         else
2272         {
2273 GetParentNode:
2274             /* get the parent node from the initial devinst */
2275             CM_Get_Parent_Ex(&dap->ParentDevInst,
2276                              dap->DeviceInfoData.DevInst,
2277                              0,
2278                              dap->hMachine);
2279         }
2280 
2281         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2282         {
2283             DeviceInfoSet = dap->CurrentDeviceInfoSet;
2284             DeviceInfoData = &dap->CurrentDeviceInfoData;
2285         }
2286         else
2287         {
2288             DeviceInfoSet = dap->DeviceInfoSet;
2289             DeviceInfoData = &dap->DeviceInfoData;
2290         }
2291     }
2292     else
2293     {
2294         DeviceInfoSet = dap->DeviceInfoSet;
2295         DeviceInfoData = &dap->DeviceInfoData;
2296     }
2297 
2298     dap->HasDriverPage = TRUE;
2299     dap->HasResourcePage = TRUE;
2300     dap->HasPowerPage = TRUE;
2301     if (IsDriverInstalled(DeviceInfoData->DevInst,
2302                           dap->hMachine,
2303                           &bDrvInstalled) &&
2304         bDrvInstalled)
2305     {
2306         if (SetupDiCallClassInstaller((dap->ShowRemotePages ?
2307                                            DIF_ADDREMOTEPROPERTYPAGE_ADVANCED :
2308                                            DIF_ADDPROPERTYPAGE_ADVANCED),
2309                                       DeviceInfoSet,
2310                                       DeviceInfoData))
2311         {
2312             /* get install params */
2313             InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2314             if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
2315                                                 DeviceInfoData,
2316                                                 &InstallParams))
2317             {
2318                 /* zero the flags */
2319                 InstallParams.Flags = 0;
2320                 InstallParams.FlagsEx = 0;
2321             }
2322 
2323             dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
2324             dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
2325             dap->HasPowerPage = !(InstallParams.FlagsEx & DI_FLAGSEX_POWERPAGE_ADDED);
2326         }
2327     }
2328 
2329     /* get the device icon */
2330     if (dap->hDevIcon != NULL)
2331     {
2332         DestroyIcon(dap->hDevIcon);
2333         dap->hDevIcon = NULL;
2334     }
2335     if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
2336                               &dap->hDevIcon,
2337                               NULL))
2338     {
2339         dap->hDevIcon = NULL;
2340     }
2341 
2342     /* get the device name */
2343     if (GetDeviceDescriptionString(DeviceInfoSet,
2344                                    DeviceInfoData,
2345                                    dap->szDevName,
2346                                    sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
2347     {
2348         PropSheet_SetTitle(hPropSheetDlg,
2349                            PSH_PROPTITLE,
2350                            dap->szDevName);
2351     }
2352 
2353     /* set the device image */
2354     SendDlgItemMessage(hwndDlg,
2355                        IDC_DEVICON,
2356                        STM_SETICON,
2357                        (WPARAM)dap->hDevIcon,
2358                        0);
2359 
2360     /* set the device name edit control text */
2361     SetDlgItemText(hwndDlg,
2362                    IDC_DEVNAME,
2363                    dap->szDevName);
2364 
2365     /* set the device type edit control text */
2366     if (GetDeviceTypeString(DeviceInfoData,
2367                             dap->szTemp,
2368                             sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2369     {
2370         SetDlgItemText(hwndDlg,
2371                        IDC_DEVTYPE,
2372                        dap->szTemp);
2373     }
2374 
2375     /* set the device manufacturer edit control text */
2376     if (GetDeviceManufacturerString(DeviceInfoSet,
2377                                     DeviceInfoData,
2378                                     dap->szTemp,
2379                                     sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2380     {
2381         SetDlgItemText(hwndDlg,
2382                        IDC_DEVMANUFACTURER,
2383                        dap->szTemp);
2384     }
2385 
2386     /* set the device location edit control text */
2387     if (GetDeviceLocationString(DeviceInfoSet,
2388                                 DeviceInfoData,
2389                                 dap->ParentDevInst,
2390                                 dap->szTemp,
2391                                 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2392     {
2393         SetDlgItemText(hwndDlg,
2394                        IDC_DEVLOCATION,
2395                        dap->szTemp);
2396     }
2397 
2398     /* set the device status edit control text */
2399     if (GetDeviceStatusString(DeviceInfoData->DevInst,
2400                               dap->hMachine,
2401                               dap->szTemp,
2402                               sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2403     {
2404         SetDlgItemText(hwndDlg,
2405                        IDC_DEVSTATUS,
2406                        dap->szTemp);
2407     }
2408 
2409     /* set the device troubleshoot button text and disable it if necessary */
2410     hDevProbBtn = GetDlgItem(hwndDlg,
2411                              IDC_DEVPROBLEM);
2412     cr = CM_Get_DevNode_Status_Ex(&Status,
2413                                   &ProblemNumber,
2414                                   DeviceInfoData->DevInst,
2415                                   0,
2416                                   dap->hMachine);
2417     if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
2418     {
2419         switch (ProblemNumber)
2420         {
2421             case CM_PROB_DEVLOADER_FAILED:
2422             {
2423                 /* FIXME - only if it's not a root bus devloader,
2424                            disable the button otherwise */
2425                 TroubleShootStrId = IDS_UPDATEDRV;
2426                 break;
2427             }
2428 
2429             case CM_PROB_OUT_OF_MEMORY:
2430             case CM_PROB_ENTRY_IS_WRONG_TYPE:
2431             case CM_PROB_LACKED_ARBITRATOR:
2432             case CM_PROB_FAILED_START:
2433             case CM_PROB_LIAR:
2434             case CM_PROB_UNKNOWN_RESOURCE:
2435             {
2436                 TroubleShootStrId = IDS_UPDATEDRV;
2437                 break;
2438             }
2439 
2440             case CM_PROB_BOOT_CONFIG_CONFLICT:
2441             case CM_PROB_NORMAL_CONFLICT:
2442             case CM_PROB_REENUMERATION:
2443             {
2444                 /* FIXME - Troubleshoot conflict */
2445                 break;
2446             }
2447 
2448             case CM_PROB_FAILED_FILTER:
2449             case CM_PROB_REINSTALL:
2450             case CM_PROB_FAILED_INSTALL:
2451             {
2452                 TroubleShootStrId = IDS_REINSTALLDRV;
2453                 break;
2454             }
2455 
2456             case CM_PROB_DEVLOADER_NOT_FOUND:
2457             {
2458                 /* FIXME - 4 cases:
2459                    1) if it's a missing system devloader:
2460                       - disable the button (Reinstall Driver)
2461                    2) if it's not a system devloader but still missing:
2462                       - Reinstall Driver
2463                    3) if it's not a system devloader but the file can be found:
2464                       - Update Driver
2465                    4) if it's a missing or empty software key
2466                       - Update Driver
2467                  */
2468                 break;
2469             }
2470 
2471             case CM_PROB_INVALID_DATA:
2472             case CM_PROB_PARTIAL_LOG_CONF:
2473             case CM_PROB_NO_VALID_LOG_CONF:
2474             case CM_PROB_HARDWARE_DISABLED:
2475             case CM_PROB_CANT_SHARE_IRQ:
2476             case CM_PROB_TRANSLATION_FAILED:
2477             case CM_PROB_SYSTEM_SHUTDOWN:
2478             case CM_PROB_PHANTOM:
2479                 bDevActionAvailable = FALSE;
2480                 break;
2481 
2482             case CM_PROB_NOT_VERIFIED:
2483             case CM_PROB_DEVICE_NOT_THERE:
2484                 /* FIXME - search hardware */
2485                 break;
2486 
2487             case CM_PROB_NEED_RESTART:
2488             case CM_PROB_WILL_BE_REMOVED:
2489             case CM_PROB_MOVED:
2490             case CM_PROB_TOO_EARLY:
2491             case CM_PROB_DISABLED_SERVICE:
2492                 TroubleShootStrId = IDS_REBOOT;
2493                 break;
2494 
2495             case CM_PROB_REGISTRY:
2496                 /* FIXME - check registry? */
2497                 break;
2498 
2499             case CM_PROB_DISABLED:
2500                 /* if device was disabled by the user: */
2501                 TroubleShootStrId = IDS_ENABLEDEV;
2502                 /* FIXME - otherwise disable button because the device was
2503                            disabled by the system*/
2504                 break;
2505 
2506             case CM_PROB_DEVLOADER_NOT_READY:
2507                 /* FIXME - if it's a graphics adapter:
2508                            - if it's a a secondary adapter and the main adapter
2509                              couldn't be found
2510                              - disable  button
2511                            - else
2512                              - Properties
2513                          - else
2514                            - Update driver
2515                  */
2516                 break;
2517 
2518             case CM_PROB_FAILED_ADD:
2519                 TroubleShootStrId = IDS_PROPERTIES;
2520                 break;
2521         }
2522     }
2523 
2524     if (LoadString(hDllInstance,
2525                    TroubleShootStrId,
2526                    dap->szTemp,
2527                    sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
2528     {
2529         SetWindowText(hDevProbBtn,
2530                       dap->szTemp);
2531     }
2532     EnableWindow(hDevProbBtn,
2533                  dap->IsAdmin && bDevActionAvailable);
2534 
2535     /* check if the device can be enabled/disabled */
2536     hDevUsage = GetDlgItem(hwndDlg,
2537                            IDC_DEVUSAGE);
2538 
2539     dap->CanDisable = FALSE;
2540     dap->DeviceStarted = FALSE;
2541 
2542     if (CanDisableDevice(DeviceInfoData->DevInst,
2543                          dap->hMachine,
2544                          &bFlag))
2545     {
2546         dap->CanDisable = bFlag;
2547     }
2548 
2549     if (IsDeviceStarted(DeviceInfoData->DevInst,
2550                         dap->hMachine,
2551                         &bFlag))
2552     {
2553         dap->DeviceStarted = bFlag;
2554     }
2555 
2556     /* enable/disable the device usage controls */
2557     EnableWindow(GetDlgItem(hwndDlg,
2558                             IDC_DEVUSAGELABEL),
2559                  dap->CanDisable && dap->IsAdmin);
2560     EnableWindow(hDevUsage,
2561                  dap->CanDisable && dap->IsAdmin);
2562 
2563     /* clear the combobox */
2564     SendMessage(hDevUsage,
2565                 CB_RESETCONTENT,
2566                 0,
2567                 0);
2568     if (dap->CanDisable)
2569     {
2570         InitDevUsageActions(hwndDlg,
2571                             hDevUsage,
2572                             dap);
2573     }
2574 
2575     /* find out how many new device property sheets to add.
2576        fake a PROPSHEETHEADER structure, we don't plan to
2577        call PropertySheet again!*/
2578     psh.dwSize = sizeof(PROPSHEETHEADER);
2579     psh.dwFlags = 0;
2580     psh.nPages = 0;
2581 
2582     /* get the number of device property sheets for the device */
2583     if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2584                                           DeviceInfoData,
2585                                           &psh,
2586                                           0,
2587                                           &nDriverPages,
2588                                           dap->PropertySheetType) &&
2589         nDriverPages != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2590     {
2591         dap->nDevPropSheets += nDriverPages;
2592     }
2593     else
2594     {
2595         nDriverPages = 0;
2596     }
2597 
2598     dap->pResourceList = GetResourceList(dap->szDeviceID);
2599 
2600     /* include the driver page */
2601     if (dap->HasDriverPage)
2602         dap->nDevPropSheets++;
2603 
2604     /* include the details page */
2605     if (dap->Extended)
2606         dap->nDevPropSheets++;
2607 
2608     if (dap->HasResourcePage && dap->pResourceList != NULL)
2609         dap->nDevPropSheets++;
2610 
2611     /* add the device property sheets */
2612     if (dap->nDevPropSheets != 0)
2613     {
2614         dap->DevPropSheets = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
2615                                                          HEAP_ZERO_MEMORY,
2616                                                          dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
2617         if (dap->DevPropSheets != NULL)
2618         {
2619             if (nDriverPages != 0)
2620             {
2621                 psh.phpage = dap->DevPropSheets;
2622 
2623                 /* query the device property sheet pages to add */
2624                 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2625                                                      DeviceInfoData,
2626                                                      &psh,
2627                                                      dap->nDevPropSheets,
2628                                                      NULL,
2629                                                      dap->PropertySheetType))
2630                 {
2631                     /* add the property sheets */
2632                     for (iPage = 0;
2633                          iPage < nDriverPages;
2634                          iPage++)
2635                     {
2636                         if (PropSheet_AddPage(hPropSheetDlg,
2637                                               dap->DevPropSheets[iPage]))
2638                         {
2639                             RecalcPages = TRUE;
2640                         }
2641                     }
2642 
2643                     dap->FreeDevPropSheets = TRUE;
2644                 }
2645                 else
2646                 {
2647                     /* cleanup, we were unable to get the device property sheets */
2648                     iPage = nDriverPages;
2649                     dap->nDevPropSheets -= nDriverPages;
2650                     nDriverPages = 0;
2651                 }
2652             }
2653             else
2654                 iPage = 0;
2655 
2656             /* add the driver page if necessary */
2657             if (dap->HasDriverPage)
2658             {
2659                 PROPSHEETPAGE pspDriver = {0};
2660                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2661                 pspDriver.dwFlags = PSP_DEFAULT;
2662                 pspDriver.hInstance = hDllInstance;
2663                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDRIVER);
2664                 pspDriver.pfnDlgProc = AdvProcDriverDlgProc;
2665                 pspDriver.lParam = (LPARAM)dap;
2666                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2667                 if (dap->DevPropSheets[iPage] != NULL)
2668                 {
2669                     if (PropSheet_AddPage(hPropSheetDlg,
2670                                           dap->DevPropSheets[iPage]))
2671                     {
2672                         iPage++;
2673                         RecalcPages = TRUE;
2674                     }
2675                     else
2676                     {
2677                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2678                         dap->DevPropSheets[iPage] = NULL;
2679                     }
2680                 }
2681             }
2682 
2683             if (dap->Extended)
2684             {
2685                 /* Add the details page */
2686                 PROPSHEETPAGE pspDetails = {0};
2687                 pspDetails.dwSize = sizeof(PROPSHEETPAGE);
2688                 pspDetails.dwFlags = PSP_DEFAULT;
2689                 pspDetails.hInstance = hDllInstance;
2690                 pspDetails.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDETAILS);
2691                 pspDetails.pfnDlgProc = AdvProcDetailsDlgProc;
2692                 pspDetails.lParam = (LPARAM)dap;
2693                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDetails);
2694                 if (dap->DevPropSheets[iPage] != NULL)
2695                 {
2696                     if (PropSheet_AddPage(hPropSheetDlg,
2697                                           dap->DevPropSheets[iPage]))
2698                     {
2699                         iPage++;
2700                         RecalcPages = TRUE;
2701                     }
2702                     else
2703                     {
2704                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2705                         dap->DevPropSheets[iPage] = NULL;
2706                     }
2707                 }
2708             }
2709 
2710             if (dap->HasResourcePage && dap->pResourceList)
2711             {
2712                 PROPSHEETPAGE pspDriver = {0};
2713                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2714                 pspDriver.dwFlags = PSP_DEFAULT;
2715                 pspDriver.hInstance = hDllInstance;
2716                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICERESOURCES);
2717                 pspDriver.pfnDlgProc = ResourcesProcDriverDlgProc;
2718                 pspDriver.lParam = (LPARAM)dap;
2719                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2720                 if (dap->DevPropSheets[iPage] != NULL)
2721                 {
2722                     if (PropSheet_AddPage(hPropSheetDlg,
2723                                           dap->DevPropSheets[iPage]))
2724                     {
2725                         iPage++;
2726                         RecalcPages = TRUE;
2727                     }
2728                     else
2729                     {
2730                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2731                         dap->DevPropSheets[iPage] = NULL;
2732                     }
2733                 }
2734             }
2735             /* FIXME: Add the power page */
2736         }
2737         else
2738             dap->nDevPropSheets = 0;
2739     }
2740 
2741     if (RecalcPages)
2742     {
2743         PropSheet_RecalcPageSizes(hPropSheetDlg);
2744     }
2745 
2746     /* finally, disable the apply button */
2747     PropSheet_UnChanged(hPropSheetDlg,
2748                         hwndDlg);
2749     dap->DeviceUsageChanged = FALSE;
2750 }
2751 
2752 
2753 static LRESULT
2754 CALLBACK
2755 DlgParentSubWndProc(IN HWND hwnd,
2756                     IN UINT uMsg,
2757                     IN WPARAM wParam,
2758                     IN LPARAM lParam)
2759 {
2760     PDEVADVPROP_INFO dap;
2761 
2762     dap = (PDEVADVPROP_INFO)GetProp(hwnd,
2763                                     L"DevMgrDevChangeSub");
2764     if (dap != NULL)
2765     {
2766         if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
2767         {
2768             SendMessage(dap->hWndGeneralPage,
2769                         WM_DEVICECHANGE,
2770                         wParam,
2771                         lParam);
2772         }
2773 
2774         /* pass the message the the old window proc */
2775         return CallWindowProc(dap->ParentOldWndProc,
2776                               hwnd,
2777                               uMsg,
2778                               wParam,
2779                               lParam);
2780     }
2781     else
2782     {
2783         /* this is not a good idea if the subclassed window was an ansi
2784            window, but we failed finding out the previous window proc
2785            so we can't use CallWindowProc. This should rarely - if ever -
2786            happen. */
2787 
2788         return DefWindowProc(hwnd,
2789                              uMsg,
2790                              wParam,
2791                              lParam);
2792     }
2793 }
2794 
2795 
2796 static INT_PTR
2797 CALLBACK
2798 AdvPropGeneralDlgProc(IN HWND hwndDlg,
2799                       IN UINT uMsg,
2800                       IN WPARAM wParam,
2801                       IN LPARAM lParam)
2802 {
2803     PDEVADVPROP_INFO dap;
2804     INT_PTR Ret = FALSE;
2805 
2806     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
2807 
2808     if (dap != NULL || uMsg == WM_INITDIALOG)
2809     {
2810         switch (uMsg)
2811         {
2812             case WM_COMMAND:
2813             {
2814                 switch (LOWORD(wParam))
2815                 {
2816                     case IDC_DEVUSAGE:
2817                     {
2818                         if (HIWORD(wParam) == CBN_SELCHANGE)
2819                         {
2820                             PropSheet_Changed(GetParent(hwndDlg),
2821                                               hwndDlg);
2822                             dap->DeviceUsageChanged = TRUE;
2823                         }
2824                         break;
2825                     }
2826 
2827                     case IDC_DEVPROBLEM:
2828                     {
2829                         if (dap->IsAdmin)
2830                         {
2831                             /* display the device problem wizard */
2832                             ShowDeviceProblemWizard(hwndDlg,
2833                                                     dap->DeviceInfoSet,
2834                                                     &dap->DeviceInfoData,
2835                                                     dap->hMachine);
2836                         }
2837                         break;
2838                     }
2839                 }
2840                 break;
2841             }
2842 
2843             case WM_NOTIFY:
2844             {
2845                 NMHDR *hdr = (NMHDR*)lParam;
2846                 switch (hdr->code)
2847                 {
2848                     case PSN_APPLY:
2849                         ApplyGeneralSettings(hwndDlg,
2850                                              dap);
2851                         break;
2852                 }
2853                 break;
2854             }
2855 
2856             case WM_INITDIALOG:
2857             {
2858                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
2859                 if (dap != NULL)
2860                 {
2861                     HWND hWndParent;
2862 
2863                     dap->hWndGeneralPage = hwndDlg;
2864 
2865                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
2866 
2867                     /* subclass the parent window to always receive
2868                        WM_DEVICECHANGE messages */
2869                     hWndParent = GetParent(hwndDlg);
2870                     if (hWndParent != NULL)
2871                     {
2872                         /* subclass the parent window. This is not safe
2873                            if the parent window belongs to another thread! */
2874                         dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
2875                                                                           GWLP_WNDPROC,
2876                                                                           (LONG_PTR)DlgParentSubWndProc);
2877 
2878                         if (dap->ParentOldWndProc != NULL &&
2879                             SetProp(hWndParent,
2880                                     L"DevMgrDevChangeSub",
2881                                     (HANDLE)dap))
2882                         {
2883                             dap->hWndParent = hWndParent;
2884                         }
2885                     }
2886 
2887                     /* do not call UpdateDevInfo directly in here because it modifies
2888                        the pages of the property sheet! */
2889                     PostMessage(hwndDlg,
2890                                 PM_INITIALIZE,
2891                                 0,
2892                                 0);
2893                 }
2894                 Ret = TRUE;
2895                 break;
2896             }
2897 
2898             case WM_DEVICECHANGE:
2899             {
2900                 /* FIXME - don't call UpdateDevInfo for all events */
2901                 UpdateDevInfo(hwndDlg,
2902                               dap,
2903                               TRUE);
2904                 Ret = TRUE;
2905                 break;
2906             }
2907 
2908             case PM_INITIALIZE:
2909             {
2910                 UpdateDevInfo(hwndDlg,
2911                               dap,
2912                               FALSE);
2913                 dap->PageInitialized = TRUE;
2914                 break;
2915             }
2916 
2917             case WM_DESTROY:
2918             {
2919                 /* restore the old window proc of the subclassed parent window */
2920                 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
2921                 {
2922                     if (SetWindowLongPtr(dap->hWndParent,
2923                                          GWLP_WNDPROC,
2924                                          (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
2925                     {
2926                         RemoveProp(dap->hWndParent,
2927                                    L"DevMgrDevChangeSub");
2928                     }
2929                 }
2930                 break;
2931             }
2932         }
2933     }
2934 
2935     return Ret;
2936 }
2937 
2938 
2939 INT_PTR
2940 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
2941                                 IN LPCWSTR lpDeviceID  OPTIONAL,
2942                                 IN HDEVINFO DeviceInfoSet,
2943                                 IN PSP_DEVINFO_DATA DeviceInfoData,
2944                                 IN HINSTANCE hComCtl32,
2945                                 IN LPCWSTR lpMachineName,
2946                                 IN DWORD dwFlags)
2947 {
2948     PROPSHEETHEADER psh = {0};
2949     PROPSHEETPAGE pspGeneral = {0};
2950     PPROPERTYSHEETW pPropertySheetW;
2951     PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
2952     PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
2953     PDEVADVPROP_INFO DevAdvPropInfo;
2954     HMACHINE hMachine = NULL;
2955     DWORD DevIdSize = 0;
2956     INT_PTR Ret = -1;
2957 
2958     /* we don't want to statically link against comctl32, so find the
2959        functions we need dynamically */
2960     pPropertySheetW =
2961         (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
2962                                         "PropertySheetW");
2963     pCreatePropertySheetPageW =
2964         (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
2965                                                   "CreatePropertySheetPageW");
2966     pDestroyPropertySheetPage =
2967         (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
2968                                                   "DestroyPropertySheetPage");
2969     if (pPropertySheetW == NULL ||
2970         pCreatePropertySheetPageW == NULL ||
2971         pDestroyPropertySheetPage == NULL)
2972     {
2973         return -1;
2974     }
2975 
2976     if (lpDeviceID == NULL)
2977     {
2978         /* find out how much size is needed for the device id */
2979         if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
2980                                        DeviceInfoData,
2981                                        NULL,
2982                                        0,
2983                                        &DevIdSize))
2984         {
2985             ERR("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
2986             return -1;
2987         }
2988 
2989         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2990         {
2991             return -1;
2992         }
2993     }
2994     else
2995     {
2996         DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
2997     }
2998 
2999     if (lpMachineName != NULL && lpMachineName[0] != L'\0')
3000     {
3001         CONFIGRET cr = CM_Connect_Machine(lpMachineName,
3002                                           &hMachine);
3003         if (cr != CR_SUCCESS)
3004         {
3005             return -1;
3006         }
3007     }
3008 
3009     /* create the internal structure associated with the "General",
3010        "Driver", ... pages */
3011     DevAdvPropInfo = (PDEVADVPROP_INFO)HeapAlloc(GetProcessHeap(),
3012                                                  HEAP_ZERO_MEMORY,
3013                                                  FIELD_OFFSET(DEVADVPROP_INFO,
3014                                                               szDeviceID) +
3015                                                      (DevIdSize * sizeof(WCHAR)));
3016     if (DevAdvPropInfo == NULL)
3017     {
3018         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3019         goto Cleanup;
3020     }
3021 
3022     if (lpDeviceID == NULL)
3023     {
3024         /* read the device instance id */
3025         if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
3026                                         DeviceInfoData,
3027                                         DevAdvPropInfo->szDeviceID,
3028                                         DevIdSize,
3029                                         NULL))
3030         {
3031             goto Cleanup;
3032         }
3033     }
3034     else
3035     {
3036         /* copy the device instance id supplied by the caller */
3037         wcscpy(DevAdvPropInfo->szDeviceID,
3038                lpDeviceID);
3039     }
3040 
3041     DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
3042     DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
3043     DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
3044     DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3045 
3046     DevAdvPropInfo->ShowRemotePages = (lpMachineName != NULL && lpMachineName[0] != L'\0');
3047     DevAdvPropInfo->hMachine = hMachine;
3048     DevAdvPropInfo->lpMachineName = lpMachineName;
3049     DevAdvPropInfo->szDevName[0] = L'\0';
3050     DevAdvPropInfo->hComCtl32 = hComCtl32;
3051     DevAdvPropInfo->pCreatePropertySheetPageW = pCreatePropertySheetPageW;
3052     DevAdvPropInfo->pDestroyPropertySheetPage = pDestroyPropertySheetPage;
3053 
3054     DevAdvPropInfo->IsAdmin = TRUE;// IsUserAdmin();
3055     DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
3056     DevAdvPropInfo->Extended = ((dwFlags & DPF_EXTENDED) != 0);
3057 
3058     psh.dwSize = sizeof(PROPSHEETHEADER);
3059     psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
3060     psh.hwndParent = hWndParent;
3061     psh.pszCaption = DevAdvPropInfo->szDevName;
3062 
3063     DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
3064                                             DIGCDP_FLAG_REMOTE_ADVANCED :
3065                                             DIGCDP_FLAG_ADVANCED;
3066 
3067     psh.phpage = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
3068                                              HEAP_ZERO_MEMORY,
3069                                              1 * sizeof(HPROPSHEETPAGE));
3070     if (psh.phpage == NULL)
3071     {
3072         goto Cleanup;
3073     }
3074 
3075     /* add the "General" property sheet */
3076     pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
3077     pspGeneral.dwFlags = PSP_DEFAULT;
3078     pspGeneral.hInstance = hDllInstance;
3079     pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
3080     pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
3081     pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
3082     psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
3083     if (psh.phpage[psh.nPages] != NULL)
3084     {
3085         psh.nPages++;
3086     }
3087 
3088     DevAdvPropInfo->nDevPropSheets = psh.nPages;
3089 
3090     if (psh.nPages != 0)
3091     {
3092         Ret = pPropertySheetW(&psh);
3093 
3094         /* NOTE: no need to destroy the property sheets anymore! */
3095     }
3096     else
3097     {
3098         UINT i;
3099 
3100 Cleanup:
3101         /* in case of failure the property sheets must be destroyed */
3102         if (psh.phpage != NULL)
3103         {
3104             for (i = 0;
3105                  i < psh.nPages;
3106                  i++)
3107             {
3108                 if (psh.phpage[i] != NULL)
3109                 {
3110                     pDestroyPropertySheetPage(psh.phpage[i]);
3111                 }
3112             }
3113         }
3114     }
3115 
3116     if (Ret != 1)
3117     {
3118         SP_DEVINSTALL_PARAMS_W DeviceInstallParams;
3119 
3120         DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
3121         if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
3122                                            DeviceInfoData,
3123                                            &DeviceInstallParams))
3124         {
3125             SP_PROPCHANGE_PARAMS PropChangeParams;
3126             PropChangeParams.ClassInstallHeader.cbSize = sizeof(PropChangeParams.ClassInstallHeader);
3127             PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
3128             PropChangeParams.Scope = DICS_FLAG_GLOBAL;
3129             PropChangeParams.StateChange = DICS_PROPCHANGE;
3130 
3131             SetupDiSetClassInstallParamsW(DeviceInfoSet,
3132                                           DeviceInfoData,
3133                                           (PSP_CLASSINSTALL_HEADER)&PropChangeParams,
3134                                           sizeof(PropChangeParams));
3135 
3136             SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
3137                                       DeviceInfoSet,
3138                                       DeviceInfoData);
3139 
3140             DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_PROPCHANGE_PENDING;
3141             SetupDiSetDeviceInstallParamsW(DeviceInfoSet,
3142                                            DeviceInfoData,
3143                                            &DeviceInstallParams);
3144         }
3145     }
3146 
3147     if (DevAdvPropInfo != NULL)
3148     {
3149         if (DevAdvPropInfo->FreeDevPropSheets)
3150         {
3151             /* don't free the array if it's the one allocated in
3152                DisplayDeviceAdvancedProperties */
3153             HeapFree(GetProcessHeap(),
3154                      0,
3155                      DevAdvPropInfo->DevPropSheets);
3156         }
3157 
3158         if (DevAdvPropInfo->CloseDevInst)
3159         {
3160             /* close the device info set in case a new one was created */
3161             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
3162         }
3163 
3164         if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
3165         {
3166             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
3167         }
3168 
3169         if (DevAdvPropInfo->hDevIcon != NULL)
3170         {
3171             DestroyIcon(DevAdvPropInfo->hDevIcon);
3172         }
3173 
3174         if (DevAdvPropInfo->pResourceList != NULL)
3175             HeapFree(GetProcessHeap(), 0, DevAdvPropInfo->pResourceList);
3176 
3177         HeapFree(GetProcessHeap(),
3178                  0,
3179                  DevAdvPropInfo);
3180     }
3181 
3182     if (psh.phpage != NULL)
3183     {
3184         HeapFree(GetProcessHeap(),
3185                  0,
3186                  psh.phpage);
3187     }
3188 
3189     if (hMachine != NULL)
3190     {
3191         CM_Disconnect_Machine(hMachine);
3192     }
3193 
3194     return Ret;
3195 }
3196