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