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