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