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