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