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                 break;
595             }
596 
597             case WM_NOTIFY:
598             {
599                 NMHDR *hdr = (NMHDR*)lParam;
600                 switch (hdr->code)
601                 {
602                     case PSN_APPLY:
603                         break;
604                 }
605                 break;
606             }
607 
608             case WM_INITDIALOG:
609             {
610                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
611                 if (dap != NULL)
612                 {
613                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
614 
615                     UpdateDriverDlg(hwndDlg,
616                                     dap);
617                 }
618                 Ret = TRUE;
619                 break;
620             }
621         }
622     }
623 
624     return Ret;
625 }
626 
627 
628 static VOID
629 SetListViewText(HWND hwnd,
630                 INT iItem,
631                 LPCWSTR lpText)
632 {
633     LVITEM li;
634 
635     li.mask = LVIF_TEXT | LVIF_STATE;
636     li.iItem = iItem;
637     li.iSubItem = 0;
638     li.state = 0; //(li.iItem == 0 ? LVIS_SELECTED : 0);
639     li.stateMask = LVIS_SELECTED;
640     li.pszText = (LPWSTR)lpText;
641     (void)ListView_InsertItem(hwnd,
642                               &li);
643 }
644 
645 
646 static VOID
647 UpdateDetailsDlg(IN HWND hwndDlg,
648                  IN PDEVADVPROP_INFO dap)
649 {
650     HWND hwndComboBox;
651     HWND hwndListView;
652     LV_COLUMN lvc;
653     RECT rcClient;
654 
655     UINT i;
656     UINT Properties[] =
657     {
658         IDS_PROP_DEVICEID,
659         IDS_PROP_HARDWAREIDS,
660         IDS_PROP_COMPATIBLEIDS,
661         IDS_PROP_MATCHINGDEVICEID,
662         IDS_PROP_SERVICE,
663         IDS_PROP_ENUMERATOR,
664         IDS_PROP_CAPABILITIES,
665         IDS_PROP_DEVNODEFLAGS,
666         IDS_PROP_CONFIGFLAGS,
667         IDS_PROP_CSCONFIGFLAGS,
668         IDS_PROP_EJECTIONRELATIONS,
669         IDS_PROP_REMOVALRELATIONS,
670         IDS_PROP_BUSRELATIONS,
671         IDS_PROP_DEVUPPERFILTERS,
672         IDS_PROP_DEVLOWERFILTERS,
673         IDS_PROP_CLASSUPPERFILTERS,
674         IDS_PROP_CLASSLOWERFILTERS,
675         IDS_PROP_CLASSINSTALLER,
676         IDS_PROP_CLASSCOINSTALLER,
677         IDS_PROP_DEVICECOINSTALLER,
678         IDS_PROP_FIRMWAREREVISION,
679         IDS_PROP_CURRENTPOWERSTATE,
680         IDS_PROP_POWERCAPABILITIES,
681         IDS_PROP_POWERSTATEMAPPINGS
682     };
683 
684 
685     /* set the device image */
686     SendDlgItemMessage(hwndDlg,
687                        IDC_DEVICON,
688                        STM_SETICON,
689                        (WPARAM)dap->hDevIcon,
690                        0);
691 
692     /* set the device name edit control text */
693     SetDlgItemText(hwndDlg,
694                    IDC_DEVNAME,
695                    dap->szDevName);
696 
697 
698     hwndComboBox = GetDlgItem(hwndDlg,
699                               IDC_DETAILSPROPNAME);
700 
701     hwndListView = GetDlgItem(hwndDlg,
702                               IDC_DETAILSPROPVALUE);
703 
704     for (i = 0; i != sizeof(Properties) / sizeof(Properties[0]); i++)
705     {
706         /* fill in the device usage combo box */
707         if (LoadString(hDllInstance,
708                        Properties[i],
709                        dap->szTemp,
710                        sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
711         {
712             SendMessage(hwndComboBox,
713                         CB_ADDSTRING,
714                         0,
715                         (LPARAM)dap->szTemp);
716         }
717     }
718 
719 
720     GetClientRect(hwndListView,
721                   &rcClient);
722 
723     /* add a column to the list view control */
724     lvc.mask = LVCF_FMT | LVCF_WIDTH;
725     lvc.fmt = LVCFMT_LEFT;
726     lvc.cx = rcClient.right;
727     (void)ListView_InsertColumn(hwndListView,
728                                 0,
729                                 &lvc);
730 
731     SendMessage(hwndComboBox,
732                 CB_SETCURSEL,
733                 0,
734                 0);
735 
736     SetListViewText(hwndListView, 0, dap->szDeviceID);
737 
738     SetFocus(hwndComboBox);
739 }
740 
741 
742 static VOID
743 DisplayDevicePropertyText(IN PDEVADVPROP_INFO dap,
744                           IN HWND hwndListView,
745                           IN DWORD dwProperty)
746 {
747     HDEVINFO DeviceInfoSet;
748     PSP_DEVINFO_DATA DeviceInfoData;
749     DWORD dwType;
750     DWORD dwSize;
751     DWORD dwValue;
752     LPBYTE lpBuffer;
753     LPWSTR lpStr;
754     INT len;
755     INT index;
756 
757     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
758     {
759         DeviceInfoSet = dap->CurrentDeviceInfoSet;
760         DeviceInfoData = &dap->CurrentDeviceInfoData;
761     }
762     else
763     {
764         DeviceInfoSet = dap->DeviceInfoSet;
765         DeviceInfoData = &dap->DeviceInfoData;
766     }
767 
768     dwSize = 0;
769     SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
770                                      DeviceInfoData,
771                                      dwProperty,
772                                      &dwType,
773                                      NULL,
774                                      0,
775                                      &dwSize);
776     if (dwSize == 0)
777     {
778         if (GetLastError() != ERROR_FILE_NOT_FOUND)
779         {
780             swprintf(dap->szTemp, L"Error: Getting the size failed! (Error: %ld)", GetLastError());
781             SetListViewText(hwndListView, 0, dap->szTemp);
782         }
783         return;
784     }
785 
786     if (dwType == REG_SZ)
787         dwSize += sizeof(WCHAR);
788 
789     lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
790                                  HEAP_ZERO_MEMORY,
791                                  dwSize);
792     if (lpBuffer == NULL)
793     {
794         SetListViewText(hwndListView, 0, L"Error: Allocating the buffer failed!");
795         return;
796     }
797 
798     if (SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
799                                          DeviceInfoData,
800                                          dwProperty,
801                                          &dwType,
802                                          lpBuffer,
803                                          dwSize,
804                                          &dwSize))
805     {
806         if (dwType == REG_SZ)
807         {
808             SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
809         }
810         else if (dwType == REG_MULTI_SZ)
811         {
812             lpStr = (LPWSTR)lpBuffer;
813             index = 0;
814             while (*lpStr != 0)
815             {
816                 len = wcslen(lpStr) + 1;
817 
818                 SetListViewText(hwndListView, index, lpStr);
819 
820                 lpStr += len;
821                 index++;
822             }
823         }
824         else if (dwType == REG_DWORD)
825         {
826             dwValue = *(DWORD *) lpBuffer;
827 
828             switch (dwProperty)
829             {
830                 case SPDRP_CAPABILITIES:
831                     index = 0;
832                     if (dwValue & CM_DEVCAP_LOCKSUPPORTED)
833                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_LOCKSUPPORTED");
834                     if (dwValue & CM_DEVCAP_EJECTSUPPORTED)
835                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_EJECTSUPPORTED");
836                     if (dwValue & CM_DEVCAP_REMOVABLE)
837                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_REMOVABLE");
838                     if (dwValue & CM_DEVCAP_DOCKDEVICE)
839                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_DOCKDEVICE");
840                     if (dwValue & CM_DEVCAP_UNIQUEID)
841                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_UNIQUEID");
842                     if (dwValue & CM_DEVCAP_SILENTINSTALL)
843                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_SILENTINSTALL");
844                     if (dwValue & CM_DEVCAP_RAWDEVICEOK)
845                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_RAWDEVICEOK");
846                     if (dwValue & CM_DEVCAP_SURPRISEREMOVALOK)
847                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_SURPRISEREMOVALOK");
848                     if (dwValue & CM_DEVCAP_HARDWAREDISABLED)
849                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_HARDWAREDISABLED");
850                     if (dwValue & CM_DEVCAP_NONDYNAMIC)
851                         SetListViewText(hwndListView, index++, L"CM_DEVCAP_NONDYNAMIC");
852                     break;
853 
854                 case SPDRP_CONFIGFLAGS:
855                     index = 0;
856                     if (dwValue & CONFIGFLAG_DISABLED)
857                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_DISABLED");
858                     if (dwValue & CONFIGFLAG_REMOVED)
859                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_REMOVED");
860                     if (dwValue & CONFIGFLAG_MANUAL_INSTALL)
861                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_MANUAL_INSTALL");
862                     if (dwValue & CONFIGFLAG_IGNORE_BOOT_LC)
863                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_IGNORE_BOOT_LC");
864                     if (dwValue & CONFIGFLAG_NET_BOOT)
865                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_NET_BOOT");
866                     if (dwValue & CONFIGFLAG_REINSTALL)
867                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_REINSTALL");
868                     if (dwValue & CONFIGFLAG_FAILEDINSTALL)
869                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_FAILEDINSTALL");
870                     if (dwValue & CONFIGFLAG_CANTSTOPACHILD)
871                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_CANTSTOPACHILD");
872                     if (dwValue & CONFIGFLAG_OKREMOVEROM)
873                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_OKREMOVEROM");
874                     if (dwValue & CONFIGFLAG_NOREMOVEEXIT)
875                         SetListViewText(hwndListView, index++, L"CONFIGFLAG_NOREMOVEEXIT");
876                     break;
877 
878                 default:
879                     swprintf(dap->szTemp, L"0x%08lx", dwValue);
880                     SetListViewText(hwndListView, 0, dap->szTemp);
881                     break;
882             }
883         }
884         else
885         {
886             SetListViewText(hwndListView, 0, L"Error: Unsupported value type!");
887 
888         }
889     }
890     else
891     {
892         SetListViewText(hwndListView, 0, L"Error: Retrieving the value failed!");
893     }
894 
895     HeapFree(GetProcessHeap(),
896              0,
897              lpBuffer);
898 }
899 
900 static VOID
901 DisplayDevNodeFlags(IN PDEVADVPROP_INFO dap,
902                     IN HWND hwndListView)
903 {
904     DWORD dwStatus = 0;
905     DWORD dwProblem = 0;
906     INT index;
907 
908     CM_Get_DevNode_Status_Ex(&dwStatus,
909                              &dwProblem,
910                              dap->DeviceInfoData.DevInst,
911                              0,
912                              dap->hMachine);
913 
914     index = 0;
915     if (dwStatus & DN_ROOT_ENUMERATED)
916         SetListViewText(hwndListView, index++, L"DN_ROOT_ENUMERATED");
917     if (dwStatus & DN_DRIVER_LOADED)
918         SetListViewText(hwndListView, index++, L"DN_DRIVER_LOADED");
919     if (dwStatus & DN_ENUM_LOADED)
920         SetListViewText(hwndListView, index++, L"DN_ENUM_LOADED");
921     if (dwStatus & DN_STARTED)
922         SetListViewText(hwndListView, index++, L"DN_STARTED");
923     if (dwStatus & DN_MANUAL)
924         SetListViewText(hwndListView, index++, L"DN_MANUAL");
925     if (dwStatus & DN_NEED_TO_ENUM)
926         SetListViewText(hwndListView, index++, L"DN_NEED_TO_ENUM");
927     if (dwStatus & DN_DRIVER_BLOCKED)
928         SetListViewText(hwndListView, index++, L"DN_DRIVER_BLOCKED");
929     if (dwStatus & DN_HARDWARE_ENUM)
930         SetListViewText(hwndListView, index++, L"DN_HARDWARE_ENUM");
931     if (dwStatus & DN_NEED_RESTART)
932         SetListViewText(hwndListView, index++, L"DN_NEED_RESTART");
933     if (dwStatus & DN_CHILD_WITH_INVALID_ID)
934         SetListViewText(hwndListView, index++, L"DN_CHILD_WITH_INVALID_ID");
935     if (dwStatus & DN_HAS_PROBLEM)
936         SetListViewText(hwndListView, index++, L"DN_HAS_PROBLEM");
937     if (dwStatus & DN_FILTERED)
938         SetListViewText(hwndListView, index++, L"DN_FILTERED");
939     if (dwStatus & DN_LEGACY_DRIVER)
940         SetListViewText(hwndListView, index++, L"DN_LEGACY_DRIVER");
941     if (dwStatus & DN_DISABLEABLE)
942         SetListViewText(hwndListView, index++, L"DN_DISABLEABLE");
943     if (dwStatus & DN_REMOVABLE)
944         SetListViewText(hwndListView, index++, L"DN_REMOVABLE");
945     if (dwStatus & DN_PRIVATE_PROBLEM)
946         SetListViewText(hwndListView, index++, L"DN_PRIVATE_PROBLEM");
947     if (dwStatus & DN_MF_PARENT)
948         SetListViewText(hwndListView, index++, L"DN_MF_PARENT");
949     if (dwStatus & DN_MF_CHILD)
950         SetListViewText(hwndListView, index++, L"DN_MF_CHILD");
951     if (dwStatus & DN_WILL_BE_REMOVED)
952         SetListViewText(hwndListView, index++, L"DN_WILL_BE_REMOVED");
953 
954     if (dwStatus & DN_NOT_FIRST_TIMEE)
955         SetListViewText(hwndListView, index++, L"DN_NOT_FIRST_TIMEE");
956     if (dwStatus & DN_STOP_FREE_RES)
957         SetListViewText(hwndListView, index++, L"DN_STOP_FREE_RES");
958     if (dwStatus & DN_REBAL_CANDIDATE)
959         SetListViewText(hwndListView, index++, L"DN_REBAL_CANDIDATE");
960     if (dwStatus & DN_BAD_PARTIAL)
961         SetListViewText(hwndListView, index++, L"DN_BAD_PARTIAL");
962     if (dwStatus & DN_NT_ENUMERATOR)
963         SetListViewText(hwndListView, index++, L"DN_NT_ENUMERATOR");
964     if (dwStatus & DN_NT_DRIVER)
965         SetListViewText(hwndListView, index++, L"DN_NT_DRIVER");
966 
967     if (dwStatus & DN_NEEDS_LOCKING)
968         SetListViewText(hwndListView, index++, L"DN_NEEDS_LOCKING");
969     if (dwStatus & DN_ARM_WAKEUP)
970         SetListViewText(hwndListView, index++, L"DN_ARM_WAKEUP");
971     if (dwStatus & DN_APM_ENUMERATOR)
972         SetListViewText(hwndListView, index++, L"DN_APM_ENUMERATOR");
973     if (dwStatus & DN_APM_DRIVER)
974         SetListViewText(hwndListView, index++, L"DN_APM_DRIVER");
975     if (dwStatus & DN_SILENT_INSTALL)
976         SetListViewText(hwndListView, index++, L"DN_SILENT_INSTALL");
977     if (dwStatus & DN_NO_SHOW_IN_DM)
978         SetListViewText(hwndListView, index++, L"DN_NO_SHOW_IN_DM");
979     if (dwStatus & DN_BOOT_LOG_PROB)
980         SetListViewText(hwndListView, index++, L"DN_BOOT_LOG_PROB");
981 
982 //    swprintf(dap->szTemp, L"0x%08x", dwStatus);
983 //    SetListViewText(hwndListView, 0, dap->szTemp);
984 }
985 
986 
987 static VOID
988 DisplayDevNodeEnumerator(IN PDEVADVPROP_INFO dap,
989                          IN HWND hwndListView)
990 {
991     PSP_DEVINFO_DATA DeviceInfoData;
992 
993     DWORD dwType = 0;
994     WCHAR szBuffer[256];
995     DWORD dwSize = 256 * sizeof(WCHAR);
996 
997     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
998     {
999         DeviceInfoData = &dap->CurrentDeviceInfoData;
1000     }
1001     else
1002     {
1003         DeviceInfoData = &dap->DeviceInfoData;
1004     }
1005 
1006     CM_Get_DevNode_Registry_Property_ExW(DeviceInfoData->DevInst,
1007                                          CM_DRP_ENUMERATOR_NAME,
1008                                          &dwType,
1009                                          &szBuffer,
1010                                          &dwSize,
1011                                          0,
1012                                          dap->hMachine);
1013 
1014     SetListViewText(hwndListView, 0, szBuffer);
1015 }
1016 
1017 
1018 static VOID
1019 DisplayCsFlags(IN PDEVADVPROP_INFO dap,
1020                IN HWND hwndListView)
1021 {
1022     DWORD dwValue = 0;
1023     INT index;
1024 
1025     CM_Get_HW_Prof_Flags_Ex(dap->szDevName,
1026                             0, /* current hardware profile */
1027                             &dwValue,
1028                             0,
1029                             dap->hMachine);
1030 
1031     index = 0;
1032     if (dwValue & CSCONFIGFLAG_DISABLED)
1033         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DISABLED");
1034 
1035     if (dwValue & CSCONFIGFLAG_DO_NOT_CREATE)
1036         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_CREATE");
1037 
1038     if (dwValue & CSCONFIGFLAG_DO_NOT_START)
1039         SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_START");
1040 }
1041 
1042 
1043 static VOID
1044 DisplayMatchingDeviceId(IN PDEVADVPROP_INFO dap,
1045                         IN HWND hwndListView)
1046 {
1047     HDEVINFO DeviceInfoSet;
1048     PSP_DEVINFO_DATA DeviceInfoData;
1049     WCHAR szBuffer[256];
1050     HKEY hKey;
1051     DWORD dwSize;
1052     DWORD dwType;
1053 
1054     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1055     {
1056         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1057         DeviceInfoData = &dap->CurrentDeviceInfoData;
1058     }
1059     else
1060     {
1061         DeviceInfoSet = dap->DeviceInfoSet;
1062         DeviceInfoData = &dap->DeviceInfoData;
1063     }
1064 
1065     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
1066                                 DeviceInfoData,
1067                                 DICS_FLAG_GLOBAL,
1068                                 0,
1069                                 DIREG_DRV,
1070                                 KEY_QUERY_VALUE);
1071     if (hKey != INVALID_HANDLE_VALUE)
1072     {
1073         dwSize = 256 * sizeof(WCHAR);
1074         if (RegQueryValueEx(hKey,
1075                             L"MatchingDeviceId",
1076                             NULL,
1077                             &dwType,
1078                             (LPBYTE)szBuffer,
1079                             &dwSize) == ERROR_SUCCESS)
1080         {
1081             SetListViewText(hwndListView, 0, szBuffer);
1082         }
1083 
1084         RegCloseKey(hKey);
1085     }
1086 }
1087 
1088 
1089 static VOID
1090 DisplayClassCoinstallers(IN PDEVADVPROP_INFO dap,
1091                           IN HWND hwndListView)
1092 {
1093     HDEVINFO DeviceInfoSet;
1094     PSP_DEVINFO_DATA DeviceInfoData;
1095     WCHAR szClassGuid[45];
1096     HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
1097     DWORD dwSize;
1098     DWORD dwType;
1099     LPBYTE lpBuffer = NULL;
1100     LPWSTR lpStr;
1101     INT index;
1102     INT len;
1103     LONG lError;
1104 
1105     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1106     {
1107         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1108         DeviceInfoData = &dap->CurrentDeviceInfoData;
1109     }
1110     else
1111     {
1112         DeviceInfoSet = dap->DeviceInfoSet;
1113         DeviceInfoData = &dap->DeviceInfoData;
1114     }
1115 
1116     dwSize = 45 * sizeof(WCHAR);
1117     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1118                                           DeviceInfoData,
1119                                           SPDRP_CLASSGUID,
1120                                           &dwType,
1121                                           (LPBYTE)szClassGuid,
1122                                           dwSize,
1123                                           &dwSize))
1124         return;
1125 
1126     lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1127                            L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
1128                            0,
1129                            GENERIC_READ,
1130                            &hKey);
1131     if (lError != ERROR_SUCCESS)
1132         return;
1133 
1134     dwSize = 0;
1135     lError = RegQueryValueEx(hKey,
1136                              szClassGuid,
1137                              NULL,
1138                              &dwType,
1139                              NULL,
1140                              &dwSize);
1141     if (lError != ERROR_SUCCESS)
1142         goto done;
1143 
1144     if (dwSize == 0)
1145         goto done;
1146 
1147     lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1148                                  HEAP_ZERO_MEMORY,
1149                                  dwSize);
1150 
1151     RegQueryValueEx(hKey,
1152                     szClassGuid,
1153                     NULL,
1154                     &dwType,
1155                     lpBuffer,
1156                     &dwSize);
1157 
1158     lpStr = (LPWSTR)lpBuffer;
1159     index = 0;
1160     while (*lpStr != 0)
1161     {
1162         len = wcslen(lpStr) + 1;
1163 
1164         SetListViewText(hwndListView, index, lpStr);
1165 
1166         lpStr += len;
1167         index++;
1168     }
1169 
1170 done:
1171     if (lpBuffer != NULL)
1172         HeapFree(GetProcessHeap(), 0, lpBuffer);
1173 
1174     if (hKey != INVALID_HANDLE_VALUE)
1175         RegCloseKey(hKey);
1176 }
1177 
1178 
1179 static VOID
1180 DisplayDeviceCoinstallers(IN PDEVADVPROP_INFO dap,
1181                           IN HWND hwndListView)
1182 {
1183     HDEVINFO DeviceInfoSet;
1184     PSP_DEVINFO_DATA DeviceInfoData;
1185     HKEY hKey;
1186     DWORD dwSize;
1187     DWORD dwType;
1188     LPBYTE lpBuffer;
1189     LPWSTR lpStr;
1190     INT index;
1191     INT len;
1192 
1193     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1194     {
1195         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1196         DeviceInfoData = &dap->CurrentDeviceInfoData;
1197     }
1198     else
1199     {
1200         DeviceInfoSet = dap->DeviceInfoSet;
1201         DeviceInfoData = &dap->DeviceInfoData;
1202     }
1203 
1204     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
1205                                 DeviceInfoData,
1206                                 DICS_FLAG_GLOBAL,
1207                                 0,
1208                                 DIREG_DRV,
1209                                 KEY_QUERY_VALUE);
1210     if (hKey != INVALID_HANDLE_VALUE)
1211     {
1212         dwSize = 0;
1213         if (RegQueryValueEx(hKey,
1214                             L"CoInstallers32",
1215                             NULL,
1216                             &dwType,
1217                             NULL,
1218                             &dwSize) == ERROR_SUCCESS &&
1219             dwSize > 0)
1220         {
1221 
1222             lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1223                                          HEAP_ZERO_MEMORY,
1224                                          dwSize);
1225 
1226             RegQueryValueEx(hKey,
1227                             L"CoInstallers32",
1228                             NULL,
1229                             &dwType,
1230                             lpBuffer,
1231                             &dwSize);
1232 
1233             lpStr = (LPWSTR)lpBuffer;
1234             index = 0;
1235             while (*lpStr != 0)
1236             {
1237                 len = wcslen(lpStr) + 1;
1238 
1239                 SetListViewText(hwndListView, index, lpStr);
1240 
1241                 lpStr += len;
1242                 index++;
1243             }
1244 
1245             HeapFree(GetProcessHeap(),
1246                      0,
1247                      lpBuffer);
1248         }
1249 
1250         RegCloseKey(hKey);
1251     }
1252 }
1253 
1254 
1255 static VOID
1256 DisplayClassProperties(IN PDEVADVPROP_INFO dap,
1257                        IN HWND hwndListView,
1258                        IN LPCWSTR lpProperty)
1259 {
1260     HDEVINFO DeviceInfoSet;
1261     PSP_DEVINFO_DATA DeviceInfoData;
1262     WCHAR szClassGuid[45];
1263     DWORD dwSize;
1264     DWORD dwType;
1265     HKEY hKey;
1266     GUID ClassGuid;
1267     LPBYTE lpBuffer;
1268     LPWSTR lpStr;
1269     INT index = 0;
1270     INT len;
1271 
1272     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1273     {
1274         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1275         DeviceInfoData = &dap->CurrentDeviceInfoData;
1276     }
1277     else
1278     {
1279         DeviceInfoSet = dap->DeviceInfoSet;
1280         DeviceInfoData = &dap->DeviceInfoData;
1281     }
1282 
1283     dwSize = 45 * sizeof(WCHAR);
1284     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1285                                           DeviceInfoData,
1286                                           SPDRP_CLASSGUID,
1287                                           &dwType,
1288                                           (LPBYTE)szClassGuid,
1289                                           dwSize,
1290                                           &dwSize))
1291         return;
1292 
1293     pSetupGuidFromString(szClassGuid,
1294                          &ClassGuid);
1295 
1296     hKey = SetupDiOpenClassRegKey(&ClassGuid,
1297                                   KEY_QUERY_VALUE);
1298     if (hKey != INVALID_HANDLE_VALUE)
1299     {
1300         dwSize = 0;
1301         if (RegQueryValueEx(hKey,
1302                             lpProperty,
1303                             NULL,
1304                             &dwType,
1305                             NULL,
1306                             &dwSize) == ERROR_SUCCESS &&
1307             dwSize > 0)
1308         {
1309             lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(),
1310                                          HEAP_ZERO_MEMORY,
1311                                          dwSize);
1312 
1313             RegQueryValueEx(hKey,
1314                             lpProperty,
1315                             NULL,
1316                             &dwType,
1317                             lpBuffer,
1318                             &dwSize);
1319 
1320             if (dwType == REG_SZ)
1321             {
1322                 SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
1323             }
1324             else if (dwType == REG_MULTI_SZ)
1325             {
1326                 lpStr = (LPWSTR)lpBuffer;
1327                 index = 0;
1328                 while (*lpStr != 0)
1329                 {
1330                     len = wcslen(lpStr) + 1;
1331 
1332                     SetListViewText(hwndListView, index, lpStr);
1333 
1334                     lpStr += len;
1335                     index++;
1336                 }
1337             }
1338 
1339             HeapFree(GetProcessHeap(),
1340                      0,
1341                      lpBuffer);
1342         }
1343 
1344         RegCloseKey(hKey);
1345     }
1346 }
1347 
1348 
1349 static VOID
1350 DisplayDeviceRelations(
1351     IN PDEVADVPROP_INFO dap,
1352     IN HWND hwndListView,
1353     IN ULONG ulFlags)
1354 {
1355     ULONG ulLength = 0;
1356     LPWSTR pszBuffer = NULL, pszStr;
1357     INT index = 0, len;
1358     CONFIGRET ret;
1359 
1360     ret = CM_Get_Device_ID_List_Size_ExW(&ulLength,
1361                                          dap->szDeviceID,
1362                                          ulFlags,
1363                                          NULL);
1364     if (ret != CR_SUCCESS)
1365         return;
1366 
1367     pszBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(),
1368                                   HEAP_ZERO_MEMORY,
1369                                   ulLength * sizeof(WCHAR));
1370     if (pszBuffer == NULL)
1371         return;
1372 
1373     ret = CM_Get_Device_ID_List_ExW(dap->szDeviceID,
1374                                     pszBuffer,
1375                                     ulLength,
1376                                     ulFlags,
1377                                     NULL);
1378     if (ret != CR_SUCCESS)
1379     {
1380         HeapFree(GetProcessHeap(), 0, pszBuffer);
1381         return;
1382     }
1383 
1384     pszStr = pszBuffer;
1385     index = 0;
1386     while (*pszStr != 0)
1387     {
1388         len = wcslen(pszStr) + 1;
1389 
1390         SetListViewText(hwndListView, index, pszStr);
1391 
1392         pszStr += len;
1393         index++;
1394     }
1395 
1396     HeapFree(GetProcessHeap(), 0, pszBuffer);
1397 }
1398 
1399 
1400 static VOID
1401 DisplayCurrentPowerState(
1402     IN PDEVADVPROP_INFO dap,
1403     IN HWND hwndListView)
1404 {
1405     HDEVINFO DeviceInfoSet;
1406     PSP_DEVINFO_DATA DeviceInfoData;
1407     CM_POWER_DATA PowerData;
1408     DWORD dwSize, dwType;
1409     PCWSTR lpText = NULL;
1410 
1411     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1412     {
1413         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1414         DeviceInfoData = &dap->CurrentDeviceInfoData;
1415     }
1416     else
1417     {
1418         DeviceInfoSet = dap->DeviceInfoSet;
1419         DeviceInfoData = &dap->DeviceInfoData;
1420     }
1421 
1422     dwSize = sizeof(CM_POWER_DATA);
1423     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1424                                           DeviceInfoData,
1425                                           SPDRP_DEVICE_POWER_DATA,
1426                                           &dwType,
1427                                           (LPBYTE)&PowerData,
1428                                           dwSize,
1429                                           &dwSize))
1430         return;
1431 
1432     switch (PowerData.PD_MostRecentPowerState)
1433     {
1434 //        case PowerDeviceUnspecified:
1435 
1436         case PowerDeviceD0:
1437             lpText = L"D0";
1438             break;
1439 
1440         case PowerDeviceD1:
1441             lpText = L"D1";
1442             break;
1443 
1444         case PowerDeviceD2:
1445             lpText = L"D2";
1446             break;
1447 
1448         case PowerDeviceD3:
1449             lpText = L"D3";
1450             break;
1451 
1452         default:
1453             break;
1454     }
1455 
1456     if (lpText != NULL)
1457         SetListViewText(hwndListView, 0, lpText);
1458 }
1459 
1460 
1461 static VOID
1462 DisplayPowerCapabilities(
1463     IN PDEVADVPROP_INFO dap,
1464     IN HWND hwndListView)
1465 {
1466     HDEVINFO DeviceInfoSet;
1467     PSP_DEVINFO_DATA DeviceInfoData;
1468     CM_POWER_DATA PowerData;
1469     DWORD dwSize, dwType;
1470     INT index = 0;
1471 
1472     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1473     {
1474         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1475         DeviceInfoData = &dap->CurrentDeviceInfoData;
1476     }
1477     else
1478     {
1479         DeviceInfoSet = dap->DeviceInfoSet;
1480         DeviceInfoData = &dap->DeviceInfoData;
1481     }
1482 
1483     dwSize = sizeof(CM_POWER_DATA);
1484     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1485                                           DeviceInfoData,
1486                                           SPDRP_DEVICE_POWER_DATA,
1487                                           &dwType,
1488                                           (LPBYTE)&PowerData,
1489                                           dwSize,
1490                                           &dwSize))
1491         return;
1492 
1493     if (PowerData.PD_Capabilities & PDCAP_D0_SUPPORTED)
1494         SetListViewText(hwndListView, index++, L"PDCAP_D0_SUPPORTED");
1495 
1496     if (PowerData.PD_Capabilities & PDCAP_D1_SUPPORTED)
1497         SetListViewText(hwndListView, index++, L"PDCAP_D1_SUPPORTED");
1498 
1499     if (PowerData.PD_Capabilities & PDCAP_D2_SUPPORTED)
1500         SetListViewText(hwndListView, index++, L"PDCAP_D2_SUPPORTED");
1501 
1502     if (PowerData.PD_Capabilities & PDCAP_D3_SUPPORTED)
1503         SetListViewText(hwndListView, index++, L"PDCAP_D3_SUPPORTED");
1504 
1505     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D0_SUPPORTED)
1506         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D0_SUPPORTED");
1507 
1508     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D1_SUPPORTED)
1509         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D1_SUPPORTED");
1510 
1511     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D2_SUPPORTED)
1512         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D2_SUPPORTED");
1513 
1514     if (PowerData.PD_Capabilities & PDCAP_WAKE_FROM_D3_SUPPORTED)
1515         SetListViewText(hwndListView, index++, L"PDCAP_WAKE_FROM_D3_SUPPORTED");
1516 
1517     if (PowerData.PD_Capabilities & PDCAP_WARM_EJECT_SUPPORTED)
1518         SetListViewText(hwndListView, index++, L"PDCAP_WARM_EJECT_SUPPORTED");
1519 }
1520 
1521 
1522 static VOID
1523 DisplayPowerStateMappings(
1524     IN PDEVADVPROP_INFO dap,
1525     IN HWND hwndListView)
1526 {
1527     HDEVINFO DeviceInfoSet;
1528     PSP_DEVINFO_DATA DeviceInfoData;
1529     CM_POWER_DATA PowerData;
1530     DWORD dwSize, dwType;
1531     INT i;
1532     DEVICE_POWER_STATE PowerState;
1533     WCHAR szSystemStateBuffer[40];
1534     WCHAR szDeviceStateBuffer[40];
1535     WCHAR szOutBuffer[100];
1536 
1537     if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
1538     {
1539         DeviceInfoSet = dap->CurrentDeviceInfoSet;
1540         DeviceInfoData = &dap->CurrentDeviceInfoData;
1541     }
1542     else
1543     {
1544         DeviceInfoSet = dap->DeviceInfoSet;
1545         DeviceInfoData = &dap->DeviceInfoData;
1546     }
1547 
1548     dwSize = sizeof(CM_POWER_DATA);
1549     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
1550                                           DeviceInfoData,
1551                                           SPDRP_DEVICE_POWER_DATA,
1552                                           &dwType,
1553                                           (LPBYTE)&PowerData,
1554                                           dwSize,
1555                                           &dwSize))
1556         return;
1557 
1558     for (i = PowerSystemWorking; i < PowerSystemMaximum; i++)
1559     {
1560         PowerState = PowerData.PD_PowerStateMapping[i];
1561         if ((PowerState >= PowerDeviceUnspecified) && (PowerState <= PowerDeviceD3))
1562         {
1563             swprintf(szSystemStateBuffer, L"S%u", i - 1);
1564 
1565             switch (PowerState)
1566             {
1567                 case PowerDeviceUnspecified:
1568                     wcscpy(szDeviceStateBuffer, L"Not specified");
1569                     break;
1570 
1571                 case PowerDeviceD0:
1572                     wcscpy(szDeviceStateBuffer, L"D0");
1573                     break;
1574 
1575                 case PowerDeviceD1:
1576                     wcscpy(szDeviceStateBuffer, L"D1");
1577                     break;
1578 
1579                 case PowerDeviceD2:
1580                     wcscpy(szDeviceStateBuffer, L"D2");
1581                     break;
1582 
1583                 case PowerDeviceD3:
1584                     wcscpy(szDeviceStateBuffer, L"D3");
1585                     break;
1586 
1587                 default:
1588                     break;
1589             }
1590 
1591             swprintf(szOutBuffer, L"%s -> %s", szSystemStateBuffer, szDeviceStateBuffer);
1592             SetListViewText(hwndListView, i, szOutBuffer);
1593         }
1594     }
1595 }
1596 
1597 
1598 static VOID
1599 DisplayDeviceProperties(IN PDEVADVPROP_INFO dap,
1600                         IN HWND hwndComboBox,
1601                         IN HWND hwndListView)
1602 {
1603     INT Index;
1604 
1605     Index = (INT)SendMessage(hwndComboBox,
1606                              CB_GETCURSEL,
1607                              0,
1608                              0);
1609     if (Index == CB_ERR)
1610         return;
1611 
1612     (void)ListView_DeleteAllItems(hwndListView);
1613 
1614     switch (Index)
1615     {
1616         case 0: /* Device ID */
1617             SetListViewText(hwndListView, 0, dap->szDeviceID);
1618             break;
1619 
1620         case 1: /* Hardware ID */
1621             DisplayDevicePropertyText(dap,
1622                                       hwndListView,
1623                                       SPDRP_HARDWAREID);
1624             break;
1625 
1626         case 2: /* Compatible IDs */
1627             DisplayDevicePropertyText(dap,
1628                                       hwndListView,
1629                                       SPDRP_COMPATIBLEIDS);
1630             break;
1631 
1632         case 3: /* Matching ID */
1633             DisplayMatchingDeviceId(dap,
1634                                     hwndListView);
1635             break;
1636 
1637         case 4: /* Service */
1638             DisplayDevicePropertyText(dap,
1639                                       hwndListView,
1640                                       SPDRP_SERVICE);
1641             break;
1642 
1643         case 5: /* Enumerator */
1644             DisplayDevNodeEnumerator(dap,
1645                                      hwndListView);
1646             break;
1647 
1648         case 6: /* Capabilities */
1649             DisplayDevicePropertyText(dap,
1650                                       hwndListView,
1651                                       SPDRP_CAPABILITIES);
1652             break;
1653 
1654         case 7: /* Devnode Flags */
1655             DisplayDevNodeFlags(dap,
1656                                 hwndListView);
1657             break;
1658 
1659         case 8: /* Config Flags */
1660             DisplayDevicePropertyText(dap,
1661                                       hwndListView,
1662                                       SPDRP_CONFIGFLAGS);
1663             break;
1664 
1665         case 9: /* CSConfig Flags */
1666             DisplayCsFlags(dap,
1667                            hwndListView);
1668             break;
1669 
1670         case 10: /* Ejection relation */
1671             DisplayDeviceRelations(dap,
1672                                    hwndListView,
1673                                    CM_GETIDLIST_FILTER_EJECTRELATIONS);
1674             break;
1675 
1676         case 11: /* Removal relations */
1677             DisplayDeviceRelations(dap,
1678                                    hwndListView,
1679                                    CM_GETIDLIST_FILTER_REMOVALRELATIONS);
1680             break;
1681 
1682         case 12: /* Bus relation */
1683             DisplayDeviceRelations(dap,
1684                                    hwndListView,
1685                                    CM_GETIDLIST_FILTER_BUSRELATIONS);
1686             break;
1687 
1688         case 13: /* Device Upper Filters */
1689             DisplayDevicePropertyText(dap,
1690                                       hwndListView,
1691                                       SPDRP_UPPERFILTERS);
1692             break;
1693 
1694         case 14: /* Device Lower Filters */
1695             DisplayDevicePropertyText(dap,
1696                                       hwndListView,
1697                                       SPDRP_LOWERFILTERS);
1698             break;
1699 
1700         case 15: /* Class Upper Filters */
1701             DisplayClassProperties(dap,
1702                                    hwndListView,
1703                                    L"UpperFilters");
1704             break;
1705 
1706         case 16: /* Class Lower Filters */
1707             DisplayClassProperties(dap,
1708                                    hwndListView,
1709                                    L"LowerFilters");
1710             break;
1711 
1712         case 17: /* Class Installer */
1713             DisplayClassProperties(dap,
1714                                    hwndListView,
1715                                    L"Installer32");
1716             break;
1717 
1718         case 18: /* Class Coinstaller */
1719             DisplayClassCoinstallers(dap,
1720                                      hwndListView);
1721             break;
1722 
1723         case 19: /* Device Coinstaller */
1724             DisplayDeviceCoinstallers(dap,
1725                                       hwndListView);
1726             break;
1727 
1728 #if 0
1729         case 20: /* Firmware Revision */
1730             break;
1731 #endif
1732 
1733         case 21: /* Current Power State */
1734             DisplayCurrentPowerState(dap,
1735                                      hwndListView);
1736             break;
1737 
1738         case 22: /* Power Capabilities */
1739             DisplayPowerCapabilities(dap,
1740                                      hwndListView);
1741             break;
1742 
1743         case 23: /* Power State Mappings */
1744             DisplayPowerStateMappings(dap,
1745                                       hwndListView);
1746             break;
1747 
1748         default:
1749             SetListViewText(hwndListView, 0, L"<Not implemented yet>");
1750             break;
1751     }
1752 }
1753 
1754 
1755 static INT_PTR
1756 CALLBACK
1757 AdvProcDetailsDlgProc(IN HWND hwndDlg,
1758                       IN UINT uMsg,
1759                       IN WPARAM wParam,
1760                       IN LPARAM lParam)
1761 {
1762     PDEVADVPROP_INFO dap;
1763     INT_PTR Ret = FALSE;
1764 
1765     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
1766 
1767     if (dap != NULL || uMsg == WM_INITDIALOG)
1768     {
1769         switch (uMsg)
1770         {
1771             case WM_COMMAND:
1772             {
1773                 switch (LOWORD(wParam))
1774                 {
1775                     case IDC_DETAILSPROPNAME:
1776                         if (HIWORD(wParam) == CBN_SELCHANGE)
1777                         {
1778                             DisplayDeviceProperties(dap,
1779                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPNAME),
1780                                                     GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE));
1781                         }
1782                         break;
1783                 }
1784                 break;
1785             }
1786 
1787             case WM_NOTIFY:
1788             {
1789                 NMHDR *hdr = (NMHDR*)lParam;
1790                 switch (hdr->code)
1791                 {
1792                     case PSN_APPLY:
1793                         break;
1794                 }
1795                 break;
1796             }
1797 
1798             case WM_INITDIALOG:
1799             {
1800                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
1801                 if (dap != NULL)
1802                 {
1803                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
1804 
1805                     UpdateDetailsDlg(hwndDlg,
1806                                      dap);
1807                 }
1808                 Ret = TRUE;
1809                 break;
1810             }
1811         }
1812     }
1813 
1814     return Ret;
1815 }
1816 
1817 
1818 static VOID
1819 InitDevUsageActions(IN HWND hwndDlg,
1820                     IN HWND hComboBox,
1821                     IN PDEVADVPROP_INFO dap)
1822 {
1823     INT Index;
1824     UINT i;
1825     UINT Actions[] =
1826     {
1827         IDS_ENABLEDEVICE,
1828         IDS_DISABLEDEVICE,
1829     };
1830 
1831     for (i = 0;
1832          i != sizeof(Actions) / sizeof(Actions[0]);
1833          i++)
1834     {
1835         /* fill in the device usage combo box */
1836         if (LoadString(hDllInstance,
1837                        Actions[i],
1838                        dap->szTemp,
1839                        sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
1840         {
1841             Index = (INT)SendMessage(hComboBox,
1842                                      CB_ADDSTRING,
1843                                      0,
1844                                      (LPARAM)dap->szTemp);
1845             if (Index != CB_ERR)
1846             {
1847                 SendMessage(hComboBox,
1848                             CB_SETITEMDATA,
1849                             (WPARAM)Index,
1850                             (LPARAM)Actions[i]);
1851 
1852                 switch (Actions[i])
1853                 {
1854                     case IDS_ENABLEDEVICE:
1855                         if (dap->DeviceStarted)
1856                         {
1857                             SendMessage(hComboBox,
1858                                         CB_SETCURSEL,
1859                                         (WPARAM)Index,
1860                                         0);
1861                         }
1862                         break;
1863 
1864                     case IDS_DISABLEDEVICE:
1865                         if (!dap->DeviceStarted)
1866                         {
1867                             SendMessage(hComboBox,
1868                                         CB_SETCURSEL,
1869                                         (WPARAM)Index,
1870                                         0);
1871                         }
1872                         break;
1873 
1874                     default:
1875                         break;
1876                 }
1877             }
1878         }
1879     }
1880 }
1881 
1882 
1883 static UINT
1884 GetSelectedUsageAction(IN HWND hComboBox)
1885 {
1886     INT Index;
1887     UINT Ret = 0;
1888 
1889     Index = (INT)SendMessage(hComboBox,
1890                              CB_GETCURSEL,
1891                              0,
1892                              0);
1893     if (Index != CB_ERR)
1894     {
1895         INT iRet = (INT) SendMessage(hComboBox,
1896                                CB_GETITEMDATA,
1897                                (WPARAM)Index,
1898                                0);
1899         if (iRet != CB_ERR)
1900         {
1901             Ret = (UINT)iRet;
1902         }
1903     }
1904 
1905     return Ret;
1906 }
1907 
1908 
1909 static BOOL
1910 ApplyGeneralSettings(IN HWND hwndDlg,
1911                      IN PDEVADVPROP_INFO dap)
1912 {
1913     BOOL Ret = FALSE;
1914 
1915     if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
1916     {
1917         UINT SelectedUsageAction;
1918         BOOL NeedReboot = FALSE;
1919 
1920         SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
1921                                                                 IDC_DEVUSAGE));
1922         switch (SelectedUsageAction)
1923         {
1924             case IDS_ENABLEDEVICE:
1925                 if (!dap->DeviceStarted)
1926                 {
1927                     Ret = EnableDevice(dap->DeviceInfoSet,
1928                                        &dap->DeviceInfoData,
1929                                        TRUE,
1930                                        0,
1931                                        &NeedReboot);
1932                 }
1933                 break;
1934 
1935             case IDS_DISABLEDEVICE:
1936                 if (dap->DeviceStarted)
1937                 {
1938                     Ret = EnableDevice(dap->DeviceInfoSet,
1939                                        &dap->DeviceInfoData,
1940                                        FALSE,
1941                                        0,
1942                                        &NeedReboot);
1943                 }
1944                 break;
1945 
1946             default:
1947                 break;
1948         }
1949 
1950         if (Ret)
1951         {
1952             if (NeedReboot)
1953             {
1954                 /* make PropertySheet() return PSM_REBOOTSYSTEM */
1955                 PropSheet_RebootSystem(hwndDlg);
1956             }
1957         }
1958         else
1959         {
1960             /* FIXME - display an error message */
1961             FIXME("Failed to enable/disable device! LastError: %d\n",
1962                   GetLastError());
1963         }
1964     }
1965     else
1966         Ret = !dap->DeviceUsageChanged;
1967 
1968     /* disable the apply button */
1969     PropSheet_UnChanged(GetParent(hwndDlg),
1970                         hwndDlg);
1971     dap->DeviceUsageChanged = FALSE;
1972     return Ret;
1973 }
1974 
1975 
1976 static VOID
1977 UpdateDevInfo(IN HWND hwndDlg,
1978               IN PDEVADVPROP_INFO dap,
1979               IN BOOL ReOpen)
1980 {
1981     HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
1982     CONFIGRET cr;
1983     ULONG Status, ProblemNumber;
1984     SP_DEVINSTALL_PARAMS_W InstallParams;
1985     UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
1986     BOOL bFlag, bDevActionAvailable = TRUE;
1987     BOOL bDrvInstalled = FALSE;
1988     DWORD iPage;
1989     HDEVINFO DeviceInfoSet = NULL;
1990     PSP_DEVINFO_DATA DeviceInfoData = NULL;
1991     PROPSHEETHEADER psh;
1992     DWORD nDriverPages = 0;
1993     BOOL RecalcPages = FALSE;
1994 
1995     hPropSheetDlg = GetParent(hwndDlg);
1996 
1997     if (dap->PageInitialized)
1998     {
1999         /* switch to the General page */
2000         PropSheet_SetCurSelByID(hPropSheetDlg,
2001                                 IDD_DEVICEGENERAL);
2002 
2003         /* remove and destroy the existing device property sheet pages */
2004         if (dap->DevPropSheets != NULL)
2005         {
2006             for (iPage = 0;
2007                  iPage != dap->nDevPropSheets;
2008                  iPage++)
2009             {
2010                 if (dap->DevPropSheets[iPage] != NULL)
2011                 {
2012                     PropSheet_RemovePage(hPropSheetDlg,
2013                                          (WPARAM) -1,
2014                                          dap->DevPropSheets[iPage]);
2015                     RecalcPages = TRUE;
2016                 }
2017             }
2018         }
2019     }
2020 
2021     iPage = 0;
2022 
2023     if (dap->FreeDevPropSheets)
2024     {
2025         /* don't free the array if it's the one allocated in
2026            DisplayDeviceAdvancedProperties */
2027         HeapFree(GetProcessHeap(),
2028                  0,
2029                  dap->DevPropSheets);
2030 
2031         dap->FreeDevPropSheets = FALSE;
2032     }
2033 
2034     dap->DevPropSheets = NULL;
2035     dap->nDevPropSheets = 0;
2036 
2037     if (ReOpen)
2038     {
2039         /* create a new device info set and re-open the device */
2040         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2041         {
2042             SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
2043         }
2044 
2045         dap->ParentDevInst = 0;
2046         dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
2047                                                                   hwndDlg,
2048                                                                   dap->lpMachineName,
2049                                                                   NULL);
2050         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2051         {
2052             if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
2053                                       dap->szDeviceID,
2054                                       hwndDlg,
2055                                       0,
2056                                       &dap->CurrentDeviceInfoData))
2057             {
2058                 if (dap->CloseDevInst)
2059                 {
2060                     SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
2061                 }
2062 
2063                 dap->CloseDevInst = TRUE;
2064                 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
2065                 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
2066                 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
2067             }
2068             else
2069                 goto GetParentNode;
2070         }
2071         else
2072         {
2073 GetParentNode:
2074             /* get the parent node from the initial devinst */
2075             CM_Get_Parent_Ex(&dap->ParentDevInst,
2076                              dap->DeviceInfoData.DevInst,
2077                              0,
2078                              dap->hMachine);
2079         }
2080 
2081         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2082         {
2083             DeviceInfoSet = dap->CurrentDeviceInfoSet;
2084             DeviceInfoData = &dap->CurrentDeviceInfoData;
2085         }
2086         else
2087         {
2088             DeviceInfoSet = dap->DeviceInfoSet;
2089             DeviceInfoData = &dap->DeviceInfoData;
2090         }
2091     }
2092     else
2093     {
2094         DeviceInfoSet = dap->DeviceInfoSet;
2095         DeviceInfoData = &dap->DeviceInfoData;
2096     }
2097 
2098     dap->HasDriverPage = FALSE;
2099     dap->HasResourcePage = FALSE;
2100     dap->HasPowerPage = FALSE;
2101     if (IsDriverInstalled(DeviceInfoData->DevInst,
2102                           dap->hMachine,
2103                           &bDrvInstalled) &&
2104         bDrvInstalled)
2105     {
2106         if (SetupDiCallClassInstaller((dap->ShowRemotePages ?
2107                                            DIF_ADDREMOTEPROPERTYPAGE_ADVANCED :
2108                                            DIF_ADDPROPERTYPAGE_ADVANCED),
2109                                       DeviceInfoSet,
2110                                       DeviceInfoData))
2111         {
2112             /* get install params */
2113             InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
2114             if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
2115                                                 DeviceInfoData,
2116                                                 &InstallParams))
2117             {
2118                 /* zero the flags */
2119                 InstallParams.Flags = 0;
2120             }
2121 
2122             dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
2123             dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
2124             dap->HasPowerPage = !(InstallParams.Flags & DI_FLAGSEX_POWERPAGE_ADDED);
2125         }
2126     }
2127 
2128     /* get the device icon */
2129     if (dap->hDevIcon != NULL)
2130     {
2131         DestroyIcon(dap->hDevIcon);
2132         dap->hDevIcon = NULL;
2133     }
2134     if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
2135                               &dap->hDevIcon,
2136                               NULL))
2137     {
2138         dap->hDevIcon = NULL;
2139     }
2140 
2141     /* get the device name */
2142     if (GetDeviceDescriptionString(DeviceInfoSet,
2143                                    DeviceInfoData,
2144                                    dap->szDevName,
2145                                    sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
2146     {
2147         PropSheet_SetTitle(hPropSheetDlg,
2148                            PSH_PROPTITLE,
2149                            dap->szDevName);
2150     }
2151 
2152     /* set the device image */
2153     SendDlgItemMessage(hwndDlg,
2154                        IDC_DEVICON,
2155                        STM_SETICON,
2156                        (WPARAM)dap->hDevIcon,
2157                        0);
2158 
2159     /* set the device name edit control text */
2160     SetDlgItemText(hwndDlg,
2161                    IDC_DEVNAME,
2162                    dap->szDevName);
2163 
2164     /* set the device type edit control text */
2165     if (GetDeviceTypeString(DeviceInfoData,
2166                             dap->szTemp,
2167                             sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2168     {
2169         SetDlgItemText(hwndDlg,
2170                        IDC_DEVTYPE,
2171                        dap->szTemp);
2172     }
2173 
2174     /* set the device manufacturer edit control text */
2175     if (GetDeviceManufacturerString(DeviceInfoSet,
2176                                     DeviceInfoData,
2177                                     dap->szTemp,
2178                                     sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2179     {
2180         SetDlgItemText(hwndDlg,
2181                        IDC_DEVMANUFACTURER,
2182                        dap->szTemp);
2183     }
2184 
2185     /* set the device location edit control text */
2186     if (GetDeviceLocationString(DeviceInfoSet,
2187                                 DeviceInfoData,
2188                                 dap->ParentDevInst,
2189                                 dap->szTemp,
2190                                 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2191     {
2192         SetDlgItemText(hwndDlg,
2193                        IDC_DEVLOCATION,
2194                        dap->szTemp);
2195     }
2196 
2197     /* set the device status edit control text */
2198     if (GetDeviceStatusString(DeviceInfoData->DevInst,
2199                               dap->hMachine,
2200                               dap->szTemp,
2201                               sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
2202     {
2203         SetDlgItemText(hwndDlg,
2204                        IDC_DEVSTATUS,
2205                        dap->szTemp);
2206     }
2207 
2208     /* set the device troubleshoot button text and disable it if necessary */
2209     hDevProbBtn = GetDlgItem(hwndDlg,
2210                              IDC_DEVPROBLEM);
2211     cr = CM_Get_DevNode_Status_Ex(&Status,
2212                                   &ProblemNumber,
2213                                   DeviceInfoData->DevInst,
2214                                   0,
2215                                   dap->hMachine);
2216     if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
2217     {
2218         switch (ProblemNumber)
2219         {
2220             case CM_PROB_DEVLOADER_FAILED:
2221             {
2222                 /* FIXME - only if it's not a root bus devloader,
2223                            disable the button otherwise */
2224                 TroubleShootStrId = IDS_UPDATEDRV;
2225                 break;
2226             }
2227 
2228             case CM_PROB_OUT_OF_MEMORY:
2229             case CM_PROB_ENTRY_IS_WRONG_TYPE:
2230             case CM_PROB_LACKED_ARBITRATOR:
2231             case CM_PROB_FAILED_START:
2232             case CM_PROB_LIAR:
2233             case CM_PROB_UNKNOWN_RESOURCE:
2234             {
2235                 TroubleShootStrId = IDS_UPDATEDRV;
2236                 break;
2237             }
2238 
2239             case CM_PROB_BOOT_CONFIG_CONFLICT:
2240             case CM_PROB_NORMAL_CONFLICT:
2241             case CM_PROB_REENUMERATION:
2242             {
2243                 /* FIXME - Troubleshoot conflict */
2244                 break;
2245             }
2246 
2247             case CM_PROB_FAILED_FILTER:
2248             case CM_PROB_REINSTALL:
2249             case CM_PROB_FAILED_INSTALL:
2250             {
2251                 TroubleShootStrId = IDS_REINSTALLDRV;
2252                 break;
2253             }
2254 
2255             case CM_PROB_DEVLOADER_NOT_FOUND:
2256             {
2257                 /* FIXME - 4 cases:
2258                    1) if it's a missing system devloader:
2259                       - disable the button (Reinstall Driver)
2260                    2) if it's not a system devloader but still missing:
2261                       - Reinstall Driver
2262                    3) if it's not a system devloader but the file can be found:
2263                       - Update Driver
2264                    4) if it's a missing or empty software key
2265                       - Update Driver
2266                  */
2267                 break;
2268             }
2269 
2270             case CM_PROB_INVALID_DATA:
2271             case CM_PROB_PARTIAL_LOG_CONF:
2272             case CM_PROB_NO_VALID_LOG_CONF:
2273             case CM_PROB_HARDWARE_DISABLED:
2274             case CM_PROB_CANT_SHARE_IRQ:
2275             case CM_PROB_TRANSLATION_FAILED:
2276             case CM_PROB_SYSTEM_SHUTDOWN:
2277             case CM_PROB_PHANTOM:
2278                 bDevActionAvailable = FALSE;
2279                 break;
2280 
2281             case CM_PROB_NOT_VERIFIED:
2282             case CM_PROB_DEVICE_NOT_THERE:
2283                 /* FIXME - search hardware */
2284                 break;
2285 
2286             case CM_PROB_NEED_RESTART:
2287             case CM_PROB_WILL_BE_REMOVED:
2288             case CM_PROB_MOVED:
2289             case CM_PROB_TOO_EARLY:
2290             case CM_PROB_DISABLED_SERVICE:
2291                 TroubleShootStrId = IDS_REBOOT;
2292                 break;
2293 
2294             case CM_PROB_REGISTRY:
2295                 /* FIXME - check registry? */
2296                 break;
2297 
2298             case CM_PROB_DISABLED:
2299                 /* if device was disabled by the user: */
2300                 TroubleShootStrId = IDS_ENABLEDEV;
2301                 /* FIXME - otherwise disable button because the device was
2302                            disabled by the system*/
2303                 break;
2304 
2305             case CM_PROB_DEVLOADER_NOT_READY:
2306                 /* FIXME - if it's a graphics adapter:
2307                            - if it's a a secondary adapter and the main adapter
2308                              couldn't be found
2309                              - disable  button
2310                            - else
2311                              - Properties
2312                          - else
2313                            - Update driver
2314                  */
2315                 break;
2316 
2317             case CM_PROB_FAILED_ADD:
2318                 TroubleShootStrId = IDS_PROPERTIES;
2319                 break;
2320         }
2321     }
2322 
2323     if (LoadString(hDllInstance,
2324                    TroubleShootStrId,
2325                    dap->szTemp,
2326                    sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
2327     {
2328         SetWindowText(hDevProbBtn,
2329                       dap->szTemp);
2330     }
2331     EnableWindow(hDevProbBtn,
2332                  dap->IsAdmin && bDevActionAvailable);
2333 
2334     /* check if the device can be enabled/disabled */
2335     hDevUsage = GetDlgItem(hwndDlg,
2336                            IDC_DEVUSAGE);
2337 
2338     dap->CanDisable = FALSE;
2339     dap->DeviceStarted = FALSE;
2340 
2341     if (CanDisableDevice(DeviceInfoData->DevInst,
2342                          dap->hMachine,
2343                          &bFlag))
2344     {
2345         dap->CanDisable = bFlag;
2346     }
2347 
2348     if (IsDeviceStarted(DeviceInfoData->DevInst,
2349                         dap->hMachine,
2350                         &bFlag))
2351     {
2352         dap->DeviceStarted = bFlag;
2353     }
2354 
2355     /* enable/disable the device usage controls */
2356     EnableWindow(GetDlgItem(hwndDlg,
2357                             IDC_DEVUSAGELABEL),
2358                  dap->CanDisable && dap->IsAdmin);
2359     EnableWindow(hDevUsage,
2360                  dap->CanDisable && dap->IsAdmin);
2361 
2362     /* clear the combobox */
2363     SendMessage(hDevUsage,
2364                 CB_RESETCONTENT,
2365                 0,
2366                 0);
2367     if (dap->CanDisable)
2368     {
2369         InitDevUsageActions(hwndDlg,
2370                             hDevUsage,
2371                             dap);
2372     }
2373 
2374     /* find out how many new device property sheets to add.
2375        fake a PROPSHEETHEADER structure, we don't plan to
2376        call PropertySheet again!*/
2377     psh.dwSize = sizeof(PROPSHEETHEADER);
2378     psh.dwFlags = 0;
2379     psh.nPages = 0;
2380 
2381     /* get the number of device property sheets for the device */
2382     if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2383                                           DeviceInfoData,
2384                                           &psh,
2385                                           0,
2386                                           &nDriverPages,
2387                                           dap->PropertySheetType) &&
2388         nDriverPages != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2389     {
2390         dap->nDevPropSheets += nDriverPages;
2391     }
2392     else
2393     {
2394         nDriverPages = 0;
2395     }
2396 
2397     /* include the driver page */
2398     if (dap->HasDriverPage)
2399         dap->nDevPropSheets++;
2400 
2401     /* include the details page */
2402     if (dap->Extended)
2403         dap->nDevPropSheets++;
2404 
2405     if (dap->HasResourcePage)
2406         dap->nDevPropSheets++;
2407 
2408     /* add the device property sheets */
2409     if (dap->nDevPropSheets != 0)
2410     {
2411         dap->DevPropSheets = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
2412                                                          HEAP_ZERO_MEMORY,
2413                                                          dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
2414         if (dap->DevPropSheets != NULL)
2415         {
2416             if (nDriverPages != 0)
2417             {
2418                 psh.phpage = dap->DevPropSheets;
2419 
2420                 /* query the device property sheet pages to add */
2421                 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
2422                                                      DeviceInfoData,
2423                                                      &psh,
2424                                                      dap->nDevPropSheets,
2425                                                      NULL,
2426                                                      dap->PropertySheetType))
2427                 {
2428                     /* add the property sheets */
2429                     for (iPage = 0;
2430                          iPage < nDriverPages;
2431                          iPage++)
2432                     {
2433                         if (PropSheet_AddPage(hPropSheetDlg,
2434                                               dap->DevPropSheets[iPage]))
2435                         {
2436                             RecalcPages = TRUE;
2437                         }
2438                     }
2439 
2440                     dap->FreeDevPropSheets = TRUE;
2441                 }
2442                 else
2443                 {
2444                     /* cleanup, we were unable to get the device property sheets */
2445                     iPage = nDriverPages;
2446                     dap->nDevPropSheets -= nDriverPages;
2447                     nDriverPages = 0;
2448                 }
2449             }
2450             else
2451                 iPage = 0;
2452 
2453             /* add the driver page if necessary */
2454             if (dap->HasDriverPage)
2455             {
2456                 PROPSHEETPAGE pspDriver = {0};
2457                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2458                 pspDriver.dwFlags = PSP_DEFAULT;
2459                 pspDriver.hInstance = hDllInstance;
2460                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDRIVER);
2461                 pspDriver.pfnDlgProc = AdvProcDriverDlgProc;
2462                 pspDriver.lParam = (LPARAM)dap;
2463                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2464                 if (dap->DevPropSheets[iPage] != NULL)
2465                 {
2466                     if (PropSheet_AddPage(hPropSheetDlg,
2467                                           dap->DevPropSheets[iPage]))
2468                     {
2469                         iPage++;
2470                         RecalcPages = TRUE;
2471                     }
2472                     else
2473                     {
2474                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2475                         dap->DevPropSheets[iPage] = NULL;
2476                     }
2477                 }
2478             }
2479 
2480             if (dap->Extended)
2481             {
2482                 /* Add the details page */
2483                 PROPSHEETPAGE pspDetails = {0};
2484                 pspDetails.dwSize = sizeof(PROPSHEETPAGE);
2485                 pspDetails.dwFlags = PSP_DEFAULT;
2486                 pspDetails.hInstance = hDllInstance;
2487                 pspDetails.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDETAILS);
2488                 pspDetails.pfnDlgProc = AdvProcDetailsDlgProc;
2489                 pspDetails.lParam = (LPARAM)dap;
2490                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDetails);
2491                 if (dap->DevPropSheets[iPage] != NULL)
2492                 {
2493                     if (PropSheet_AddPage(hPropSheetDlg,
2494                                           dap->DevPropSheets[iPage]))
2495                     {
2496                         iPage++;
2497                         RecalcPages = TRUE;
2498                     }
2499                     else
2500                     {
2501                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2502                         dap->DevPropSheets[iPage] = NULL;
2503                     }
2504                 }
2505             }
2506 
2507             if (dap->HasResourcePage)
2508             {
2509                 PROPSHEETPAGE pspDriver = {0};
2510                 pspDriver.dwSize = sizeof(PROPSHEETPAGE);
2511                 pspDriver.dwFlags = PSP_DEFAULT;
2512                 pspDriver.hInstance = hDllInstance;
2513                 pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICERESOURCES);
2514                 pspDriver.pfnDlgProc = ResourcesProcDriverDlgProc;
2515                 pspDriver.lParam = (LPARAM)dap;
2516                 dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
2517                 if (dap->DevPropSheets[iPage] != NULL)
2518                 {
2519                     if (PropSheet_AddPage(hPropSheetDlg,
2520                                           dap->DevPropSheets[iPage]))
2521                     {
2522                         iPage++;
2523                         RecalcPages = TRUE;
2524                     }
2525                     else
2526                     {
2527                         dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
2528                         dap->DevPropSheets[iPage] = NULL;
2529                     }
2530                 }
2531             }
2532             /* FIXME: Add the power page */
2533         }
2534         else
2535             dap->nDevPropSheets = 0;
2536     }
2537 
2538     if (RecalcPages)
2539     {
2540         PropSheet_RecalcPageSizes(hPropSheetDlg);
2541     }
2542 
2543     /* finally, disable the apply button */
2544     PropSheet_UnChanged(hPropSheetDlg,
2545                         hwndDlg);
2546     dap->DeviceUsageChanged = FALSE;
2547 }
2548 
2549 
2550 static LRESULT
2551 CALLBACK
2552 DlgParentSubWndProc(IN HWND hwnd,
2553                     IN UINT uMsg,
2554                     IN WPARAM wParam,
2555                     IN LPARAM lParam)
2556 {
2557     PDEVADVPROP_INFO dap;
2558 
2559     dap = (PDEVADVPROP_INFO)GetProp(hwnd,
2560                                     L"DevMgrDevChangeSub");
2561     if (dap != NULL)
2562     {
2563         if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
2564         {
2565             SendMessage(dap->hWndGeneralPage,
2566                         WM_DEVICECHANGE,
2567                         wParam,
2568                         lParam);
2569         }
2570 
2571         /* pass the message the the old window proc */
2572         return CallWindowProc(dap->ParentOldWndProc,
2573                               hwnd,
2574                               uMsg,
2575                               wParam,
2576                               lParam);
2577     }
2578     else
2579     {
2580         /* this is not a good idea if the subclassed window was an ansi
2581            window, but we failed finding out the previous window proc
2582            so we can't use CallWindowProc. This should rarely - if ever -
2583            happen. */
2584 
2585         return DefWindowProc(hwnd,
2586                              uMsg,
2587                              wParam,
2588                              lParam);
2589     }
2590 }
2591 
2592 
2593 static INT_PTR
2594 CALLBACK
2595 AdvPropGeneralDlgProc(IN HWND hwndDlg,
2596                       IN UINT uMsg,
2597                       IN WPARAM wParam,
2598                       IN LPARAM lParam)
2599 {
2600     PDEVADVPROP_INFO dap;
2601     INT_PTR Ret = FALSE;
2602 
2603     dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
2604 
2605     if (dap != NULL || uMsg == WM_INITDIALOG)
2606     {
2607         switch (uMsg)
2608         {
2609             case WM_COMMAND:
2610             {
2611                 switch (LOWORD(wParam))
2612                 {
2613                     case IDC_DEVUSAGE:
2614                     {
2615                         if (HIWORD(wParam) == CBN_SELCHANGE)
2616                         {
2617                             PropSheet_Changed(GetParent(hwndDlg),
2618                                               hwndDlg);
2619                             dap->DeviceUsageChanged = TRUE;
2620                         }
2621                         break;
2622                     }
2623 
2624                     case IDC_DEVPROBLEM:
2625                     {
2626                         if (dap->IsAdmin)
2627                         {
2628                             /* display the device problem wizard */
2629                             ShowDeviceProblemWizard(hwndDlg,
2630                                                     dap->DeviceInfoSet,
2631                                                     &dap->DeviceInfoData,
2632                                                     dap->hMachine);
2633                         }
2634                         break;
2635                     }
2636                 }
2637                 break;
2638             }
2639 
2640             case WM_NOTIFY:
2641             {
2642                 NMHDR *hdr = (NMHDR*)lParam;
2643                 switch (hdr->code)
2644                 {
2645                     case PSN_APPLY:
2646                         ApplyGeneralSettings(hwndDlg,
2647                                              dap);
2648                         break;
2649                 }
2650                 break;
2651             }
2652 
2653             case WM_INITDIALOG:
2654             {
2655                 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
2656                 if (dap != NULL)
2657                 {
2658                     HWND hWndParent;
2659 
2660                     dap->hWndGeneralPage = hwndDlg;
2661 
2662                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)dap);
2663 
2664                     /* subclass the parent window to always receive
2665                        WM_DEVICECHANGE messages */
2666                     hWndParent = GetParent(hwndDlg);
2667                     if (hWndParent != NULL)
2668                     {
2669                         /* subclass the parent window. This is not safe
2670                            if the parent window belongs to another thread! */
2671                         dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
2672                                                                           GWLP_WNDPROC,
2673                                                                           (LONG_PTR)DlgParentSubWndProc);
2674 
2675                         if (dap->ParentOldWndProc != NULL &&
2676                             SetProp(hWndParent,
2677                                     L"DevMgrDevChangeSub",
2678                                     (HANDLE)dap))
2679                         {
2680                             dap->hWndParent = hWndParent;
2681                         }
2682                     }
2683 
2684                     /* do not call UpdateDevInfo directly in here because it modifies
2685                        the pages of the property sheet! */
2686                     PostMessage(hwndDlg,
2687                                 PM_INITIALIZE,
2688                                 0,
2689                                 0);
2690                 }
2691                 Ret = TRUE;
2692                 break;
2693             }
2694 
2695             case WM_DEVICECHANGE:
2696             {
2697                 /* FIXME - don't call UpdateDevInfo for all events */
2698                 UpdateDevInfo(hwndDlg,
2699                               dap,
2700                               TRUE);
2701                 Ret = TRUE;
2702                 break;
2703             }
2704 
2705             case PM_INITIALIZE:
2706             {
2707                 UpdateDevInfo(hwndDlg,
2708                               dap,
2709                               FALSE);
2710                 dap->PageInitialized = TRUE;
2711                 break;
2712             }
2713 
2714             case WM_DESTROY:
2715             {
2716                 /* restore the old window proc of the subclassed parent window */
2717                 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
2718                 {
2719                     if (SetWindowLongPtr(dap->hWndParent,
2720                                          GWLP_WNDPROC,
2721                                          (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
2722                     {
2723                         RemoveProp(dap->hWndParent,
2724                                    L"DevMgrDevChangeSub");
2725                     }
2726                 }
2727                 break;
2728             }
2729         }
2730     }
2731 
2732     return Ret;
2733 }
2734 
2735 
2736 INT_PTR
2737 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
2738                                 IN LPCWSTR lpDeviceID  OPTIONAL,
2739                                 IN HDEVINFO DeviceInfoSet,
2740                                 IN PSP_DEVINFO_DATA DeviceInfoData,
2741                                 IN HINSTANCE hComCtl32,
2742                                 IN LPCWSTR lpMachineName,
2743                                 IN DWORD dwFlags)
2744 {
2745     PROPSHEETHEADER psh = {0};
2746     PROPSHEETPAGE pspGeneral = {0};
2747     PPROPERTYSHEETW pPropertySheetW;
2748     PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
2749     PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
2750     PDEVADVPROP_INFO DevAdvPropInfo;
2751     HMACHINE hMachine = NULL;
2752     DWORD DevIdSize = 0;
2753     INT_PTR Ret = -1;
2754 
2755     /* we don't want to statically link against comctl32, so find the
2756        functions we need dynamically */
2757     pPropertySheetW =
2758         (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
2759                                         "PropertySheetW");
2760     pCreatePropertySheetPageW =
2761         (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
2762                                                   "CreatePropertySheetPageW");
2763     pDestroyPropertySheetPage =
2764         (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
2765                                                   "DestroyPropertySheetPage");
2766     if (pPropertySheetW == NULL ||
2767         pCreatePropertySheetPageW == NULL ||
2768         pDestroyPropertySheetPage == NULL)
2769     {
2770         return -1;
2771     }
2772 
2773     if (lpDeviceID == NULL)
2774     {
2775         /* find out how much size is needed for the device id */
2776         if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
2777                                        DeviceInfoData,
2778                                        NULL,
2779                                        0,
2780                                        &DevIdSize))
2781         {
2782             ERR("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
2783             return -1;
2784         }
2785 
2786         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2787         {
2788             return -1;
2789         }
2790     }
2791     else
2792     {
2793         DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
2794     }
2795 
2796     if (lpMachineName != NULL && lpMachineName[0] != L'\0')
2797     {
2798         CONFIGRET cr = CM_Connect_Machine(lpMachineName,
2799                                           &hMachine);
2800         if (cr != CR_SUCCESS)
2801         {
2802             return -1;
2803         }
2804     }
2805 
2806     /* create the internal structure associated with the "General",
2807        "Driver", ... pages */
2808     DevAdvPropInfo = (PDEVADVPROP_INFO)HeapAlloc(GetProcessHeap(),
2809                                                  HEAP_ZERO_MEMORY,
2810                                                  FIELD_OFFSET(DEVADVPROP_INFO,
2811                                                               szDeviceID) +
2812                                                      (DevIdSize * sizeof(WCHAR)));
2813     if (DevAdvPropInfo == NULL)
2814     {
2815         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2816         goto Cleanup;
2817     }
2818 
2819     if (lpDeviceID == NULL)
2820     {
2821         /* read the device instance id */
2822         if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
2823                                         DeviceInfoData,
2824                                         DevAdvPropInfo->szDeviceID,
2825                                         DevIdSize,
2826                                         NULL))
2827         {
2828             goto Cleanup;
2829         }
2830     }
2831     else
2832     {
2833         /* copy the device instance id supplied by the caller */
2834         wcscpy(DevAdvPropInfo->szDeviceID,
2835                lpDeviceID);
2836     }
2837 
2838     DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
2839     DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
2840     DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
2841     DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
2842 
2843     DevAdvPropInfo->ShowRemotePages = (lpMachineName != NULL && lpMachineName[0] != L'\0');
2844     DevAdvPropInfo->hMachine = hMachine;
2845     DevAdvPropInfo->lpMachineName = lpMachineName;
2846     DevAdvPropInfo->szDevName[0] = L'\0';
2847     DevAdvPropInfo->hComCtl32 = hComCtl32;
2848     DevAdvPropInfo->pCreatePropertySheetPageW = pCreatePropertySheetPageW;
2849     DevAdvPropInfo->pDestroyPropertySheetPage = pDestroyPropertySheetPage;
2850 
2851     DevAdvPropInfo->IsAdmin = TRUE;// IsUserAdmin();
2852     DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
2853     DevAdvPropInfo->Extended = ((dwFlags & DPF_EXTENDED) != 0);
2854 
2855     psh.dwSize = sizeof(PROPSHEETHEADER);
2856     psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
2857     psh.hwndParent = hWndParent;
2858     psh.pszCaption = DevAdvPropInfo->szDevName;
2859 
2860     DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
2861                                             DIGCDP_FLAG_REMOTE_ADVANCED :
2862                                             DIGCDP_FLAG_ADVANCED;
2863 
2864     psh.phpage = (HPROPSHEETPAGE *)HeapAlloc(GetProcessHeap(),
2865                                              HEAP_ZERO_MEMORY,
2866                                              1 * sizeof(HPROPSHEETPAGE));
2867     if (psh.phpage == NULL)
2868     {
2869         goto Cleanup;
2870     }
2871 
2872     /* add the "General" property sheet */
2873     pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
2874     pspGeneral.dwFlags = PSP_DEFAULT;
2875     pspGeneral.hInstance = hDllInstance;
2876     pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
2877     pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
2878     pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
2879     psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
2880     if (psh.phpage[psh.nPages] != NULL)
2881     {
2882         psh.nPages++;
2883     }
2884 
2885     DevAdvPropInfo->nDevPropSheets = psh.nPages;
2886 
2887     if (psh.nPages != 0)
2888     {
2889         Ret = pPropertySheetW(&psh);
2890 
2891         /* NOTE: no need to destroy the property sheets anymore! */
2892     }
2893     else
2894     {
2895         UINT i;
2896 
2897 Cleanup:
2898         /* in case of failure the property sheets must be destroyed */
2899         if (psh.phpage != NULL)
2900         {
2901             for (i = 0;
2902                  i < psh.nPages;
2903                  i++)
2904             {
2905                 if (psh.phpage[i] != NULL)
2906                 {
2907                     pDestroyPropertySheetPage(psh.phpage[i]);
2908                 }
2909             }
2910         }
2911     }
2912 
2913     if (DevAdvPropInfo != NULL)
2914     {
2915         if (DevAdvPropInfo->FreeDevPropSheets)
2916         {
2917             /* don't free the array if it's the one allocated in
2918                DisplayDeviceAdvancedProperties */
2919             HeapFree(GetProcessHeap(),
2920                      0,
2921                      DevAdvPropInfo->DevPropSheets);
2922         }
2923 
2924         if (DevAdvPropInfo->CloseDevInst)
2925         {
2926             /* close the device info set in case a new one was created */
2927             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
2928         }
2929 
2930         if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
2931         {
2932             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
2933         }
2934 
2935         if (DevAdvPropInfo->hDevIcon != NULL)
2936         {
2937             DestroyIcon(DevAdvPropInfo->hDevIcon);
2938         }
2939 
2940         HeapFree(GetProcessHeap(),
2941                  0,
2942                  DevAdvPropInfo);
2943     }
2944 
2945     if (psh.phpage != NULL)
2946     {
2947         HeapFree(GetProcessHeap(),
2948                  0,
2949                  psh.phpage);
2950     }
2951 
2952     if (hMachine != NULL)
2953     {
2954         CM_Disconnect_Machine(hMachine);
2955     }
2956 
2957     return Ret;
2958 }
2959