[CRT] Remove useless #undef abort from process.h
[reactos.git] / dll / win32 / syssetup / wizard.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: System setup
4 * FILE: dll/win32/syssetup/wizard.c
5 * PURPOSE: GUI controls
6 * PROGRAMMERS: Eric Kohl
7 * Pierre Schweitzer <heis_spiter@hotmail.com>
8 * Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
9 * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10 * Oleg Dubinskiy <oleg.dubinskij30@gmail.com>
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include "precomp.h"
16
17 #include <stdlib.h>
18 #include <time.h>
19 #include <winnls.h>
20 #include <windowsx.h>
21 #include <wincon.h>
22 #include <shlobj.h>
23 #include <shlwapi.h>
24 #include <tzlib.h>
25 #include <strsafe.h>
26
27 #define NDEBUG
28 #include <debug.h>
29
30 #define PM_REGISTRATION_NOTIFY (WM_APP + 1)
31 /* Private Message used to communicate progress from the background
32 registration thread to the main thread.
33 wParam = 0 Registration in progress
34 = 1 Registration completed
35 lParam = Pointer to a REGISTRATIONNOTIFY structure */
36
37 #define PM_ITEM_START (WM_APP + 2)
38 #define PM_ITEM_END (WM_APP + 3)
39 #define PM_STEP_START (WM_APP + 4)
40 #define PM_STEP_END (WM_APP + 5)
41 #define PM_ITEMS_DONE (WM_APP + 6)
42
43 typedef struct _REGISTRATIONNOTIFY
44 {
45 ULONG Progress;
46 UINT ActivityID;
47 LPCWSTR CurrentItem;
48 LPCWSTR ErrorMessage;
49 UINT MessageID;
50 DWORD LastError;
51 } REGISTRATIONNOTIFY, *PREGISTRATIONNOTIFY;
52
53 typedef struct _ITEMSDATA
54 {
55 HWND hwndDlg;
56 } ITEMSDATA, *PITEMSDATA;
57
58 typedef struct _REGISTRATIONDATA
59 {
60 HWND hwndDlg;
61 ULONG DllCount;
62 ULONG Registered;
63 PVOID DefaultContext;
64 } REGISTRATIONDATA, *PREGISTRATIONDATA;
65
66 typedef struct _TIMEZONE_ENTRY
67 {
68 struct _TIMEZONE_ENTRY *Prev;
69 struct _TIMEZONE_ENTRY *Next;
70 WCHAR Description[128]; /* 'Display' */
71 WCHAR StandardName[32]; /* 'Std' */
72 WCHAR DaylightName[32]; /* 'Dlt' */
73 REG_TZI_FORMAT TimezoneInfo; /* 'TZI' */
74 ULONG Index;
75 } TIMEZONE_ENTRY, *PTIMEZONE_ENTRY;
76
77
78 /* FUNCTIONS ****************************************************************/
79
80 extern void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
81
82
83 static VOID
84 CenterWindow(HWND hWnd)
85 {
86 HWND hWndParent;
87 RECT rcParent;
88 RECT rcWindow;
89
90 hWndParent = GetParent(hWnd);
91 if (hWndParent == NULL)
92 hWndParent = GetDesktopWindow();
93
94 GetWindowRect(hWndParent, &rcParent);
95 GetWindowRect(hWnd, &rcWindow);
96
97 SetWindowPos(hWnd,
98 HWND_TOP,
99 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
100 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
101 0,
102 0,
103 SWP_NOSIZE);
104 }
105
106
107 static HFONT
108 CreateTitleFont(VOID)
109 {
110 LOGFONTW LogFont = {0};
111 HDC hdc;
112 HFONT hFont;
113
114 LogFont.lfWeight = FW_BOLD;
115 wcscpy(LogFont.lfFaceName, L"MS Shell Dlg");
116
117 hdc = GetDC(NULL);
118 LogFont.lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72);
119
120 hFont = CreateFontIndirectW(&LogFont);
121
122 ReleaseDC(NULL, hdc);
123
124 return hFont;
125 }
126
127
128 static HFONT
129 CreateBoldFont(VOID)
130 {
131 LOGFONTW tmpFont = {0};
132 HFONT hBoldFont;
133 HDC hDc;
134
135 /* Grabs the Drawing Context */
136 hDc = GetDC(NULL);
137
138 tmpFont.lfHeight = -MulDiv(8, GetDeviceCaps(hDc, LOGPIXELSY), 72);
139 tmpFont.lfWeight = FW_BOLD;
140 wcscpy(tmpFont.lfFaceName, L"MS Shell Dlg");
141
142 hBoldFont = CreateFontIndirectW(&tmpFont);
143
144 ReleaseDC(NULL, hDc);
145
146 return hBoldFont;
147 }
148
149 static INT_PTR CALLBACK
150 GplDlgProc(HWND hwndDlg,
151 UINT uMsg,
152 WPARAM wParam,
153 LPARAM lParam)
154 {
155 HRSRC GplTextResource;
156 HGLOBAL GplTextMem;
157 PVOID GplTextLocked;
158 PCHAR GplText;
159 DWORD Size;
160
161
162 switch (uMsg)
163 {
164 case WM_INITDIALOG:
165 GplTextResource = FindResourceW(hDllInstance, MAKEINTRESOURCE(IDR_GPL), L"RT_TEXT");
166 if (NULL == GplTextResource)
167 {
168 break;
169 }
170 Size = SizeofResource(hDllInstance, GplTextResource);
171 if (0 == Size)
172 {
173 break;
174 }
175 GplText = HeapAlloc(GetProcessHeap(), 0, Size + 1);
176 if (NULL == GplText)
177 {
178 break;
179 }
180 GplTextMem = LoadResource(hDllInstance, GplTextResource);
181 if (NULL == GplTextMem)
182 {
183 HeapFree(GetProcessHeap(), 0, GplText);
184 break;
185 }
186 GplTextLocked = LockResource(GplTextMem);
187 if (NULL == GplTextLocked)
188 {
189 HeapFree(GetProcessHeap(), 0, GplText);
190 break;
191 }
192 memcpy(GplText, GplTextLocked, Size);
193 GplText[Size] = '\0';
194 SendMessageA(GetDlgItem(hwndDlg, IDC_GPL_TEXT), WM_SETTEXT, 0, (LPARAM) GplText);
195 HeapFree(GetProcessHeap(), 0, GplText);
196 SetFocus(GetDlgItem(hwndDlg, IDOK));
197 return FALSE;
198
199 case WM_CLOSE:
200 EndDialog(hwndDlg, IDCANCEL);
201 break;
202
203 case WM_COMMAND:
204 if (HIWORD(wParam) == BN_CLICKED && IDOK == LOWORD(wParam))
205 {
206 EndDialog(hwndDlg, IDOK);
207 }
208 break;
209
210 default:
211 break;
212 }
213
214 return FALSE;
215 }
216
217
218 static INT_PTR CALLBACK
219 WelcomeDlgProc(HWND hwndDlg,
220 UINT uMsg,
221 WPARAM wParam,
222 LPARAM lParam)
223 {
224 PSETUPDATA pSetupData;
225
226 pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
227
228 switch (uMsg)
229 {
230 case WM_INITDIALOG:
231 {
232 HWND hwndControl;
233 DWORD dwStyle;
234
235 /* Get pointer to the global setup data */
236 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
237 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
238
239 hwndControl = GetParent(hwndDlg);
240
241 /* Center the wizard window */
242 CenterWindow (hwndControl);
243
244 /* Hide the system menu */
245 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE);
246 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
247
248 /* Hide and disable the 'Cancel' button */
249 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
250 ShowWindow (hwndControl, SW_HIDE);
251 EnableWindow (hwndControl, FALSE);
252
253 /* Set title font */
254 SendDlgItemMessage(hwndDlg,
255 IDC_WELCOMETITLE,
256 WM_SETFONT,
257 (WPARAM)pSetupData->hTitleFont,
258 (LPARAM)TRUE);
259 }
260 break;
261
262
263 case WM_NOTIFY:
264 {
265 LPNMHDR lpnm = (LPNMHDR)lParam;
266
267 switch (lpnm->code)
268 {
269 case PSN_SETACTIVE:
270 LogItem(L"BEGIN", L"WelcomePage");
271 /* Enable the Next button */
272 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
273 if (pSetupData->UnattendSetup)
274 {
275 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_ACKPAGE);
276 return TRUE;
277 }
278 break;
279
280 case PSN_WIZNEXT:
281 LogItem(L"END", L"WelcomePage");
282 break;
283
284 case PSN_WIZBACK:
285 pSetupData->UnattendSetup = FALSE;
286 break;
287
288 default:
289 break;
290 }
291 }
292 break;
293
294 default:
295 break;
296 }
297
298 return FALSE;
299 }
300
301
302 static INT_PTR CALLBACK
303 AckPageDlgProc(HWND hwndDlg,
304 UINT uMsg,
305 WPARAM wParam,
306 LPARAM lParam)
307 {
308 LPNMHDR lpnm;
309 PWCHAR Projects;
310 PWCHAR End, CurrentProject;
311 INT ProjectsSize, ProjectsCount;
312 PSETUPDATA pSetupData;
313
314 pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
315
316 switch (uMsg)
317 {
318 case WM_INITDIALOG:
319 {
320 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
321 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
322
323 Projects = NULL;
324 ProjectsSize = 256;
325 while (TRUE)
326 {
327 Projects = HeapAlloc(GetProcessHeap(), 0, ProjectsSize * sizeof(WCHAR));
328 if (NULL == Projects)
329 {
330 return FALSE;
331 }
332 ProjectsCount = LoadStringW(hDllInstance, IDS_ACKPROJECTS, Projects, ProjectsSize);
333 if (0 == ProjectsCount)
334 {
335 HeapFree(GetProcessHeap(), 0, Projects);
336 return FALSE;
337 }
338 if (ProjectsCount < ProjectsSize - 1)
339 {
340 break;
341 }
342 HeapFree(GetProcessHeap(), 0, Projects);
343 ProjectsSize *= 2;
344 }
345
346 CurrentProject = Projects;
347 while (*CurrentProject != L'\0')
348 {
349 End = wcschr(CurrentProject, L'\n');
350 if (NULL != End)
351 {
352 *End = L'\0';
353 }
354 (void)ListBox_AddString(GetDlgItem(hwndDlg, IDC_PROJECTS), CurrentProject);
355 if (NULL != End)
356 {
357 CurrentProject = End + 1;
358 }
359 else
360 {
361 CurrentProject += wcslen(CurrentProject);
362 }
363 }
364 HeapFree(GetProcessHeap(), 0, Projects);
365 }
366 break;
367
368 case WM_COMMAND:
369 if (HIWORD(wParam) == BN_CLICKED && IDC_VIEWGPL == LOWORD(wParam))
370 {
371 DialogBox(hDllInstance, MAKEINTRESOURCE(IDD_GPL), NULL, GplDlgProc);
372 SetForegroundWindow(GetParent(hwndDlg));
373 }
374 break;
375
376 case WM_NOTIFY:
377 {
378 lpnm = (LPNMHDR)lParam;
379
380 switch (lpnm->code)
381 {
382 case PSN_SETACTIVE:
383 /* Enable the Back and Next buttons */
384 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
385 if (pSetupData->UnattendSetup)
386 {
387 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_PRODUCT);
388 return TRUE;
389 }
390 break;
391
392 case PSN_WIZBACK:
393 pSetupData->UnattendSetup = FALSE;
394 break;
395
396 default:
397 break;
398 }
399 }
400 break;
401
402 default:
403 break;
404 }
405
406 return FALSE;
407 }
408
409 static const WCHAR s_szProductOptions[] = L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
410 static const WCHAR s_szRosVersion[] = L"SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version";
411 static const WCHAR s_szControlWindows[] = L"SYSTEM\\CurrentControlSet\\Control\\Windows";
412 static const WCHAR s_szWinlogon[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon";
413 static const WCHAR s_szDefaultSoundEvents[] = L"AppEvents\\Schemes\\Apps\\.Default";
414 static const WCHAR s_szExplorerSoundEvents[] = L"AppEvents\\Schemes\\Apps\\Explorer";
415
416 typedef struct _PRODUCT_OPTION_DATA
417 {
418 LPCWSTR ProductSuite;
419 LPCWSTR ProductType;
420 DWORD ReportAsWorkstation;
421 DWORD CSDVersion;
422 DWORD LogonType;
423 } PRODUCT_OPTION_DATA;
424
425 static const PRODUCT_OPTION_DATA s_ProductOptionData[] =
426 {
427 { L"Terminal Server\0", L"ServerNT", 0, 0x200, 0 },
428 { L"\0", L"WinNT", 1, 0x300, 1 }
429 };
430
431 static const WCHAR* s_DefaultSoundEvents[][2] =
432 {
433 { L".Default", L"%SystemRoot%\\Media\\ReactOS_Default.wav" },
434 { L"AppGPFault", L"" },
435 { L"Close", L"" },
436 { L"CriticalBatteryAlarm", L"%SystemRoot%\\Media\\ReactOS_Battery_Critical.wav" },
437 { L"DeviceConnect", L"%SystemRoot%\\Media\\ReactOS_Hardware_Insert.wav" },
438 { L"DeviceDisconnect", L"%SystemRoot%\\Media\\ReactOS_Hardware_Remove.wav" },
439 { L"DeviceFail", L"%SystemRoot%\\Media\\ReactOS_Hardware_Fail.wav" },
440 { L"LowBatteryAlarm", L"%SystemRoot%\\Media\\ReactOS_Battery_Low.wav" },
441 { L"MailBeep", L"%SystemRoot%\\Media\\ReactOS_Notify.wav" },
442 { L"Maximize", L"%SystemRoot%\\Media\\ReactOS_Restore.wav" },
443 { L"MenuCommand", L"%SystemRoot%\\Media\\ReactOS_Menu_Command.wav" },
444 { L"MenuPopup", L"" },
445 { L"Minimize", L"%SystemRoot%\\Media\\ReactOS_Minimize.wav" },
446 { L"Open", L"" },
447 { L"PrintComplete", L"%SystemRoot%\\Media\\ReactOS_Print_Complete.wav" },
448 { L"RestoreDown", L"" },
449 { L"RestoreUp", L"" },
450 { L"SystemAsterisk", L"%SystemRoot%\\Media\\ReactOS_Ding.wav" },
451 { L"SystemExclamation", L"%SystemRoot%\\Media\\ReactOS_Exclamation.wav" },
452 { L"SystemExit", L"%SystemRoot%\\Media\\ReactOS_Shutdown.wav" },
453 { L"SystemHand", L"%SystemRoot%\\Media\\ReactOS_Critical_Stop.wav" },
454 { L"SystemNotification", L"%SystemRoot%\\Media\\ReactOS_Balloon.wav" },
455 { L"SystemQuestion", L"%SystemRoot%\\Media\\ReactOS_Ding.wav" },
456 { L"SystemStart", L"%SystemRoot%\\Media\\ReactOS_Startup.wav" },
457 { L"WindowsLogoff", L"%SystemRoot%\\Media\\ReactOS_LogOff.wav" }
458 /* Logon sound is already set by default for both Server and Workstation */
459 };
460
461 static const WCHAR* s_ExplorerSoundEvents[][2] =
462 {
463 { L"EmptyRecycleBin", L"%SystemRoot%\\Media\\ReactOS_Recycle.wav" },
464 { L"Navigating", L"%SystemRoot%\\Media\\ReactOS_Start.wav" }
465 };
466
467 static BOOL
468 DoWriteSoundEvents(HKEY hKey,
469 LPCWSTR lpSubkey,
470 LPCWSTR lpEventsArray[][2],
471 DWORD dwSize)
472 {
473 HKEY hRootKey, hEventKey, hDefaultKey;
474 LONG error;
475 ULONG i;
476 WCHAR szDest[MAX_PATH];
477 DWORD dwAttribs;
478 DWORD cbData;
479
480 /* Open the sound events key */
481 error = RegOpenKeyExW(hKey, lpSubkey, 0, KEY_READ, &hRootKey);
482 if (error)
483 {
484 DPRINT1("RegOpenKeyExW failed\n");
485 goto Error;
486 }
487
488 /* Set each sound event */
489 for (i = 0; i < dwSize; i++)
490 {
491 /*
492 * Verify that the sound file exists and is an actual file.
493 */
494
495 /* Expand the sound file path */
496 if (!ExpandEnvironmentStringsW(lpEventsArray[i][1], szDest, _countof(szDest)))
497 {
498 /* Failed to expand, continue with the next sound event */
499 continue;
500 }
501
502 /* Check if the sound file exists and isn't a directory */
503 dwAttribs = GetFileAttributesW(szDest);
504 if ((dwAttribs == INVALID_FILE_ATTRIBUTES) ||
505 (dwAttribs & FILE_ATTRIBUTE_DIRECTORY))
506 {
507 /* It does not, just continue with the next sound event */
508 continue;
509 }
510
511 /*
512 * Create the sound event entry.
513 */
514
515 /* Open the sound event subkey */
516 error = RegOpenKeyExW(hRootKey, lpEventsArray[i][0], 0, KEY_READ, &hEventKey);
517 if (error)
518 {
519 /* Failed to open, continue with next sound event */
520 continue;
521 }
522
523 /* Open .Default subkey */
524 error = RegOpenKeyExW(hEventKey, L".Default", 0, KEY_WRITE, &hDefaultKey);
525 RegCloseKey(hEventKey);
526 if (error)
527 {
528 /* Failed to open, continue with next sound event */
529 continue;
530 }
531
532 /* Associate the sound file to this sound event */
533 cbData = (lstrlenW(lpEventsArray[i][1]) + 1) * sizeof(WCHAR);
534 error = RegSetValueExW(hDefaultKey, NULL, 0, REG_EXPAND_SZ, (const BYTE *)lpEventsArray[i][1], cbData);
535 RegCloseKey(hDefaultKey);
536 if (error)
537 {
538 /* Failed to set the value, continue with next sound event */
539 continue;
540 }
541 }
542
543 Error:
544 if (hRootKey)
545 RegCloseKey(hRootKey);
546
547 return error == ERROR_SUCCESS;
548 }
549
550 static BOOL
551 DoWriteProductOption(PRODUCT_OPTION nOption)
552 {
553 HKEY hKey;
554 LONG error;
555 LPCWSTR pszData;
556 DWORD dwValue, cbData;
557 const PRODUCT_OPTION_DATA *pData = &s_ProductOptionData[nOption];
558 ASSERT(0 <= nOption && nOption < _countof(s_ProductOptionData));
559
560 /* open ProductOptions key */
561 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szProductOptions, 0, KEY_WRITE, &hKey);
562 if (error)
563 {
564 DPRINT1("RegOpenKeyExW failed\n");
565 goto Error;
566 }
567
568 /* write ProductSuite */
569 pszData = pData->ProductSuite;
570 cbData = (lstrlenW(pszData) + 2) * sizeof(WCHAR);
571 error = RegSetValueExW(hKey, L"ProductSuite", 0, REG_MULTI_SZ, (const BYTE *)pszData, cbData);
572 if (error)
573 {
574 DPRINT1("RegSetValueExW failed\n");
575 goto Error;
576 }
577
578 /* write ProductType */
579 pszData = pData->ProductType;
580 cbData = (lstrlenW(pszData) + 1) * sizeof(WCHAR);
581 error = RegSetValueExW(hKey, L"ProductType", 0, REG_SZ, (const BYTE *)pszData, cbData);
582 if (error)
583 {
584 DPRINT1("RegSetValueExW failed\n");
585 goto Error;
586 }
587
588 RegCloseKey(hKey);
589
590 /* open ReactOS version key */
591 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szRosVersion, 0, KEY_WRITE, &hKey);
592 if (error)
593 {
594 DPRINT1("RegOpenKeyExW failed\n");
595 goto Error;
596 }
597
598 /* write ReportAsWorkstation */
599 dwValue = pData->ReportAsWorkstation;
600 cbData = sizeof(dwValue);
601 error = RegSetValueExW(hKey, L"ReportAsWorkstation", 0, REG_DWORD, (const BYTE *)&dwValue, cbData);
602 if (error)
603 {
604 DPRINT1("RegSetValueExW failed\n");
605 goto Error;
606 }
607
608 RegCloseKey(hKey);
609
610 /* open Control Windows key */
611 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szControlWindows, 0, KEY_WRITE, &hKey);
612 if (error)
613 {
614 DPRINT1("RegOpenKeyExW failed\n");
615 goto Error;
616 }
617
618 /* write Control Windows CSDVersion */
619 dwValue = pData->CSDVersion;
620 cbData = sizeof(dwValue);
621 error = RegSetValueExW(hKey, L"CSDVersion", 0, REG_DWORD, (const BYTE *)&dwValue, cbData);
622 if (error)
623 {
624 DPRINT1("RegSetValueExW failed\n");
625 goto Error;
626 }
627
628 RegCloseKey(hKey);
629
630 /* open Winlogon key */
631 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szWinlogon, 0, KEY_WRITE, &hKey);
632 if (error)
633 {
634 DPRINT1("RegOpenKeyExW failed\n");
635 goto Error;
636 }
637
638 /* write LogonType */
639 dwValue = pData->LogonType;
640 cbData = sizeof(dwValue);
641 error = RegSetValueExW(hKey, L"LogonType", 0, REG_DWORD, (const BYTE *)&dwValue, cbData);
642 if (error)
643 {
644 DPRINT1("RegSetValueExW failed\n");
645 goto Error;
646 }
647
648 if (nOption == PRODUCT_OPTION_WORKSTATION)
649 {
650 /* Write system sound events values for Workstation */
651 DoWriteSoundEvents(HKEY_CURRENT_USER, s_szDefaultSoundEvents, s_DefaultSoundEvents, _countof(s_DefaultSoundEvents));
652 DoWriteSoundEvents(HKEY_CURRENT_USER, s_szExplorerSoundEvents, s_ExplorerSoundEvents, _countof(s_ExplorerSoundEvents));
653 }
654
655 Error:
656 if (hKey)
657 RegCloseKey(hKey);
658
659 return error == ERROR_SUCCESS;
660 }
661
662 static void
663 OnChooseOption(HWND hwndDlg, PRODUCT_OPTION nOption)
664 {
665 WCHAR szText[256];
666 ASSERT(0 <= nOption && nOption < _countof(s_ProductOptionData));
667
668 switch (nOption)
669 {
670 case PRODUCT_OPTION_SERVER:
671 LoadStringW(hDllInstance, IDS_PRODUCTSERVERINFO, szText, _countof(szText));
672 break;
673
674 case PRODUCT_OPTION_WORKSTATION:
675 LoadStringW(hDllInstance, IDS_PRODUCTWORKSTATIONINFO, szText, _countof(szText));
676 break;
677
678 default:
679 return;
680 }
681
682 SetDlgItemTextW(hwndDlg, IDC_PRODUCT_DESCRIPTION, szText);
683 }
684
685 static INT_PTR CALLBACK
686 ProductPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
687 {
688 LPNMHDR lpnm;
689 PSETUPDATA pSetupData;
690 INT iItem;
691 WCHAR szText[64], szDefault[64];
692 HICON hIcon;
693
694 pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
695
696 switch (uMsg)
697 {
698 case WM_INITDIALOG:
699 {
700 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
701 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
702
703 LoadStringW(hDllInstance, IDS_DEFAULT, szDefault, _countof(szDefault));
704
705 LoadStringW(hDllInstance, IDS_PRODUCTSERVERNAME, szText, _countof(szText));
706 if (PRODUCT_OPTION_DEFAULT == PRODUCT_OPTION_SERVER)
707 {
708 StringCchCatW(szText, _countof(szText), L" ");
709 StringCchCatW(szText, _countof(szText), szDefault);
710 }
711 SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_OPTIONS, CB_ADDSTRING, 0, (LPARAM)szText);
712
713 LoadStringW(hDllInstance, IDS_PRODUCTWORKSTATIONNAME, szText, _countof(szText));
714 if (PRODUCT_OPTION_DEFAULT == PRODUCT_OPTION_WORKSTATION)
715 {
716 StringCchCatW(szText, _countof(szText), L" ");
717 StringCchCatW(szText, _countof(szText), szDefault);
718 }
719 SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_OPTIONS, CB_ADDSTRING, 0, (LPARAM)szText);
720
721 SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_OPTIONS, CB_SETCURSEL, PRODUCT_OPTION_DEFAULT, 0);
722 OnChooseOption(hwndDlg, PRODUCT_OPTION_DEFAULT);
723
724 hIcon = LoadIcon(NULL, IDI_WINLOGO);
725 SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_ICON, STM_SETICON, (WPARAM)hIcon, 0);
726 return TRUE;
727 }
728
729 case WM_COMMAND:
730 if (HIWORD(wParam) == CBN_SELCHANGE && IDC_PRODUCT_OPTIONS == LOWORD(wParam))
731 {
732 iItem = SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_OPTIONS, CB_GETCURSEL, 0, 0);
733 OnChooseOption(hwndDlg, (PRODUCT_OPTION)iItem);
734 }
735 break;
736
737 case WM_NOTIFY:
738 {
739 lpnm = (LPNMHDR)lParam;
740
741 switch (lpnm->code)
742 {
743 case PSN_SETACTIVE:
744 /* Enable the Back and Next buttons */
745 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
746 if (pSetupData->UnattendSetup)
747 {
748 OnChooseOption(hwndDlg, pSetupData->ProductOption);
749 DoWriteProductOption(pSetupData->ProductOption);
750 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_LOCALEPAGE);
751 return TRUE;
752 }
753 break;
754
755 case PSN_WIZNEXT:
756 iItem = SendDlgItemMessageW(hwndDlg, IDC_PRODUCT_OPTIONS, CB_GETCURSEL, 0, 0);
757 pSetupData->ProductOption = (PRODUCT_OPTION)iItem;
758 DoWriteProductOption(pSetupData->ProductOption);
759 break;
760
761 case PSN_WIZBACK:
762 pSetupData->UnattendSetup = FALSE;
763 break;
764
765 default:
766 break;
767 }
768 }
769 break;
770
771 default:
772 break;
773 }
774
775 return FALSE;
776 }
777
778 static
779 BOOL
780 WriteOwnerSettings(WCHAR * OwnerName,
781 WCHAR * OwnerOrganization)
782 {
783 HKEY hKey;
784 LONG res;
785
786 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
787 L"Software\\Microsoft\\Windows NT\\CurrentVersion",
788 0,
789 KEY_ALL_ACCESS,
790 &hKey);
791
792 if (res != ERROR_SUCCESS)
793 {
794 return FALSE;
795 }
796
797 res = RegSetValueExW(hKey,
798 L"RegisteredOwner",
799 0,
800 REG_SZ,
801 (LPBYTE)OwnerName,
802 (wcslen(OwnerName) + 1) * sizeof(WCHAR));
803
804 if (res != ERROR_SUCCESS)
805 {
806 RegCloseKey(hKey);
807 return FALSE;
808 }
809
810 res = RegSetValueExW(hKey,
811 L"RegisteredOrganization",
812 0,
813 REG_SZ,
814 (LPBYTE)OwnerOrganization,
815 (wcslen(OwnerOrganization) + 1) * sizeof(WCHAR));
816
817 RegCloseKey(hKey);
818 return (res == ERROR_SUCCESS);
819 }
820
821 static INT_PTR CALLBACK
822 OwnerPageDlgProc(HWND hwndDlg,
823 UINT uMsg,
824 WPARAM wParam,
825 LPARAM lParam)
826 {
827 WCHAR OwnerName[51];
828 WCHAR OwnerOrganization[51];
829 WCHAR Title[64];
830 WCHAR ErrorName[256];
831 LPNMHDR lpnm;
832 PSETUPDATA pSetupData;
833
834 pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
835
836 switch (uMsg)
837 {
838 case WM_INITDIALOG:
839 {
840 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
841 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
842
843 /* set a localized ('Owner') placeholder string as default */
844 if (LoadStringW(hDllInstance, IDS_MACHINE_OWNER_NAME, OwnerName, _countof(OwnerName)))
845 {
846 SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, WM_SETTEXT, 0, (LPARAM)OwnerName);
847 }
848
849 SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, EM_LIMITTEXT, 50, 0);
850 SendDlgItemMessage(hwndDlg, IDC_OWNERORGANIZATION, EM_LIMITTEXT, 50, 0);
851
852 /* Set focus to owner name */
853 SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
854
855 /* Select the default text to quickly overwrite it by typing */
856 SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, EM_SETSEL, 0, -1);
857 }
858 break;
859
860
861 case WM_NOTIFY:
862 {
863 lpnm = (LPNMHDR)lParam;
864
865 switch (lpnm->code)
866 {
867 case PSN_SETACTIVE:
868 /* Enable the Back and Next buttons */
869 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
870 if (pSetupData->UnattendSetup)
871 {
872 SendMessage(GetDlgItem(hwndDlg, IDC_OWNERNAME), WM_SETTEXT, 0, (LPARAM)pSetupData->OwnerName);
873 SendMessage(GetDlgItem(hwndDlg, IDC_OWNERORGANIZATION), WM_SETTEXT, 0, (LPARAM)pSetupData->OwnerOrganization);
874 if (WriteOwnerSettings(pSetupData->OwnerName, pSetupData->OwnerOrganization))
875 {
876 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_COMPUTERPAGE);
877 return TRUE;
878 }
879 }
880 break;
881
882 case PSN_WIZNEXT:
883 OwnerName[0] = 0;
884 if (GetDlgItemTextW(hwndDlg, IDC_OWNERNAME, OwnerName, 50) == 0)
885 {
886 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
887 {
888 wcscpy(Title, L"ReactOS Setup");
889 }
890 if (0 == LoadStringW(hDllInstance, IDS_WZD_NAME, ErrorName, ARRAYSIZE(ErrorName)))
891 {
892 wcscpy(ErrorName, L"Setup cannot continue until you enter your name.");
893 }
894 MessageBoxW(hwndDlg, ErrorName, Title, MB_ICONERROR | MB_OK);
895
896 SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
897 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
898
899 return TRUE;
900 }
901
902 OwnerOrganization[0] = 0;
903 GetDlgItemTextW(hwndDlg, IDC_OWNERORGANIZATION, OwnerOrganization, 50);
904
905 if (!WriteOwnerSettings(OwnerName, OwnerOrganization))
906 {
907 SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
908 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
909 return TRUE;
910 }
911
912 case PSN_WIZBACK:
913 pSetupData->UnattendSetup = FALSE;
914 break;
915
916 default:
917 break;
918 }
919 }
920 break;
921
922 default:
923 break;
924 }
925
926 return FALSE;
927 }
928
929 static
930 BOOL
931 WriteComputerSettings(WCHAR * ComputerName, HWND hwndDlg)
932 {
933 WCHAR Title[64];
934 WCHAR ErrorComputerName[256];
935 LONG lError;
936 HKEY hKey = NULL;
937
938 if (!SetComputerNameW(ComputerName))
939 {
940 if (hwndDlg != NULL)
941 {
942 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
943 {
944 wcscpy(Title, L"ReactOS Setup");
945 }
946 if (0 == LoadStringW(hDllInstance, IDS_WZD_SETCOMPUTERNAME, ErrorComputerName,
947 ARRAYSIZE(ErrorComputerName)))
948 {
949 wcscpy(ErrorComputerName, L"Setup failed to set the computer name.");
950 }
951 MessageBoxW(hwndDlg, ErrorComputerName, Title, MB_ICONERROR | MB_OK);
952 }
953
954 return FALSE;
955 }
956
957 /* Set the physical DNS domain */
958 SetComputerNameExW(ComputerNamePhysicalDnsDomain, L"");
959
960 /* Set the physical DNS hostname */
961 SetComputerNameExW(ComputerNamePhysicalDnsHostname, ComputerName);
962
963 /* Set the accounts domain name */
964 SetAccountsDomainSid(NULL, ComputerName);
965
966 /* Now we need to set the Hostname */
967 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
968 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
969 0,
970 KEY_SET_VALUE,
971 &hKey);
972 if (lError != ERROR_SUCCESS)
973 {
974 DPRINT1("RegOpenKeyExW for Tcpip\\Parameters failed (%08lX)\n", lError);
975 return TRUE;
976 }
977
978 lError = RegSetValueEx(hKey,
979 L"Hostname",
980 0,
981 REG_SZ,
982 (LPBYTE)ComputerName,
983 (wcslen(ComputerName) + 1) * sizeof(WCHAR));
984 if (lError != ERROR_SUCCESS)
985 {
986 DPRINT1("RegSetValueEx(\"Hostname\") failed (%08lX)\n", lError);
987 }
988
989 RegCloseKey(hKey);
990
991 return TRUE;
992 }
993
994
995 static
996 BOOL
997 WriteDefaultLogonData(LPWSTR Domain)
998 {
999 WCHAR szAdministratorName[256];
1000 HKEY hKey = NULL;
1001 LONG lError;
1002
1003 if (LoadStringW(hDllInstance,
1004 IDS_ADMINISTRATOR_NAME,
1005 szAdministratorName,
1006 ARRAYSIZE(szAdministratorName)) == 0)
1007 {
1008 wcscpy(szAdministratorName, L"Administrator");
1009 }
1010
1011 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1012 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
1013 0,
1014 KEY_SET_VALUE,
1015 &hKey);
1016 if (lError != ERROR_SUCCESS)
1017 return FALSE;
1018
1019 lError = RegSetValueEx(hKey,
1020 L"DefaultDomainName",
1021 0,
1022 REG_SZ,
1023 (LPBYTE)Domain,
1024 (wcslen(Domain)+ 1) * sizeof(WCHAR));
1025 if (lError != ERROR_SUCCESS)
1026 {
1027 DPRINT1("RegSetValueEx(\"DefaultDomainName\") failed!\n");
1028 }
1029
1030 lError = RegSetValueEx(hKey,
1031 L"DefaultUserName",
1032 0,
1033 REG_SZ,
1034 (LPBYTE)szAdministratorName,
1035 (wcslen(szAdministratorName)+ 1) * sizeof(WCHAR));
1036 if (lError != ERROR_SUCCESS)
1037 {
1038 DPRINT1("RegSetValueEx(\"DefaultUserName\") failed!\n");
1039 }
1040
1041 RegCloseKey(hKey);
1042
1043 return TRUE;
1044 }
1045
1046
1047 /* lpBuffer will be filled with a 15-char string (plus the null terminator) */
1048 static void
1049 GenerateComputerName(LPWSTR lpBuffer)
1050 {
1051 static const WCHAR Chars[] = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1052 static const unsigned cChars = sizeof(Chars) / sizeof(WCHAR) - 1;
1053 unsigned i;
1054
1055 wcscpy(lpBuffer, L"REACTOS-");
1056
1057 srand(GetTickCount());
1058
1059 /* fill in 7 characters */
1060 for (i = 8; i < 15; i++)
1061 lpBuffer[i] = Chars[rand() % cChars];
1062
1063 lpBuffer[15] = UNICODE_NULL; /* NULL-terminate */
1064 }
1065
1066 static INT_PTR CALLBACK
1067 ComputerPageDlgProc(HWND hwndDlg,
1068 UINT uMsg,
1069 WPARAM wParam,
1070 LPARAM lParam)
1071 {
1072 WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1073 WCHAR Password1[128];
1074 WCHAR Password2[128];
1075 PWCHAR Password;
1076 WCHAR Title[64];
1077 WCHAR EmptyComputerName[256], NotMatchPassword[256], WrongPassword[256];
1078 LPNMHDR lpnm;
1079 PSETUPDATA pSetupData;
1080
1081 pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1082
1083 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
1084 {
1085 wcscpy(Title, L"ReactOS Setup");
1086 }
1087
1088 switch (uMsg)
1089 {
1090 case WM_INITDIALOG:
1091 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1092 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
1093
1094 /* Generate a new pseudo-random computer name */
1095 GenerateComputerName(ComputerName);
1096
1097 /* Display current computer name */
1098 SetDlgItemTextW(hwndDlg, IDC_COMPUTERNAME, ComputerName);
1099
1100 /* Set text limits */
1101 SendDlgItemMessage(hwndDlg, IDC_COMPUTERNAME, EM_LIMITTEXT, MAX_COMPUTERNAME_LENGTH, 0);
1102 SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD1, EM_LIMITTEXT, 127, 0);
1103 SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD2, EM_LIMITTEXT, 127, 0);
1104
1105 /* Set focus to computer name */
1106 SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
1107 if (pSetupData->UnattendSetup)
1108 {
1109 SendMessage(GetDlgItem(hwndDlg, IDC_COMPUTERNAME), WM_SETTEXT, 0, (LPARAM)pSetupData->ComputerName);
1110 SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD1), WM_SETTEXT, 0, (LPARAM)pSetupData->AdminPassword);
1111 SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD2), WM_SETTEXT, 0, (LPARAM)pSetupData->AdminPassword);
1112 WriteComputerSettings(pSetupData->ComputerName, NULL);
1113 SetAdministratorPassword(pSetupData->AdminPassword);
1114 }
1115
1116 /* Store the administrator account name as the default user name */
1117 WriteDefaultLogonData(pSetupData->ComputerName);
1118 break;
1119
1120
1121 case WM_NOTIFY:
1122 {
1123 lpnm = (LPNMHDR)lParam;
1124
1125 switch (lpnm->code)
1126 {
1127 case PSN_SETACTIVE:
1128 /* Enable the Back and Next buttons */
1129 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
1130 if (pSetupData->UnattendSetup && WriteComputerSettings(pSetupData->ComputerName, hwndDlg))
1131 {
1132 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_THEMEPAGE);
1133 return TRUE;
1134 }
1135 break;
1136
1137 case PSN_WIZNEXT:
1138 if (0 == GetDlgItemTextW(hwndDlg, IDC_COMPUTERNAME, ComputerName, MAX_COMPUTERNAME_LENGTH + 1))
1139 {
1140 if (0 == LoadStringW(hDllInstance, IDS_WZD_COMPUTERNAME, EmptyComputerName,
1141 ARRAYSIZE(EmptyComputerName)))
1142 {
1143 wcscpy(EmptyComputerName, L"Setup cannot continue until you enter the name of your computer.");
1144 }
1145 MessageBoxW(hwndDlg, EmptyComputerName, Title, MB_ICONERROR | MB_OK);
1146 SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
1147 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
1148 return TRUE;
1149 }
1150
1151 /* No need to check computer name for invalid characters,
1152 * SetComputerName() will do it for us */
1153
1154 if (!WriteComputerSettings(ComputerName, hwndDlg))
1155 {
1156 SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
1157 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
1158 return TRUE;
1159 }
1160
1161 #ifdef PASSWORDS_MANDATORY
1162 /* Check if admin passwords have been entered */
1163 if ((GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD1, Password1, 128) == 0) ||
1164 (GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD2, Password2, 128) == 0))
1165 {
1166 if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDEMPTY, EmptyPassword,
1167 ARRAYSIZE(EmptyPassword)))
1168 {
1169 wcscpy(EmptyPassword, L"You must enter a password !");
1170 }
1171 MessageBoxW(hwndDlg, EmptyPassword, Title, MB_ICONERROR | MB_OK);
1172 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
1173 return TRUE;
1174 }
1175 #else
1176 GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD1, Password1, 128);
1177 GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD2, Password2, 128);
1178 #endif
1179 /* Check if passwords match */
1180 if (wcscmp(Password1, Password2))
1181 {
1182 if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDMATCH, NotMatchPassword,
1183 ARRAYSIZE(NotMatchPassword)))
1184 {
1185 wcscpy(NotMatchPassword, L"The passwords you entered do not match. Please enter the desired password again.");
1186 }
1187 MessageBoxW(hwndDlg, NotMatchPassword, Title, MB_ICONERROR | MB_OK);
1188 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
1189 return TRUE;
1190 }
1191
1192 /* Check password for invalid characters */
1193 Password = (PWCHAR)Password1;
1194 while (*Password)
1195 {
1196 if (!isprint(*Password))
1197 {
1198 if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDCHAR, WrongPassword,
1199 ARRAYSIZE(WrongPassword)))
1200 {
1201 wcscpy(WrongPassword, L"The password you entered contains invalid characters. Please enter a cleaned password.");
1202 }
1203 MessageBoxW(hwndDlg, WrongPassword, Title, MB_ICONERROR | MB_OK);
1204 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
1205 return TRUE;
1206 }
1207 Password++;
1208 }
1209
1210 /* Set admin password */
1211 SetAdministratorPassword(Password1);
1212 break;
1213
1214 case PSN_WIZBACK:
1215 pSetupData->UnattendSetup = FALSE;
1216 break;
1217
1218 default:
1219 break;
1220 }
1221 }
1222 break;
1223
1224 default:
1225 break;
1226 }
1227
1228 return FALSE;
1229 }
1230
1231
1232 static VOID
1233 SetUserLocaleName(HWND hwnd)
1234 {
1235 WCHAR CurLocale[256] = L"";
1236 WCHAR CurGeo[256] = L"";
1237 WCHAR ResText[256] = L"";
1238 WCHAR LocaleText[256 * 2];
1239
1240 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SLANGUAGE, CurLocale, ARRAYSIZE(CurLocale));
1241 GetGeoInfoW(GetUserGeoID(GEOCLASS_NATION), GEO_FRIENDLYNAME, CurGeo, ARRAYSIZE(CurGeo), GetThreadLocale());
1242
1243 LoadStringW(hDllInstance, IDS_LOCALETEXT, ResText, ARRAYSIZE(ResText));
1244 StringCchPrintfW(LocaleText, ARRAYSIZE(LocaleText), ResText, CurLocale, CurGeo);
1245
1246 SetWindowTextW(hwnd, LocaleText);
1247 }
1248
1249 static VOID
1250 SetKeyboardLayoutName(HWND hwnd)
1251 {
1252 HKL hkl;
1253 BOOL LayoutSpecial = FALSE;
1254 WCHAR LayoutPath[256];
1255 WCHAR LocaleName[32];
1256 WCHAR SpecialId[5] = L"";
1257 WCHAR ResText[256] = L"";
1258 DWORD dwValueSize;
1259 HKEY hKey;
1260 UINT i;
1261
1262 /* Get the default input language and method */
1263 if (!SystemParametersInfoW(SPI_GETDEFAULTINPUTLANG, 0, (LPDWORD)&hkl, 0))
1264 {
1265 hkl = GetKeyboardLayout(0);
1266 }
1267
1268 if ((HIWORD(hkl) & 0xF000) == 0xF000)
1269 {
1270 /* Process keyboard layout with special id */
1271 StringCchPrintfW(SpecialId, ARRAYSIZE(SpecialId), L"%04x", (HIWORD(hkl) & 0x0FFF));
1272 LayoutSpecial = TRUE;
1273 }
1274
1275 #define MAX_LAYOUTS_PER_LANGID 0x10000
1276 for (i = 0; i < (LayoutSpecial ? MAX_LAYOUTS_PER_LANGID : 1); i++)
1277 {
1278 /* Generate a hexadecimal identifier for keyboard layout registry key */
1279 StringCchPrintfW(LocaleName, ARRAYSIZE(LocaleName), L"%08lx", (i << 16) | LOWORD(hkl));
1280
1281 StringCchCopyW(LayoutPath, ARRAYSIZE(LayoutPath), L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\");
1282 StringCchCatW(LayoutPath, ARRAYSIZE(LayoutPath), LocaleName);
1283 *LocaleName = UNICODE_NULL;
1284
1285 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1286 LayoutPath,
1287 0,
1288 KEY_ALL_ACCESS,
1289 &hKey) == ERROR_SUCCESS)
1290 {
1291 /* Make sure the keyboard layout key we opened is the one we need.
1292 * If the layout has no special id, just pass this check. */
1293 dwValueSize = sizeof(LocaleName);
1294 if (!LayoutSpecial ||
1295 ((RegQueryValueExW(hKey,
1296 L"Layout Id",
1297 NULL,
1298 NULL,
1299 (PVOID)&LocaleName,
1300 &dwValueSize) == ERROR_SUCCESS) &&
1301 (wcscmp(LocaleName, SpecialId) == 0)))
1302 {
1303 *LocaleName = UNICODE_NULL;
1304 dwValueSize = sizeof(LocaleName);
1305 RegQueryValueExW(hKey,
1306 L"Layout Text",
1307 NULL,
1308 NULL,
1309 (PVOID)&LocaleName,
1310 &dwValueSize);
1311 /* Let the loop know where to stop */
1312 i = MAX_LAYOUTS_PER_LANGID;
1313 }
1314 RegCloseKey(hKey);
1315 }
1316 else
1317 {
1318 /* Keyboard layout registry keys are expected to go in order without gaps */
1319 break;
1320 }
1321 }
1322 #undef MAX_LAYOUTS_PER_LANGID
1323
1324 LoadStringW(hDllInstance, IDS_LAYOUTTEXT, ResText, ARRAYSIZE(ResText));
1325 StringCchPrintfW(LayoutPath, ARRAYSIZE(LayoutPath), ResText, LocaleName);
1326
1327 SetWindowTextW(hwnd, LayoutPath);
1328 }
1329
1330
1331 static BOOL
1332 RunControlPanelApplet(HWND hwnd, PCWSTR pwszCPLParameters)
1333 {
1334 MSG msg;
1335 HWND MainWindow = GetParent(hwnd);
1336 STARTUPINFOW StartupInfo;
1337 PROCESS_INFORMATION ProcessInformation;
1338 WCHAR CmdLine[MAX_PATH] = L"rundll32.exe shell32.dll,Control_RunDLL ";
1339
1340 if (!pwszCPLParameters)
1341 {
1342 MessageBoxW(hwnd, L"Error: Failed to launch the Control Panel Applet.", NULL, MB_ICONERROR);
1343 return FALSE;
1344 }
1345
1346 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
1347 StartupInfo.cb = sizeof(StartupInfo);
1348 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
1349
1350 ASSERT(_countof(CmdLine) > wcslen(CmdLine) + wcslen(pwszCPLParameters));
1351 wcscat(CmdLine, pwszCPLParameters);
1352
1353 if (!CreateProcessW(NULL,
1354 CmdLine,
1355 NULL,
1356 NULL,
1357 FALSE,
1358 0,
1359 NULL,
1360 NULL,
1361 &StartupInfo,
1362 &ProcessInformation))
1363 {
1364 MessageBoxW(hwnd, L"Error: Failed to launch the Control Panel Applet.", NULL, MB_ICONERROR);
1365 return FALSE;
1366 }
1367
1368 /* Disable the Back and Next buttons and the main window
1369 * while we're interacting with the control panel applet */
1370 PropSheet_SetWizButtons(MainWindow, 0);
1371 EnableWindow(MainWindow, FALSE);
1372
1373 while ((MsgWaitForMultipleObjects(1, &ProcessInformation.hProcess, FALSE, INFINITE, QS_ALLINPUT|QS_ALLPOSTMESSAGE )) != WAIT_OBJECT_0)
1374 {
1375 /* We still need to process main window messages to avoid freeze */
1376 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
1377 {
1378 TranslateMessage(&msg);
1379 DispatchMessageW(&msg);
1380 }
1381 }
1382 CloseHandle(ProcessInformation.hThread);
1383 CloseHandle(ProcessInformation.hProcess);
1384
1385 /* Enable the Back and Next buttons and the main window again */
1386 PropSheet_SetWizButtons(MainWindow, PSWIZB_BACK | PSWIZB_NEXT);
1387 EnableWindow(MainWindow, TRUE);
1388
1389 return TRUE;
1390 }
1391
1392 static VOID
1393 WriteUserLocale(VOID)
1394 {
1395 HKEY hKey;
1396 LCID lcid;
1397 WCHAR Locale[12];
1398
1399 lcid = GetSystemDefaultLCID();
1400
1401 if (GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, Locale, ARRAYSIZE(Locale)) != 0)
1402 {
1403 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Control Panel\\International",
1404 0, NULL, REG_OPTION_NON_VOLATILE,
1405 KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1406 {
1407 RegSetValueExW(hKey, L"Locale", 0, REG_SZ, (LPBYTE)Locale, (wcslen(Locale) + 1) * sizeof(WCHAR));
1408 RegCloseKey(hKey);
1409 }
1410 }
1411 }
1412
1413 static INT_PTR CALLBACK
1414 LocalePageDlgProc(HWND hwndDlg,
1415 UINT uMsg,
1416 WPARAM wParam,
1417 LPARAM lParam)
1418 {
1419 PSETUPDATA SetupData;
1420
1421 /* Retrieve pointer to the global setup data */
1422 SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1423
1424 switch (uMsg)
1425 {
1426 case WM_INITDIALOG:
1427 {
1428 /* Save pointer to the global setup data */
1429 SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1430 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
1431 WriteUserLocale();
1432
1433 SetUserLocaleName(GetDlgItem(hwndDlg, IDC_LOCALETEXT));
1434 SetKeyboardLayoutName(GetDlgItem(hwndDlg, IDC_LAYOUTTEXT));
1435 }
1436 break;
1437
1438 case WM_COMMAND:
1439 if (HIWORD(wParam) == BN_CLICKED)
1440 {
1441 switch (LOWORD(wParam))
1442 {
1443 case IDC_CUSTOMLOCALE:
1444 RunControlPanelApplet(hwndDlg, L"intl.cpl,,5");
1445 SetUserLocaleName(GetDlgItem(hwndDlg, IDC_LOCALETEXT));
1446 break;
1447
1448 case IDC_CUSTOMLAYOUT:
1449 RunControlPanelApplet(hwndDlg, L"input.dll,@1");
1450 SetKeyboardLayoutName(GetDlgItem(hwndDlg, IDC_LAYOUTTEXT));
1451 break;
1452 }
1453 }
1454 break;
1455
1456 case WM_NOTIFY:
1457 {
1458 LPNMHDR lpnm = (LPNMHDR)lParam;
1459
1460 switch (lpnm->code)
1461 {
1462 case PSN_SETACTIVE:
1463 /* Enable the Back and Next buttons */
1464 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
1465 if (SetupData->UnattendSetup)
1466 {
1467 // if (!*SetupData->SourcePath)
1468 {
1469 RunControlPanelApplet(hwndDlg, L"intl.cpl,,/f:\"$winnt$.inf\""); // Should be in System32
1470 }
1471
1472 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_OWNERPAGE);
1473 return TRUE;
1474 }
1475 break;
1476
1477 case PSN_WIZNEXT:
1478 break;
1479
1480 case PSN_WIZBACK:
1481 SetupData->UnattendSetup = FALSE;
1482 break;
1483
1484 default:
1485 break;
1486 }
1487 }
1488 break;
1489
1490 default:
1491 break;
1492 }
1493
1494 return FALSE;
1495 }
1496
1497
1498 static PTIMEZONE_ENTRY
1499 GetLargerTimeZoneEntry(PSETUPDATA SetupData, DWORD Index)
1500 {
1501 PTIMEZONE_ENTRY Entry;
1502
1503 Entry = SetupData->TimeZoneListHead;
1504 while (Entry != NULL)
1505 {
1506 if (Entry->Index >= Index)
1507 return Entry;
1508
1509 Entry = Entry->Next;
1510 }
1511
1512 return NULL;
1513 }
1514
1515 static LONG
1516 RetrieveTimeZone(
1517 IN HKEY hZoneKey,
1518 IN PVOID Context)
1519 {
1520 LONG lError;
1521 PSETUPDATA SetupData = (PSETUPDATA)Context;
1522 PTIMEZONE_ENTRY Entry;
1523 PTIMEZONE_ENTRY Current;
1524 ULONG DescriptionSize;
1525 ULONG StandardNameSize;
1526 ULONG DaylightNameSize;
1527
1528 Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY));
1529 if (Entry == NULL)
1530 {
1531 return ERROR_NOT_ENOUGH_MEMORY;
1532 }
1533
1534 DescriptionSize = sizeof(Entry->Description);
1535 StandardNameSize = sizeof(Entry->StandardName);
1536 DaylightNameSize = sizeof(Entry->DaylightName);
1537
1538 lError = QueryTimeZoneData(hZoneKey,
1539 &Entry->Index,
1540 &Entry->TimezoneInfo,
1541 Entry->Description,
1542 &DescriptionSize,
1543 Entry->StandardName,
1544 &StandardNameSize,
1545 Entry->DaylightName,
1546 &DaylightNameSize);
1547 if (lError != ERROR_SUCCESS)
1548 {
1549 HeapFree(GetProcessHeap(), 0, Entry);
1550 return lError;
1551 }
1552
1553 if (SetupData->TimeZoneListHead == NULL &&
1554 SetupData->TimeZoneListTail == NULL)
1555 {
1556 Entry->Prev = NULL;
1557 Entry->Next = NULL;
1558 SetupData->TimeZoneListHead = Entry;
1559 SetupData->TimeZoneListTail = Entry;
1560 }
1561 else
1562 {
1563 Current = GetLargerTimeZoneEntry(SetupData, Entry->Index);
1564 if (Current != NULL)
1565 {
1566 if (Current == SetupData->TimeZoneListHead)
1567 {
1568 /* Prepend to head */
1569 Entry->Prev = NULL;
1570 Entry->Next = SetupData->TimeZoneListHead;
1571 SetupData->TimeZoneListHead->Prev = Entry;
1572 SetupData->TimeZoneListHead = Entry;
1573 }
1574 else
1575 {
1576 /* Insert before current */
1577 Entry->Prev = Current->Prev;
1578 Entry->Next = Current;
1579 Current->Prev->Next = Entry;
1580 Current->Prev = Entry;
1581 }
1582 }
1583 else
1584 {
1585 /* Append to tail */
1586 Entry->Prev = SetupData->TimeZoneListTail;
1587 Entry->Next = NULL;
1588 SetupData->TimeZoneListTail->Next = Entry;
1589 SetupData->TimeZoneListTail = Entry;
1590 }
1591 }
1592
1593 return ERROR_SUCCESS;
1594 }
1595
1596 static VOID
1597 CreateTimeZoneList(PSETUPDATA SetupData)
1598 {
1599 EnumerateTimeZoneList(RetrieveTimeZone, SetupData);
1600 }
1601
1602 static VOID
1603 DestroyTimeZoneList(PSETUPDATA SetupData)
1604 {
1605 PTIMEZONE_ENTRY Entry;
1606
1607 while (SetupData->TimeZoneListHead != NULL)
1608 {
1609 Entry = SetupData->TimeZoneListHead;
1610
1611 SetupData->TimeZoneListHead = Entry->Next;
1612 if (SetupData->TimeZoneListHead != NULL)
1613 {
1614 SetupData->TimeZoneListHead->Prev = NULL;
1615 }
1616
1617 HeapFree(GetProcessHeap(), 0, Entry);
1618 }
1619
1620 SetupData->TimeZoneListTail = NULL;
1621 }
1622
1623
1624 static VOID
1625 ShowTimeZoneList(HWND hwnd, PSETUPDATA SetupData, DWORD dwEntryIndex)
1626 {
1627 PTIMEZONE_ENTRY Entry;
1628 DWORD dwIndex = 0;
1629 DWORD dwCount;
1630
1631 GetTimeZoneListIndex(&dwEntryIndex);
1632
1633 Entry = SetupData->TimeZoneListHead;
1634 while (Entry != NULL)
1635 {
1636 dwCount = SendMessage(hwnd,
1637 CB_ADDSTRING,
1638 0,
1639 (LPARAM)Entry->Description);
1640
1641 if (dwEntryIndex != 0 && dwEntryIndex == Entry->Index)
1642 dwIndex = dwCount;
1643
1644 Entry = Entry->Next;
1645 }
1646
1647 SendMessage(hwnd,
1648 CB_SETCURSEL,
1649 (WPARAM)dwIndex,
1650 0);
1651 }
1652
1653
1654 static VOID
1655 SetLocalTimeZone(HWND hwnd, PSETUPDATA SetupData)
1656 {
1657 TIME_ZONE_INFORMATION TimeZoneInformation;
1658 PTIMEZONE_ENTRY Entry;
1659 DWORD dwIndex;
1660 DWORD i;
1661
1662 dwIndex = SendMessage(hwnd,
1663 CB_GETCURSEL,
1664 0,
1665 0);
1666
1667 i = 0;
1668 Entry = SetupData->TimeZoneListHead;
1669 while (i < dwIndex)
1670 {
1671 if (Entry == NULL)
1672 return;
1673
1674 i++;
1675 Entry = Entry->Next;
1676 }
1677
1678 wcscpy(TimeZoneInformation.StandardName,
1679 Entry->StandardName);
1680 wcscpy(TimeZoneInformation.DaylightName,
1681 Entry->DaylightName);
1682
1683 TimeZoneInformation.Bias = Entry->TimezoneInfo.Bias;
1684 TimeZoneInformation.StandardBias = Entry->TimezoneInfo.StandardBias;
1685 TimeZoneInformation.DaylightBias = Entry->TimezoneInfo.DaylightBias;
1686
1687 memcpy(&TimeZoneInformation.StandardDate,
1688 &Entry->TimezoneInfo.StandardDate,
1689 sizeof(SYSTEMTIME));
1690 memcpy(&TimeZoneInformation.DaylightDate,
1691 &Entry->TimezoneInfo.DaylightDate,
1692 sizeof(SYSTEMTIME));
1693
1694 /* Set time zone information */
1695 SetTimeZoneInformation(&TimeZoneInformation);
1696 }
1697
1698
1699 static BOOL
1700 GetLocalSystemTime(HWND hwnd, PSETUPDATA SetupData)
1701 {
1702 SYSTEMTIME Date;
1703 SYSTEMTIME Time;
1704
1705 if (DateTime_GetSystemtime(GetDlgItem(hwnd, IDC_DATEPICKER), &Date) != GDT_VALID)
1706 {
1707 return FALSE;
1708 }
1709
1710 if (DateTime_GetSystemtime(GetDlgItem(hwnd, IDC_TIMEPICKER), &Time) != GDT_VALID)
1711 {
1712 return FALSE;
1713 }
1714
1715 SetupData->SystemTime.wYear = Date.wYear;
1716 SetupData->SystemTime.wMonth = Date.wMonth;
1717 SetupData->SystemTime.wDayOfWeek = Date.wDayOfWeek;
1718 SetupData->SystemTime.wDay = Date.wDay;
1719 SetupData->SystemTime.wHour = Time.wHour;
1720 SetupData->SystemTime.wMinute = Time.wMinute;
1721 SetupData->SystemTime.wSecond = Time.wSecond;
1722 SetupData->SystemTime.wMilliseconds = Time.wMilliseconds;
1723
1724 return TRUE;
1725 }
1726
1727
1728 static BOOL
1729 SetSystemLocalTime(HWND hwnd, PSETUPDATA SetupData)
1730 {
1731 BOOL Ret = FALSE;
1732
1733 /*
1734 * Call SetLocalTime twice to ensure correct results
1735 */
1736 Ret = SetLocalTime(&SetupData->SystemTime) &&
1737 SetLocalTime(&SetupData->SystemTime);
1738
1739 return Ret;
1740 }
1741
1742
1743 static VOID
1744 UpdateLocalSystemTime(HWND hwnd, SYSTEMTIME LocalTime)
1745 {
1746 DateTime_SetSystemtime(GetDlgItem(hwnd, IDC_DATEPICKER), GDT_VALID, &LocalTime);
1747 DateTime_SetSystemtime(GetDlgItem(hwnd, IDC_TIMEPICKER), GDT_VALID, &LocalTime);
1748 }
1749
1750
1751 static BOOL
1752 WriteDateTimeSettings(HWND hwndDlg, PSETUPDATA SetupData)
1753 {
1754 WCHAR Title[64];
1755 WCHAR ErrorLocalTime[256];
1756
1757 GetLocalSystemTime(hwndDlg, SetupData);
1758 SetLocalTimeZone(GetDlgItem(hwndDlg, IDC_TIMEZONELIST),
1759 SetupData);
1760
1761 SetAutoDaylight(SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT,
1762 BM_GETCHECK, 0, 0) != BST_UNCHECKED);
1763 if (!SetSystemLocalTime(hwndDlg, SetupData))
1764 {
1765 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
1766 {
1767 wcscpy(Title, L"ReactOS Setup");
1768 }
1769 if (0 == LoadStringW(hDllInstance, IDS_WZD_LOCALTIME, ErrorLocalTime,
1770 ARRAYSIZE(ErrorLocalTime)))
1771 {
1772 wcscpy(ErrorLocalTime, L"Setup was unable to set the local time.");
1773 }
1774 MessageBoxW(hwndDlg, ErrorLocalTime, Title, MB_ICONWARNING | MB_OK);
1775 return FALSE;
1776 }
1777
1778 return TRUE;
1779 }
1780
1781
1782 static INT_PTR CALLBACK
1783 DateTimePageDlgProc(HWND hwndDlg,
1784 UINT uMsg,
1785 WPARAM wParam,
1786 LPARAM lParam)
1787 {
1788 PSETUPDATA SetupData;
1789
1790 /* Retrieve pointer to the global setup data */
1791 SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1792
1793 switch (uMsg)
1794 {
1795 case WM_INITDIALOG:
1796 {
1797 /* Save pointer to the global setup data */
1798 SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1799 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
1800
1801 CreateTimeZoneList(SetupData);
1802
1803 if (SetupData->UnattendSetup)
1804 {
1805 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST),
1806 SetupData, SetupData->TimeZoneIndex);
1807
1808 if (!SetupData->DisableAutoDaylightTimeSet)
1809 {
1810 SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
1811 }
1812 }
1813 else
1814 {
1815 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST),
1816 SetupData, -1);
1817
1818 SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
1819 }
1820 break;
1821 }
1822
1823 case WM_TIMER:
1824 {
1825 SYSTEMTIME LocalTime;
1826
1827 GetLocalTime(&LocalTime);
1828 UpdateLocalSystemTime(hwndDlg, LocalTime);
1829
1830 // Reset timeout.
1831 SetTimer(hwndDlg, 1, 1000 - LocalTime.wMilliseconds, NULL);
1832 break;
1833 }
1834
1835 case WM_NOTIFY:
1836 switch (((LPNMHDR)lParam)->code)
1837 {
1838 case PSN_SETACTIVE:
1839 {
1840 SYSTEMTIME LocalTime;
1841
1842 GetLocalTime(&LocalTime);
1843 UpdateLocalSystemTime(hwndDlg, LocalTime);
1844
1845 /* Enable the Back and Next buttons */
1846 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
1847
1848 if (SetupData->UnattendSetup && WriteDateTimeSettings(hwndDlg, SetupData))
1849 {
1850 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SetupData->uFirstNetworkWizardPage);
1851 return TRUE;
1852 }
1853
1854 SetTimer(hwndDlg, 1, 1000 - LocalTime.wMilliseconds, NULL);
1855 break;
1856 }
1857
1858 case PSN_KILLACTIVE:
1859 case DTN_DATETIMECHANGE:
1860 // NB: Not re-set until changing page (PSN_SETACTIVE).
1861 KillTimer(hwndDlg, 1);
1862 break;
1863
1864 case PSN_WIZNEXT:
1865 WriteDateTimeSettings(hwndDlg, SetupData);
1866 break;
1867
1868 case PSN_WIZBACK:
1869 SetupData->UnattendSetup = FALSE;
1870 break;
1871
1872 default:
1873 break;
1874 }
1875 break;
1876
1877 case WM_DESTROY:
1878 DestroyTimeZoneList(SetupData);
1879 break;
1880
1881 default:
1882 break;
1883 }
1884
1885 return FALSE;
1886 }
1887
1888 static struct ThemeInfo
1889 {
1890 LPCWSTR PreviewBitmap;
1891 UINT DisplayName;
1892 LPCWSTR ThemeFile;
1893
1894 } Themes[] = {
1895 { MAKEINTRESOURCE(IDB_CLASSIC), IDS_CLASSIC, NULL },
1896 { MAKEINTRESOURCE(IDB_LAUTUS), IDS_LAUTUS, L"themes\\lautus\\lautus.msstyles" },
1897 { MAKEINTRESOURCE(IDB_LUNAR), IDS_LUNAR, L"themes\\lunar\\lunar.msstyles" },
1898 { MAKEINTRESOURCE(IDB_MIZU), IDS_MIZU, L"themes\\mizu\\mizu.msstyles"},
1899 };
1900
1901 static INT_PTR CALLBACK
1902 ThemePageDlgProc(HWND hwndDlg,
1903 UINT uMsg,
1904 WPARAM wParam,
1905 LPARAM lParam)
1906 {
1907 PSETUPDATA SetupData;
1908 LPNMLISTVIEW pnmv;
1909
1910 /* Retrieve pointer to the global setup data */
1911 SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1912
1913 switch (uMsg)
1914 {
1915 case WM_INITDIALOG:
1916 {
1917 HWND hListView;
1918 HIMAGELIST himl;
1919 DWORD n;
1920 LVITEM lvi = {0};
1921
1922 /* Save pointer to the global setup data */
1923 SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1924 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
1925
1926 hListView = GetDlgItem(hwndDlg, IDC_THEMEPICKER);
1927
1928 /* Common */
1929 himl = ImageList_Create(180, 163, ILC_COLOR32 | ILC_MASK, ARRAYSIZE(Themes), 1);
1930 lvi.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
1931
1932 for (n = 0; n < ARRAYSIZE(Themes); ++n)
1933 {
1934 WCHAR DisplayName[100] = {0};
1935 /* Load the bitmap */
1936 HANDLE image = LoadImageW(hDllInstance, Themes[n].PreviewBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
1937 ImageList_AddMasked(himl, image, RGB(255,0,255));
1938
1939 /* Load the string */
1940 LoadStringW(hDllInstance, Themes[n].DisplayName, DisplayName, ARRAYSIZE(DisplayName));
1941 DisplayName[ARRAYSIZE(DisplayName)-1] = UNICODE_NULL;
1942
1943 /* Add the listview item */
1944 lvi.iItem = n;
1945 lvi.iImage = n;
1946 lvi.pszText = DisplayName;
1947 ListView_InsertItem(hListView, &lvi);
1948 }
1949
1950 /* Register the imagelist */
1951 ListView_SetImageList(hListView, himl, LVSIL_NORMAL);
1952 /* Transparant background */
1953 ListView_SetBkColor(hListView, CLR_NONE);
1954 ListView_SetTextBkColor(hListView, CLR_NONE);
1955 /* Reduce the size between the items */
1956 ListView_SetIconSpacing(hListView, 190, 173);
1957 break;
1958 }
1959 case WM_NOTIFY:
1960 switch (((LPNMHDR)lParam)->code)
1961 {
1962 //case LVN_ITEMCHANGING:
1963 case LVN_ITEMCHANGED:
1964 pnmv = (LPNMLISTVIEW)lParam;
1965 if ((pnmv->uChanged & LVIF_STATE) && (pnmv->uNewState & LVIS_SELECTED))
1966 {
1967 int iTheme = pnmv->iItem;
1968 DPRINT1("Selected theme: %u\n", Themes[iTheme].DisplayName);
1969
1970 if (Themes[iTheme].ThemeFile)
1971 {
1972 WCHAR wszParams[1024];
1973 WCHAR wszTheme[MAX_PATH];
1974 WCHAR* format = L"desk.cpl desk,@Appearance /Action:ActivateMSTheme /file:\"%s\"";
1975
1976 SHGetFolderPathAndSubDirW(0, CSIDL_RESOURCES, NULL, SHGFP_TYPE_DEFAULT, Themes[iTheme].ThemeFile, wszTheme);
1977 swprintf(wszParams, format, wszTheme);
1978 RunControlPanelApplet(hwndDlg, wszParams);
1979 }
1980 else
1981 {
1982 RunControlPanelApplet(hwndDlg, L"desk.cpl desk,@Appearance /Action:ActivateMSTheme");
1983 }
1984 }
1985 break;
1986 case PSN_SETACTIVE:
1987 /* Enable the Back and Next buttons */
1988 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
1989 if (SetupData->UnattendSetup)
1990 {
1991 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SetupData->uFirstNetworkWizardPage);
1992 return TRUE;
1993 }
1994 break;
1995
1996 case PSN_WIZNEXT:
1997 break;
1998
1999 case PSN_WIZBACK:
2000 SetupData->UnattendSetup = FALSE;
2001 break;
2002
2003 default:
2004 break;
2005 }
2006 break;
2007
2008 default:
2009 break;
2010 }
2011
2012 return FALSE;
2013 }
2014
2015 static UINT CALLBACK
2016 RegistrationNotificationProc(PVOID Context,
2017 UINT Notification,
2018 UINT_PTR Param1,
2019 UINT_PTR Param2)
2020 {
2021 PREGISTRATIONDATA RegistrationData;
2022 REGISTRATIONNOTIFY RegistrationNotify;
2023 PSP_REGISTER_CONTROL_STATUSW StatusInfo;
2024 UINT MessageID;
2025
2026 RegistrationData = (PREGISTRATIONDATA)Context;
2027
2028 if (Notification == SPFILENOTIFY_STARTREGISTRATION ||
2029 Notification == SPFILENOTIFY_ENDREGISTRATION)
2030 {
2031 StatusInfo = (PSP_REGISTER_CONTROL_STATUSW) Param1;
2032 RegistrationNotify.CurrentItem = wcsrchr(StatusInfo->FileName, L'\\');
2033 if (RegistrationNotify.CurrentItem == NULL)
2034 {
2035 RegistrationNotify.CurrentItem = StatusInfo->FileName;
2036 }
2037 else
2038 {
2039 RegistrationNotify.CurrentItem++;
2040 }
2041
2042 if (Notification == SPFILENOTIFY_STARTREGISTRATION)
2043 {
2044 DPRINT("Received SPFILENOTIFY_STARTREGISTRATION notification for %S\n",
2045 StatusInfo->FileName);
2046 RegistrationNotify.ErrorMessage = NULL;
2047 RegistrationNotify.Progress = RegistrationData->Registered;
2048 SendMessage(RegistrationData->hwndDlg, PM_STEP_START, 0, (LPARAM)&RegistrationNotify);
2049 }
2050 else
2051 {
2052 DPRINT("Received SPFILENOTIFY_ENDREGISTRATION notification for %S\n",
2053 StatusInfo->FileName);
2054 DPRINT("Win32Error %u FailureCode %u\n", StatusInfo->Win32Error,
2055 StatusInfo->FailureCode);
2056 if (StatusInfo->FailureCode != SPREG_SUCCESS)
2057 {
2058 switch (StatusInfo->FailureCode)
2059 {
2060 case SPREG_LOADLIBRARY:
2061 MessageID = IDS_LOADLIBRARY_FAILED;
2062 break;
2063 case SPREG_GETPROCADDR:
2064 MessageID = IDS_GETPROCADDR_FAILED;
2065 break;
2066 case SPREG_REGSVR:
2067 MessageID = IDS_REGSVR_FAILED;
2068 break;
2069 case SPREG_DLLINSTALL:
2070 MessageID = IDS_DLLINSTALL_FAILED;
2071 break;
2072 case SPREG_TIMEOUT:
2073 MessageID = IDS_TIMEOUT;
2074 break;
2075 default:
2076 MessageID = IDS_REASON_UNKNOWN;
2077 break;
2078 }
2079
2080 RegistrationNotify.MessageID = MessageID;
2081 RegistrationNotify.LastError = StatusInfo->Win32Error;
2082 }
2083 else
2084 {
2085 RegistrationNotify.MessageID = 0;
2086 RegistrationNotify.LastError = ERROR_SUCCESS;
2087 }
2088
2089 if (RegistrationData->Registered < RegistrationData->DllCount)
2090 {
2091 RegistrationData->Registered++;
2092 }
2093
2094 RegistrationNotify.Progress = RegistrationData->Registered;
2095 SendMessage(RegistrationData->hwndDlg, PM_STEP_END, 0, (LPARAM)&RegistrationNotify);
2096 }
2097
2098 return FILEOP_DOIT;
2099 }
2100 else
2101 {
2102 DPRINT1("Received unexpected notification %u\n", Notification);
2103 return SetupDefaultQueueCallback(RegistrationData->DefaultContext,
2104 Notification, Param1, Param2);
2105 }
2106 }
2107
2108
2109 static
2110 DWORD
2111 RegisterDlls(
2112 PITEMSDATA pItemsData)
2113 {
2114 REGISTRATIONDATA RegistrationData;
2115 WCHAR SectionName[512];
2116 INFCONTEXT Context;
2117 LONG DllCount = 0;
2118 DWORD LastError = NO_ERROR;
2119
2120 ZeroMemory(&RegistrationData, sizeof(REGISTRATIONDATA));
2121 RegistrationData.hwndDlg = pItemsData->hwndDlg;
2122 RegistrationData.Registered = 0;
2123
2124 if (!SetupFindFirstLineW(hSysSetupInf, L"RegistrationPhase2",
2125 L"RegisterDlls", &Context))
2126 {
2127 DPRINT1("No RegistrationPhase2 section found\n");
2128 return FALSE;
2129 }
2130
2131 if (!SetupGetStringFieldW(&Context, 1, SectionName,
2132 ARRAYSIZE(SectionName),
2133 NULL))
2134 {
2135 DPRINT1("Unable to retrieve section name\n");
2136 return FALSE;
2137 }
2138
2139 DllCount = SetupGetLineCountW(hSysSetupInf, SectionName);
2140 DPRINT1("SectionName %S DllCount %ld\n", SectionName, DllCount);
2141 if (DllCount < 0)
2142 {
2143 SetLastError(STATUS_NOT_FOUND);
2144 return FALSE;
2145 }
2146
2147 RegistrationData.DllCount = (ULONG)DllCount;
2148 RegistrationData.DefaultContext = SetupInitDefaultQueueCallback(RegistrationData.hwndDlg);
2149
2150 SendMessage(pItemsData->hwndDlg, PM_ITEM_START, 0, (LPARAM)RegistrationData.DllCount);
2151
2152 _SEH2_TRY
2153 {
2154 if (!SetupInstallFromInfSectionW(GetParent(RegistrationData.hwndDlg),
2155 hSysSetupInf,
2156 L"RegistrationPhase2",
2157 SPINST_REGISTRY | SPINST_REGISTERCALLBACKAWARE | SPINST_REGSVR,
2158 0,
2159 NULL,
2160 0,
2161 RegistrationNotificationProc,
2162 &RegistrationData,
2163 NULL,
2164 NULL))
2165 {
2166 LastError = GetLastError();
2167 }
2168 }
2169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2170 {
2171 DPRINT("Catching exception\n");
2172 LastError = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
2173 }
2174 _SEH2_END;
2175
2176 SetupTermDefaultQueueCallback(RegistrationData.DefaultContext);
2177
2178 SendMessage(pItemsData->hwndDlg, PM_ITEM_END, 0, LastError);
2179
2180 return 0;
2181 }
2182
2183
2184 static
2185 DWORD
2186 CALLBACK
2187 ItemCompletionThread(
2188 LPVOID Parameter)
2189 {
2190 PITEMSDATA pItemsData;
2191 HWND hwndDlg;
2192
2193 pItemsData = (PITEMSDATA)Parameter;
2194 hwndDlg = pItemsData->hwndDlg;
2195
2196 RegisterDlls(pItemsData);
2197
2198 RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
2199
2200 /* FIXME: Add completion steps here! */
2201
2202 // FIXME: Move this call to a separate cleanup page!
2203 RtlCreateBootStatusDataFile();
2204
2205 /* Free the items data */
2206 HeapFree(GetProcessHeap(), 0, pItemsData);
2207
2208 /* Tell the wizard page that we are done */
2209 PostMessage(hwndDlg, PM_ITEMS_DONE, 0, 0);
2210
2211 return 0;
2212 }
2213
2214
2215 static
2216 BOOL
2217 RunItemCompletionThread(
2218 _In_ HWND hwndDlg)
2219 {
2220 HANDLE hCompletionThread;
2221 PITEMSDATA pItemsData;
2222
2223 pItemsData = HeapAlloc(GetProcessHeap(), 0, sizeof(ITEMSDATA));
2224 if (pItemsData == NULL)
2225 return FALSE;
2226
2227 pItemsData->hwndDlg = hwndDlg;
2228
2229 hCompletionThread = CreateThread(NULL,
2230 0,
2231 ItemCompletionThread,
2232 pItemsData,
2233 0,
2234 NULL);
2235 if (hCompletionThread == NULL)
2236 {
2237 HeapFree(GetProcessHeap(), 0, pItemsData);
2238 }
2239 else
2240 {
2241 CloseHandle(hCompletionThread);
2242 return TRUE;
2243 }
2244
2245 return FALSE;
2246 }
2247
2248 static
2249 VOID
2250 ShowItemError(
2251 HWND hwndDlg,
2252 DWORD LastError)
2253 {
2254 LPWSTR ErrorMessage = NULL;
2255 WCHAR UnknownError[84];
2256 WCHAR Title[64];
2257
2258 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2259 NULL, LastError, 0, ErrorMessage, 0, NULL) == 0)
2260 {
2261 if (LoadStringW(hDllInstance, IDS_UNKNOWN_ERROR,
2262 UnknownError,
2263 ARRAYSIZE(UnknownError) - 20) == 0)
2264 {
2265 wcscpy(UnknownError, L"Unknown error");
2266 }
2267 wcscat(UnknownError, L" ");
2268 _ultow(LastError, UnknownError + wcslen(UnknownError), 10);
2269 ErrorMessage = UnknownError;
2270 }
2271
2272 if (ErrorMessage != NULL)
2273 {
2274 if (LoadStringW(hDllInstance, IDS_REACTOS_SETUP,
2275 Title, ARRAYSIZE(Title)) == 0)
2276 {
2277 wcscpy(Title, L"ReactOS Setup");
2278 }
2279
2280 MessageBoxW(hwndDlg, ErrorMessage, Title, MB_ICONERROR | MB_OK);
2281 }
2282
2283 if (ErrorMessage != NULL &&
2284 ErrorMessage != UnknownError)
2285 {
2286 LocalFree(ErrorMessage);
2287 }
2288 }
2289
2290
2291 static
2292 VOID
2293 ShowStepError(
2294 HWND hwndDlg,
2295 PREGISTRATIONNOTIFY RegistrationNotify)
2296 {
2297 WCHAR ErrorMessage[128];
2298 WCHAR Title[64];
2299
2300 if (LoadStringW(hDllInstance, RegistrationNotify->MessageID,
2301 ErrorMessage,
2302 ARRAYSIZE(ErrorMessage)) == 0)
2303 {
2304 ErrorMessage[0] = L'\0';
2305 }
2306
2307 if (RegistrationNotify->MessageID != IDS_TIMEOUT)
2308 {
2309 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2310 RegistrationNotify->LastError, 0,
2311 ErrorMessage + wcslen(ErrorMessage),
2312 ARRAYSIZE(ErrorMessage) - wcslen(ErrorMessage),
2313 NULL);
2314 }
2315
2316 if (ErrorMessage[0] != L'\0')
2317 {
2318 if (LoadStringW(hDllInstance, IDS_REACTOS_SETUP,
2319 Title, ARRAYSIZE(Title)) == 0)
2320 {
2321 wcscpy(Title, L"ReactOS Setup");
2322 }
2323
2324 MessageBoxW(hwndDlg, ErrorMessage,
2325 Title, MB_ICONERROR | MB_OK);
2326 }
2327 }
2328
2329
2330 static INT_PTR CALLBACK
2331 ProcessPageDlgProc(HWND hwndDlg,
2332 UINT uMsg,
2333 WPARAM wParam,
2334 LPARAM lParam)
2335 {
2336 PSETUPDATA SetupData;
2337 PREGISTRATIONNOTIFY RegistrationNotify;
2338
2339 /* Retrieve pointer to the global setup data */
2340 SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
2341
2342 switch (uMsg)
2343 {
2344 case WM_INITDIALOG:
2345 /* Save pointer to the global setup data */
2346 SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
2347 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
2348 ShowWindow(GetDlgItem(hwndDlg, IDC_TASKTEXT2), SW_HIDE);
2349 ShowWindow(GetDlgItem(hwndDlg, IDC_TASKTEXT3), SW_HIDE);
2350 ShowWindow(GetDlgItem(hwndDlg, IDC_TASKTEXT4), SW_HIDE);
2351 break;
2352
2353 case WM_NOTIFY:
2354 switch (((LPNMHDR)lParam)->code)
2355 {
2356 case PSN_SETACTIVE:
2357 /* Disable the Back and Next buttons */
2358 PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
2359 RunItemCompletionThread(hwndDlg);
2360 break;
2361
2362 case PSN_WIZNEXT:
2363 break;
2364
2365 case PSN_WIZBACK:
2366 SetupData->UnattendSetup = FALSE;
2367 break;
2368
2369 default:
2370 break;
2371 }
2372 break;
2373
2374 case PM_ITEM_START:
2375 DPRINT("PM_ITEM_START %lu\n", (ULONG)lParam);
2376 SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, (ULONG)lParam));
2377 SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETPOS, 0, 0);
2378 SendDlgItemMessage(hwndDlg, IDC_TASKTEXT1 + wParam, WM_SETFONT, (WPARAM)SetupData->hBoldFont, (LPARAM)TRUE);
2379 break;
2380
2381 case PM_ITEM_END:
2382 DPRINT("PM_ITEM_END\n");
2383 if (lParam == ERROR_SUCCESS)
2384 {
2385 }
2386 else
2387 {
2388 ShowItemError(hwndDlg, (DWORD)lParam);
2389 }
2390 break;
2391
2392 case PM_STEP_START:
2393 DPRINT("PM_STEP_START\n");
2394 RegistrationNotify = (PREGISTRATIONNOTIFY)lParam;
2395 SendDlgItemMessage(hwndDlg, IDC_ITEM, WM_SETTEXT, 0,
2396 (LPARAM)((RegistrationNotify->CurrentItem != NULL)? RegistrationNotify->CurrentItem : L""));
2397 break;
2398
2399 case PM_STEP_END:
2400 DPRINT("PM_STEP_END\n");
2401 RegistrationNotify = (PREGISTRATIONNOTIFY)lParam;
2402 SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETPOS, RegistrationNotify->Progress, 0);
2403 if (RegistrationNotify->LastError != ERROR_SUCCESS)
2404 {
2405 ShowStepError(hwndDlg, RegistrationNotify);
2406 }
2407 break;
2408
2409 case PM_ITEMS_DONE:
2410 DPRINT("PM_ITEMS_DONE\n");
2411 /* Enable the Back and Next buttons */
2412 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
2413 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
2414 break;
2415
2416 default:
2417 break;
2418 }
2419
2420 return FALSE;
2421 }
2422
2423
2424 static VOID
2425 SetInstallationCompleted(VOID)
2426 {
2427 HKEY hKey = 0;
2428 DWORD InProgress = 0;
2429 DWORD InstallDate;
2430
2431 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
2432 L"SYSTEM\\Setup",
2433 0,
2434 KEY_WRITE,
2435 &hKey ) == ERROR_SUCCESS)
2436 {
2437 RegSetValueExW( hKey, L"SystemSetupInProgress", 0, REG_DWORD, (LPBYTE)&InProgress, sizeof(InProgress) );
2438 RegCloseKey( hKey );
2439 }
2440
2441 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
2442 L"Software\\Microsoft\\Windows NT\\CurrentVersion",
2443 0,
2444 KEY_WRITE,
2445 &hKey ) == ERROR_SUCCESS)
2446 {
2447 InstallDate = (DWORD)time(NULL);
2448 RegSetValueExW( hKey, L"InstallDate", 0, REG_DWORD, (LPBYTE)&InstallDate, sizeof(InstallDate) );
2449 RegCloseKey( hKey );
2450 }
2451 }
2452
2453 static INT_PTR CALLBACK
2454 FinishDlgProc(HWND hwndDlg,
2455 UINT uMsg,
2456 WPARAM wParam,
2457 LPARAM lParam)
2458 {
2459
2460 switch (uMsg)
2461 {
2462 case WM_INITDIALOG:
2463 {
2464 /* Get pointer to the global setup data */
2465 PSETUPDATA SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
2466
2467 if (!SetupData->UnattendSetup || !SetupData->DisableGeckoInst)
2468 {
2469 /* Run the Wine Gecko prompt */
2470 Control_RunDLLW(hwndDlg, 0, L"appwiz.cpl install_gecko", SW_SHOW);
2471 }
2472
2473 /* Set title font */
2474 SendDlgItemMessage(hwndDlg,
2475 IDC_FINISHTITLE,
2476 WM_SETFONT,
2477 (WPARAM)SetupData->hTitleFont,
2478 (LPARAM)TRUE);
2479 if (SetupData->UnattendSetup)
2480 {
2481 KillTimer(hwndDlg, 1);
2482 SetInstallationCompleted();
2483 PostQuitMessage(0);
2484 }
2485 }
2486 break;
2487
2488 case WM_DESTROY:
2489 {
2490 SetInstallationCompleted();
2491 PostQuitMessage(0);
2492 return TRUE;
2493 }
2494
2495 case WM_TIMER:
2496 {
2497 INT Position;
2498 HWND hWndProgress;
2499
2500 hWndProgress = GetDlgItem(hwndDlg, IDC_RESTART_PROGRESS);
2501 Position = SendMessage(hWndProgress, PBM_GETPOS, 0, 0);
2502 if (Position == 300)
2503 {
2504 KillTimer(hwndDlg, 1);
2505 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_FINISH);
2506 }
2507 else
2508 {
2509 SendMessage(hWndProgress, PBM_SETPOS, Position + 1, 0);
2510 }
2511 }
2512 return TRUE;
2513
2514 case WM_NOTIFY:
2515 {
2516 LPNMHDR lpnm = (LPNMHDR)lParam;
2517
2518 switch (lpnm->code)
2519 {
2520 case PSN_SETACTIVE:
2521 /* Enable the correct buttons on for the active page */
2522 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
2523
2524 SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETRANGE, 0,
2525 MAKELPARAM(0, 300));
2526 SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETPOS, 0, 0);
2527 SetTimer(hwndDlg, 1, 50, NULL);
2528 break;
2529
2530 case PSN_WIZFINISH:
2531 DestroyWindow(GetParent(hwndDlg));
2532 break;
2533
2534 default:
2535 break;
2536 }
2537 }
2538 break;
2539
2540 default:
2541 break;
2542 }
2543
2544 return FALSE;
2545 }
2546
2547
2548 /*
2549 * GetInstallSourceWin32 retrieves the path to the ReactOS installation medium
2550 * in Win32 format, for later use by syssetup and storage in the registry.
2551 */
2552 static BOOL
2553 GetInstallSourceWin32(
2554 OUT PWSTR pwszPath,
2555 IN DWORD cchPathMax,
2556 IN PCWSTR pwszNTPath)
2557 {
2558 WCHAR wszDrives[512];
2559 WCHAR wszNTPath[512]; // MAX_PATH ?
2560 DWORD cchDrives;
2561 PWCHAR pwszDrive;
2562
2563 *pwszPath = UNICODE_NULL;
2564
2565 cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
2566 if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
2567 {
2568 /* Buffer too small or failure */
2569 LogItem(NULL, L"GetLogicalDriveStringsW failed");
2570 return FALSE;
2571 }
2572
2573 for (pwszDrive = wszDrives; *pwszDrive; pwszDrive += wcslen(pwszDrive) + 1)
2574 {
2575 WCHAR wszBuf[MAX_PATH];
2576
2577 /* Retrieve the NT path corresponding to the current Win32 DOS path */
2578 pwszDrive[2] = UNICODE_NULL; // Temporarily remove the backslash
2579 QueryDosDeviceW(pwszDrive, wszNTPath, _countof(wszNTPath));
2580 pwszDrive[2] = L'\\'; // Restore the backslash
2581
2582 wcscat(wszNTPath, L"\\"); // Concat a backslash
2583
2584 /* Logging */
2585 wsprintf(wszBuf, L"Testing '%s' --> '%s' %s a CD",
2586 pwszDrive, wszNTPath,
2587 (GetDriveTypeW(pwszDrive) == DRIVE_CDROM) ? L"is" : L"is not");
2588 LogItem(NULL, wszBuf);
2589
2590 /* Check whether the NT path corresponds to the NT installation source path */
2591 if (!_wcsicmp(wszNTPath, pwszNTPath))
2592 {
2593 /* Found it! */
2594 wcscpy(pwszPath, pwszDrive); // cchPathMax
2595
2596 /* Logging */
2597 wsprintf(wszBuf, L"GetInstallSourceWin32: %s", pwszPath);
2598 LogItem(NULL, wszBuf);
2599 wcscat(wszBuf, L"\n");
2600 OutputDebugStringW(wszBuf);
2601
2602 return TRUE;
2603 }
2604 }
2605
2606 return FALSE;
2607 }
2608
2609 VOID
2610 ProcessUnattendSection(
2611 IN OUT PSETUPDATA pSetupData)
2612 {
2613 INFCONTEXT InfContext;
2614 WCHAR szName[256];
2615 WCHAR szValue[MAX_PATH];
2616 DWORD LineLength;
2617 HKEY hKey;
2618
2619 if (!SetupFindFirstLineW(pSetupData->hSetupInf,
2620 L"Unattend",
2621 L"UnattendSetupEnabled",
2622 &InfContext))
2623 {
2624 DPRINT1("Error: Cannot find UnattendSetupEnabled Key! %d\n", GetLastError());
2625 return;
2626 }
2627
2628 if (!SetupGetStringFieldW(&InfContext,
2629 1,
2630 szValue,
2631 ARRAYSIZE(szValue),
2632 &LineLength))
2633 {
2634 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2635 return;
2636 }
2637
2638 if (_wcsicmp(szValue, L"yes") != 0)
2639 {
2640 DPRINT("Unattend setup was disabled by UnattendSetupEnabled key.\n");
2641 return;
2642 }
2643
2644 pSetupData->UnattendSetup = TRUE;
2645
2646 if (!SetupFindFirstLineW(pSetupData->hSetupInf,
2647 L"Unattend",
2648 NULL,
2649 &InfContext))
2650 {
2651 DPRINT1("Error: SetupFindFirstLine failed %d\n", GetLastError());
2652 return;
2653 }
2654
2655 do
2656 {
2657 if (!SetupGetStringFieldW(&InfContext,
2658 0,
2659 szName,
2660 ARRAYSIZE(szName),
2661 &LineLength))
2662 {
2663 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2664 return;
2665 }
2666
2667 if (!SetupGetStringFieldW(&InfContext,
2668 1,
2669 szValue,
2670 ARRAYSIZE(szValue),
2671 &LineLength))
2672 {
2673 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2674 return;
2675 }
2676 DPRINT1("Name %S Value %S\n", szName, szValue);
2677 if (!_wcsicmp(szName, L"FullName"))
2678 {
2679 if (ARRAYSIZE(pSetupData->OwnerName) > LineLength)
2680 {
2681 wcscpy(pSetupData->OwnerName, szValue);
2682 }
2683 }
2684 else if (!_wcsicmp(szName, L"OrgName"))
2685 {
2686 if (ARRAYSIZE(pSetupData->OwnerOrganization) > LineLength)
2687 {
2688 wcscpy(pSetupData->OwnerOrganization, szValue);
2689 }
2690 }
2691 else if (!_wcsicmp(szName, L"ComputerName"))
2692 {
2693 if (ARRAYSIZE(pSetupData->ComputerName) > LineLength)
2694 {
2695 wcscpy(pSetupData->ComputerName, szValue);
2696 }
2697 }
2698 else if (!_wcsicmp(szName, L"AdminPassword"))
2699 {
2700 if (ARRAYSIZE(pSetupData->AdminPassword) > LineLength)
2701 {
2702 wcscpy(pSetupData->AdminPassword, szValue);
2703 }
2704 }
2705 else if (!_wcsicmp(szName, L"TimeZoneIndex"))
2706 {
2707 pSetupData->TimeZoneIndex = _wtoi(szValue);
2708 }
2709 else if (!_wcsicmp(szName, L"DisableAutoDaylightTimeSet"))
2710 {
2711 pSetupData->DisableAutoDaylightTimeSet = _wtoi(szValue);
2712 }
2713 else if (!_wcsicmp(szName, L"DisableGeckoInst"))
2714 {
2715 if (!_wcsicmp(szValue, L"yes"))
2716 pSetupData->DisableGeckoInst = TRUE;
2717 else
2718 pSetupData->DisableGeckoInst = FALSE;
2719 }
2720 else if (!_wcsicmp(szName, L"ProductOption"))
2721 {
2722 pSetupData->ProductOption = (PRODUCT_OPTION)_wtoi(szValue);
2723 }
2724 } while (SetupFindNextLine(&InfContext, &InfContext));
2725
2726 if (SetupFindFirstLineW(pSetupData->hSetupInf,
2727 L"Display",
2728 NULL,
2729 &InfContext))
2730 {
2731 DEVMODEW dm = { { 0 } };
2732 dm.dmSize = sizeof(dm);
2733 if (EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dm))
2734 {
2735 do
2736 {
2737 int iValue;
2738 if (!SetupGetStringFieldW(&InfContext,
2739 0,
2740 szName,
2741 ARRAYSIZE(szName),
2742 &LineLength))
2743 {
2744 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2745 return;
2746 }
2747
2748 if (!SetupGetStringFieldW(&InfContext,
2749 1,
2750 szValue,
2751 ARRAYSIZE(szValue),
2752 &LineLength))
2753 {
2754 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2755 return;
2756 }
2757 iValue = _wtoi(szValue);
2758 DPRINT1("Name %S Value %i\n", szName, iValue);
2759
2760 if (!iValue)
2761 continue;
2762
2763 if (!_wcsicmp(szName, L"BitsPerPel"))
2764 {
2765 dm.dmFields |= DM_BITSPERPEL;
2766 dm.dmBitsPerPel = iValue;
2767 }
2768 else if (!_wcsicmp(szName, L"XResolution"))
2769 {
2770 dm.dmFields |= DM_PELSWIDTH;
2771 dm.dmPelsWidth = iValue;
2772 }
2773 else if (!_wcsicmp(szName, L"YResolution"))
2774 {
2775 dm.dmFields |= DM_PELSHEIGHT;
2776 dm.dmPelsHeight = iValue;
2777 }
2778 else if (!_wcsicmp(szName, L"VRefresh"))
2779 {
2780 dm.dmFields |= DM_DISPLAYFREQUENCY;
2781 dm.dmDisplayFrequency = iValue;
2782 }
2783 } while (SetupFindNextLine(&InfContext, &InfContext));
2784
2785 ChangeDisplaySettingsW(&dm, CDS_UPDATEREGISTRY);
2786 }
2787 }
2788
2789 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2790 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
2791 0,
2792 KEY_SET_VALUE,
2793 &hKey) != ERROR_SUCCESS)
2794 {
2795 DPRINT1("Error: failed to open HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\n");
2796 return;
2797 }
2798
2799 if (SetupFindFirstLineW(pSetupData->hSetupInf,
2800 L"GuiRunOnce",
2801 NULL,
2802 &InfContext))
2803 {
2804 int i = 0;
2805 do
2806 {
2807 if (SetupGetStringFieldW(&InfContext,
2808 0,
2809 szValue,
2810 ARRAYSIZE(szValue),
2811 NULL))
2812 {
2813 WCHAR szPath[MAX_PATH];
2814 swprintf(szName, L"%d", i);
2815 DPRINT("szName %S szValue %S\n", szName, szValue);
2816
2817 if (ExpandEnvironmentStringsW(szValue, szPath, MAX_PATH))
2818 {
2819 DPRINT("value %S\n", szPath);
2820 if (RegSetValueExW(hKey,
2821 szName,
2822 0,
2823 REG_SZ,
2824 (const BYTE*)szPath,
2825 (wcslen(szPath) + 1) * sizeof(WCHAR)) == ERROR_SUCCESS)
2826 {
2827 i++;
2828 }
2829 }
2830 }
2831 } while (SetupFindNextLine(&InfContext, &InfContext));
2832 }
2833
2834 RegCloseKey(hKey);
2835
2836 if (SetupFindFirstLineW(pSetupData->hSetupInf,
2837 L"Env",
2838 NULL,
2839 &InfContext))
2840 {
2841 if (RegCreateKeyExW(
2842 HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, NULL,
2843 REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS)
2844 {
2845 DPRINT1("Error: failed to open HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\n");
2846 return;
2847 }
2848 do
2849 {
2850 if (!SetupGetStringFieldW(&InfContext,
2851 0,
2852 szName,
2853 ARRAYSIZE(szName),
2854 &LineLength))
2855 {
2856 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2857 return;
2858 }
2859
2860 if (!SetupGetStringFieldW(&InfContext,
2861 1,
2862 szValue,
2863 ARRAYSIZE(szValue),
2864 &LineLength))
2865 {
2866 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2867 return;
2868 }
2869 DPRINT1("[ENV] %S=%S\n", szName, szValue);
2870
2871 DWORD dwType = wcschr(szValue, '%') != NULL ? REG_EXPAND_SZ : REG_SZ;
2872
2873 if (RegSetValueExW(hKey, szName, 0, dwType, (const BYTE*)szValue, (DWORD)(wcslen(szValue) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS)
2874 {
2875 DPRINT1(" - Error %d\n", GetLastError());
2876 }
2877
2878 } while (SetupFindNextLine(&InfContext, &InfContext));
2879
2880 RegCloseKey(hKey);
2881 }
2882 }
2883
2884 static BOOL
2885 PathIsEqual(
2886 IN LPCWSTR lpPath1,
2887 IN LPCWSTR lpPath2)
2888 {
2889 WCHAR szPath1[MAX_PATH];
2890 WCHAR szPath2[MAX_PATH];
2891
2892 /* If something goes wrong, better return TRUE,
2893 * so the calling function returns early.
2894 */
2895 if (!PathCanonicalizeW(szPath1, lpPath1))
2896 return TRUE;
2897
2898 if (!PathAddBackslashW(szPath1))
2899 return TRUE;
2900
2901 if (!PathCanonicalizeW(szPath2, lpPath2))
2902 return TRUE;
2903
2904 if (!PathAddBackslashW(szPath2))
2905 return TRUE;
2906
2907 return (_wcsicmp(szPath1, szPath2) == 0);
2908 }
2909
2910 static VOID
2911 AddInstallationSource(
2912 IN HKEY hKey,
2913 IN LPWSTR lpPath)
2914 {
2915 LONG res;
2916 DWORD dwRegType;
2917 DWORD dwPathLength = 0;
2918 DWORD dwNewLength = 0;
2919 LPWSTR Buffer = NULL;
2920 LPWSTR Path;
2921
2922 res = RegQueryValueExW(
2923 hKey,
2924 L"Installation Sources",
2925 NULL,
2926 &dwRegType,
2927 NULL,
2928 &dwPathLength);
2929
2930 if (res != ERROR_SUCCESS ||
2931 dwRegType != REG_MULTI_SZ ||
2932 dwPathLength == 0 ||
2933 dwPathLength % sizeof(WCHAR) != 0)
2934 {
2935 dwPathLength = 0;
2936 goto set;
2937 }
2938
2939 /* Reserve space for existing data + new string */
2940 dwNewLength = dwPathLength + (wcslen(lpPath) + 1) * sizeof(WCHAR);
2941 Buffer = HeapAlloc(GetProcessHeap(), 0, dwNewLength);
2942 if (!Buffer)
2943 return;
2944
2945 ZeroMemory(Buffer, dwNewLength);
2946
2947 res = RegQueryValueExW(
2948 hKey,
2949 L"Installation Sources",
2950 NULL,
2951 NULL,
2952 (LPBYTE)Buffer,
2953 &dwPathLength);
2954
2955 if (res != ERROR_SUCCESS)
2956 {
2957 HeapFree(GetProcessHeap(), 0, Buffer);
2958 dwPathLength = 0;
2959 goto set;
2960 }
2961
2962 /* Sanity check, these should already be zeros */
2963 Buffer[dwPathLength / sizeof(WCHAR) - 2] = UNICODE_NULL;
2964 Buffer[dwPathLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
2965
2966 for (Path = Buffer; *Path; Path += wcslen(Path) + 1)
2967 {
2968 /* Check if path is already added */
2969 if (PathIsEqual(Path, lpPath))
2970 goto cleanup;
2971 }
2972
2973 Path = Buffer + dwPathLength / sizeof(WCHAR) - 1;
2974
2975 set:
2976 if (dwPathLength == 0)
2977 {
2978 dwNewLength = (wcslen(lpPath) + 1 + 1) * sizeof(WCHAR);
2979 Buffer = HeapAlloc(GetProcessHeap(), 0, dwNewLength);
2980 if (!Buffer)
2981 return;
2982
2983 Path = Buffer;
2984 }
2985
2986 StringCbCopyW(Path, dwNewLength - (Path - Buffer) * sizeof(WCHAR), lpPath);
2987 Buffer[dwNewLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
2988
2989 RegSetValueExW(
2990 hKey,
2991 L"Installation Sources",
2992 0,
2993 REG_MULTI_SZ,
2994 (LPBYTE)Buffer,
2995 dwNewLength);
2996
2997 cleanup:
2998 HeapFree(GetProcessHeap(), 0, Buffer);
2999 }
3000
3001 VOID
3002 ProcessSetupInf(
3003 IN OUT PSETUPDATA pSetupData)
3004 {
3005 WCHAR szPath[MAX_PATH];
3006 WCHAR szValue[MAX_PATH];
3007 INFCONTEXT InfContext;
3008 DWORD LineLength;
3009 HKEY hKey;
3010 LONG res;
3011
3012 pSetupData->hSetupInf = INVALID_HANDLE_VALUE;
3013
3014 /* Retrieve the path of the setup INF */
3015 GetSystemDirectoryW(szPath, _countof(szPath));
3016 wcscat(szPath, L"\\$winnt$.inf");
3017
3018 /* Open the setup INF */
3019 pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
3020 NULL,
3021 INF_STYLE_OLDNT,
3022 NULL);
3023 if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
3024 {
3025 DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
3026 return;
3027 }
3028
3029
3030 /* Retrieve the NT source path from which the 1st-stage installer was run */
3031 if (!SetupFindFirstLineW(pSetupData->hSetupInf,
3032 L"data",
3033 L"sourcepath",
3034 &InfContext))
3035 {
3036 DPRINT1("Error: Cannot find sourcepath Key! %d\n", GetLastError());
3037 return;
3038 }
3039
3040 if (!SetupGetStringFieldW(&InfContext,
3041 1,
3042 szValue,
3043 ARRAYSIZE(szValue),
3044 &LineLength))
3045 {
3046 DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
3047 return;
3048 }
3049
3050 *pSetupData->SourcePath = UNICODE_NULL;
3051
3052 /* Close the setup INF as we are going to modify it manually */
3053 if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
3054 SetupCloseInfFile(pSetupData->hSetupInf);
3055
3056
3057 /* Find the installation source path in Win32 format */
3058 if (!GetInstallSourceWin32(pSetupData->SourcePath,
3059 _countof(pSetupData->SourcePath),
3060 szValue))
3061 {
3062 *pSetupData->SourcePath = UNICODE_NULL;
3063 }
3064
3065 /* Save the path in Win32 format in the setup INF */
3066 swprintf(szValue, L"\"%s\"", pSetupData->SourcePath);
3067 WritePrivateProfileStringW(L"data", L"dospath", szValue, szPath);
3068
3069 /*
3070 * Save it also in the registry, in the following keys:
3071 * - HKLM\Software\Microsoft\Windows\CurrentVersion\Setup ,
3072 * values "SourcePath" and "ServicePackSourcePath" (REG_SZ);
3073 * - HKLM\Software\Microsoft\Windows NT\CurrentVersion ,
3074 * value "SourcePath" (REG_SZ); set to the full path (e.g. D:\I386).
3075 */
3076 #if 0
3077 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3078 L"Software\\Microsoft\\Windows NT\\CurrentVersion",
3079 0,
3080 KEY_ALL_ACCESS,
3081 &hKey);
3082
3083 if (res != ERROR_SUCCESS)
3084 {
3085 return FALSE;
3086 }
3087 #endif
3088
3089 res = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3090 L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
3091 0, NULL,
3092 REG_OPTION_NON_VOLATILE,
3093 KEY_ALL_ACCESS, // KEY_WRITE
3094 NULL,
3095 &hKey,
3096 NULL);
3097 if (res == ERROR_SUCCESS)
3098 {
3099 AddInstallationSource(hKey, pSetupData->SourcePath);
3100
3101 res = RegSetValueExW(hKey,
3102 L"SourcePath",
3103 0,
3104 REG_SZ,
3105 (LPBYTE)pSetupData->SourcePath,
3106 (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
3107
3108 res = RegSetValueExW(hKey,
3109 L"ServicePackSourcePath",
3110 0,
3111 REG_SZ,
3112 (LPBYTE)pSetupData->SourcePath,
3113 (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
3114
3115 RegCloseKey(hKey);
3116 }
3117
3118
3119 /* Now, re-open the setup INF (this must succeed) */
3120 pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
3121 NULL,
3122 INF_STYLE_OLDNT,
3123 NULL);
3124 if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
3125 {
3126 DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
3127 return;
3128 }
3129
3130 /* Process the unattended section of the setup file */
3131 ProcessUnattendSection(pSetupData);
3132 }
3133
3134 typedef DWORD(WINAPI *PFNREQUESTWIZARDPAGES)(PDWORD, HPROPSHEETPAGE *, PSETUPDATA);
3135
3136 VOID
3137 InstallWizard(VOID)
3138 {
3139 PROPSHEETHEADER psh = {0};
3140 HPROPSHEETPAGE *phpage = NULL;
3141 PROPSHEETPAGE psp = {0};
3142 UINT nPages = 0;
3143 HWND hWnd;
3144 MSG msg;
3145 PSETUPDATA pSetupData = NULL;
3146 HMODULE hNetShell = NULL;
3147 PFNREQUESTWIZARDPAGES pfn = NULL;
3148 DWORD dwPageCount = 10, dwNetworkPageCount = 0;
3149
3150 LogItem(L"BEGIN_SECTION", L"InstallWizard");
3151
3152 /* Allocate setup data */
3153 pSetupData = HeapAlloc(GetProcessHeap(),
3154 HEAP_ZERO_MEMORY,
3155 sizeof(SETUPDATA));
3156 if (pSetupData == NULL)
3157 {
3158 LogItem(NULL, L"SetupData allocation failed!");
3159 MessageBoxW(NULL,
3160 L"Setup failed to allocate global data!",
3161 L"ReactOS Setup",
3162 MB_ICONERROR | MB_OK);
3163 goto done;
3164 }
3165 pSetupData->ProductOption = PRODUCT_OPTION_DEFAULT;
3166
3167 hNetShell = LoadLibraryW(L"netshell.dll");
3168 if (hNetShell != NULL)
3169 {
3170 DPRINT("Netshell.dll loaded!\n");
3171
3172 pfn = (PFNREQUESTWIZARDPAGES)GetProcAddress(hNetShell,
3173 "NetSetupRequestWizardPages");
3174 if (pfn != NULL)
3175 {
3176 pfn(&dwNetworkPageCount, NULL, NULL);
3177 dwPageCount += dwNetworkPageCount;
3178 }
3179 }
3180
3181 DPRINT("PageCount: %lu\n", dwPageCount);
3182
3183 phpage = HeapAlloc(GetProcessHeap(),
3184 HEAP_ZERO_MEMORY,
3185 dwPageCount * sizeof(HPROPSHEETPAGE));
3186 if (phpage == NULL)
3187 {
3188 LogItem(NULL, L"Page array allocation failed!");
3189 MessageBoxW(NULL,
3190 L"Setup failed to allocate page array!",
3191 L"ReactOS Setup",
3192 MB_ICONERROR | MB_OK);
3193 goto done;
3194 }
3195
3196 /* Process the $winnt$.inf setup file */
3197 ProcessSetupInf(pSetupData);
3198
3199 /* Create the Welcome page */
3200 psp.dwSize = sizeof(PROPSHEETPAGE);
3201 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
3202 psp.hInstance = hDllInstance;
3203 psp.lParam = (LPARAM)pSetupData;
3204 psp.pfnDlgProc = WelcomeDlgProc;
3205 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
3206 phpage[nPages++] = CreatePropertySheetPage(&psp);
3207
3208 /* Create the Acknowledgements page */
3209 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3210 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_ACKTITLE);
3211 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_ACKSUBTITLE);
3212 psp.pszTemplate = MAKEINTRESOURCE(IDD_ACKPAGE);
3213 psp.pfnDlgProc = AckPageDlgProc;
3214 phpage[nPages++] = CreatePropertySheetPage(&psp);
3215
3216 /* Create the Product page */
3217 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3218 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_PRODUCTTITLE);
3219 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_PRODUCTSUBTITLE);
3220 psp.pszTemplate = MAKEINTRESOURCE(IDD_PRODUCT);
3221 psp.pfnDlgProc = ProductPageDlgProc;
3222 phpage[nPages++] = CreatePropertySheetPage(&psp);
3223
3224 /* Create the Locale page */
3225 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3226 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_LOCALETITLE);
3227 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LOCALESUBTITLE);
3228 psp.pfnDlgProc = LocalePageDlgProc;
3229 psp.pszTemplate = MAKEINTRESOURCE(IDD_LOCALEPAGE);
3230 phpage[nPages++] = CreatePropertySheetPage(&psp);
3231
3232 /* Create the Owner page */
3233 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3234 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_OWNERTITLE);
3235 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_OWNERSUBTITLE);
3236 psp.pszTemplate = MAKEINTRESOURCE(IDD_OWNERPAGE);
3237 psp.pfnDlgProc = OwnerPageDlgProc;
3238 phpage[nPages++] = CreatePropertySheetPage(&psp);
3239
3240 /* Create the Computer page */
3241 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3242 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_COMPUTERTITLE);
3243 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_COMPUTERSUBTITLE);
3244 psp.pfnDlgProc = ComputerPageDlgProc;
3245 psp.pszTemplate = MAKEINTRESOURCE(IDD_COMPUTERPAGE);
3246 phpage[nPages++] = CreatePropertySheetPage(&psp);
3247
3248 /* Create the DateTime page */
3249 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3250 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_DATETIMETITLE);
3251 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_DATETIMESUBTITLE);
3252 psp.pfnDlgProc = DateTimePageDlgProc;
3253 psp.pszTemplate = MAKEINTRESOURCE(IDD_DATETIMEPAGE);
3254 phpage[nPages++] = CreatePropertySheetPage(&psp);
3255
3256 /* Create the theme selection page */
3257 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3258 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONTITLE);
3259 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONSUBTITLE);
3260 psp.pfnDlgProc = ThemePageDlgProc;
3261 psp.pszTemplate = MAKEINTRESOURCE(IDD_THEMEPAGE);
3262 phpage[nPages++] = CreatePropertySheetPage(&psp);
3263
3264 pSetupData->uFirstNetworkWizardPage = IDD_PROCESSPAGE;
3265 pSetupData->uPostNetworkWizardPage = IDD_PROCESSPAGE;
3266
3267 if (pfn)
3268 {
3269 pfn(&dwNetworkPageCount, &phpage[nPages], pSetupData);
3270 nPages += dwNetworkPageCount;
3271 }
3272
3273 /* Create the Process page */
3274 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
3275 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_PROCESSTITLE);
3276 psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_PROCESSSUBTITLE);
3277 psp.pfnDlgProc = ProcessPageDlgProc;
3278 psp.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSPAGE);
3279 phpage[nPages++] = CreatePropertySheetPage(&psp);
3280
3281 /* Create the Finish page */
3282 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
3283 psp.pfnDlgProc = FinishDlgProc;
3284 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
3285 phpage[nPages++] = CreatePropertySheetPage(&psp);
3286
3287 ASSERT(nPages == dwPageCount);
3288
3289 /* Create the property sheet */
3290 psh.dwSize = sizeof(PROPSHEETHEADER);
3291 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER | PSH_MODELESS;
3292 psh.hInstance = hDllInstance;
3293 psh.hwndParent = NULL;
3294 psh.nPages = nPages;
3295 psh.nStartPage = 0;
3296 psh.phpage = phpage;
3297 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
3298 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
3299
3300 /* Create title font */
3301 pSetupData->hTitleFont = CreateTitleFont();
3302 pSetupData->hBoldFont = CreateBoldFont();
3303
3304 /* Display the wizard */
3305 hWnd = (HWND)PropertySheet(&psh);
3306 ShowWindow(hWnd, SW_SHOW);
3307
3308 while (GetMessage(&msg, NULL, 0, 0))
3309 {
3310 if (!IsDialogMessage(hWnd, &msg))
3311 {
3312 TranslateMessage(&msg);
3313 DispatchMessage(&msg);
3314 }
3315 }
3316
3317 DeleteObject(pSetupData->hBoldFont);
3318 DeleteObject(pSetupData->hTitleFont);
3319
3320 if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
3321 SetupCloseInfFile(pSetupData->hSetupInf);
3322
3323 done:
3324 if (phpage != NULL)
3325 HeapFree(GetProcessHeap(), 0, phpage);
3326
3327 if (hNetShell != NULL)
3328 FreeLibrary(hNetShell);
3329
3330 if (pSetupData != NULL)
3331 HeapFree(GetProcessHeap(), 0, pSetupData);
3332
3333 LogItem(L"END_SECTION", L"InstallWizard");
3334 }
3335
3336 /* EOF */