xref: /reactos/dll/win32/syssetup/wizard.c (revision 279107d5)
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 
1597 static INT_PTR CALLBACK
1598 ThemePageDlgProc(HWND hwndDlg,
1599                     UINT uMsg,
1600                     WPARAM wParam,
1601                     LPARAM lParam)
1602 {
1603     PSETUPDATA SetupData;
1604 
1605     /* Retrieve pointer to the global setup data */
1606     SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1607 
1608     switch (uMsg)
1609     {
1610         case WM_INITDIALOG:
1611         {
1612             BUTTON_IMAGELIST imldata = {0, {0,10,0,10}, BUTTON_IMAGELIST_ALIGN_TOP};
1613 
1614             /* Save pointer to the global setup data */
1615             SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1616             SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
1617 
1618             imldata.himl = ImageList_LoadImage(hDllInstance, MAKEINTRESOURCE(IDB_CLASSIC), 0, 0, 0x00FF00FF, IMAGE_BITMAP, LR_CREATEDIBSECTION);
1619             SendDlgItemMessage(hwndDlg, IDC_CLASSICSTYLE, BCM_SETIMAGELIST, 0, (LPARAM)&imldata);
1620 
1621             imldata.himl = ImageList_LoadImage(hDllInstance, MAKEINTRESOURCE(IDB_LAUTUS), 0, 0, 0x00FF00FF , IMAGE_BITMAP, LR_CREATEDIBSECTION);
1622             SendDlgItemMessage(hwndDlg, IDC_THEMEDSTYLE, BCM_SETIMAGELIST, 0, (LPARAM)&imldata);
1623 
1624             SendDlgItemMessage(hwndDlg, IDC_CLASSICSTYLE, BM_SETCHECK, BST_CHECKED, 0);
1625             break;
1626         }
1627         case WM_COMMAND:
1628             if (HIWORD(wParam) == BN_CLICKED)
1629             {
1630                 switch (LOWORD(wParam))
1631                 {
1632                     case IDC_THEMEDSTYLE:
1633                     {
1634                         WCHAR wszParams[1024];
1635                         WCHAR wszTheme[MAX_PATH];
1636                         WCHAR* format = L"desk.cpl desk,@Appearance /Action:ActivateMSTheme /file:\"%s\"";
1637 
1638                         SHGetFolderPathAndSubDirW(0, CSIDL_RESOURCES, NULL, SHGFP_TYPE_DEFAULT, L"themes\\lautus\\lautus.msstyles", wszTheme);
1639                         swprintf(wszParams, format, wszTheme);
1640                         RunControlPanelApplet(hwndDlg, wszParams);
1641                         break;
1642                     }
1643                     case IDC_CLASSICSTYLE:
1644                         RunControlPanelApplet(hwndDlg, L"desk.cpl desk,@Appearance /Action:ActivateMSTheme");
1645                         break;
1646                 }
1647             }
1648         case WM_NOTIFY:
1649             switch (((LPNMHDR)lParam)->code)
1650             {
1651                 case PSN_SETACTIVE:
1652                     /* Enable the Back and Next buttons */
1653                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
1654                     if (SetupData->UnattendSetup)
1655                     {
1656                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SetupData->uFirstNetworkWizardPage);
1657                         return TRUE;
1658                     }
1659                     break;
1660 
1661                 case PSN_WIZNEXT:
1662                     break;
1663 
1664                 case PSN_WIZBACK:
1665                     SetupData->UnattendSetup = FALSE;
1666                     break;
1667 
1668                 default:
1669                     break;
1670             }
1671             break;
1672 
1673         default:
1674             break;
1675     }
1676 
1677     return FALSE;
1678 }
1679 
1680 static UINT CALLBACK
1681 RegistrationNotificationProc(PVOID Context,
1682                              UINT Notification,
1683                              UINT_PTR Param1,
1684                              UINT_PTR Param2)
1685 {
1686     PREGISTRATIONDATA RegistrationData;
1687     REGISTRATIONNOTIFY RegistrationNotify;
1688     PSP_REGISTER_CONTROL_STATUSW StatusInfo;
1689     UINT MessageID;
1690     WCHAR ErrorMessage[128];
1691 
1692     RegistrationData = (PREGISTRATIONDATA) Context;
1693 
1694     if (SPFILENOTIFY_STARTREGISTRATION == Notification ||
1695             SPFILENOTIFY_ENDREGISTRATION == Notification)
1696     {
1697         StatusInfo = (PSP_REGISTER_CONTROL_STATUSW) Param1;
1698         RegistrationNotify.CurrentItem = wcsrchr(StatusInfo->FileName, L'\\');
1699         if (NULL == RegistrationNotify.CurrentItem)
1700         {
1701             RegistrationNotify.CurrentItem = StatusInfo->FileName;
1702         }
1703         else
1704         {
1705             RegistrationNotify.CurrentItem++;
1706         }
1707 
1708         if (SPFILENOTIFY_STARTREGISTRATION == Notification)
1709         {
1710             DPRINT("Received SPFILENOTIFY_STARTREGISTRATION notification for %S\n",
1711                    StatusInfo->FileName);
1712             RegistrationNotify.ErrorMessage = NULL;
1713             RegistrationNotify.Progress = RegistrationData->Registered;
1714         }
1715         else
1716         {
1717             DPRINT("Received SPFILENOTIFY_ENDREGISTRATION notification for %S\n",
1718                    StatusInfo->FileName);
1719             DPRINT("Win32Error %u FailureCode %u\n", StatusInfo->Win32Error,
1720                    StatusInfo->FailureCode);
1721             if (SPREG_SUCCESS != StatusInfo->FailureCode)
1722             {
1723                 switch(StatusInfo->FailureCode)
1724                 {
1725                     case SPREG_LOADLIBRARY:
1726                         MessageID = IDS_LOADLIBRARY_FAILED;
1727                         break;
1728                     case SPREG_GETPROCADDR:
1729                         MessageID = IDS_GETPROCADDR_FAILED;
1730                         break;
1731                     case SPREG_REGSVR:
1732                         MessageID = IDS_REGSVR_FAILED;
1733                         break;
1734                     case SPREG_DLLINSTALL:
1735                         MessageID = IDS_DLLINSTALL_FAILED;
1736                         break;
1737                     case SPREG_TIMEOUT:
1738                         MessageID = IDS_TIMEOUT;
1739                         break;
1740                     default:
1741                         MessageID = IDS_REASON_UNKNOWN;
1742                         break;
1743                 }
1744                 if (0 == LoadStringW(hDllInstance, MessageID,
1745                                      ErrorMessage,
1746                                      ARRAYSIZE(ErrorMessage)))
1747                 {
1748                     ErrorMessage[0] = L'\0';
1749                 }
1750                 if (SPREG_TIMEOUT != StatusInfo->FailureCode)
1751                 {
1752                     FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1753                                    StatusInfo->Win32Error, 0,
1754                                    ErrorMessage + wcslen(ErrorMessage),
1755                                    ARRAYSIZE(ErrorMessage) - wcslen(ErrorMessage),
1756                                    NULL);
1757                 }
1758                 RegistrationNotify.ErrorMessage = ErrorMessage;
1759             }
1760             else
1761             {
1762                 RegistrationNotify.ErrorMessage = NULL;
1763             }
1764             if (RegistrationData->Registered < RegistrationData->DllCount)
1765             {
1766                 RegistrationData->Registered++;
1767             }
1768         }
1769 
1770         RegistrationNotify.Progress = RegistrationData->Registered;
1771         RegistrationNotify.ActivityID = IDS_REGISTERING_COMPONENTS;
1772         SendMessage(RegistrationData->hwndDlg, PM_REGISTRATION_NOTIFY,
1773                     0, (LPARAM) &RegistrationNotify);
1774 
1775         return FILEOP_DOIT;
1776     }
1777     else
1778     {
1779         DPRINT1("Received unexpected notification %u\n", Notification);
1780         return SetupDefaultQueueCallback(RegistrationData->DefaultContext,
1781                                          Notification, Param1, Param2);
1782     }
1783 }
1784 
1785 
1786 static DWORD CALLBACK
1787 RegistrationProc(LPVOID Parameter)
1788 {
1789     PREGISTRATIONDATA RegistrationData;
1790     REGISTRATIONNOTIFY RegistrationNotify;
1791     DWORD LastError = NO_ERROR;
1792     WCHAR UnknownError[84];
1793 
1794     RegistrationData = (PREGISTRATIONDATA) Parameter;
1795     RegistrationData->Registered = 0;
1796     RegistrationData->DefaultContext = SetupInitDefaultQueueCallback(RegistrationData->hwndDlg);
1797 
1798     _SEH2_TRY
1799     {
1800         if (!SetupInstallFromInfSectionW(GetParent(RegistrationData->hwndDlg),
1801         hSysSetupInf,
1802         L"RegistrationPhase2",
1803         SPINST_REGISTRY |
1804         SPINST_REGISTERCALLBACKAWARE  |
1805         SPINST_REGSVR,
1806         0,
1807         NULL,
1808         0,
1809         RegistrationNotificationProc,
1810         RegistrationData,
1811         NULL,
1812         NULL))
1813         {
1814             LastError = GetLastError();
1815         }
1816     }
1817     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1818     {
1819         DPRINT("Catching exception\n");
1820         LastError = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
1821     }
1822     _SEH2_END;
1823 
1824     if (NO_ERROR == LastError)
1825     {
1826         RegistrationNotify.ErrorMessage = NULL;
1827     }
1828     else
1829     {
1830         DPRINT1("SetupInstallFromInfSection failed with error %u\n",
1831                 LastError);
1832         if (0 == FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1833                                 FORMAT_MESSAGE_FROM_SYSTEM, NULL, LastError, 0,
1834                                 (LPWSTR) &RegistrationNotify.ErrorMessage, 0,
1835                                 NULL))
1836         {
1837             if (0 == LoadStringW(hDllInstance, IDS_UNKNOWN_ERROR,
1838                                  UnknownError,
1839                                  ARRAYSIZE(UnknownError) - 20))
1840             {
1841                 wcscpy(UnknownError, L"Unknown error");
1842             }
1843             wcscat(UnknownError, L" ");
1844             _ultow(LastError, UnknownError + wcslen(UnknownError), 10);
1845             RegistrationNotify.ErrorMessage = UnknownError;
1846         }
1847     }
1848 
1849     RegistrationNotify.Progress = RegistrationData->DllCount;
1850     RegistrationNotify.ActivityID = IDS_REGISTERING_COMPONENTS;
1851     RegistrationNotify.CurrentItem = NULL;
1852     SendMessage(RegistrationData->hwndDlg, PM_REGISTRATION_NOTIFY,
1853                 1, (LPARAM) &RegistrationNotify);
1854     if (NULL != RegistrationNotify.ErrorMessage &&
1855             UnknownError != RegistrationNotify.ErrorMessage)
1856     {
1857         LocalFree((PVOID) RegistrationNotify.ErrorMessage);
1858     }
1859 
1860     SetupTermDefaultQueueCallback(RegistrationData->DefaultContext);
1861     HeapFree(GetProcessHeap(), 0, RegistrationData);
1862 
1863     RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
1864 
1865     // FIXME: Move this call to a separate cleanup page!
1866     RtlCreateBootStatusDataFile();
1867 
1868     return 0;
1869 }
1870 
1871 
1872 static BOOL
1873 StartComponentRegistration(HWND hwndDlg, PULONG MaxProgress)
1874 {
1875     HANDLE RegistrationThread;
1876     LONG DllCount;
1877     INFCONTEXT Context;
1878     WCHAR SectionName[512];
1879     PREGISTRATIONDATA RegistrationData;
1880 
1881     DllCount = -1;
1882     if (!SetupFindFirstLineW(hSysSetupInf, L"RegistrationPhase2",
1883                              L"RegisterDlls", &Context))
1884     {
1885         DPRINT1("No RegistrationPhase2 section found\n");
1886         return FALSE;
1887     }
1888     if (!SetupGetStringFieldW(&Context, 1, SectionName,
1889                               ARRAYSIZE(SectionName),
1890                               NULL))
1891     {
1892         DPRINT1("Unable to retrieve section name\n");
1893         return FALSE;
1894     }
1895     DllCount = SetupGetLineCountW(hSysSetupInf, SectionName);
1896     DPRINT("SectionName %S DllCount %ld\n", SectionName, DllCount);
1897     if (DllCount < 0)
1898     {
1899         SetLastError(STATUS_NOT_FOUND);
1900         return FALSE;
1901     }
1902 
1903     *MaxProgress = (ULONG) DllCount;
1904 
1905     /*
1906      * Create a background thread to do the actual registrations, so the
1907      * main thread can just run its message loop.
1908      */
1909     RegistrationThread = NULL;
1910     RegistrationData = HeapAlloc(GetProcessHeap(), 0,
1911                                  sizeof(REGISTRATIONDATA));
1912     if (RegistrationData != NULL)
1913     {
1914         RegistrationData->hwndDlg = hwndDlg;
1915         RegistrationData->DllCount = DllCount;
1916         RegistrationThread = CreateThread(NULL, 0, RegistrationProc,
1917                                           RegistrationData, 0, NULL);
1918         if (RegistrationThread != NULL)
1919         {
1920             CloseHandle(RegistrationThread);
1921         }
1922         else
1923         {
1924             DPRINT1("CreateThread failed, error %u\n", GetLastError());
1925             HeapFree(GetProcessHeap(), 0, RegistrationData);
1926             return FALSE;
1927         }
1928     }
1929     else
1930     {
1931         DPRINT1("HeapAlloc() failed, error %u\n", GetLastError());
1932         return FALSE;
1933     }
1934 
1935     return TRUE;
1936 }
1937 
1938 
1939 static INT_PTR CALLBACK
1940 ProcessPageDlgProc(HWND hwndDlg,
1941                    UINT uMsg,
1942                    WPARAM wParam,
1943                    LPARAM lParam)
1944 {
1945     PSETUPDATA SetupData;
1946     PREGISTRATIONNOTIFY RegistrationNotify;
1947     static UINT oldActivityID = -1;
1948     WCHAR Title[64];
1949 
1950     /* Retrieve pointer to the global setup data */
1951     SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1952 
1953     switch (uMsg)
1954     {
1955         case WM_INITDIALOG:
1956         {
1957             /* Save pointer to the global setup data */
1958             SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
1959             SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
1960         }
1961         break;
1962 
1963         case WM_NOTIFY:
1964         {
1965             LPNMHDR lpnm = (LPNMHDR)lParam;
1966             ULONG MaxProgress = 0;
1967 
1968             switch (lpnm->code)
1969             {
1970                 case PSN_SETACTIVE:
1971                     /* Disable the Back and Next buttons */
1972                     PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
1973 
1974                     StartComponentRegistration(hwndDlg, &MaxProgress);
1975 
1976                     SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETRANGE,
1977                                        0, MAKELPARAM(0, MaxProgress));
1978                     SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETPOS,
1979                                        0, 0);
1980                     break;
1981 
1982                 case PSN_WIZNEXT:
1983                     break;
1984 
1985                 case PSN_WIZBACK:
1986                     SetupData->UnattendSetup = FALSE;
1987                     break;
1988 
1989                 default:
1990                     break;
1991             }
1992         }
1993         break;
1994 
1995         case PM_REGISTRATION_NOTIFY:
1996         {
1997             WCHAR Activity[64];
1998             RegistrationNotify = (PREGISTRATIONNOTIFY) lParam;
1999             // update if necessary only
2000             if (oldActivityID != RegistrationNotify->ActivityID)
2001             {
2002                 if (0 != LoadStringW(hDllInstance, RegistrationNotify->ActivityID,
2003                                      Activity,
2004                                      ARRAYSIZE(Activity)))
2005                 {
2006                     SendDlgItemMessageW(hwndDlg, IDC_ACTIVITY, WM_SETTEXT,
2007                                         0, (LPARAM) Activity);
2008                 }
2009                 oldActivityID = RegistrationNotify->ActivityID;
2010             }
2011             SendDlgItemMessageW(hwndDlg, IDC_ITEM, WM_SETTEXT, 0,
2012                                 (LPARAM)(NULL == RegistrationNotify->CurrentItem ?
2013                                          L"" : RegistrationNotify->CurrentItem));
2014             SendDlgItemMessage(hwndDlg, IDC_PROCESSPROGRESS, PBM_SETPOS,
2015                                RegistrationNotify->Progress, 0);
2016             if (NULL != RegistrationNotify->ErrorMessage)
2017             {
2018                 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP,
2019                                      Title, ARRAYSIZE(Title)))
2020                 {
2021                     wcscpy(Title, L"ReactOS Setup");
2022                 }
2023                 MessageBoxW(hwndDlg, RegistrationNotify->ErrorMessage,
2024                             Title, MB_ICONERROR | MB_OK);
2025 
2026             }
2027 
2028             if (wParam)
2029             {
2030                 /* Enable the Back and Next buttons */
2031                 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
2032                 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
2033             }
2034         }
2035         return TRUE;
2036 
2037         default:
2038             break;
2039     }
2040 
2041     return FALSE;
2042 }
2043 
2044 
2045 static VOID
2046 SetInstallationCompleted(VOID)
2047 {
2048     HKEY hKey = 0;
2049     DWORD InProgress = 0;
2050     DWORD InstallDate;
2051 
2052     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
2053                        L"SYSTEM\\Setup",
2054                        0,
2055                        KEY_WRITE,
2056                        &hKey ) == ERROR_SUCCESS)
2057     {
2058         RegSetValueExW( hKey, L"SystemSetupInProgress", 0, REG_DWORD, (LPBYTE)&InProgress, sizeof(InProgress) );
2059         RegCloseKey( hKey );
2060     }
2061 
2062     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
2063                        L"Software\\Microsoft\\Windows NT\\CurrentVersion",
2064                        0,
2065                        KEY_WRITE,
2066                        &hKey ) == ERROR_SUCCESS)
2067     {
2068         InstallDate = (DWORD)time(NULL);
2069         RegSetValueExW( hKey, L"InstallDate", 0, REG_DWORD, (LPBYTE)&InstallDate, sizeof(InstallDate) );
2070         RegCloseKey( hKey );
2071     }
2072 }
2073 
2074 static INT_PTR CALLBACK
2075 FinishDlgProc(HWND hwndDlg,
2076               UINT uMsg,
2077               WPARAM wParam,
2078               LPARAM lParam)
2079 {
2080 
2081     switch (uMsg)
2082     {
2083         case WM_INITDIALOG:
2084         {
2085             /* Get pointer to the global setup data */
2086             PSETUPDATA SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
2087 
2088             if (!SetupData->UnattendSetup || !SetupData->DisableGeckoInst)
2089             {
2090                 /* Run the Wine Gecko prompt */
2091                 Control_RunDLLW(hwndDlg, 0, L"appwiz.cpl install_gecko", SW_SHOW);
2092             }
2093 
2094             /* Set title font */
2095             SendDlgItemMessage(hwndDlg,
2096                                IDC_FINISHTITLE,
2097                                WM_SETFONT,
2098                                (WPARAM)SetupData->hTitleFont,
2099                                (LPARAM)TRUE);
2100             if (SetupData->UnattendSetup)
2101             {
2102                 KillTimer(hwndDlg, 1);
2103                 SetInstallationCompleted();
2104                 PostQuitMessage(0);
2105             }
2106         }
2107         break;
2108 
2109         case WM_DESTROY:
2110         {
2111             SetInstallationCompleted();
2112             PostQuitMessage(0);
2113             return TRUE;
2114         }
2115 
2116         case WM_TIMER:
2117         {
2118             INT Position;
2119             HWND hWndProgress;
2120 
2121             hWndProgress = GetDlgItem(hwndDlg, IDC_RESTART_PROGRESS);
2122             Position = SendMessage(hWndProgress, PBM_GETPOS, 0, 0);
2123             if (Position == 300)
2124             {
2125                 KillTimer(hwndDlg, 1);
2126                 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_FINISH);
2127             }
2128             else
2129             {
2130                 SendMessage(hWndProgress, PBM_SETPOS, Position + 1, 0);
2131             }
2132         }
2133         return TRUE;
2134 
2135         case WM_NOTIFY:
2136         {
2137             LPNMHDR lpnm = (LPNMHDR)lParam;
2138 
2139             switch (lpnm->code)
2140             {
2141                 case PSN_SETACTIVE:
2142                     /* Enable the correct buttons on for the active page */
2143                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
2144 
2145                     SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETRANGE, 0,
2146                                        MAKELPARAM(0, 300));
2147                     SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETPOS, 0, 0);
2148                     SetTimer(hwndDlg, 1, 50, NULL);
2149                     break;
2150 
2151                 case PSN_WIZFINISH:
2152                     DestroyWindow(GetParent(hwndDlg));
2153                     break;
2154 
2155                 default:
2156                     break;
2157             }
2158         }
2159         break;
2160 
2161         default:
2162             break;
2163     }
2164 
2165     return FALSE;
2166 }
2167 
2168 
2169 /*
2170  * GetInstallSourceWin32 retrieves the path to the ReactOS installation medium
2171  * in Win32 format, for later use by syssetup and storage in the registry.
2172  */
2173 static BOOL
2174 GetInstallSourceWin32(
2175     OUT PWSTR pwszPath,
2176     IN DWORD cchPathMax,
2177     IN PCWSTR pwszNTPath)
2178 {
2179     WCHAR wszDrives[512];
2180     WCHAR wszNTPath[512]; // MAX_PATH ?
2181     DWORD cchDrives;
2182     PWCHAR pwszDrive;
2183 
2184     *pwszPath = UNICODE_NULL;
2185 
2186     cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
2187     if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
2188     {
2189         /* Buffer too small or failure */
2190         LogItem(NULL, L"GetLogicalDriveStringsW failed");
2191         return FALSE;
2192     }
2193 
2194     for (pwszDrive = wszDrives; *pwszDrive; pwszDrive += wcslen(pwszDrive) + 1)
2195     {
2196         WCHAR wszBuf[MAX_PATH];
2197 
2198         /* Retrieve the NT path corresponding to the current Win32 DOS path */
2199         pwszDrive[2] = UNICODE_NULL; // Temporarily remove the backslash
2200         QueryDosDeviceW(pwszDrive, wszNTPath, _countof(wszNTPath));
2201         pwszDrive[2] = L'\\';        // Restore the backslash
2202 
2203         wcscat(wszNTPath, L"\\");    // Concat a backslash
2204 
2205         /* Logging */
2206         wsprintf(wszBuf, L"Testing '%s' --> '%s' %s a CD",
2207                  pwszDrive, wszNTPath,
2208                  (GetDriveTypeW(pwszDrive) == DRIVE_CDROM) ? L"is" : L"is not");
2209         LogItem(NULL, wszBuf);
2210 
2211         /* Check whether the NT path corresponds to the NT installation source path */
2212         if (!_wcsicmp(wszNTPath, pwszNTPath))
2213         {
2214             /* Found it! */
2215             wcscpy(pwszPath, pwszDrive); // cchPathMax
2216 
2217             /* Logging */
2218             wsprintf(wszBuf, L"GetInstallSourceWin32: %s", pwszPath);
2219             LogItem(NULL, wszBuf);
2220             wcscat(wszBuf, L"\n");
2221             OutputDebugStringW(wszBuf);
2222 
2223             return TRUE;
2224         }
2225     }
2226 
2227     return FALSE;
2228 }
2229 
2230 VOID
2231 ProcessUnattendSection(
2232     IN OUT PSETUPDATA pSetupData)
2233 {
2234     INFCONTEXT InfContext;
2235     WCHAR szName[256];
2236     WCHAR szValue[MAX_PATH];
2237     DWORD LineLength;
2238     HKEY hKey;
2239 
2240     if (!SetupFindFirstLineW(pSetupData->hSetupInf,
2241                              L"Unattend",
2242                              L"UnattendSetupEnabled",
2243                              &InfContext))
2244     {
2245         DPRINT1("Error: Cannot find UnattendSetupEnabled Key! %d\n", GetLastError());
2246         return;
2247     }
2248 
2249     if (!SetupGetStringFieldW(&InfContext,
2250                               1,
2251                               szValue,
2252                               ARRAYSIZE(szValue),
2253                               &LineLength))
2254     {
2255         DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2256         return;
2257     }
2258 
2259     if (_wcsicmp(szValue, L"yes") != 0)
2260     {
2261         DPRINT("Unattend setup was disabled by UnattendSetupEnabled key.\n");
2262         return;
2263     }
2264 
2265     pSetupData->UnattendSetup = TRUE;
2266 
2267     if (!SetupFindFirstLineW(pSetupData->hSetupInf,
2268                              L"Unattend",
2269                              NULL,
2270                              &InfContext))
2271     {
2272         DPRINT1("Error: SetupFindFirstLine failed %d\n", GetLastError());
2273         return;
2274     }
2275 
2276     do
2277     {
2278         if (!SetupGetStringFieldW(&InfContext,
2279                                   0,
2280                                   szName,
2281                                   ARRAYSIZE(szName),
2282                                   &LineLength))
2283         {
2284             DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2285             return;
2286         }
2287 
2288         if (!SetupGetStringFieldW(&InfContext,
2289                                   1,
2290                                   szValue,
2291                                   ARRAYSIZE(szValue),
2292                                   &LineLength))
2293         {
2294             DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2295             return;
2296         }
2297         DPRINT1("Name %S Value %S\n", szName, szValue);
2298         if (!_wcsicmp(szName, L"FullName"))
2299         {
2300             if (ARRAYSIZE(pSetupData->OwnerName) > LineLength)
2301             {
2302                 wcscpy(pSetupData->OwnerName, szValue);
2303             }
2304         }
2305         else if (!_wcsicmp(szName, L"OrgName"))
2306         {
2307             if (ARRAYSIZE(pSetupData->OwnerOrganization) > LineLength)
2308             {
2309                 wcscpy(pSetupData->OwnerOrganization, szValue);
2310             }
2311         }
2312         else if (!_wcsicmp(szName, L"ComputerName"))
2313         {
2314             if (ARRAYSIZE(pSetupData->ComputerName) > LineLength)
2315             {
2316                 wcscpy(pSetupData->ComputerName, szValue);
2317             }
2318         }
2319         else if (!_wcsicmp(szName, L"AdminPassword"))
2320         {
2321             if (ARRAYSIZE(pSetupData->AdminPassword) > LineLength)
2322             {
2323                 wcscpy(pSetupData->AdminPassword, szValue);
2324             }
2325         }
2326         else if (!_wcsicmp(szName, L"TimeZoneIndex"))
2327         {
2328             pSetupData->TimeZoneIndex = _wtoi(szValue);
2329         }
2330         else if (!_wcsicmp(szName, L"DisableAutoDaylightTimeSet"))
2331         {
2332             pSetupData->DisableAutoDaylightTimeSet = _wtoi(szValue);
2333         }
2334         else if (!_wcsicmp(szName, L"DisableGeckoInst"))
2335         {
2336             if (!_wcsicmp(szValue, L"yes"))
2337                 pSetupData->DisableGeckoInst = TRUE;
2338             else
2339                 pSetupData->DisableGeckoInst = FALSE;
2340         }
2341 
2342     } while (SetupFindNextLine(&InfContext, &InfContext));
2343 
2344     if (SetupFindFirstLineW(pSetupData->hSetupInf,
2345                             L"Display",
2346                             NULL,
2347                             &InfContext))
2348     {
2349         DEVMODEW dm = { { 0 } };
2350         dm.dmSize = sizeof(dm);
2351         if (EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dm))
2352         {
2353             do
2354             {
2355                 int iValue;
2356                 if (!SetupGetStringFieldW(&InfContext,
2357                                           0,
2358                                           szName,
2359                                           ARRAYSIZE(szName),
2360                                           &LineLength))
2361                 {
2362                     DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2363                     return;
2364                 }
2365 
2366                 if (!SetupGetStringFieldW(&InfContext,
2367                                           1,
2368                                           szValue,
2369                                           ARRAYSIZE(szValue),
2370                                           &LineLength))
2371                 {
2372                     DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2373                     return;
2374                 }
2375                 iValue = _wtoi(szValue);
2376                 DPRINT1("Name %S Value %i\n", szName, iValue);
2377 
2378                 if (!iValue)
2379                     continue;
2380 
2381                 if (!_wcsicmp(szName, L"BitsPerPel"))
2382                 {
2383                     dm.dmFields |= DM_BITSPERPEL;
2384                     dm.dmBitsPerPel = iValue;
2385                 }
2386                 else if (!_wcsicmp(szName, L"XResolution"))
2387                 {
2388                     dm.dmFields |= DM_PELSWIDTH;
2389                     dm.dmPelsWidth = iValue;
2390                 }
2391                 else if (!_wcsicmp(szName, L"YResolution"))
2392                 {
2393                     dm.dmFields |= DM_PELSHEIGHT;
2394                     dm.dmPelsHeight = iValue;
2395                 }
2396                 else if (!_wcsicmp(szName, L"VRefresh"))
2397                 {
2398                     dm.dmFields |= DM_DISPLAYFREQUENCY;
2399                     dm.dmDisplayFrequency = iValue;
2400                 }
2401             } while (SetupFindNextLine(&InfContext, &InfContext));
2402 
2403             ChangeDisplaySettingsW(&dm, CDS_UPDATEREGISTRY);
2404         }
2405     }
2406 
2407     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2408                       L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
2409                       0,
2410                       KEY_SET_VALUE,
2411                       &hKey) != ERROR_SUCCESS)
2412     {
2413         DPRINT1("Error: failed to open HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\n");
2414         return;
2415     }
2416 
2417     if (SetupFindFirstLineW(pSetupData->hSetupInf,
2418                             L"GuiRunOnce",
2419                             NULL,
2420                             &InfContext))
2421     {
2422         int i = 0;
2423         do
2424         {
2425             if (SetupGetStringFieldW(&InfContext,
2426                                      0,
2427                                      szValue,
2428                                      ARRAYSIZE(szValue),
2429                                      NULL))
2430             {
2431                 WCHAR szPath[MAX_PATH];
2432                 swprintf(szName, L"%d", i);
2433                 DPRINT("szName %S szValue %S\n", szName, szValue);
2434 
2435                 if (ExpandEnvironmentStringsW(szValue, szPath, MAX_PATH))
2436                 {
2437                     DPRINT("value %S\n", szPath);
2438                     if (RegSetValueExW(hKey,
2439                                        szName,
2440                                        0,
2441                                        REG_SZ,
2442                                        (const BYTE*)szPath,
2443                                        (wcslen(szPath) + 1) * sizeof(WCHAR)) == ERROR_SUCCESS)
2444                     {
2445                         i++;
2446                     }
2447                 }
2448             }
2449         } while (SetupFindNextLine(&InfContext, &InfContext));
2450     }
2451 
2452     RegCloseKey(hKey);
2453 }
2454 
2455 VOID
2456 ProcessSetupInf(
2457     IN OUT PSETUPDATA pSetupData)
2458 {
2459     WCHAR szPath[MAX_PATH];
2460     WCHAR szValue[MAX_PATH];
2461     INFCONTEXT InfContext;
2462     DWORD LineLength;
2463     HKEY hKey;
2464     LONG res;
2465 
2466     pSetupData->hSetupInf = INVALID_HANDLE_VALUE;
2467 
2468     /* Retrieve the path of the setup INF */
2469     GetSystemDirectoryW(szPath, _countof(szPath));
2470     wcscat(szPath, L"\\$winnt$.inf");
2471 
2472     /* Open the setup INF */
2473     pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
2474                                               NULL,
2475                                               INF_STYLE_OLDNT,
2476                                               NULL);
2477     if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
2478     {
2479         DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
2480         return;
2481     }
2482 
2483 
2484     /* Retrieve the NT source path from which the 1st-stage installer was run */
2485     if (!SetupFindFirstLineW(pSetupData->hSetupInf,
2486                              L"data",
2487                              L"sourcepath",
2488                              &InfContext))
2489     {
2490         DPRINT1("Error: Cannot find UnattendSetupEnabled Key! %d\n", GetLastError());
2491         return;
2492     }
2493 
2494     if (!SetupGetStringFieldW(&InfContext,
2495                               1,
2496                               szValue,
2497                               ARRAYSIZE(szValue),
2498                               &LineLength))
2499     {
2500         DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
2501         return;
2502     }
2503 
2504     *pSetupData->SourcePath = UNICODE_NULL;
2505 
2506     /* Close the setup INF as we are going to modify it manually */
2507     if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
2508         SetupCloseInfFile(pSetupData->hSetupInf);
2509 
2510 
2511     /* Find the installation source path in Win32 format */
2512     if (!GetInstallSourceWin32(pSetupData->SourcePath,
2513                                _countof(pSetupData->SourcePath),
2514                                szValue))
2515     {
2516         *pSetupData->SourcePath = UNICODE_NULL;
2517     }
2518 
2519     /* Save the path in Win32 format in the setup INF */
2520     swprintf(szValue, L"\"%s\"", pSetupData->SourcePath);
2521     WritePrivateProfileStringW(L"data", L"dospath", szValue, szPath);
2522 
2523     /*
2524      * Save it also in the registry, in the following keys:
2525      * - HKLM\Software\Microsoft\Windows\CurrentVersion\Setup ,
2526      *   values "SourcePath" and "ServicePackSourcePath" (REG_SZ);
2527      * - HKLM\Software\Microsoft\Windows NT\CurrentVersion ,
2528      *   value "SourcePath" (REG_SZ); set to the full path (e.g. D:\I386).
2529      */
2530 #if 0
2531     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2532                         L"Software\\Microsoft\\Windows NT\\CurrentVersion",
2533                         0,
2534                         KEY_ALL_ACCESS,
2535                         &hKey);
2536 
2537     if (res != ERROR_SUCCESS)
2538     {
2539         return FALSE;
2540     }
2541 #endif
2542 
2543     res = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
2544                           L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
2545                           0, NULL,
2546                           REG_OPTION_NON_VOLATILE,
2547                           KEY_ALL_ACCESS, // KEY_WRITE
2548                           NULL,
2549                           &hKey,
2550                           NULL);
2551     if (res == ERROR_SUCCESS)
2552     {
2553         res = RegSetValueExW(hKey,
2554                              L"SourcePath",
2555                              0,
2556                              REG_SZ,
2557                              (LPBYTE)pSetupData->SourcePath,
2558                              (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
2559 
2560         res = RegSetValueExW(hKey,
2561                              L"ServicePackSourcePath",
2562                              0,
2563                              REG_SZ,
2564                              (LPBYTE)pSetupData->SourcePath,
2565                              (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
2566 
2567         RegCloseKey(hKey);
2568     }
2569 
2570 
2571     /* Now, re-open the setup INF (this must succeed) */
2572     pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
2573                                               NULL,
2574                                               INF_STYLE_OLDNT,
2575                                               NULL);
2576     if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
2577     {
2578         DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
2579         return;
2580     }
2581 
2582     /* Process the unattended section of the setup file */
2583     ProcessUnattendSection(pSetupData);
2584 }
2585 
2586 typedef DWORD(WINAPI *PFNREQUESTWIZARDPAGES)(PDWORD, HPROPSHEETPAGE *, PSETUPDATA);
2587 
2588 VOID
2589 InstallWizard(VOID)
2590 {
2591     PROPSHEETHEADER psh;
2592     HPROPSHEETPAGE *phpage = NULL;
2593     PROPSHEETPAGE psp = {0};
2594     UINT nPages = 0;
2595     HWND hWnd;
2596     MSG msg;
2597     PSETUPDATA pSetupData = NULL;
2598     HMODULE hNetShell = NULL;
2599     PFNREQUESTWIZARDPAGES pfn = NULL;
2600     DWORD dwPageCount = 9, dwNetworkPageCount = 0;
2601 
2602     LogItem(L"BEGIN_SECTION", L"InstallWizard");
2603 
2604     /* Allocate setup data */
2605     pSetupData = HeapAlloc(GetProcessHeap(),
2606                            HEAP_ZERO_MEMORY,
2607                            sizeof(SETUPDATA));
2608     if (pSetupData == NULL)
2609     {
2610         LogItem(NULL, L"SetupData allocation failed!");
2611         MessageBoxW(NULL,
2612                     L"Setup failed to allocate global data!",
2613                     L"ReactOS Setup",
2614                     MB_ICONERROR | MB_OK);
2615         goto done;
2616     }
2617 
2618     hNetShell = LoadLibraryW(L"netshell.dll");
2619     if (hNetShell != NULL)
2620     {
2621         DPRINT("Netshell.dll loaded!\n");
2622 
2623         pfn = (PFNREQUESTWIZARDPAGES)GetProcAddress(hNetShell,
2624                                                     "NetSetupRequestWizardPages");
2625         if (pfn != NULL)
2626         {
2627             pfn(&dwNetworkPageCount, NULL, NULL);
2628             dwPageCount += dwNetworkPageCount;
2629         }
2630     }
2631 
2632     DPRINT("PageCount: %lu\n", dwPageCount);
2633 
2634     phpage = HeapAlloc(GetProcessHeap(),
2635                        HEAP_ZERO_MEMORY,
2636                        dwPageCount * sizeof(HPROPSHEETPAGE));
2637     if (phpage == NULL)
2638     {
2639         LogItem(NULL, L"Page array allocation failed!");
2640         MessageBoxW(NULL,
2641                     L"Setup failed to allocate page array!",
2642                     L"ReactOS Setup",
2643                     MB_ICONERROR | MB_OK);
2644         goto done;
2645     }
2646 
2647     /* Process the $winnt$.inf setup file */
2648     ProcessSetupInf(pSetupData);
2649 
2650     /* Create the Welcome page */
2651     psp.dwSize = sizeof(PROPSHEETPAGE);
2652     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
2653     psp.hInstance = hDllInstance;
2654     psp.lParam = (LPARAM)pSetupData;
2655     psp.pfnDlgProc = WelcomeDlgProc;
2656     psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
2657     phpage[nPages++] = CreatePropertySheetPage(&psp);
2658 
2659     /* Create the Acknowledgements page */
2660     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2661     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_ACKTITLE);
2662     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_ACKSUBTITLE);
2663     psp.pszTemplate = MAKEINTRESOURCE(IDD_ACKPAGE);
2664     psp.pfnDlgProc = AckPageDlgProc;
2665     phpage[nPages++] = CreatePropertySheetPage(&psp);
2666 
2667     /* Create the Locale page */
2668     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2669     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_LOCALETITLE);
2670     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LOCALESUBTITLE);
2671     psp.pfnDlgProc = LocalePageDlgProc;
2672     psp.pszTemplate = MAKEINTRESOURCE(IDD_LOCALEPAGE);
2673     phpage[nPages++] = CreatePropertySheetPage(&psp);
2674 
2675     /* Create the Owner page */
2676     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2677     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_OWNERTITLE);
2678     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_OWNERSUBTITLE);
2679     psp.pszTemplate = MAKEINTRESOURCE(IDD_OWNERPAGE);
2680     psp.pfnDlgProc = OwnerPageDlgProc;
2681     phpage[nPages++] = CreatePropertySheetPage(&psp);
2682 
2683     /* Create the Computer page */
2684     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2685     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_COMPUTERTITLE);
2686     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_COMPUTERSUBTITLE);
2687     psp.pfnDlgProc = ComputerPageDlgProc;
2688     psp.pszTemplate = MAKEINTRESOURCE(IDD_COMPUTERPAGE);
2689     phpage[nPages++] = CreatePropertySheetPage(&psp);
2690 
2691     /* Create the DateTime page */
2692     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2693     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_DATETIMETITLE);
2694     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_DATETIMESUBTITLE);
2695     psp.pfnDlgProc = DateTimePageDlgProc;
2696     psp.pszTemplate = MAKEINTRESOURCE(IDD_DATETIMEPAGE);
2697     phpage[nPages++] = CreatePropertySheetPage(&psp);
2698 
2699     /* Create the theme selection page */
2700     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2701     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONTITLE);
2702     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONSUBTITLE);
2703     psp.pfnDlgProc = ThemePageDlgProc;
2704     psp.pszTemplate = MAKEINTRESOURCE(IDD_THEMEPAGE);
2705     phpage[nPages++] = CreatePropertySheetPage(&psp);
2706 
2707     pSetupData->uFirstNetworkWizardPage = IDD_PROCESSPAGE;
2708     pSetupData->uPostNetworkWizardPage = IDD_PROCESSPAGE;
2709 
2710     if (pfn)
2711     {
2712         pfn(&dwNetworkPageCount, &phpage[nPages], pSetupData);
2713         nPages += dwNetworkPageCount;
2714     }
2715 
2716     /* Create the Process page */
2717     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
2718     psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_PROCESSTITLE);
2719     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_PROCESSSUBTITLE);
2720     psp.pfnDlgProc = ProcessPageDlgProc;
2721     psp.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSPAGE);
2722     phpage[nPages++] = CreatePropertySheetPage(&psp);
2723 
2724     /* Create the Finish page */
2725     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
2726     psp.pfnDlgProc = FinishDlgProc;
2727     psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
2728     phpage[nPages++] = CreatePropertySheetPage(&psp);
2729 
2730     ASSERT(nPages == dwPageCount);
2731 
2732     /* Create the property sheet */
2733     psh.dwSize = sizeof(PROPSHEETHEADER);
2734     psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER | PSH_MODELESS;
2735     psh.hInstance = hDllInstance;
2736     psh.hwndParent = NULL;
2737     psh.nPages = nPages;
2738     psh.nStartPage = 0;
2739     psh.phpage = phpage;
2740     psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
2741     psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
2742 
2743     /* Create title font */
2744     pSetupData->hTitleFont = CreateTitleFont();
2745     pSetupData->hBoldFont  = CreateBoldFont();
2746 
2747     /* Display the wizard */
2748     hWnd = (HWND)PropertySheet(&psh);
2749     ShowWindow(hWnd, SW_SHOW);
2750 
2751     while (GetMessage(&msg, NULL, 0, 0))
2752     {
2753         if (!IsDialogMessage(hWnd, &msg))
2754         {
2755             TranslateMessage(&msg);
2756             DispatchMessage(&msg);
2757         }
2758     }
2759 
2760     DeleteObject(pSetupData->hBoldFont);
2761     DeleteObject(pSetupData->hTitleFont);
2762 
2763     if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
2764         SetupCloseInfFile(pSetupData->hSetupInf);
2765 
2766 done:
2767     if (phpage != NULL)
2768         HeapFree(GetProcessHeap(), 0, phpage);
2769 
2770     if (hNetShell != NULL)
2771         FreeLibrary(hNetShell);
2772 
2773     if (pSetupData != NULL)
2774         HeapFree(GetProcessHeap(), 0, pSetupData);
2775 
2776     LogItem(L"END_SECTION", L"InstallWizard");
2777 }
2778 
2779 /* EOF */
2780