german translation update
[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 #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 SetupDiSetDeviceRegistryProperty(
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;
240 LPTSTR Buffer = NULL;
241 LPCTSTR 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 = RegQueryValueEx(
259 hKey,
260 _T("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(TCHAR));
273 if (!Buffer)
274 {
275 TRACE("HeapAlloc() failed\n");
276 goto cleanup;
277 }
278 rc = RegQueryValueEx(
279 hKey,
280 _T("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 += _tcslen(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 LPTSTR CustomPath = NULL;
311 DWORD CustomPathLength;
312 LPTSTR Buffer = NULL;
313 LPTSTR 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(TCHAR));
324 if (!CustomPath)
325 {
326 TRACE("HeapAlloc() failed\n");
327 goto cleanup;
328 }
329 CustomPathLength = ComboBox_GetText(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(TCHAR));
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 && _tcsicmp(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 _tcscpy(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 = RegSetValueEx(
397 hKey,
398 _T("Installation Sources"),
399 0,
400 REG_MULTI_SZ,
401 (const BYTE*)Buffer,
402 TotalLength * sizeof(TCHAR));
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
425 /* Retrieve pointer to the global setup data */
426 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
427
428 switch (uMsg)
429 {
430 case WM_INITDIALOG:
431 {
432 HWND hwndControl;
433 DWORD dwStyle;
434
435 /* Get pointer to the global setup data */
436 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
437 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
438
439 hwndControl = GetParent(hwndDlg);
440
441 /* Center the wizard window */
442 CenterWindow(hwndControl);
443
444 /* Hide the system menu */
445 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
446 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
447
448 /* Set title font */
449 SendDlgItemMessage(
450 hwndDlg,
451 IDC_WELCOMETITLE,
452 WM_SETFONT,
453 (WPARAM)DevInstData->hTitleFont,
454 (LPARAM)TRUE);
455
456 SendDlgItemMessage(
457 hwndDlg,
458 IDC_DEVICE,
459 WM_SETTEXT,
460 0,
461 (LPARAM)DevInstData->buffer);
462
463 SendDlgItemMessage(
464 hwndDlg,
465 IDC_RADIO_AUTO,
466 BM_SETCHECK,
467 (WPARAM)TRUE,
468 (LPARAM)0);
469 break;
470 }
471
472 case WM_NOTIFY:
473 {
474 LPNMHDR lpnm = (LPNMHDR)lParam;
475
476 switch (lpnm->code)
477 {
478 case PSN_SETACTIVE:
479 /* Enable the Next button */
480 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
481 break;
482
483 case PSN_WIZNEXT:
484 /* Handle a Next button click, if necessary */
485 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED)
486 {
487 if (PrepareFoldersToScan(DevInstData, TRUE, FALSE, NULL))
488 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV);
489 else
490 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED);
491 }
492 return TRUE;
493
494 default:
495 break;
496 }
497 break;
498 }
499
500 default:
501 break;
502 }
503
504 return FALSE;
505 }
506
507 static void
508 IncludePath(HWND Dlg, BOOL Enabled)
509 {
510 EnableWindow(GetDlgItem(Dlg, IDC_COMBO_PATH), Enabled);
511 EnableWindow(GetDlgItem(Dlg, IDC_BROWSE), Enabled);
512 }
513
514 static void
515 AutoDriver(HWND Dlg, BOOL Enabled)
516 {
517 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_MEDIA), Enabled);
518 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_PATH), Enabled);
519 IncludePath(Dlg, Enabled & IsDlgButtonChecked(Dlg, IDC_CHECK_PATH));
520 }
521
522 static INT_PTR CALLBACK
523 CHSourceDlgProc(
524 IN HWND hwndDlg,
525 IN UINT uMsg,
526 IN WPARAM wParam,
527 IN LPARAM lParam)
528 {
529 PDEVINSTDATA DevInstData;
530
531 /* Retrieve pointer to the global setup data */
532 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
533
534 switch (uMsg)
535 {
536 case WM_INITDIALOG:
537 {
538 HWND hwndControl;
539 DWORD dwStyle;
540
541 /* Get pointer to the global setup data */
542 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
543 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
544
545 hwndControl = GetParent(hwndDlg);
546
547 /* Center the wizard window */
548 CenterWindow(hwndControl);
549
550 /* Hide the system menu */
551 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
552 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
553
554 PopulateCustomPathCombo(GetDlgItem(hwndDlg, IDC_COMBO_PATH));
555
556 SendDlgItemMessage(
557 hwndDlg,
558 IDC_RADIO_SEARCHHERE,
559 BM_SETCHECK,
560 (WPARAM)TRUE,
561 (LPARAM)0);
562 AutoDriver(hwndDlg, TRUE);
563 IncludePath(hwndDlg, FALSE);
564
565 /* Disable manual driver choice for now */
566 EnableWindow(GetDlgItem(hwndDlg, IDC_RADIO_CHOOSE), FALSE);
567
568 break;
569 }
570
571 case WM_COMMAND:
572 {
573 switch (LOWORD(wParam))
574 {
575 case IDC_RADIO_SEARCHHERE:
576 AutoDriver(hwndDlg, TRUE);
577 return TRUE;
578
579 case IDC_RADIO_CHOOSE:
580 AutoDriver(hwndDlg, FALSE);
581 return TRUE;
582
583 case IDC_CHECK_PATH:
584 IncludePath(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH));
585 return TRUE;
586
587 case IDC_BROWSE:
588 {
589 BROWSEINFO bi = { 0, };
590 LPITEMIDLIST pidl;
591
592 bi.hwndOwner = hwndDlg;
593 bi.ulFlags = BIF_RETURNONLYFSDIRS;
594 pidl = SHBrowseForFolder(&bi);
595 if (pidl)
596 {
597 TCHAR Directory[MAX_PATH];
598 IMalloc* malloc;
599
600 if (SHGetPathFromIDList(pidl, Directory))
601 {
602 /* Set the IDC_COMBO_PATH text */
603 ComboBox_SetText(GetDlgItem(hwndDlg, IDC_COMBO_PATH), Directory);
604 }
605
606 /* Free memory, if possible */
607 if (SUCCEEDED(SHGetMalloc(&malloc)))
608 {
609 FIXME("Memory leak!\n");
610 //malloc->Free(pidl);
611 //malloc->Release();
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 /* FIXME */;
654 return TRUE;
655
656 default:
657 break;
658 }
659 break;
660 }
661
662 default:
663 break;
664 }
665
666 return FALSE;
667 }
668
669 static INT_PTR CALLBACK
670 SearchDrvDlgProc(
671 IN HWND hwndDlg,
672 IN UINT uMsg,
673 IN WPARAM wParam,
674 IN LPARAM lParam)
675 {
676 PDEVINSTDATA DevInstData;
677 DWORD dwThreadId;
678
679 /* Retrieve pointer to the global setup data */
680 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
681
682 switch (uMsg)
683 {
684 case WM_INITDIALOG:
685 {
686 HWND hwndControl;
687 DWORD dwStyle;
688
689 /* Get pointer to the global setup data */
690 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
691 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
692
693 DevInstData->hDialog = hwndDlg;
694 hwndControl = GetParent(hwndDlg);
695
696 /* Center the wizard window */
697 CenterWindow(hwndControl);
698
699 SendDlgItemMessage(
700 hwndDlg,
701 IDC_DEVICE,
702 WM_SETTEXT,
703 0,
704 (LPARAM)DevInstData->buffer);
705
706 /* Hide the system menu */
707 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
708 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
709 break;
710 }
711
712 case WM_SEARCH_FINISHED:
713 {
714 CloseHandle(hThread);
715 hThread = 0;
716 if (wParam == 0)
717 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NODRIVER);
718 else
719 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLDRV);
720 break;
721 }
722
723 case WM_NOTIFY:
724 {
725 LPNMHDR lpnm = (LPNMHDR)lParam;
726
727 switch (lpnm->code)
728 {
729 case PSN_SETACTIVE:
730 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
731 /* Yes, we can safely ignore the problem (if any) */
732 SetupDiDestroyDriverInfoList(
733 DevInstData->hDevInfo,
734 &DevInstData->devInfoData,
735 SPDIT_COMPATDRIVER);
736 hThread = CreateThread(NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId);
737 break;
738
739 case PSN_KILLACTIVE:
740 if (hThread != 0)
741 {
742 SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
743 return TRUE;
744 }
745 break;
746
747 case PSN_WIZNEXT:
748 /* Handle a Next button click, if necessary */
749 break;
750
751 default:
752 break;
753 }
754 break;
755 }
756
757 default:
758 break;
759 }
760
761 return FALSE;
762 }
763
764 static INT_PTR CALLBACK
765 InstallDrvDlgProc(
766 IN HWND hwndDlg,
767 IN UINT uMsg,
768 IN WPARAM wParam,
769 IN LPARAM lParam)
770 {
771 PDEVINSTDATA DevInstData;
772 DWORD dwThreadId;
773
774 /* Retrieve pointer to the global setup data */
775 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
776
777 switch (uMsg)
778 {
779 case WM_INITDIALOG:
780 {
781 HWND hwndControl;
782 DWORD dwStyle;
783
784 /* Get pointer to the global setup data */
785 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
786 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
787
788 DevInstData->hDialog = hwndDlg;
789 hwndControl = GetParent(hwndDlg);
790
791 /* Center the wizard window */
792 CenterWindow(hwndControl);
793
794 SendDlgItemMessage(
795 hwndDlg,
796 IDC_DEVICE,
797 WM_SETTEXT,
798 0,
799 (LPARAM)DevInstData->drvInfoData.Description);
800
801 /* Hide the system menu */
802 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
803 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
804 break;
805 }
806
807 case WM_INSTALL_FINISHED:
808 {
809 CloseHandle(hThread);
810 hThread = 0;
811 if (wParam == 0)
812 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_FINISHPAGE);
813 else
814 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED);
815 break;
816 }
817
818 case WM_NOTIFY:
819 {
820 LPNMHDR lpnm = (LPNMHDR)lParam;
821
822 switch (lpnm->code)
823 {
824 case PSN_SETACTIVE:
825 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
826 hThread = CreateThread(NULL, 0, InstallDriverProc, DevInstData, 0, &dwThreadId);
827 break;
828
829 case PSN_KILLACTIVE:
830 if (hThread != 0)
831 {
832 SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
833 return TRUE;
834 }
835 break;
836
837 case PSN_WIZNEXT:
838 /* Handle a Next button click, if necessary */
839 break;
840
841 default:
842 break;
843 }
844 break;
845 }
846
847 default:
848 break;
849 }
850
851 return FALSE;
852 }
853
854 static INT_PTR CALLBACK
855 NoDriverDlgProc(
856 IN HWND hwndDlg,
857 IN UINT uMsg,
858 IN WPARAM wParam,
859 IN LPARAM lParam)
860 {
861 PDEVINSTDATA DevInstData;
862 HWND hwndControl;
863
864 /* Get pointer to the global setup data */
865 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
866
867 switch (uMsg)
868 {
869 case WM_INITDIALOG:
870 {
871 BOOL DisableableDevice = FALSE;
872
873 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
874 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
875
876 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
877 ShowWindow(hwndControl, SW_HIDE);
878 EnableWindow(hwndControl, FALSE);
879
880 /* Set title font */
881 SendDlgItemMessage(
882 hwndDlg,
883 IDC_FINISHTITLE,
884 WM_SETFONT,
885 (WPARAM)DevInstData->hTitleFont,
886 (LPARAM)TRUE);
887
888 /* disable the "do not show this dialog anymore" checkbox
889 if the device cannot be disabled */
890 CanDisableDevice(
891 DevInstData->devInfoData.DevInst,
892 NULL,
893 &DisableableDevice);
894 EnableWindow(
895 GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG),
896 DisableableDevice);
897 break;
898 }
899
900 case WM_NOTIFY:
901 {
902 LPNMHDR lpnm = (LPNMHDR)lParam;
903
904 switch (lpnm->code)
905 {
906 case PSN_SETACTIVE:
907 /* Enable the correct buttons on for the active page */
908 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
909 break;
910
911 case PSN_WIZBACK:
912 /* Handle a Back button click, if necessary */
913 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
914 ShowWindow(hwndControl, SW_SHOW);
915 EnableWindow(hwndControl, TRUE);
916 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_CHSOURCE);
917 return TRUE;
918
919 case PSN_WIZFINISH:
920 {
921 BOOL DisableableDevice = FALSE;
922 BOOL IsStarted = FALSE;
923
924 if (CanDisableDevice(DevInstData->devInfoData.DevInst,
925 NULL,
926 &DisableableDevice) &&
927 DisableableDevice &&
928 IsDeviceStarted(
929 DevInstData->devInfoData.DevInst,
930 NULL,
931 &IsStarted) &&
932 !IsStarted &&
933 SendDlgItemMessage(
934 hwndDlg,
935 IDC_DONOTSHOWDLG,
936 BM_GETCHECK,
937 (WPARAM)0, (LPARAM)0) == BST_CHECKED)
938 {
939 /* disable the device */
940 StartDevice(
941 DevInstData->hDevInfo,
942 &DevInstData->devInfoData,
943 FALSE,
944 0,
945 NULL);
946 }
947 break;
948 }
949
950 default:
951 break;
952 }
953 break;
954 }
955
956 default:
957 break;
958 }
959
960 return FALSE;
961 }
962
963 static INT_PTR CALLBACK
964 InstallFailedDlgProc(
965 IN HWND hwndDlg,
966 IN UINT uMsg,
967 IN WPARAM wParam,
968 IN LPARAM lParam)
969 {
970 PDEVINSTDATA DevInstData;
971
972 /* Retrieve pointer to the global setup data */
973 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
974
975 switch (uMsg)
976 {
977 case WM_INITDIALOG:
978 {
979 HWND hwndControl;
980
981 /* Get pointer to the global setup data */
982 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
983 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
984
985 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
986 ShowWindow(hwndControl, SW_HIDE);
987 EnableWindow(hwndControl, FALSE);
988
989 SendDlgItemMessage(
990 hwndDlg,
991 IDC_DEVICE,
992 WM_SETTEXT,
993 0,
994 (LPARAM)DevInstData->drvInfoData.Description);
995
996 /* Set title font */
997 SendDlgItemMessage(
998 hwndDlg,
999 IDC_FINISHTITLE,
1000 WM_SETFONT,
1001 (WPARAM)DevInstData->hTitleFont,
1002 (LPARAM)TRUE);
1003 break;
1004 }
1005
1006 case WM_NOTIFY:
1007 {
1008 LPNMHDR lpnm = (LPNMHDR)lParam;
1009
1010 switch (lpnm->code)
1011 {
1012 case PSN_SETACTIVE:
1013 /* Enable the correct buttons on for the active page */
1014 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
1015 break;
1016
1017 case PSN_WIZBACK:
1018 /* Handle a Back button click, if necessary */
1019 break;
1020
1021 case PSN_WIZFINISH:
1022 /* Handle a Finish button click, if necessary */
1023 break;
1024
1025 default:
1026 break;
1027 }
1028 break;
1029 }
1030
1031 default:
1032 break;
1033 }
1034
1035 return FALSE;
1036 }
1037
1038 static INT_PTR CALLBACK
1039 FinishDlgProc(
1040 IN HWND hwndDlg,
1041 IN UINT uMsg,
1042 IN WPARAM wParam,
1043 IN LPARAM lParam)
1044 {
1045 PDEVINSTDATA DevInstData;
1046
1047 /* Retrieve pointer to the global setup data */
1048 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWL_USERDATA);
1049
1050 switch (uMsg)
1051 {
1052 case WM_INITDIALOG:
1053 {
1054 HWND hwndControl;
1055
1056 /* Get pointer to the global setup data */
1057 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1058 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
1059
1060 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
1061 ShowWindow(hwndControl, SW_HIDE);
1062 EnableWindow(hwndControl, FALSE);
1063
1064 SendDlgItemMessage(
1065 hwndDlg,
1066 IDC_DEVICE,
1067 WM_SETTEXT,
1068 0,
1069 (LPARAM)DevInstData->drvInfoData.Description);
1070
1071 /* Set title font */
1072 SendDlgItemMessage(
1073 hwndDlg,
1074 IDC_FINISHTITLE,
1075 WM_SETFONT,
1076 (WPARAM)DevInstData->hTitleFont,
1077 (LPARAM)TRUE);
1078 break;
1079 }
1080
1081 case WM_NOTIFY:
1082 {
1083 LPNMHDR lpnm = (LPNMHDR)lParam;
1084
1085 switch (lpnm->code)
1086 {
1087 case PSN_SETACTIVE:
1088 /* Enable the correct buttons on for the active page */
1089 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
1090 break;
1091
1092 case PSN_WIZBACK:
1093 /* Handle a Back button click, if necessary */
1094 break;
1095
1096 case PSN_WIZFINISH:
1097 /* Handle a Finish button click, if necessary */
1098 break;
1099
1100 default:
1101 break;
1102 }
1103 break;
1104 }
1105
1106 default:
1107 break;
1108 }
1109
1110 return FALSE;
1111 }
1112
1113 static HFONT
1114 CreateTitleFont(VOID)
1115 {
1116 NONCLIENTMETRICS ncm;
1117 LOGFONT LogFont;
1118 HDC hdc;
1119 INT FontSize;
1120 HFONT hFont;
1121
1122 ncm.cbSize = sizeof(NONCLIENTMETRICS);
1123 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
1124
1125 LogFont = ncm.lfMessageFont;
1126 LogFont.lfWeight = FW_BOLD;
1127 _tcscpy(LogFont.lfFaceName, _T("MS Shell Dlg"));
1128
1129 hdc = GetDC(NULL);
1130 FontSize = 12;
1131 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
1132 hFont = CreateFontIndirect(&LogFont);
1133 ReleaseDC(NULL, hdc);
1134
1135 return hFont;
1136 }
1137
1138 BOOL
1139 DisplayWizard(
1140 IN PDEVINSTDATA DevInstData,
1141 IN HWND hwndParent,
1142 IN UINT startPage)
1143 {
1144 PROPSHEETHEADER psh;
1145 HPROPSHEETPAGE ahpsp[IDD_FINISHPAGE + 1];
1146 PROPSHEETPAGE psp;
1147
1148 /* Create the Welcome page */
1149 ZeroMemory(&psp, sizeof(PROPSHEETPAGE));
1150 psp.dwSize = sizeof(PROPSHEETPAGE);
1151 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1152 psp.hInstance = hDllInstance;
1153 psp.lParam = (LPARAM)DevInstData;
1154 psp.pfnDlgProc = WelcomeDlgProc;
1155 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
1156 ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp);
1157
1158 /* Create the Select Source page */
1159 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1160 psp.pfnDlgProc = CHSourceDlgProc;
1161 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE);
1162 ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp);
1163
1164 /* Create the Search driver page */
1165 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1166 psp.pfnDlgProc = SearchDrvDlgProc;
1167 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV);
1168 ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp);
1169
1170 /* Create the Install driver page */
1171 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1172 psp.pfnDlgProc = InstallDrvDlgProc;
1173 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLDRV);
1174 ahpsp[IDD_INSTALLDRV] = CreatePropertySheetPage(&psp);
1175
1176 /* Create the No driver page */
1177 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1178 psp.pfnDlgProc = NoDriverDlgProc;
1179 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER);
1180 ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp);
1181
1182 /* Create the Install failed page */
1183 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1184 psp.pfnDlgProc = InstallFailedDlgProc;
1185 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFAILED);
1186 ahpsp[IDD_INSTALLFAILED] = CreatePropertySheetPage(&psp);
1187
1188 /* Create the Finish page */
1189 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1190 psp.pfnDlgProc = FinishDlgProc;
1191 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
1192 ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp);
1193
1194 /* Create the property sheet */
1195 psh.dwSize = sizeof(PROPSHEETHEADER);
1196 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
1197 psh.hInstance = hDllInstance;
1198 psh.hwndParent = hwndParent;
1199 psh.nPages = IDD_FINISHPAGE + 1;
1200 psh.nStartPage = startPage;
1201 psh.phpage = ahpsp;
1202 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
1203 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
1204
1205 /* Create title font */
1206 DevInstData->hTitleFont = CreateTitleFont();
1207
1208 /* Display the wizard */
1209 PropertySheet(&psh);
1210
1211 DeleteObject(DevInstData->hTitleFont);
1212
1213 return TRUE;
1214 }