* Sync up to trunk head (r64939).
[reactos.git] / dll / win32 / newdev / wizard.c
1 /*
2 * New device installer (newdev.dll)
3 *
4 * Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "newdev_private.h"
22
23 #include <wincon.h>
24 #include <cfgmgr32.h>
25 #include <shlobj.h>
26
27 HANDLE hThread;
28
29 static VOID
30 CenterWindow(
31 IN HWND hWnd)
32 {
33 HWND hWndParent;
34 RECT rcParent;
35 RECT rcWindow;
36
37 hWndParent = GetParent(hWnd);
38 if (hWndParent == NULL)
39 hWndParent = GetDesktopWindow();
40
41 GetWindowRect(hWndParent, &rcParent);
42 GetWindowRect(hWnd, &rcWindow);
43
44 SetWindowPos(
45 hWnd,
46 HWND_TOP,
47 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
48 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
49 0,
50 0,
51 SWP_NOSIZE);
52 }
53
54 static BOOL
55 CanDisableDevice(
56 IN DEVINST DevInst,
57 IN HMACHINE hMachine,
58 OUT BOOL *CanDisable)
59 {
60 CONFIGRET cr;
61 ULONG Status, ProblemNumber;
62 BOOL Ret = FALSE;
63
64 cr = CM_Get_DevNode_Status_Ex(&Status,
65 &ProblemNumber,
66 DevInst,
67 0,
68 hMachine);
69 if (cr == CR_SUCCESS)
70 {
71 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
72 Ret = TRUE;
73 }
74
75 return Ret;
76 }
77
78 static BOOL
79 IsDeviceStarted(
80 IN DEVINST DevInst,
81 IN HMACHINE hMachine,
82 OUT BOOL *IsEnabled)
83 {
84 CONFIGRET cr;
85 ULONG Status, ProblemNumber;
86 BOOL Ret = FALSE;
87
88 cr = CM_Get_DevNode_Status_Ex(
89 &Status,
90 &ProblemNumber,
91 DevInst,
92 0,
93 hMachine);
94 if (cr == CR_SUCCESS)
95 {
96 *IsEnabled = ((Status & DN_STARTED) != 0);
97 Ret = TRUE;
98 }
99
100 return Ret;
101 }
102
103 static BOOL
104 StartDevice(
105 IN HDEVINFO DeviceInfoSet,
106 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
107 IN BOOL bEnable,
108 IN DWORD HardwareProfile OPTIONAL,
109 OUT BOOL *bNeedReboot OPTIONAL)
110 {
111 SP_PROPCHANGE_PARAMS pcp;
112 SP_DEVINSTALL_PARAMS dp;
113 DWORD LastErr;
114 BOOL Ret = FALSE;
115
116 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
117 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
118 pcp.HwProfile = HardwareProfile;
119
120 if (bEnable)
121 {
122 /* try to enable the device on the global profile */
123 pcp.StateChange = DICS_ENABLE;
124 pcp.Scope = DICS_FLAG_GLOBAL;
125
126 /* ignore errors */
127 LastErr = GetLastError();
128 if (SetupDiSetClassInstallParams(
129 DeviceInfoSet,
130 DevInfoData,
131 &pcp.ClassInstallHeader,
132 sizeof(SP_PROPCHANGE_PARAMS)))
133 {
134 SetupDiCallClassInstaller(
135 DIF_PROPERTYCHANGE,
136 DeviceInfoSet,
137 DevInfoData);
138 }
139 SetLastError(LastErr);
140 }
141
142 /* try config-specific */
143 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
144 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
145
146 if (SetupDiSetClassInstallParams(
147 DeviceInfoSet,
148 DevInfoData,
149 &pcp.ClassInstallHeader,
150 sizeof(SP_PROPCHANGE_PARAMS)) &&
151 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
152 DeviceInfoSet,
153 DevInfoData))
154 {
155 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
156 if (SetupDiGetDeviceInstallParams(
157 DeviceInfoSet,
158 DevInfoData,
159 &dp))
160 {
161 if (bNeedReboot != NULL)
162 {
163 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
164 }
165
166 Ret = TRUE;
167 }
168 }
169 return Ret;
170 }
171
172 static DWORD WINAPI
173 FindDriverProc(
174 IN LPVOID lpParam)
175 {
176 PDEVINSTDATA DevInstData;
177 DWORD config_flags;
178 BOOL result = FALSE;
179
180 DevInstData = (PDEVINSTDATA)lpParam;
181
182 result = ScanFoldersForDriver(DevInstData);
183
184 if (result)
185 {
186 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0);
187 }
188 else
189 {
190 /* Update device configuration */
191 if (SetupDiGetDeviceRegistryProperty(
192 DevInstData->hDevInfo,
193 &DevInstData->devInfoData,
194 SPDRP_CONFIGFLAGS,
195 NULL,
196 (BYTE *)&config_flags,
197 sizeof(config_flags),
198 NULL))
199 {
200 config_flags |= CONFIGFLAG_FAILEDINSTALL;
201 SetupDiSetDeviceRegistryPropertyW(
202 DevInstData->hDevInfo,
203 &DevInstData->devInfoData,
204 SPDRP_CONFIGFLAGS,
205 (BYTE *)&config_flags, sizeof(config_flags));
206 }
207
208 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0);
209 }
210 return 0;
211 }
212
213 static DWORD WINAPI
214 InstallDriverProc(
215 IN LPVOID lpParam)
216 {
217 PDEVINSTDATA DevInstData;
218 BOOL res;
219
220 DevInstData = (PDEVINSTDATA)lpParam;
221 res = InstallCurrentDriver(DevInstData);
222 PostMessage(DevInstData->hDialog, WM_INSTALL_FINISHED, res ? 0 : 1, 0);
223 return 0;
224 }
225
226 static VOID
227 PopulateCustomPathCombo(
228 IN HWND hwndCombo)
229 {
230 HKEY hKey = NULL;
231 DWORD dwRegType;
232 DWORD dwPathLength = 0;
233 LPWSTR Buffer = NULL;
234 LPCWSTR Path;
235 LONG rc;
236
237 (void)ComboBox_ResetContent(hwndCombo);
238
239 /* RegGetValue would have been better... */
240 rc = RegOpenKeyEx(
241 HKEY_LOCAL_MACHINE,
242 REGSTR_PATH_SETUP REGSTR_KEY_SETUP,
243 0,
244 KEY_QUERY_VALUE,
245 &hKey);
246 if (rc != ERROR_SUCCESS)
247 {
248 TRACE("RegOpenKeyEx() failed with error 0x%lx\n", rc);
249 goto cleanup;
250 }
251 rc = RegQueryValueExW(
252 hKey,
253 L"Installation Sources",
254 NULL,
255 &dwRegType,
256 NULL,
257 &dwPathLength);
258 if (rc != ERROR_SUCCESS || dwRegType != REG_MULTI_SZ)
259 {
260 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc);
261 goto cleanup;
262 }
263
264 /* Allocate enough space to add 2 NULL chars at the end of the string */
265 Buffer = HeapAlloc(GetProcessHeap(), 0, dwPathLength + 2 * sizeof(WCHAR));
266 if (!Buffer)
267 {
268 TRACE("HeapAlloc() failed\n");
269 goto cleanup;
270 }
271 rc = RegQueryValueExW(
272 hKey,
273 L"Installation Sources",
274 NULL,
275 NULL,
276 (LPBYTE)Buffer,
277 &dwPathLength);
278 if (rc != ERROR_SUCCESS)
279 {
280 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc);
281 goto cleanup;
282 }
283 Buffer[dwPathLength] = Buffer[dwPathLength + 1] = '\0';
284
285 /* Populate combo box */
286 for (Path = Buffer; *Path; Path += wcslen(Path) + 1)
287 {
288 (void)ComboBox_AddString(hwndCombo, Path);
289 if (Path == Buffer)
290 (void)ComboBox_SetCurSel(hwndCombo, 0);
291 }
292
293 cleanup:
294 if (hKey != NULL)
295 RegCloseKey(hKey);
296 HeapFree(GetProcessHeap(), 0, Buffer);
297 }
298
299 static VOID
300 SaveCustomPath(
301 IN HWND hwndCombo)
302 {
303 LPWSTR CustomPath = NULL;
304 DWORD CustomPathLength;
305 LPWSTR Buffer = NULL;
306 LPWSTR pBuffer; /* Pointer into Buffer */
307 int ItemsCount, Length;
308 DWORD i;
309 DWORD TotalLength = 0;
310 BOOL UseCustomPath = TRUE;
311 HKEY hKey = NULL;
312 LONG rc;
313
314 /* Get custom path */
315 Length = ComboBox_GetTextLength(hwndCombo) + 1;
316 CustomPath = HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
317 if (!CustomPath)
318 {
319 TRACE("HeapAlloc() failed\n");
320 goto cleanup;
321 }
322 CustomPathLength = GetWindowTextW(hwndCombo, CustomPath, Length) + 1;
323
324 /* Calculate length of the buffer */
325 ItemsCount = ComboBox_GetCount(hwndCombo);
326 if (ItemsCount == CB_ERR)
327 {
328 TRACE("ComboBox_GetCount() failed\n");
329 goto cleanup;
330 }
331 for (i = 0; i < ItemsCount; i++)
332 {
333 Length = ComboBox_GetLBTextLen(hwndCombo, i);
334 if (Length == CB_ERR)
335 {
336 TRACE("ComboBox_GetLBTextLen() failed\n");
337 goto cleanup;
338 }
339 TotalLength += Length + 1;
340 }
341 TotalLength++; /* Final NULL char */
342
343 /* Allocate buffer */
344 Buffer = HeapAlloc(GetProcessHeap(), 0, (CustomPathLength + TotalLength + 1) * sizeof(WCHAR));
345 if (!Buffer)
346 {
347 TRACE("HeapAlloc() failed\n");
348 goto cleanup;
349 }
350
351 /* Fill the buffer */
352 pBuffer = &Buffer[CustomPathLength];
353 for (i = 0; i < ItemsCount; i++)
354 {
355 Length = ComboBox_GetLBText(hwndCombo, i, pBuffer);
356 if (Length == CB_ERR)
357 {
358 TRACE("ComboBox_GetLBText() failed\n");
359 goto cleanup;
360 }
361 else if (UseCustomPath && _wcsicmp(CustomPath, pBuffer) == 0)
362 UseCustomPath = FALSE;
363 pBuffer += 1 + Length;
364 }
365 *pBuffer = '\0'; /* Add final NULL char */
366
367 if (!UseCustomPath)
368 {
369 /* Nothing to save to registry */
370 goto cleanup;
371 }
372
373 TotalLength += CustomPathLength;
374 wcscpy(Buffer, CustomPath);
375
376 /* Save the buffer */
377 /* RegSetKeyValue would have been better... */
378 rc = RegOpenKeyEx(
379 HKEY_LOCAL_MACHINE,
380 REGSTR_PATH_SETUP REGSTR_KEY_SETUP,
381 0,
382 KEY_SET_VALUE,
383 &hKey);
384 if (rc != ERROR_SUCCESS)
385 {
386 TRACE("RegOpenKeyEx() failed with error 0x%lx\n", rc);
387 goto cleanup;
388 }
389 rc = RegSetValueExW(
390 hKey,
391 L"Installation Sources",
392 0,
393 REG_MULTI_SZ,
394 (const BYTE*)Buffer,
395 TotalLength * sizeof(WCHAR));
396 if (rc != ERROR_SUCCESS)
397 {
398 TRACE("RegSetValueEx() failed with error 0x%lx\n", rc);
399 goto cleanup;
400 }
401
402 cleanup:
403 if (hKey != NULL)
404 RegCloseKey(hKey);
405 HeapFree(GetProcessHeap(), 0, CustomPath);
406 HeapFree(GetProcessHeap(), 0, Buffer);
407 }
408
409 static INT_PTR CALLBACK
410 WelcomeDlgProc(
411 IN HWND hwndDlg,
412 IN UINT uMsg,
413 IN WPARAM wParam,
414 IN LPARAM lParam)
415 {
416 PDEVINSTDATA DevInstData;
417 UNREFERENCED_PARAMETER(wParam);
418
419 /* Retrieve pointer to the global setup data */
420 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
421
422 switch (uMsg)
423 {
424 case WM_INITDIALOG:
425 {
426 HWND hwndControl;
427 DWORD dwStyle;
428
429 /* Get pointer to the global setup data */
430 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
431 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
432
433 hwndControl = GetParent(hwndDlg);
434
435 /* Center the wizard window */
436 CenterWindow(hwndControl);
437
438 /* Hide the system menu */
439 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE);
440 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
441
442 /* Set title font */
443 SendDlgItemMessage(
444 hwndDlg,
445 IDC_WELCOMETITLE,
446 WM_SETFONT,
447 (WPARAM)DevInstData->hTitleFont,
448 (LPARAM)TRUE);
449
450 SendDlgItemMessage(
451 hwndDlg,
452 IDC_DEVICE,
453 WM_SETTEXT,
454 0,
455 (LPARAM)DevInstData->buffer);
456
457 SendDlgItemMessage(
458 hwndDlg,
459 IDC_RADIO_AUTO,
460 BM_SETCHECK,
461 (WPARAM)TRUE,
462 (LPARAM)0);
463 break;
464 }
465
466 case WM_NOTIFY:
467 {
468 LPNMHDR lpnm = (LPNMHDR)lParam;
469
470 switch (lpnm->code)
471 {
472 case PSN_SETACTIVE:
473 /* Enable the Next button */
474 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
475 break;
476
477 case PSN_WIZNEXT:
478 /* Handle a Next button click, if necessary */
479 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED)
480 {
481 if (PrepareFoldersToScan(DevInstData, TRUE, FALSE, NULL))
482 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV);
483 else
484 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED);
485 }
486 return TRUE;
487
488 default:
489 break;
490 }
491 break;
492 }
493
494 default:
495 break;
496 }
497
498 return FALSE;
499 }
500
501 static void
502 IncludePath(HWND Dlg, BOOL Enabled)
503 {
504 EnableWindow(GetDlgItem(Dlg, IDC_COMBO_PATH), Enabled);
505 EnableWindow(GetDlgItem(Dlg, IDC_BROWSE), Enabled);
506 }
507
508 static void
509 AutoDriver(HWND Dlg, BOOL Enabled)
510 {
511 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_MEDIA), Enabled);
512 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_PATH), Enabled);
513 IncludePath(Dlg, Enabled & IsDlgButtonChecked(Dlg, IDC_CHECK_PATH));
514 }
515
516 static INT_PTR CALLBACK
517 CHSourceDlgProc(
518 IN HWND hwndDlg,
519 IN UINT uMsg,
520 IN WPARAM wParam,
521 IN LPARAM lParam)
522 {
523 PDEVINSTDATA DevInstData;
524
525 /* Retrieve pointer to the global setup data */
526 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
527
528 switch (uMsg)
529 {
530 case WM_INITDIALOG:
531 {
532 HWND hwndControl;
533 DWORD dwStyle;
534
535 /* Get pointer to the global setup data */
536 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
537 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
538
539 hwndControl = GetParent(hwndDlg);
540
541 /* Center the wizard window */
542 CenterWindow(hwndControl);
543
544 /* Hide the system menu */
545 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE);
546 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
547
548 PopulateCustomPathCombo(GetDlgItem(hwndDlg, IDC_COMBO_PATH));
549
550 SendDlgItemMessage(
551 hwndDlg,
552 IDC_RADIO_SEARCHHERE,
553 BM_SETCHECK,
554 (WPARAM)TRUE,
555 (LPARAM)0);
556 AutoDriver(hwndDlg, TRUE);
557 IncludePath(hwndDlg, FALSE);
558
559 /* Disable manual driver choice for now */
560 EnableWindow(GetDlgItem(hwndDlg, IDC_RADIO_CHOOSE), FALSE);
561
562 break;
563 }
564
565 case WM_COMMAND:
566 {
567 switch (LOWORD(wParam))
568 {
569 case IDC_RADIO_SEARCHHERE:
570 AutoDriver(hwndDlg, TRUE);
571 return TRUE;
572
573 case IDC_RADIO_CHOOSE:
574 AutoDriver(hwndDlg, FALSE);
575 return TRUE;
576
577 case IDC_CHECK_PATH:
578 IncludePath(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH));
579 return TRUE;
580
581 case IDC_BROWSE:
582 {
583 BROWSEINFO bi = { 0 };
584 LPITEMIDLIST pidl;
585
586 bi.hwndOwner = hwndDlg;
587 bi.ulFlags = BIF_RETURNONLYFSDIRS;
588 pidl = SHBrowseForFolder(&bi);
589 if (pidl)
590 {
591 WCHAR Directory[MAX_PATH];
592 IMalloc* malloc;
593
594 if (SHGetPathFromIDListW(pidl, Directory))
595 {
596 /* Set the IDC_COMBO_PATH text */
597 SetWindowTextW(GetDlgItem(hwndDlg, IDC_COMBO_PATH), Directory);
598 }
599
600 /* Free memory, if possible */
601 if (SUCCEEDED(SHGetMalloc(&malloc)))
602 {
603 IMalloc_Free(malloc, pidl);
604 IMalloc_Release(malloc);
605 }
606 return TRUE;
607 }
608 break;
609 }
610 }
611 break;
612 }
613
614 case WM_NOTIFY:
615 {
616 LPNMHDR lpnm = (LPNMHDR)lParam;
617
618 switch (lpnm->code)
619 {
620 case PSN_SETACTIVE:
621 /* Enable the Next and Back buttons */
622 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
623 break;
624
625 case PSN_WIZNEXT:
626 /* Handle a Next button click, if necessary */
627 if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_SEARCHHERE))
628 {
629 SaveCustomPath(GetDlgItem(hwndDlg, IDC_COMBO_PATH));
630 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
631 DevInstData->CustomSearchPath = NULL;
632 if (PrepareFoldersToScan(
633 DevInstData,
634 IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA),
635 IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH),
636 GetDlgItem(hwndDlg, IDC_COMBO_PATH)))
637 {
638 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV);
639 }
640 else
641 {
642 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED);
643 }
644 }
645 else
646 {
647 /* FIXME */;
648 }
649 return TRUE;
650
651 default:
652 break;
653 }
654 break;
655 }
656
657 default:
658 break;
659 }
660
661 return FALSE;
662 }
663
664 static INT_PTR CALLBACK
665 SearchDrvDlgProc(
666 IN HWND hwndDlg,
667 IN UINT uMsg,
668 IN WPARAM wParam,
669 IN LPARAM lParam)
670 {
671 PDEVINSTDATA DevInstData;
672 DWORD dwThreadId;
673
674 /* Retrieve pointer to the global setup data */
675 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
676
677 switch (uMsg)
678 {
679 case WM_INITDIALOG:
680 {
681 HWND hwndControl;
682 DWORD dwStyle;
683
684 /* Get pointer to the global setup data */
685 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
686 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
687
688 DevInstData->hDialog = hwndDlg;
689 hwndControl = GetParent(hwndDlg);
690
691 /* Center the wizard window */
692 CenterWindow(hwndControl);
693
694 SendDlgItemMessage(
695 hwndDlg,
696 IDC_DEVICE,
697 WM_SETTEXT,
698 0,
699 (LPARAM)DevInstData->buffer);
700
701 /* Hide the system menu */
702 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE);
703 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
704 break;
705 }
706
707 case WM_SEARCH_FINISHED:
708 {
709 CloseHandle(hThread);
710 hThread = 0;
711 if (wParam == 0)
712 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NODRIVER);
713 else
714 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLDRV);
715 break;
716 }
717
718 case WM_NOTIFY:
719 {
720 LPNMHDR lpnm = (LPNMHDR)lParam;
721
722 switch (lpnm->code)
723 {
724 case PSN_SETACTIVE:
725 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
726 /* Yes, we can safely ignore the problem (if any) */
727 SetupDiDestroyDriverInfoList(
728 DevInstData->hDevInfo,
729 &DevInstData->devInfoData,
730 SPDIT_COMPATDRIVER);
731 hThread = CreateThread(NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId);
732 break;
733
734 case PSN_KILLACTIVE:
735 if (hThread != 0)
736 {
737 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, TRUE);
738 return TRUE;
739 }
740 break;
741
742 case PSN_WIZNEXT:
743 /* Handle a Next button click, if necessary */
744 break;
745
746 default:
747 break;
748 }
749 break;
750 }
751
752 default:
753 break;
754 }
755
756 return FALSE;
757 }
758
759 static INT_PTR CALLBACK
760 InstallDrvDlgProc(
761 IN HWND hwndDlg,
762 IN UINT uMsg,
763 IN WPARAM wParam,
764 IN LPARAM lParam)
765 {
766 PDEVINSTDATA DevInstData;
767 DWORD dwThreadId;
768
769 /* Retrieve pointer to the global setup data */
770 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
771
772 switch (uMsg)
773 {
774 case WM_INITDIALOG:
775 {
776 HWND hwndControl;
777 DWORD dwStyle;
778
779 /* Get pointer to the global setup data */
780 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
781 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
782
783 DevInstData->hDialog = hwndDlg;
784 hwndControl = GetParent(hwndDlg);
785
786 /* Center the wizard window */
787 CenterWindow(hwndControl);
788
789 SendDlgItemMessage(
790 hwndDlg,
791 IDC_DEVICE,
792 WM_SETTEXT,
793 0,
794 (LPARAM)DevInstData->drvInfoData.Description);
795
796 /* Hide the system menu */
797 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE);
798 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
799 break;
800 }
801
802 case WM_INSTALL_FINISHED:
803 {
804 CloseHandle(hThread);
805 hThread = 0;
806 if (wParam == 0)
807 {
808 /* Should we reboot? */
809 SP_DEVINSTALL_PARAMS installParams;
810 installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
811 if (SetupDiGetDeviceInstallParams(
812 DevInstData->hDevInfo,
813 &DevInstData->devInfoData,
814 &installParams))
815 {
816 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
817 {
818 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NEEDREBOOT);
819 }
820 else
821 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_FINISHPAGE);
822 break;
823 }
824 }
825 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED);
826 break;
827 }
828
829 case WM_NOTIFY:
830 {
831 LPNMHDR lpnm = (LPNMHDR)lParam;
832
833 switch (lpnm->code)
834 {
835 case PSN_SETACTIVE:
836 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
837 hThread = CreateThread(NULL, 0, InstallDriverProc, DevInstData, 0, &dwThreadId);
838 break;
839
840 case PSN_KILLACTIVE:
841 if (hThread != 0)
842 {
843 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, TRUE);
844 return TRUE;
845 }
846 break;
847
848 case PSN_WIZNEXT:
849 /* Handle a Next button click, if necessary */
850 break;
851
852 default:
853 break;
854 }
855 break;
856 }
857
858 default:
859 break;
860 }
861
862 return FALSE;
863 }
864
865 static INT_PTR CALLBACK
866 NoDriverDlgProc(
867 IN HWND hwndDlg,
868 IN UINT uMsg,
869 IN WPARAM wParam,
870 IN LPARAM lParam)
871 {
872 PDEVINSTDATA DevInstData;
873 HWND hwndControl;
874
875 UNREFERENCED_PARAMETER(wParam);
876
877 /* Get pointer to the global setup data */
878 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
879
880 switch (uMsg)
881 {
882 case WM_INITDIALOG:
883 {
884 BOOL DisableableDevice = FALSE;
885
886 /* Get pointer to the global setup data */
887 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
888 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
889
890 /* Center the wizard window */
891 CenterWindow(GetParent(hwndDlg));
892
893 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
894 ShowWindow(hwndControl, SW_HIDE);
895 EnableWindow(hwndControl, FALSE);
896
897 /* Set title font */
898 SendDlgItemMessage(
899 hwndDlg,
900 IDC_FINISHTITLE,
901 WM_SETFONT,
902 (WPARAM)DevInstData->hTitleFont,
903 (LPARAM)TRUE);
904
905 /* disable the "do not show this dialog anymore" checkbox
906 if the device cannot be disabled */
907 CanDisableDevice(
908 DevInstData->devInfoData.DevInst,
909 NULL,
910 &DisableableDevice);
911 EnableWindow(
912 GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG),
913 DisableableDevice);
914 break;
915 }
916
917 case WM_NOTIFY:
918 {
919 LPNMHDR lpnm = (LPNMHDR)lParam;
920
921 switch (lpnm->code)
922 {
923 case PSN_SETACTIVE:
924 /* Enable the correct buttons on for the active page */
925 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
926 break;
927
928 case PSN_WIZBACK:
929 /* Handle a Back button click, if necessary */
930 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
931 ShowWindow(hwndControl, SW_SHOW);
932 EnableWindow(hwndControl, TRUE);
933 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_CHSOURCE);
934 return TRUE;
935
936 case PSN_WIZFINISH:
937 {
938 BOOL DisableableDevice = FALSE;
939 BOOL IsStarted = FALSE;
940
941 if (CanDisableDevice(DevInstData->devInfoData.DevInst,
942 NULL,
943 &DisableableDevice) &&
944 DisableableDevice &&
945 IsDeviceStarted(
946 DevInstData->devInfoData.DevInst,
947 NULL,
948 &IsStarted) &&
949 !IsStarted &&
950 SendDlgItemMessage(
951 hwndDlg,
952 IDC_DONOTSHOWDLG,
953 BM_GETCHECK,
954 (WPARAM)0, (LPARAM)0) == BST_CHECKED)
955 {
956 /* disable the device */
957 StartDevice(
958 DevInstData->hDevInfo,
959 &DevInstData->devInfoData,
960 FALSE,
961 0,
962 NULL);
963 }
964 break;
965 }
966
967 default:
968 break;
969 }
970 break;
971 }
972
973 default:
974 break;
975 }
976
977 return FALSE;
978 }
979
980 static INT_PTR CALLBACK
981 InstallFailedDlgProc(
982 IN HWND hwndDlg,
983 IN UINT uMsg,
984 IN WPARAM wParam,
985 IN LPARAM lParam)
986 {
987 PDEVINSTDATA DevInstData;
988 UNREFERENCED_PARAMETER(wParam);
989
990 /* Retrieve pointer to the global setup data */
991 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
992
993 switch (uMsg)
994 {
995 case WM_INITDIALOG:
996 {
997 HWND hwndControl;
998
999 /* Get pointer to the global setup data */
1000 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1001 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
1002
1003 /* Center the wizard window */
1004 CenterWindow(GetParent(hwndDlg));
1005
1006 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
1007 ShowWindow(hwndControl, SW_HIDE);
1008 EnableWindow(hwndControl, FALSE);
1009
1010 SendDlgItemMessage(
1011 hwndDlg,
1012 IDC_DEVICE,
1013 WM_SETTEXT,
1014 0,
1015 (LPARAM)DevInstData->drvInfoData.Description);
1016
1017 /* Set title font */
1018 SendDlgItemMessage(
1019 hwndDlg,
1020 IDC_FINISHTITLE,
1021 WM_SETFONT,
1022 (WPARAM)DevInstData->hTitleFont,
1023 (LPARAM)TRUE);
1024 break;
1025 }
1026
1027 case WM_NOTIFY:
1028 {
1029 LPNMHDR lpnm = (LPNMHDR)lParam;
1030
1031 switch (lpnm->code)
1032 {
1033 case PSN_SETACTIVE:
1034 /* Enable the correct buttons on for the active page */
1035 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
1036 break;
1037
1038 case PSN_WIZBACK:
1039 /* Handle a Back button click, if necessary */
1040 break;
1041
1042 case PSN_WIZFINISH:
1043 /* Handle a Finish button click, if necessary */
1044 break;
1045
1046 default:
1047 break;
1048 }
1049 break;
1050 }
1051
1052 default:
1053 break;
1054 }
1055
1056 return FALSE;
1057 }
1058
1059 static INT_PTR CALLBACK
1060 NeedRebootDlgProc(
1061 IN HWND hwndDlg,
1062 IN UINT uMsg,
1063 IN WPARAM wParam,
1064 IN LPARAM lParam)
1065 {
1066 PDEVINSTDATA DevInstData;
1067 UNREFERENCED_PARAMETER(wParam);
1068
1069 /* Retrieve pointer to the global setup data */
1070 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
1071
1072 switch (uMsg)
1073 {
1074 case WM_INITDIALOG:
1075 {
1076 HWND hwndControl;
1077
1078 /* Get pointer to the global setup data */
1079 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1080 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
1081
1082 /* Center the wizard window */
1083 CenterWindow(GetParent(hwndDlg));
1084
1085 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
1086 ShowWindow(hwndControl, SW_HIDE);
1087 EnableWindow(hwndControl, FALSE);
1088
1089 SendDlgItemMessage(
1090 hwndDlg,
1091 IDC_DEVICE,
1092 WM_SETTEXT,
1093 0,
1094 (LPARAM)DevInstData->drvInfoData.Description);
1095
1096 /* Set title font */
1097 SendDlgItemMessage(
1098 hwndDlg,
1099 IDC_FINISHTITLE,
1100 WM_SETFONT,
1101 (WPARAM)DevInstData->hTitleFont,
1102 (LPARAM)TRUE);
1103 break;
1104 }
1105
1106 case WM_NOTIFY:
1107 {
1108 LPNMHDR lpnm = (LPNMHDR)lParam;
1109
1110 switch (lpnm->code)
1111 {
1112 case PSN_SETACTIVE:
1113 /* Enable the correct buttons on for the active page */
1114 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
1115 break;
1116
1117 case PSN_WIZBACK:
1118 /* Handle a Back button click, if necessary */
1119 break;
1120
1121 case PSN_WIZFINISH:
1122 /* Handle a Finish button click, if necessary */
1123 break;
1124
1125 default:
1126 break;
1127 }
1128 break;
1129 }
1130
1131 default:
1132 break;
1133 }
1134
1135 return FALSE;
1136 }
1137
1138 static INT_PTR CALLBACK
1139 FinishDlgProc(
1140 IN HWND hwndDlg,
1141 IN UINT uMsg,
1142 IN WPARAM wParam,
1143 IN LPARAM lParam)
1144 {
1145 PDEVINSTDATA DevInstData;
1146 UNREFERENCED_PARAMETER(wParam);
1147
1148 /* Retrieve pointer to the global setup data */
1149 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
1150
1151 switch (uMsg)
1152 {
1153 case WM_INITDIALOG:
1154 {
1155 HWND hwndControl;
1156
1157 /* Get pointer to the global setup data */
1158 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1159 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
1160
1161 /* Center the wizard window */
1162 CenterWindow(GetParent(hwndDlg));
1163
1164 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
1165 ShowWindow(hwndControl, SW_HIDE);
1166 EnableWindow(hwndControl, FALSE);
1167
1168 SendDlgItemMessage(
1169 hwndDlg,
1170 IDC_DEVICE,
1171 WM_SETTEXT,
1172 0,
1173 (LPARAM)DevInstData->drvInfoData.Description);
1174
1175 /* Set title font */
1176 SendDlgItemMessage(
1177 hwndDlg,
1178 IDC_FINISHTITLE,
1179 WM_SETFONT,
1180 (WPARAM)DevInstData->hTitleFont,
1181 (LPARAM)TRUE);
1182 break;
1183 }
1184
1185 case WM_NOTIFY:
1186 {
1187 LPNMHDR lpnm = (LPNMHDR)lParam;
1188
1189 switch (lpnm->code)
1190 {
1191 case PSN_SETACTIVE:
1192 /* Enable the correct buttons on for the active page */
1193 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
1194 break;
1195
1196 case PSN_WIZBACK:
1197 /* Handle a Back button click, if necessary */
1198 break;
1199
1200 case PSN_WIZFINISH:
1201 /* Handle a Finish button click, if necessary */
1202 break;
1203
1204 default:
1205 break;
1206 }
1207 break;
1208 }
1209
1210 default:
1211 break;
1212 }
1213
1214 return FALSE;
1215 }
1216
1217 static HFONT
1218 CreateTitleFont(VOID)
1219 {
1220 NONCLIENTMETRICSW ncm;
1221 LOGFONTW LogFont;
1222 HDC hdc;
1223 INT FontSize;
1224 HFONT hFont;
1225
1226 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
1227 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
1228
1229 LogFont = ncm.lfMessageFont;
1230 LogFont.lfWeight = FW_BOLD;
1231 wcscpy(LogFont.lfFaceName, L"MS Shell Dlg");
1232
1233 hdc = GetDC(NULL);
1234 FontSize = 12;
1235 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
1236 hFont = CreateFontIndirectW(&LogFont);
1237 ReleaseDC(NULL, hdc);
1238
1239 return hFont;
1240 }
1241
1242 BOOL
1243 DisplayWizard(
1244 IN PDEVINSTDATA DevInstData,
1245 IN HWND hwndParent,
1246 IN UINT startPage)
1247 {
1248 PROPSHEETHEADER psh;
1249 HPROPSHEETPAGE ahpsp[IDD_MAXIMUMPAGE + 1];
1250 PROPSHEETPAGE psp;
1251
1252 /* Create the Welcome page */
1253 ZeroMemory(&psp, sizeof(PROPSHEETPAGE));
1254 psp.dwSize = sizeof(PROPSHEETPAGE);
1255 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE;
1256 psp.hInstance = hDllInstance;
1257 psp.lParam = (LPARAM)DevInstData;
1258 psp.pszTitle = MAKEINTRESOURCE(DevInstData->bUpdate ? IDS_UPDATEWIZARDTITLE : IDS_INSTALLWIZARDTITLE);
1259 psp.pfnDlgProc = WelcomeDlgProc;
1260 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
1261 ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp);
1262
1263 /* Create the Select Source page */
1264 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE;
1265 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_CHSOURCE_TITLE);
1266 psp.pfnDlgProc = CHSourceDlgProc;
1267 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE);
1268 ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp);
1269
1270 /* Create the Search driver page */
1271 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE;
1272 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SEARCHDRV_TITLE);
1273 psp.pfnDlgProc = SearchDrvDlgProc;
1274 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV);
1275 ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp);
1276
1277 /* Create the Install driver page */
1278 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE;
1279 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALLDRV_TITLE);
1280 psp.pfnDlgProc = InstallDrvDlgProc;
1281 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLDRV);
1282 ahpsp[IDD_INSTALLDRV] = CreatePropertySheetPage(&psp);
1283
1284 /* Create the No driver page */
1285 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE;
1286 psp.pfnDlgProc = NoDriverDlgProc;
1287 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER);
1288 ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp);
1289
1290 /* Create the Install failed page */
1291 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE;
1292 psp.pfnDlgProc = InstallFailedDlgProc;
1293 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFAILED);
1294 ahpsp[IDD_INSTALLFAILED] = CreatePropertySheetPage(&psp);
1295
1296 /* Create the Need reboot page */
1297 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE;
1298 psp.pfnDlgProc = NeedRebootDlgProc;
1299 psp.pszTemplate = MAKEINTRESOURCE(IDD_NEEDREBOOT);
1300 ahpsp[IDD_NEEDREBOOT] = CreatePropertySheetPage(&psp);
1301
1302 /* Create the Finish page */
1303 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE;
1304 psp.pfnDlgProc = FinishDlgProc;
1305 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
1306 ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp);
1307
1308 /* Create the property sheet */
1309 psh.dwSize = sizeof(PROPSHEETHEADER);
1310 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
1311 psh.hInstance = hDllInstance;
1312 psh.hwndParent = hwndParent;
1313 psh.nPages = IDD_MAXIMUMPAGE + 1;
1314 psh.nStartPage = startPage;
1315 psh.phpage = ahpsp;
1316 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
1317 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
1318
1319 /* Create title font */
1320 DevInstData->hTitleFont = CreateTitleFont();
1321
1322 /* Display the wizard */
1323 PropertySheet(&psh);
1324
1325 DeleteObject(DevInstData->hTitleFont);
1326
1327 return TRUE;
1328 }