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