xref: /reactos/dll/cpl/hdwwiz/hdwwiz.c (revision cc7cf826)
1 /*
2  * ReactOS New devices installation
3  * Copyright (C) 2005, 2008 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  * PROJECT:         ReactOS Add hardware control panel
21  * FILE:            dll/cpl/hdwwiz/hdwwiz.c
22  * PURPOSE:         ReactOS Add hardware control panel
23  * PROGRAMMER:      Herv� Poussineau (hpoussin@reactos.org)
24  *                  Dmitry Chapyshev (dmitry@reactos.org)
25  */
26 
27 #include "resource.h"
28 #include "hdwwiz.h"
29 
30 /* GLOBALS ******************************************************************/
31 
32 HINSTANCE hApplet = NULL;
33 HFONT hTitleFont;
34 SP_CLASSIMAGELIST_DATA ImageListData;
35 PWSTR pDeviceStatusText;
36 HANDLE hProcessHeap;
37 HDEVINFO hDevInfoTypes;
38 
39 typedef BOOL (WINAPI *PINSTALL_NEW_DEVICE)(HWND, LPGUID, PDWORD);
40 
41 
42 /* STATIC FUNCTIONS *********************************************************/
43 
44 static HFONT
45 CreateTitleFont(VOID)
46 {
47     NONCLIENTMETRICS ncm;
48     LOGFONT LogFont;
49     HDC hdc;
50     INT FontSize;
51     HFONT hFont;
52 
53     ncm.cbSize = sizeof(NONCLIENTMETRICS);
54     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
55 
56     LogFont = ncm.lfMessageFont;
57     LogFont.lfWeight = FW_BOLD;
58     wcscpy(LogFont.lfFaceName, L"MS Shell Dlg");
59 
60     hdc = GetDC(NULL);
61     FontSize = 12;
62     LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
63     hFont = CreateFontIndirect(&LogFont);
64     ReleaseDC(NULL, hdc);
65 
66     return hFont;
67 }
68 
69 static INT_PTR CALLBACK
70 StartPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
71 {
72     switch (uMsg)
73     {
74         case WM_INITDIALOG:
75         {
76             /* Set title font */
77             SendDlgItemMessage(hwndDlg, IDC_FINISHTITLE, WM_SETFONT, (WPARAM)hTitleFont, (LPARAM)TRUE);
78         }
79         break;
80 
81         case WM_NOTIFY:
82         {
83             LPNMHDR lpnm = (LPNMHDR)lParam;
84 
85             switch (lpnm->code)
86             {
87                 case PSN_SETACTIVE:
88                 {
89                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
90                 }
91                 break;
92             }
93         }
94         break;
95     }
96 
97     return FALSE;
98 }
99 
100 static INT_PTR CALLBACK
101 SearchPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
102 {
103     switch (uMsg)
104     {
105         case WM_INITDIALOG:
106         {
107             /* TODO: PnP devices search */
108         }
109         break;
110 
111         case WM_NOTIFY:
112         {
113             LPNMHDR lpnm = (LPNMHDR)lParam;
114 
115             switch (lpnm->code)
116             {
117                 case PSN_SETACTIVE:
118                 {
119                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
120                 }
121                 break;
122             }
123         }
124         break;
125     }
126 
127     return FALSE;
128 }
129 
130 static INT_PTR CALLBACK
131 IsConnectedPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
132 {
133     switch (uMsg)
134     {
135         case WM_COMMAND:
136         {
137             if(HIWORD(wParam) == BN_CLICKED)
138             {
139                 if ((SendDlgItemMessage(hwndDlg, IDC_CONNECTED, BM_GETCHECK, 0, 0) == BST_CHECKED) ||
140                     (SendDlgItemMessage(hwndDlg, IDC_NOTCONNECTED, BM_GETCHECK, 0, 0) == BST_CHECKED))
141                 {
142                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
143                 }
144                 else
145                 {
146                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
147                 }
148             }
149         }
150         break;
151 
152         case WM_NOTIFY:
153         {
154             LPNMHDR lpnm = (LPNMHDR)lParam;
155 
156             switch (lpnm->code)
157             {
158                 case PSN_SETACTIVE:
159                 {
160                     if ((SendDlgItemMessage(hwndDlg, IDC_CONNECTED, BM_GETCHECK, 0, 0) == BST_CHECKED) ||
161                         (SendDlgItemMessage(hwndDlg, IDC_NOTCONNECTED, BM_GETCHECK, 0, 0) == BST_CHECKED))
162                     {
163                         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
164                     }
165                     else
166                     {
167                         PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
168                     }
169                 }
170                 break;
171 
172                 case PSN_WIZNEXT:
173                 {
174                     if (SendDlgItemMessage(hwndDlg, IDC_NOTCONNECTED, BM_GETCHECK, 0, 0) == BST_CHECKED)
175                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_NOTCONNECTEDPAGE);
176                     else
177                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_PROBELISTPAGE);
178 
179                     return TRUE;
180                 }
181             }
182         }
183         break;
184     }
185 
186     return FALSE;
187 }
188 
189 static INT_PTR CALLBACK
190 FinishPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
191 {
192     switch (uMsg)
193     {
194         case WM_INITDIALOG:
195         {
196             /* Set title font */
197             SendDlgItemMessage(hwndDlg, IDC_FINISHTITLE, WM_SETFONT, (WPARAM)hTitleFont, (LPARAM)TRUE);
198         }
199         break;
200 
201         case WM_NOTIFY:
202         {
203             LPNMHDR lpnm = (LPNMHDR)lParam;
204 
205             switch (lpnm->code)
206             {
207                 case PSN_SETACTIVE:
208                 {
209                     /* Only "Finish" button */
210                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
211                 }
212                 break;
213             }
214         }
215         break;
216     }
217 
218     return FALSE;
219 }
220 
221 static INT_PTR CALLBACK
222 NotConnectedPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
223 {
224     switch (uMsg)
225     {
226         case WM_INITDIALOG:
227         {
228             /* Set title font */
229             SendDlgItemMessage(hwndDlg, IDC_FINISHTITLE, WM_SETFONT, (WPARAM)hTitleFont, (LPARAM)TRUE);
230         }
231         break;
232 
233         case WM_NOTIFY:
234         {
235             LPNMHDR lpnm = (LPNMHDR)lParam;
236 
237             switch (lpnm->code)
238             {
239                 case PSN_SETACTIVE:
240                 {
241                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH | PSWIZB_BACK);
242                 }
243                 break;
244 
245                 case PSN_WIZBACK:
246                 {
247                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_ISCONNECTEDPAGE);
248                     return TRUE;
249                 }
250             }
251         }
252         break;
253     }
254 
255     return FALSE;
256 }
257 
258 static VOID
259 TrimGuidString(LPWSTR szString, LPWSTR szNewString)
260 {
261     WCHAR szBuffer[39];
262     INT Index;
263 
264     if (wcslen(szString) == 38)
265     {
266         if ((szString[0] == L'{') && (szString[37] == L'}'))
267         {
268             for (Index = 0; Index < wcslen(szString); Index++)
269                 szBuffer[Index] = szString[Index + 1];
270 
271             szBuffer[36] = L'\0';
272             wcscpy(szNewString, szBuffer);
273             return;
274         }
275     }
276     wcscpy(szNewString, L"\0");
277 }
278 
279 static VOID
280 InitProbeListPage(HWND hwndDlg)
281 {
282     LV_COLUMN Column;
283     LV_ITEM Item;
284     WCHAR szBuffer[MAX_STR_SIZE], szGuid[MAX_STR_SIZE],
285           szTrimGuid[MAX_STR_SIZE], szStatusText[MAX_STR_SIZE];
286     HWND hList = GetDlgItem(hwndDlg, IDC_PROBELIST);
287     PWSTR pstrStatusText;
288     HDEVINFO hDevInfo;
289     SP_DEVINFO_DATA DevInfoData;
290     ULONG ulStatus, ulProblemNumber;
291     GUID ClassGuid;
292     RECT Rect;
293     DWORD Index;
294 
295     if (!hList) return;
296 
297     ZeroMemory(&Column, sizeof(LV_COLUMN));
298 
299     GetClientRect(hList, &Rect);
300 
301     Column.mask         = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
302     Column.fmt          = LVCFMT_LEFT;
303     Column.iSubItem     = 0;
304     Column.pszText      = NULL;
305     Column.cx           = Rect.right - GetSystemMetrics(SM_CXVSCROLL);
306     (VOID) ListView_InsertColumn(hList, 0, &Column);
307 
308     ZeroMemory(&Item, sizeof(LV_ITEM));
309 
310     LoadString(hApplet, IDS_ADDNEWDEVICE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR));
311 
312     Item.mask       = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
313     Item.pszText    = (LPWSTR) szBuffer;
314     Item.iItem      = (INT) ListView_GetItemCount(hList);
315     Item.iImage     = -1;
316     (VOID) ListView_InsertItem(hList, &Item);
317 
318     hDevInfo = SetupDiGetClassDevsEx(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT, NULL, NULL, 0);
319 
320     if (hDevInfo == INVALID_HANDLE_VALUE) return;
321 
322     /* Get the device image List */
323     ImageListData.cbSize = sizeof(ImageListData);
324     SetupDiGetClassImageList(&ImageListData);
325 
326     DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
327     for (Index = 0; TRUE; Index++)
328     {
329         szBuffer[0] = L'\0';
330 
331         if (!SetupDiEnumDeviceInfo(hDevInfo, Index, &DevInfoData)) break;
332 
333         if (CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblemNumber, DevInfoData.DevInst, 0, NULL) == CR_SUCCESS)
334         {
335             if (ulStatus & DN_NO_SHOW_IN_DM) continue;
336         }
337 
338         /* Get the device's friendly name */
339         if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
340                                               &DevInfoData,
341                                               SPDRP_FRIENDLYNAME,
342                                               0,
343                                               (BYTE*)szBuffer,
344                                               MAX_STR_SIZE,
345                                               NULL))
346         {
347             /* If the friendly name fails, try the description instead */
348             SetupDiGetDeviceRegistryProperty(hDevInfo,
349                                              &DevInfoData,
350                                              SPDRP_DEVICEDESC,
351                                              0,
352                                              (BYTE*)szBuffer,
353                                              MAX_STR_SIZE,
354                                              NULL);
355         }
356 
357         SetupDiGetDeviceRegistryProperty(hDevInfo,
358                                          &DevInfoData,
359                                          SPDRP_CLASSGUID,
360                                          0,
361                                          (BYTE*)szGuid,
362                                          MAX_STR_SIZE,
363                                          NULL);
364 
365         TrimGuidString(szGuid, szTrimGuid);
366         UuidFromStringW(szTrimGuid, &ClassGuid);
367 
368         SetupDiGetClassImageIndex(&ImageListData,
369                                   &ClassGuid,
370                                   &Item.iImage);
371 
372         DeviceProblemTextW(NULL,
373                            DevInfoData.DevInst,
374                            ulProblemNumber,
375                            szStatusText,
376                            sizeof(szStatusText) / sizeof(WCHAR));
377 
378         pstrStatusText = (PWSTR)HeapAlloc(hProcessHeap, 0, sizeof(szStatusText));
379         lstrcpy(pstrStatusText, szStatusText);
380 
381         if (szBuffer[0] != L'\0')
382         {
383             /* Set device name */
384             Item.pszText = (LPWSTR) szBuffer;
385             Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
386             Item.lParam = (LPARAM) pstrStatusText;
387             Item.iItem = (INT) ListView_GetItemCount(hList);
388             (VOID) ListView_InsertItem(hList, &Item);
389         }
390 
391         DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
392     }
393 
394     (VOID) ListView_SetImageList(hList, ImageListData.ImageList, LVSIL_SMALL);
395     (VOID) ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
396     SetupDiDestroyDeviceInfoList(hDevInfo);
397 }
398 
399 static INT_PTR CALLBACK
400 ProbeListPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
401 {
402     INT Index;
403     LVITEM Item;
404 
405     switch (uMsg)
406     {
407         case WM_INITDIALOG:
408         {
409             pDeviceStatusText = (PWSTR)HeapAlloc(hProcessHeap, 0, MAX_STR_SIZE);
410             InitProbeListPage(hwndDlg);
411         }
412         break;
413 
414         case WM_NOTIFY:
415         {
416             LPNMHDR lpnm = (LPNMHDR)lParam;
417 
418             switch (lpnm->code)
419             {
420                 case PSN_SETACTIVE:
421                 {
422                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
423                 }
424                 break;
425 
426                 case PSN_WIZNEXT:
427                 {
428                     Index = (INT) SendMessage(GetDlgItem(hwndDlg, IDC_PROBELIST), LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
429                     if (Index == -1) Index = 0;
430 
431                     if (Index == 0)
432                     {
433                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_SELECTWAYPAGE);
434                     }
435                     else
436                     {
437                         PWSTR pts;
438 
439                         ZeroMemory(&Item, sizeof(LV_ITEM));
440                         Item.mask = LVIF_PARAM;
441                         Item.iItem = Index;
442                         (VOID) ListView_GetItem(GetDlgItem(hwndDlg, IDC_PROBELIST), &Item);
443                         pts = (PWSTR) Item.lParam;
444                         wcscpy(pDeviceStatusText, pts);
445 
446                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_HWSTATUSPAGE);
447                     }
448                     return TRUE;
449                 }
450             }
451         }
452         break;
453 
454         case WM_DESTROY:
455         {
456             for (Index = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_PROBELIST)); --Index > 0;)
457             {
458                 ZeroMemory(&Item, sizeof(LV_ITEM));
459                 Item.mask = LVIF_PARAM;
460                 Item.iItem = Index;
461                 (VOID) ListView_GetItem(GetDlgItem(hwndDlg, IDC_PROBELIST), &Item);
462                 HeapFree(hProcessHeap, 0, (LPVOID) Item.lParam);
463             }
464             HeapFree(hProcessHeap, 0, (LPVOID) pDeviceStatusText);
465         }
466         break;
467     }
468 
469     return FALSE;
470 }
471 
472 static INT_PTR CALLBACK
473 SelectWayPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
474 {
475     switch (uMsg)
476     {
477         case WM_NOTIFY:
478         {
479             LPNMHDR lpnm = (LPNMHDR)lParam;
480 
481             switch (lpnm->code)
482             {
483                 case PSN_SETACTIVE:
484                 {
485                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
486                     if (SendDlgItemMessage(hwndDlg, IDC_AUTOINSTALL, BM_GETCHECK, 0, 0) == BST_CHECKED)
487                         SendDlgItemMessage(hwndDlg, IDC_MANUALLYINST, BM_SETCHECK, 0, 0);
488                     else
489                     {
490                         SendDlgItemMessage(hwndDlg, IDC_AUTOINSTALL, BM_SETCHECK, 1, 1);
491                         SendDlgItemMessage(hwndDlg, IDC_MANUALLYINST, BM_SETCHECK, 0, 0);
492                     }
493                 }
494                 break;
495 
496                 case PSN_WIZNEXT:
497                 {
498                     if (SendDlgItemMessage(hwndDlg, IDC_AUTOINSTALL, BM_GETCHECK, 0, 0) == BST_CHECKED)
499                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_PROGRESSPAGE);
500                     else
501                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_HWTYPESPAGE);
502 
503                     return TRUE;
504                 }
505             }
506         }
507         break;
508     }
509 
510     return FALSE;
511 }
512 
513 static INT_PTR CALLBACK
514 DevStatusPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
515 {
516     switch (uMsg)
517     {
518         case WM_INITDIALOG:
519         {
520             /* Set title font */
521             SendDlgItemMessage(hwndDlg, IDC_FINISHTITLE, WM_SETFONT, (WPARAM)hTitleFont, (LPARAM)TRUE);
522         }
523         break;
524 
525         case WM_NOTIFY:
526         {
527             LPNMHDR lpnm = (LPNMHDR)lParam;
528 
529             switch (lpnm->code)
530             {
531                 case PSN_SETACTIVE:
532                 {
533                     /* Set status text */
534                     SetWindowText(GetDlgItem(hwndDlg, IDC_HWSTATUSEDIT), pDeviceStatusText);
535 
536                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH | PSWIZB_BACK);
537                 }
538                 break;
539 
540                 case PSN_WIZBACK:
541                 {
542                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_PROBELISTPAGE);
543                     return TRUE;
544                 }
545             }
546         }
547         break;
548     }
549 
550     return FALSE;
551 }
552 
553 static INT
554 EnumDeviceClasses(INT ClassIndex,
555                   LPWSTR DevClassName,
556                   LPWSTR DevClassDesc,
557                   BOOL *DevPresent,
558                   INT *ClassImage)
559 {
560     GUID ClassGuid;
561     HKEY KeyClass;
562     WCHAR ClassName[MAX_STR_SIZE];
563     DWORD RequiredSize = MAX_STR_SIZE;
564     UINT Ret;
565 
566     *DevPresent = FALSE;
567     *DevClassName = L'\0';
568 
569     Ret = CM_Enumerate_Classes(ClassIndex,
570                                &ClassGuid,
571                                0);
572     if (Ret != CR_SUCCESS)
573     {
574         /* All classes enumerated */
575         if(Ret == CR_NO_SUCH_VALUE)
576         {
577             hDevInfoTypes = NULL;
578             return -1;
579         }
580 
581         if (Ret == CR_INVALID_DATA)
582         {
583             ; /* FIXME: What should we do here? */
584         }
585 
586         /* Handle other errors... */
587     }
588 
589     if (SetupDiClassNameFromGuid(&ClassGuid,
590                                  ClassName,
591                                  RequiredSize,
592                                  &RequiredSize))
593     {
594         lstrcpy(DevClassName, ClassName);
595     }
596 
597     if (!SetupDiGetClassImageIndex(&ImageListData,
598                                    &ClassGuid,
599                                    ClassImage))
600     {
601         /* FIXME: Can we do this?
602          * Set the blank icon: IDI_SETUPAPI_BLANK = 41
603          * It'll be image 24 in the imagelist */
604         *ClassImage = 24;
605     }
606 
607     /* Get device info for all devices of a particular class */
608     hDevInfoTypes = SetupDiGetClassDevs(&ClassGuid,
609                                    NULL,
610                                    NULL,
611                                    DIGCF_PRESENT);
612     if (hDevInfoTypes == INVALID_HANDLE_VALUE)
613     {
614         hDevInfoTypes = NULL;
615         return 0;
616     }
617 
618     KeyClass = SetupDiOpenClassRegKeyEx(&ClassGuid,
619                                         MAXIMUM_ALLOWED,
620                                         DIOCR_INSTALLER,
621                                         NULL,
622                                         0);
623     if (KeyClass != INVALID_HANDLE_VALUE)
624     {
625 
626         LONG dwSize = MAX_STR_SIZE;
627 
628         if (RegQueryValue(KeyClass,
629                           NULL,
630                           DevClassDesc,
631                           &dwSize) != ERROR_SUCCESS)
632         {
633             *DevClassDesc = L'\0';
634         }
635     }
636     else
637     {
638         return -3;
639     }
640 
641     *DevPresent = TRUE;
642 
643     RegCloseKey(KeyClass);
644 
645     return 0;
646 }
647 
648 static VOID
649 InitHardWareTypesPage(HWND hwndDlg)
650 {
651     HWND hList = GetDlgItem(hwndDlg, IDC_HWTYPESLIST);
652     WCHAR DevName[MAX_STR_SIZE];
653     WCHAR DevDesc[MAX_STR_SIZE];
654     BOOL DevExist = FALSE;
655     INT ClassRet, DevImage, Index = 0;
656     LV_COLUMN Column;
657     LV_ITEM Item;
658     RECT Rect;
659 
660     if (!hList) return;
661 
662     ZeroMemory(&Column, sizeof(LV_COLUMN));
663 
664     GetClientRect(hList, &Rect);
665 
666     Column.mask         = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
667     Column.fmt          = LVCFMT_LEFT;
668     Column.iSubItem     = 0;
669     Column.pszText      = NULL;
670     Column.cx           = Rect.right - GetSystemMetrics(SM_CXVSCROLL);
671     (VOID) ListView_InsertColumn(hList, 0, &Column);
672 
673     ZeroMemory(&Item, sizeof(LV_ITEM));
674 
675     do
676     {
677         ClassRet = EnumDeviceClasses(Index,
678                                      DevName,
679                                      DevDesc,
680                                      &DevExist,
681                                      &DevImage);
682 
683         if ((ClassRet != -1) && (DevExist))
684         {
685             Item.mask   = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
686             Item.iItem  = Index;
687             Item.iImage = DevImage;
688 
689             if (DevDesc[0] != L'\0')
690                 Item.pszText = (LPWSTR) DevDesc;
691             else
692                 Item.pszText = (LPWSTR) DevName;
693 
694             (VOID) ListView_InsertItem(hList, &Item);
695 
696             /* Kill InfoList initialized in EnumDeviceClasses */
697             if (hDevInfoTypes)
698             {
699                 SetupDiDestroyDeviceInfoList(hDevInfoTypes);
700                 hDevInfoTypes = NULL;
701             }
702         }
703         Index++;
704     }
705     while (ClassRet != -1);
706 
707     (VOID) ListView_SetImageList(hList, ImageListData.ImageList, LVSIL_SMALL);
708 }
709 
710 static INT_PTR CALLBACK
711 HdTypesPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
712 {
713     switch (uMsg)
714     {
715         case WM_INITDIALOG:
716         {
717             InitHardWareTypesPage(hwndDlg);
718         }
719         break;
720 
721         case WM_NOTIFY:
722         {
723             LPNMHDR lpnm = (LPNMHDR)lParam;
724 
725             switch (lpnm->code)
726             {
727                 case PSN_SETACTIVE:
728                 {
729                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
730                 }
731                 break;
732 
733                 case PSN_WIZBACK:
734                 {
735                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_SELECTWAYPAGE);
736                     return TRUE;
737                 }
738             }
739         }
740         break;
741     }
742 
743     return FALSE;
744 }
745 
746 static INT_PTR CALLBACK
747 ProgressPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
748 {
749     switch (uMsg)
750     {
751         case WM_NOTIFY:
752         {
753             LPNMHDR lpnm = (LPNMHDR)lParam;
754 
755             switch (lpnm->code)
756             {
757                 case PSN_SETACTIVE:
758                 {
759                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
760                 }
761                 break;
762 
763                 case PSN_WIZBACK:
764                 {
765                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_SELECTWAYPAGE);
766                     return TRUE;
767                 }
768             }
769         }
770         break;
771     }
772 
773     return FALSE;
774 }
775 
776 static int CALLBACK
777 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
778 {
779     // NOTE: This callback is needed to set large icon correctly.
780     HICON hIcon;
781     switch (uMsg)
782     {
783         case PSCB_INITIALIZED:
784         {
785             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDI_CPLICON));
786             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
787             break;
788         }
789     }
790     return 0;
791 }
792 
793 static VOID
794 HardwareWizardInit(HWND hwnd)
795 {
796     HPROPSHEETPAGE ahpsp[10];
797     PROPSHEETPAGE psp = {0};
798     PROPSHEETHEADER psh;
799     UINT nPages = 0;
800 
801     /* Create the Start page, until setup is working */
802     psp.dwSize = sizeof(PROPSHEETPAGE);
803     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
804     psp.hInstance = hApplet;
805     psp.lParam = 0;
806     psp.pfnDlgProc = StartPageDlgProc;
807     psp.pszTemplate = MAKEINTRESOURCE(IDD_STARTPAGE);
808     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
809 
810     /* Create search page */
811     psp.dwSize = sizeof(PROPSHEETPAGE);
812     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
813     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SEARCHTITLE);
814     psp.pszHeaderSubTitle = NULL;
815     psp.hInstance = hApplet;
816     psp.lParam = 0;
817     psp.pfnDlgProc = SearchPageDlgProc;
818     psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHPAGE);
819     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
820 
821     /* Create is connected page */
822     psp.dwSize = sizeof(PROPSHEETPAGE);
823     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
824     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_ISCONNECTED);
825     psp.pszHeaderSubTitle = NULL;
826     psp.hInstance = hApplet;
827     psp.lParam = 0;
828     psp.pfnDlgProc = IsConnectedPageDlgProc;
829     psp.pszTemplate = MAKEINTRESOURCE(IDD_ISCONNECTEDPAGE);
830     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
831 
832     /* Create probe list page */
833     psp.dwSize = sizeof(PROPSHEETPAGE);
834     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
835     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_PROBELISTTITLE);
836     psp.pszHeaderSubTitle = NULL;
837     psp.hInstance = hApplet;
838     psp.lParam = 0;
839     psp.pfnDlgProc = ProbeListPageDlgProc;
840     psp.pszTemplate = MAKEINTRESOURCE(IDD_PROBELISTPAGE);
841     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
842 
843     /* Create select search way page */
844     psp.dwSize = sizeof(PROPSHEETPAGE);
845     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
846     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SELECTWAYTITLE);
847     psp.pszHeaderSubTitle = NULL;
848     psp.hInstance = hApplet;
849     psp.lParam = 0;
850     psp.pfnDlgProc = SelectWayPageDlgProc;
851     psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTWAYPAGE);
852     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
853 
854     /* Create device status page */
855     psp.dwSize = sizeof(PROPSHEETPAGE);
856     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
857     psp.hInstance = hApplet;
858     psp.lParam = 0;
859     psp.pfnDlgProc = DevStatusPageDlgProc;
860     psp.pszTemplate = MAKEINTRESOURCE(IDD_HWSTATUSPAGE);
861     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
862 
863     /* Create hardware types page */
864     psp.dwSize = sizeof(PROPSHEETPAGE);
865     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
866     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_HDTYPESTITLE);
867     psp.pszHeaderSubTitle = NULL;
868     psp.hInstance = hApplet;
869     psp.lParam = 0;
870     psp.pfnDlgProc = HdTypesPageDlgProc;
871     psp.pszTemplate = MAKEINTRESOURCE(IDD_HWTYPESPAGE);
872     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
873 
874     /* Create progress page */
875     psp.dwSize = sizeof(PROPSHEETPAGE);
876     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
877     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SEARCHTITLE);
878     psp.pszHeaderSubTitle = NULL;
879     psp.hInstance = hApplet;
880     psp.lParam = 0;
881     psp.pfnDlgProc = ProgressPageDlgProc;
882     psp.pszTemplate = MAKEINTRESOURCE(IDD_PROGRESSPAGE);
883     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
884 
885     /* Create finish page */
886     psp.dwSize = sizeof(PROPSHEETPAGE);
887     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
888     psp.hInstance = hApplet;
889     psp.lParam = 0;
890     psp.pfnDlgProc = FinishPageDlgProc;
891     psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
892     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
893 
894     /* Create not connected page */
895     psp.dwSize = sizeof(PROPSHEETPAGE);
896     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
897     psp.hInstance = hApplet;
898     psp.lParam = 0;
899     psp.pfnDlgProc = NotConnectedPageDlgProc;
900     psp.pszTemplate = MAKEINTRESOURCE(IDD_NOTCONNECTEDPAGE);
901     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
902 
903     /* Create the property sheet */
904     psh.dwSize = sizeof(PROPSHEETHEADER);
905     psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER | PSH_USEICONID | PSH_USECALLBACK;
906     psh.hInstance = hApplet;
907     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
908     psh.hwndParent = hwnd;
909     psh.nPages = nPages;
910     psh.nStartPage = 0;
911     psh.phpage = ahpsp;
912     psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
913     psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
914     psh.pfnCallback = PropSheetProc;
915 
916     /* Create title font */
917     hTitleFont = CreateTitleFont();
918 
919     /* Display the wizard */
920     PropertySheet(&psh);
921 
922     DeleteObject(hTitleFont);
923 }
924 
925 /* FUNCTIONS ****************************************************************/
926 
927 BOOL WINAPI
928 InstallNewDevice(HWND hwndParent, LPGUID ClassGuid, PDWORD pReboot)
929 {
930     return FALSE;
931 }
932 
933 VOID WINAPI
934 AddHardwareWizard(HWND hwnd, LPWSTR lpName)
935 {
936     if (lpName != NULL)
937     {
938         DPRINT1("No support of remote installation yet!\n");
939         return;
940     }
941 
942     HardwareWizardInit(hwnd);
943 }
944 
945 /* Control Panel Callback */
946 LONG CALLBACK
947 CPlApplet(HWND hwndCpl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
948 {
949     switch (uMsg)
950     {
951         case CPL_INIT:
952             return TRUE;
953 
954         case CPL_GETCOUNT:
955             return 1;
956 
957         case CPL_INQUIRE:
958             {
959                 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
960                 CPlInfo->lData = 0;
961                 CPlInfo->idIcon = IDI_CPLICON;
962                 CPlInfo->idName = IDS_CPLNAME;
963                 CPlInfo->idInfo = IDS_CPLDESCRIPTION;
964             }
965             break;
966 
967         case CPL_DBLCLK:
968             AddHardwareWizard(hwndCpl, NULL);
969             break;
970     }
971 
972     return FALSE;
973 }
974 
975 BOOL WINAPI
976 DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
977 {
978     UNREFERENCED_PARAMETER(lpvReserved);
979 
980     switch (dwReason)
981     {
982         case DLL_PROCESS_ATTACH:
983             hApplet = hinstDLL;
984             hProcessHeap = GetProcessHeap();
985             DisableThreadLibraryCalls(hinstDLL);
986             break;
987     }
988 
989     return TRUE;
990 }
991