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