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