7801eadc9f226bdaeba3c09e489a6b49e409a3e9
[reactos.git] / reactos / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define YDEBUG
22 #include "newdev.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(newdev);
25
26 HANDLE hThread;
27
28 static VOID
29 CenterWindow(
30 IN HWND hWnd)
31 {
32 HWND hWndParent;
33 RECT rcParent;
34 RECT rcWindow;
35
36 hWndParent = GetParent(hWnd);
37 if (hWndParent == NULL)
38 hWndParent = GetDesktopWindow();
39
40 GetWindowRect(hWndParent, &rcParent);
41 GetWindowRect(hWnd, &rcWindow);
42
43 SetWindowPos(
44 hWnd,
45 HWND_TOP,
46 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
47 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
48 0,
49 0,
50 SWP_NOSIZE);
51 }
52
53 static BOOL
54 CanDisableDevice(
55 IN DEVINST DevInst,
56 IN HMACHINE hMachine,
57 OUT BOOL *CanDisable)
58 {
59 #if 0
60 /* hpoussin, Dec 2005. I've disabled this code because
61 * ntoskrnl never sets the DN_DISABLEABLE flag.
62 */
63 CONFIGRET cr;
64 ULONG Status, ProblemNumber;
65 BOOL Ret = FALSE;
66
67 cr = CM_Get_DevNode_Status_Ex(
68 &Status,
69 &ProblemNumber,
70 DevInst,
71 0,
72 hMachine);
73 if (cr == CR_SUCCESS)
74 {
75 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
76 Ret = TRUE;
77 }
78
79 return Ret;
80 #else
81 *CanDisable = TRUE;
82 return TRUE;
83 #endif
84 }
85
86 static BOOL
87 IsDeviceStarted(
88 IN DEVINST DevInst,
89 IN HMACHINE hMachine,
90 OUT BOOL *IsEnabled)
91 {
92 CONFIGRET cr;
93 ULONG Status, ProblemNumber;
94 BOOL Ret = FALSE;
95
96 cr = CM_Get_DevNode_Status_Ex(
97 &Status,
98 &ProblemNumber,
99 DevInst,
100 0,
101 hMachine);
102 if (cr == CR_SUCCESS)
103 {
104 *IsEnabled = ((Status & DN_STARTED) != 0);
105 Ret = TRUE;
106 }
107
108 return Ret;
109 }
110
111 static BOOL
112 StartDevice(
113 IN HDEVINFO DeviceInfoSet,
114 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
115 IN BOOL bEnable,
116 IN DWORD HardwareProfile OPTIONAL,
117 OUT BOOL *bNeedReboot OPTIONAL)
118 {
119 SP_PROPCHANGE_PARAMS pcp;
120 SP_DEVINSTALL_PARAMS dp;
121 DWORD LastErr;
122 BOOL Ret = FALSE;
123
124 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
125 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
126 pcp.HwProfile = HardwareProfile;
127
128 if (bEnable)
129 {
130 /* try to enable the device on the global profile */
131 pcp.StateChange = DICS_ENABLE;
132 pcp.Scope = DICS_FLAG_GLOBAL;
133
134 /* ignore errors */
135 LastErr = GetLastError();
136 if (SetupDiSetClassInstallParams(
137 DeviceInfoSet,
138 DevInfoData,
139 &pcp.ClassInstallHeader,
140 sizeof(SP_PROPCHANGE_PARAMS)))
141 {
142 SetupDiCallClassInstaller(
143 DIF_PROPERTYCHANGE,
144 DeviceInfoSet,
145 DevInfoData);
146 }
147 SetLastError(LastErr);
148 }
149
150 /* try config-specific */
151 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
152 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
153
154 if (SetupDiSetClassInstallParams(
155 DeviceInfoSet,
156 DevInfoData,
157 &pcp.ClassInstallHeader,
158 sizeof(SP_PROPCHANGE_PARAMS)) &&
159 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
160 DeviceInfoSet,
161 DevInfoData))
162 {
163 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
164 if (SetupDiGetDeviceInstallParams(
165 DeviceInfoSet,
166 DevInfoData,
167 &dp))
168 {
169 if (bNeedReboot != NULL)
170 {
171 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
172 }
173
174 Ret = TRUE;
175 }
176 }
177 return Ret;
178 }
179
180 static BOOL
181 PrepareFoldersToScan(
182 IN PDEVINSTDATA DevInstData,
183 IN HWND hwndDlg)
184 {
185 TCHAR drive[] = {'?',':',0};
186 DWORD dwDrives = 0;
187 DWORD i;
188 UINT nType;
189 DWORD CustomTextLength = 0;
190 DWORD LengthNeeded = 0;
191 LPTSTR Buffer;
192
193 TRACE("Include removable devices: %s\n", IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA) ? "yes" : "no");
194 TRACE("Include custom path : %s\n", IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH) ? "yes" : "no");
195
196 /* Calculate length needed to store the search paths */
197 if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA))
198 {
199 dwDrives = GetLogicalDrives();
200 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
201 {
202 if (dwDrives & i)
203 {
204 nType = GetDriveType(drive);
205 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
206 {
207 LengthNeeded += 3;
208 }
209 }
210 }
211 }
212 if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH))
213 {
214 CustomTextLength = 1 + SendDlgItemMessage(
215 hwndDlg,
216 IDC_COMBO_PATH,
217 WM_GETTEXTLENGTH,
218 (WPARAM)0,
219 (LPARAM)0);
220 LengthNeeded += CustomTextLength;
221 }
222
223 /* Allocate space for search paths */
224 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
225 DevInstData->CustomSearchPath = Buffer = HeapAlloc(
226 GetProcessHeap(),
227 0,
228 (LengthNeeded + 1) * sizeof(TCHAR));
229 if (!Buffer)
230 {
231 TRACE("HeapAlloc() failed\n");
232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
233 return FALSE;
234 }
235
236 /* Fill search paths */
237 if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA))
238 {
239 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
240 {
241 if (dwDrives & i)
242 {
243 nType = GetDriveType(drive);
244 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
245 {
246 Buffer += 1 + _stprintf(Buffer, drive);
247 }
248 }
249 }
250 }
251 if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH))
252 {
253 Buffer += 1 + SendDlgItemMessage(
254 hwndDlg,
255 IDC_COMBO_PATH,
256 WM_GETTEXT,
257 (WPARAM)CustomTextLength,
258 (LPARAM)Buffer);
259 }
260 *Buffer = _T('\0');
261
262 return TRUE;
263 }
264
265 static DWORD WINAPI
266 FindDriverProc(
267 IN LPVOID lpParam)
268 {
269 PDEVINSTDATA DevInstData;
270 DWORD config_flags;
271 BOOL result = FALSE;
272
273 DevInstData = (PDEVINSTDATA)lpParam;
274
275 /* Yes, we can safely ignore the problem (if any) */
276 SetupDiDestroyDriverInfoList(
277 DevInstData->hDevInfo,
278 &DevInstData->devInfoData,
279 SPDIT_COMPATDRIVER);
280
281 if (!DevInstData->CustomSearchPath)
282 {
283 /* Search in default location */
284 result = SearchDriver(DevInstData, NULL, NULL);
285 }
286 else
287 {
288 /* Search only in specified paths */
289 /* We need to check all specified directories to be
290 * sure to find the best driver for the device.
291 */
292 LPCTSTR Path;
293 for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += _tcslen(Path) + 1)
294 {
295 TRACE("Search driver in %S\n", Path);
296 if (_tcslen(Path) == 2 && Path[1] == ':')
297 {
298 if (SearchDriverRecursive(DevInstData, Path))
299 result = TRUE;
300 }
301 else
302 {
303 if (SearchDriver(DevInstData, Path, NULL))
304 result = TRUE;
305 }
306 }
307 }
308
309 if (result)
310 {
311 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0);
312 }
313 else
314 {
315 /* Update device configuration */
316 if (SetupDiGetDeviceRegistryProperty(
317 DevInstData->hDevInfo,
318 &DevInstData->devInfoData,
319 SPDRP_CONFIGFLAGS,
320 NULL,
321 (BYTE *)&config_flags,
322 sizeof(config_flags),
323 NULL))
324 {
325 config_flags |= CONFIGFLAG_FAILEDINSTALL;
326 SetupDiSetDeviceRegistryProperty(
327 DevInstData->hDevInfo,
328 &DevInstData->devInfoData,
329 SPDRP_CONFIGFLAGS,
330 (BYTE *)&config_flags, sizeof(config_flags));
331 }
332
333 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0);
334 }
335 return 0;
336 }
337
338 static VOID
339 PopulateCustomPathCombo(
340 IN HWND hwndCombo)
341 {
342 HKEY hKey = NULL;
343 DWORD dwRegType;
344 DWORD dwPathLength;
345 LPTSTR Buffer = NULL;
346 LPCTSTR Path;
347 LONG rc;
348
349 (void)ComboBox_ResetContent(hwndCombo);
350
351 /* RegGetValue would have been better... */
352 rc = RegOpenKeyEx(
353 HKEY_LOCAL_MACHINE,
354 REGSTR_PATH_SETUP REGSTR_KEY_SETUP,
355 0,
356 KEY_QUERY_VALUE,
357 &hKey);
358 if (rc != ERROR_SUCCESS)
359 {
360 TRACE("RegOpenKeyEx() failed with error 0x%lx\n", rc);
361 goto cleanup;
362 }
363 rc = RegQueryValueEx(
364 hKey,
365 _T("Installation Sources"),
366 NULL,
367 &dwRegType,
368 NULL,
369 &dwPathLength);
370 if (rc != ERROR_SUCCESS || dwRegType != REG_MULTI_SZ)
371 {
372 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc);
373 goto cleanup;
374 }
375 /* Allocate enough space to add 2 NULL chars at the end of the string */
376 Buffer = HeapAlloc(GetProcessHeap(), 0, dwPathLength + 2 * sizeof(TCHAR));
377 if (!Buffer)
378 {
379 TRACE("HeapAlloc() failed\n");
380 goto cleanup;
381 }
382 rc = RegQueryValueEx(
383 hKey,
384 _T("Installation Sources"),
385 NULL,
386 NULL,
387 (LPBYTE)Buffer,
388 &dwPathLength);
389 if (rc != ERROR_SUCCESS)
390 {
391 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc);
392 goto cleanup;
393 }
394 Buffer[dwPathLength] = Buffer[dwPathLength + 1] = '\0';
395
396 /* Populate combo box */
397 for (Path = Buffer; *Path; Path += _tcslen(Path))
398 (void)ComboBox_AddString(hwndCombo, Path);
399 (void)ComboBox_SetCurSel(hwndCombo, 0);
400
401 cleanup:
402 if (hKey != NULL)
403 RegCloseKey(hKey);
404 HeapFree(GetProcessHeap(), 0, Buffer);
405 }
406
407 static VOID
408 SaveCustomPath(
409 IN HWND hwndCombo)
410 {
411 FIXME("Stub.");
412 }
413
414 static INT_PTR CALLBACK
415 WelcomeDlgProc(
416 IN HWND hwndDlg,
417 IN UINT uMsg,
418 IN WPARAM wParam,
419 IN LPARAM lParam)
420 {
421 PDEVINSTDATA DevInstData;
422
423 /* Retrieve pointer to the global setup data */
424 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
425
426 switch (uMsg)
427 {
428 case WM_INITDIALOG:
429 {
430 HWND hwndControl;
431 DWORD dwStyle;
432
433 /* Get pointer to the global setup data */
434 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
435 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
436
437 hwndControl = GetParent(hwndDlg);
438
439 /* Center the wizard window */
440 CenterWindow(hwndControl);
441
442 /* Hide the system menu */
443 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
444 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
445
446 /* Set title font */
447 SendDlgItemMessage(
448 hwndDlg,
449 IDC_WELCOMETITLE,
450 WM_SETFONT,
451 (WPARAM)DevInstData->hTitleFont,
452 (LPARAM)TRUE);
453
454 SendDlgItemMessage(
455 hwndDlg,
456 IDC_DEVICE,
457 WM_SETTEXT,
458 0,
459 (LPARAM)DevInstData->buffer);
460
461 SendDlgItemMessage(
462 hwndDlg,
463 IDC_RADIO_AUTO,
464 BM_SETCHECK,
465 (WPARAM)TRUE,
466 (LPARAM)0);
467 break;
468 }
469
470 case WM_NOTIFY:
471 {
472 LPNMHDR lpnm = (LPNMHDR)lParam;
473
474 switch (lpnm->code)
475 {
476 case PSN_SETACTIVE:
477 /* Enable the Next button */
478 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
479 break;
480
481 case PSN_WIZNEXT:
482 /* Handle a Next button click, if necessary */
483 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED)
484 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV);
485 return TRUE;
486
487 default:
488 break;
489 }
490 break;
491 }
492
493 default:
494 break;
495 }
496
497 return FALSE;
498 }
499
500 static void
501 IncludePath(HWND Dlg, BOOL Enabled)
502 {
503 EnableWindow(GetDlgItem(Dlg, IDC_COMBO_PATH), Enabled);
504 EnableWindow(GetDlgItem(Dlg, IDC_BROWSE), /*FIXME: Enabled*/ FALSE);
505 }
506
507 static void
508 AutoDriver(HWND Dlg, BOOL Enabled)
509 {
510 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_MEDIA), Enabled);
511 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_PATH), Enabled);
512 IncludePath(Dlg, Enabled & IsDlgButtonChecked(Dlg, IDC_CHECK_PATH));
513 }
514
515 static INT_PTR CALLBACK
516 CHSourceDlgProc(
517 IN HWND hwndDlg,
518 IN UINT uMsg,
519 IN WPARAM wParam,
520 IN LPARAM lParam)
521 {
522 PDEVINSTDATA DevInstData;
523
524 /* Retrieve pointer to the global setup data */
525 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
526
527 switch (uMsg)
528 {
529 case WM_INITDIALOG:
530 {
531 HWND hwndControl;
532 DWORD dwStyle;
533
534 /* Get pointer to the global setup data */
535 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
536 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
537
538 hwndControl = GetParent(hwndDlg);
539
540 /* Center the wizard window */
541 CenterWindow(hwndControl);
542
543 /* Hide the system menu */
544 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
545 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
546
547 PopulateCustomPathCombo(GetDlgItem(hwndDlg, IDC_COMBO_PATH));
548
549 SendDlgItemMessage(
550 hwndDlg,
551 IDC_RADIO_SEARCHHERE,
552 BM_SETCHECK,
553 (WPARAM)TRUE,
554 (LPARAM)0);
555 AutoDriver(hwndDlg, TRUE);
556 IncludePath(hwndDlg, FALSE);
557
558 /* Disable manual driver choice for now */
559 EnableWindow(GetDlgItem(hwndDlg, IDC_RADIO_CHOOSE), FALSE);
560
561 break;
562 }
563
564 case WM_COMMAND:
565 {
566 switch (LOWORD(wParam))
567 {
568 case IDC_RADIO_SEARCHHERE:
569 AutoDriver(hwndDlg, TRUE);
570 return TRUE;
571
572 case IDC_RADIO_CHOOSE:
573 AutoDriver(hwndDlg, FALSE);
574 return TRUE;
575
576 case IDC_CHECK_PATH:
577 IncludePath(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH));
578 return TRUE;
579
580 case IDC_BROWSE:
581 /* FIXME: set the IDC_COMBO_PATH text */
582 FIXME("Should display browse folder dialog\n");
583 return FALSE;
584 }
585 break;
586 }
587
588 case WM_NOTIFY:
589 {
590 LPNMHDR lpnm = (LPNMHDR)lParam;
591
592 switch (lpnm->code)
593 {
594 case PSN_SETACTIVE:
595 /* Enable the Next and Back buttons */
596 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
597 break;
598
599 case PSN_WIZNEXT:
600 /* Handle a Next button click, if necessary */
601 if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_SEARCHHERE))
602 {
603 SaveCustomPath(GetDlgItem(hwndDlg, IDC_COMBO_PATH));
604 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
605 DevInstData->CustomSearchPath = NULL;
606 if (PrepareFoldersToScan(DevInstData, hwndDlg))
607 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV);
608 else
609 /* FIXME: unknown error */;
610 }
611 else
612 /* FIXME */;
613 return TRUE;
614
615 default:
616 break;
617 }
618 break;
619 }
620
621 default:
622 break;
623 }
624
625 return FALSE;
626 }
627
628 static INT_PTR CALLBACK
629 SearchDrvDlgProc(
630 IN HWND hwndDlg,
631 IN UINT uMsg,
632 IN WPARAM wParam,
633 IN LPARAM lParam)
634 {
635 PDEVINSTDATA DevInstData;
636 DWORD dwThreadId;
637
638 /* Retrieve pointer to the global setup data */
639 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
640
641 switch (uMsg)
642 {
643 case WM_INITDIALOG:
644 {
645 HWND hwndControl;
646 DWORD dwStyle;
647
648 /* Get pointer to the global setup data */
649 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
650 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
651
652 DevInstData->hDialog = hwndDlg;
653 hwndControl = GetParent(hwndDlg);
654
655 /* Center the wizard window */
656 CenterWindow(hwndControl);
657
658 SendDlgItemMessage(
659 hwndDlg,
660 IDC_DEVICE,
661 WM_SETTEXT,
662 0,
663 (LPARAM)DevInstData->buffer);
664
665 /* Hide the system menu */
666 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
667 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
668 break;
669 }
670
671 case WM_SEARCH_FINISHED:
672 {
673 CloseHandle(hThread);
674 hThread = 0;
675 if (wParam == 0)
676 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NODRIVER);
677 else
678 {
679 /* FIXME: Shouldn't belong here... */
680 InstallCurrentDriver(DevInstData);
681 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_FINISHPAGE);
682 }
683 break;
684 }
685
686 case WM_NOTIFY:
687 {
688 LPNMHDR lpnm = (LPNMHDR)lParam;
689
690 switch (lpnm->code)
691 {
692 case PSN_SETACTIVE:
693 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
694 hThread = CreateThread(NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId);
695 break;
696
697 case PSN_KILLACTIVE:
698 if (hThread != 0)
699 {
700 SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
701 return TRUE;
702 }
703 break;
704
705 case PSN_WIZNEXT:
706 /* Handle a Next button click, if necessary */
707 break;
708
709 default:
710 break;
711 }
712 break;
713 }
714
715 default:
716 break;
717 }
718
719 return FALSE;
720 }
721
722 static INT_PTR CALLBACK
723 InstallDrvDlgProc(
724 IN HWND hwndDlg,
725 IN UINT uMsg,
726 IN WPARAM wParam,
727 IN LPARAM lParam)
728 {
729 return FALSE;
730 }
731
732 static INT_PTR CALLBACK
733 NoDriverDlgProc(
734 IN HWND hwndDlg,
735 IN UINT uMsg,
736 IN WPARAM wParam,
737 IN LPARAM lParam)
738 {
739 PDEVINSTDATA DevInstData;
740
741 /* Get pointer to the global setup data */
742 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
743
744 switch (uMsg)
745 {
746 case WM_INITDIALOG:
747 {
748 HWND hwndControl;
749 BOOL DisableableDevice = FALSE;
750
751 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
752 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
753
754 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
755 ShowWindow (hwndControl, SW_HIDE);
756 EnableWindow (hwndControl, FALSE);
757
758 /* Set title font */
759 SendDlgItemMessage(
760 hwndDlg,
761 IDC_FINISHTITLE,
762 WM_SETFONT,
763 (WPARAM)DevInstData->hTitleFont,
764 (LPARAM)TRUE);
765
766 /* disable the "do not show this dialog anymore" checkbox
767 if the device cannot be disabled */
768 CanDisableDevice(
769 DevInstData->devInfoData.DevInst,
770 NULL,
771 &DisableableDevice);
772 EnableWindow(
773 GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG),
774 DisableableDevice);
775 break;
776 }
777
778 case WM_NOTIFY:
779 {
780 LPNMHDR lpnm = (LPNMHDR)lParam;
781
782 switch (lpnm->code)
783 {
784 case PSN_SETACTIVE:
785 /* Enable the correct buttons on for the active page */
786 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
787 break;
788
789 case PSN_WIZBACK:
790 /* Handle a Back button click, if necessary */
791 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_CHSOURCE);
792 return TRUE;
793
794 case PSN_WIZFINISH:
795 {
796 BOOL DisableableDevice = FALSE;
797 BOOL IsStarted = FALSE;
798
799 if (CanDisableDevice(DevInstData->devInfoData.DevInst,
800 NULL,
801 &DisableableDevice) &&
802 DisableableDevice &&
803 IsDeviceStarted(
804 DevInstData->devInfoData.DevInst,
805 NULL,
806 &IsStarted) &&
807 !IsStarted &&
808 SendDlgItemMessage(
809 hwndDlg,
810 IDC_DONOTSHOWDLG,
811 BM_GETCHECK,
812 (WPARAM)0, (LPARAM)0) == BST_CHECKED)
813 {
814 /* disable the device */
815 StartDevice(
816 DevInstData->hDevInfo,
817 &DevInstData->devInfoData,
818 FALSE,
819 0,
820 NULL);
821 }
822 break;
823 }
824
825 default:
826 break;
827 }
828 break;
829 }
830
831 default:
832 break;
833 }
834
835 return FALSE;
836 }
837
838 static INT_PTR CALLBACK
839 FinishDlgProc(
840 IN HWND hwndDlg,
841 IN UINT uMsg,
842 IN WPARAM wParam,
843 IN LPARAM lParam)
844 {
845 PDEVINSTDATA DevInstData;
846
847 /* Retrieve pointer to the global setup data */
848 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
849
850 switch (uMsg)
851 {
852 case WM_INITDIALOG:
853 {
854 HWND hwndControl;
855
856 /* Get pointer to the global setup data */
857 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
858 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
859
860 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
861 ShowWindow (hwndControl, SW_HIDE);
862 EnableWindow (hwndControl, FALSE);
863
864 SendDlgItemMessage(
865 hwndDlg,
866 IDC_DEVICE,
867 WM_SETTEXT,
868 0,
869 (LPARAM)DevInstData->drvInfoData.Description);
870
871 /* Set title font */
872 SendDlgItemMessage(
873 hwndDlg,
874 IDC_FINISHTITLE,
875 WM_SETFONT,
876 (WPARAM)DevInstData->hTitleFont,
877 (LPARAM)TRUE);
878 break;
879 }
880
881 case WM_NOTIFY:
882 {
883 LPNMHDR lpnm = (LPNMHDR)lParam;
884
885 switch (lpnm->code)
886 {
887 case PSN_SETACTIVE:
888 /* Enable the correct buttons on for the active page */
889 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
890 break;
891
892 case PSN_WIZBACK:
893 /* Handle a Back button click, if necessary */
894 break;
895
896 case PSN_WIZFINISH:
897 /* Handle a Finish button click, if necessary */
898 break;
899
900 default:
901 break;
902 }
903 break;
904 }
905
906 default:
907 break;
908 }
909
910 return FALSE;
911 }
912
913 static HFONT
914 CreateTitleFont(VOID)
915 {
916 NONCLIENTMETRICS ncm;
917 LOGFONT LogFont;
918 HDC hdc;
919 INT FontSize;
920 HFONT hFont;
921
922 ncm.cbSize = sizeof(NONCLIENTMETRICS);
923 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
924
925 LogFont = ncm.lfMessageFont;
926 LogFont.lfWeight = FW_BOLD;
927 _tcscpy(LogFont.lfFaceName, _T("MS Shell Dlg"));
928
929 hdc = GetDC(NULL);
930 FontSize = 12;
931 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
932 hFont = CreateFontIndirect(&LogFont);
933 ReleaseDC(NULL, hdc);
934
935 return hFont;
936 }
937
938 BOOL
939 DisplayWizard(
940 IN PDEVINSTDATA DevInstData,
941 IN HWND hwndParent,
942 IN UINT startPage)
943 {
944 PROPSHEETHEADER psh;
945 HPROPSHEETPAGE ahpsp[IDD_FINISHPAGE + 1];
946 PROPSHEETPAGE psp;
947
948 /* Create the Welcome page */
949 ZeroMemory(&psp, sizeof(PROPSHEETPAGE));
950 psp.dwSize = sizeof(PROPSHEETPAGE);
951 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
952 psp.hInstance = hDllInstance;
953 psp.lParam = (LPARAM)DevInstData;
954 psp.pfnDlgProc = WelcomeDlgProc;
955 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
956 ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp);
957
958 /* Create the Select Source page */
959 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
960 psp.pfnDlgProc = CHSourceDlgProc;
961 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE);
962 ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp);
963
964 /* Create the Search driver page */
965 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
966 psp.pfnDlgProc = SearchDrvDlgProc;
967 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV);
968 ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp);
969
970 /* Create the Install driver page */
971 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
972 psp.pfnDlgProc = InstallDrvDlgProc;
973 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLDRV);
974 ahpsp[IDD_INSTALLDRV] = CreatePropertySheetPage(&psp);
975
976 /* Create the Install failed page */
977 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
978 psp.pfnDlgProc = NoDriverDlgProc;
979 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER);
980 ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp);
981
982 /* Create the Finish page */
983 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
984 psp.pfnDlgProc = FinishDlgProc;
985 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
986 ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp);
987
988 /* Create the property sheet */
989 psh.dwSize = sizeof(PROPSHEETHEADER);
990 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
991 psh.hInstance = hDllInstance;
992 psh.hwndParent = hwndParent;
993 psh.nPages = 6;
994 psh.nStartPage = startPage;
995 psh.phpage = ahpsp;
996 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
997 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
998
999 /* Create title font */
1000 DevInstData->hTitleFont = CreateTitleFont();
1001
1002 /* Display the wizard */
1003 PropertySheet(&psh);
1004
1005 DeleteObject(DevInstData->hTitleFont);
1006
1007 return TRUE;
1008 }