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