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