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