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