Show the banner dialog from the loader DLL.
[setup-launcher.git] / setup-launcher.c
blob82a0969afaeb64437b63d770a620e6ef1f64982b
1 /* ---------------------------------------------------------------------------------------------- */
2 /* Setup Bootstrapper Utility */
3 /* Copyright(c) 2016-2020 LoRd_MuldeR <mulder2@gmx.de> */
4 /* */
5 /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software */
6 /* and associated documentation files (the "Software"), to deal in the Software without */
7 /* restriction, including without limitation the rights to use, copy, modify, merge, publish, */
8 /* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the */
9 /* Software is furnished to do so, subject to the following conditions: */
10 /* */
11 /* The above copyright notice and this permission notice shall be included in all copies or */
12 /* substantial portions of the Software. */
13 /* */
14 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING */
15 /* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
16 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, */
17 /* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
18 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
19 /* ---------------------------------------------------------------------------------------------- */
21 #if !defined(BUILD_EXE) && !defined(BUILD_DLL)
22 #error Nothing to do!
23 #endif
24 #if defined(BUILD_EXE) && defined(BUILD_DLL)
25 #error Inconsistent build flags!
26 #endif
27 #if !defined(BUILD_DATE_F) || !defined(BUILD_DATE_X)
28 #error Build date is not defined!
29 #endif
31 #include <Windows.h>
32 #include <wchar.h>
33 #include <stdarg.h>
35 // ==========================================================================
36 // COMMON FUNCTIONS
37 // ==========================================================================
39 #define MAX_STRLEN 32768U
41 #define _STRINGIFY(X) L###X
42 #define STRINGIFY(X) _STRINGIFY(X)
44 #define _HEXLIFY(X) 0x##X
45 #define HEXLIFY(X) _HEXLIFY(X)
47 #define RECT_W(X) (((X).right > (X).left) ? ((X).right - (X).left) : 0)
48 #define RECT_H(X) (((X).bottom > (X).top) ? ((X).bottom - (X).top) : 0)
50 #define TITLE(STR) \
51 ({ \
52 const wchar_t *const _title = (STR); \
53 (_title && (*_title)) ? _title : L"Setup Bootstrapper"; \
56 static const unsigned long API_VERSION = HEXLIFY(BUILD_DATE_X);
58 // ----------------------------------------------------
59 // String Functions
60 // ----------------------------------------------------
62 /*Note: Cannot use wcsncpy_s() or wcsncat_s(), because they were NOT available in Windows XP yet!*/
64 #define ENSURE_NULL_TERMINATED(BUFF,SIZE) do \
65 { \
66 (BUFF)[(SIZE) - 1U] = L'\0'; \
67 } \
68 while(0)
70 static wchar_t *copy(wchar_t *const buffer, const wchar_t *const str, const size_t buff_size)
72 wcsncpy(buffer, str, buff_size);
73 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by wcsncpy()!*/
74 return buffer;
77 static wchar_t *append(wchar_t *const buffer, const wchar_t *const str, const size_t buff_size)
79 const size_t current_len = wcslen(buffer);
80 if(current_len < (buff_size - 1U))
82 wcsncat(buffer, str, buff_size - current_len - 1U);
84 return buffer;
87 static wchar_t *format(wchar_t *const buffer, const size_t buff_size, const wchar_t *const format, ...)
89 va_list args;
90 va_start(args, format);
91 _vsnwprintf(buffer, buff_size, format, args);
92 va_end(args);
93 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
94 return buffer;
97 static wchar_t *append_format(wchar_t *const buffer, const size_t buff_size, const wchar_t *const format, ...)
99 const size_t current_len = wcslen(buffer);
100 if(current_len < (buff_size - 1U))
102 va_list args;
103 va_start(args, format);
104 _vsnwprintf(buffer + current_len, buff_size - current_len, format, args);
105 va_end(args);
106 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
108 return buffer;
111 static size_t max_index(const size_t pos_a, const size_t pos_b)
113 if((pos_a != SIZE_MAX) && (pos_b != SIZE_MAX))
115 return pos_a > pos_b ? pos_a : pos_b;
117 return (pos_a != SIZE_MAX) ? pos_a : pos_b;
120 static size_t last_index(const wchar_t *const haystack, const wchar_t needle)
122 const wchar_t *ptr;
123 if(ptr = wcsrchr(haystack, needle))
125 return ptr - haystack;
127 return SIZE_MAX;
130 static BOOL contains_space(const wchar_t *str)
132 for(; *str != L'\0'; ++str)
134 if(iswspace(*str))
136 return TRUE;
139 return FALSE;
142 static BOOL starts_with(const wchar_t *const str, const wchar_t *const prefix)
144 if(*str)
146 const size_t len_str = wcslen(str), len_prefix = wcslen(prefix);
147 if(len_str >= len_prefix)
149 return (_wcsnicmp(str, prefix, len_prefix) == 0);
152 return FALSE;
155 // ----------------------------------------------------
156 // Path Functions
157 // ----------------------------------------------------
159 static BOOL get_executable_path(wchar_t *const path, const size_t max_len)
161 const DWORD ret = GetModuleFileNameW(NULL, path, max_len);
162 if((ret > 0U) || (ret < max_len))
164 return TRUE;
166 return FALSE;
169 static BOOL get_system_path(wchar_t *const path, const size_t max_len)
171 const DWORD ret = GetSystemDirectoryW(path, max_len);
172 if((ret > 0U) || (ret < max_len))
174 return TRUE;
176 return FALSE;
179 static wchar_t *skip_directory_part(wchar_t *const path)
181 const size_t pos_sep = max_index(last_index(path, L'/'), last_index(path, L'\\'));
182 if (pos_sep != SIZE_MAX)
184 return path + (pos_sep + 1U);
186 return path;
189 static void get_absolute_path(const wchar_t *const path, wchar_t *const full_path, const size_t max_len, const wchar_t **const file_name)
191 const DWORD ret = GetFullPathNameW(path, max_len, full_path, (LPWSTR*)file_name);
192 if(!((ret > 0U) && (ret < max_len)))
194 copy(full_path, path, max_len);
195 if(file_name)
197 *file_name = skip_directory_part(full_path);
202 static wchar_t *remove_file_name(wchar_t *const path)
204 wchar_t *const file_name = skip_directory_part(path);
205 if(*file_name)
207 *file_name = L'\0';
209 return path;
212 static wchar_t *remove_file_extension(wchar_t *const path)
214 wchar_t *const file_name = skip_directory_part(path);
215 if(*file_name)
217 const size_t pos_ext = last_index(file_name, L'.');
218 if((pos_ext != SIZE_MAX) && (pos_ext > 0U))
220 file_name[pos_ext] = L'\0';
223 return path;
226 static wchar_t *trim_trailing_separators(wchar_t *const path, const BOOL force)
228 size_t length = wcslen(path);
229 while ((length > (force ? 0U : 1U)) && ((path[length - 1U] == L'/') || (path[length - 1U] == L'\\')))
231 if((!force) && path[length - 2U] == L':')
233 break;
235 path[--length] = L'\0';
237 return path;
240 static BOOL file_exists(const wchar_t *const path)
242 const DWORD attributes = GetFileAttributesW(path);
243 return ((attributes != INVALID_FILE_ATTRIBUTES) && (!(attributes & FILE_ATTRIBUTE_DIRECTORY)));
246 // ----------------------------------------------------
247 // Command-line Functions
248 // ----------------------------------------------------
250 #define TRY_APPEND(OUT,LEN,MAX_LEN,CHR) do \
252 if((LEN) < ((MAX_LEN) - 1U)) \
254 (OUT)[(LEN)++] = (CHR); \
256 else \
258 goto exit_loop; \
261 while(0)
263 static BOOL get_first_parameter(const wchar_t *cmdLine, wchar_t *const out, const size_t max_len)
265 size_t len = 0U, escape_count = 0U;
266 BOOL flag_quote = FALSE;
267 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
269 ++cmdLine;
271 for (; *cmdLine != L'\0'; ++cmdLine)
273 if (*cmdLine == L'\\')
275 ++escape_count;
276 continue;
278 else if (escape_count)
280 if (*cmdLine == L'"')
282 const size_t modul = escape_count % 2U;
283 for (escape_count /= 2U; escape_count; --escape_count)
285 TRY_APPEND(out, len, max_len, L'\\');
287 if (!modul)
289 flag_quote = (!flag_quote);
290 continue;
293 else
295 for (; escape_count; --escape_count)
297 TRY_APPEND(out, len, max_len, L'\\');
301 else if (*cmdLine == L'"')
303 flag_quote = (!flag_quote);
304 continue;
306 if ((!flag_quote) && iswspace(*cmdLine))
308 break; /*stop!*/
310 TRY_APPEND(out, len, max_len, *cmdLine);
312 for (; escape_count; --escape_count)
314 TRY_APPEND(out, len, max_len, L'\\');
316 exit_loop:
317 out[len] = L'\0';
318 return (len > 0U);
321 static const wchar_t *get_extra_parameters(const wchar_t *cmdLine)
323 size_t escape_count = 0U;
324 BOOL flag_quote = FALSE;
325 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
327 ++cmdLine;
329 for (; *cmdLine != L'\0'; ++cmdLine)
331 if (*cmdLine == L'\\')
333 ++escape_count;
334 continue;
336 else if (escape_count)
338 if (*cmdLine == L'"')
340 if (!(escape_count % 2U))
342 escape_count = 0U;
343 flag_quote = (!flag_quote);
344 continue;
347 escape_count = 0U;
349 else if (*cmdLine == L'"')
351 flag_quote = (!flag_quote);
352 continue;
354 if ((!flag_quote) && iswspace(*cmdLine))
356 break; /*stop!*/
359 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
361 ++cmdLine;
363 return cmdLine;
366 // ----------------------------------------------------
367 // UAC Functions
368 // ----------------------------------------------------
370 static BOOL is_elevated(void)
372 const DWORD version = GetVersion();
373 if(((DWORD)LOBYTE(LOWORD(version))) > 5U)
375 BOOL elevated = FALSE;
376 HANDLE hToken;
377 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
379 DWORD cbSize = sizeof(TOKEN_ELEVATION_TYPE);
380 TOKEN_ELEVATION_TYPE elevation_type;
381 if(GetTokenInformation(hToken, TokenElevationType, &elevation_type, sizeof(TOKEN_ELEVATION_TYPE), &cbSize))
383 switch(elevation_type)
385 case TokenElevationTypeFull:
386 case TokenElevationTypeDefault:
387 elevated = TRUE;
388 break;
391 CloseHandle(hToken);
393 return elevated;
395 else
397 return TRUE; /*for Windows XP support*/
401 // ----------------------------------------------------
402 // Window Functions
403 // ----------------------------------------------------
405 #define IDI_ICON1 101
407 #define PROCESS_MESSAGES(X) do \
409 const HWND _hwnd = (X); \
410 if(_hwnd) \
411 process_messages(_hwnd); \
413 while(0)
415 static HWND create_banner(const HINSTANCE hInstance, const wchar_t *const title, WNDPROC wndproc)
417 HWND hwnd = CreateWindowExW(0, L"#32770", TITLE(title), WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 384, 96, NULL, NULL, hInstance, NULL);
418 if (hwnd != NULL)
420 RECT workRect, wndRect;
421 HICON hIcon;
422 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc);
423 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
424 if (SystemParametersInfoW(SPI_GETWORKAREA, 0, &workRect, 0) && GetWindowRect(hwnd, &wndRect))
426 MoveWindow(hwnd, (RECT_W(workRect)-RECT_W(wndRect))/2, (RECT_H(workRect)-RECT_H(wndRect))/2, RECT_W(wndRect), RECT_H(wndRect), TRUE);
428 if((hIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_ICON1), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED)) != NULL)
430 SendMessage(hwnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
432 if((hIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_ICON1), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR | LR_SHARED)) != NULL)
434 SendMessage(hwnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
437 return hwnd;
440 static void process_messages(const HWND hwnd)
442 MSG msg = {};
443 for (unsigned short i = 0U; i < 8U; ++i)
445 BOOL flag = FALSE;
446 if(i > 0U)
448 Sleep(1); /*delay*/
450 for (unsigned short k = 0U; k < 8192U; ++k)
452 if (PeekMessageW(&msg, hwnd, 0U, 0U, PM_REMOVE))
454 flag = TRUE;
455 TranslateMessage(&msg);
456 DispatchMessageW(&msg);
457 continue;
459 break;
461 if(!flag)
463 break; /*did not process any messages*/
468 static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
470 PAINTSTRUCT ps;
471 HDC hdc;
472 switch(uMsg)
474 case WM_PAINT:
475 if(hdc = BeginPaint(hwnd, &ps))
477 FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
478 DrawTextExW(hdc, L"Setup is launching, please stay tuned...", -1, &ps.rcPaint, DT_CENTER|DT_SINGLELINE|DT_VCENTER, NULL);
479 EndPaint(hwnd, &ps);
481 case WM_CLOSE:
482 return 0; /*ignore WM_CLOSE msg*/
483 default:
484 return DefWindowProc(hwnd, uMsg, wParam, lParam);
488 static BOOL show_window(const HWND hwnd)
490 BOOL result = FALSE;
491 if(hwnd != NULL)
493 result = ShowWindow(hwnd, SW_SHOWNORMAL);
494 process_messages(hwnd);
495 Sleep(25);
496 SetForegroundWindow(hwnd);
497 SetCapture(hwnd);
499 return result;
502 // ----------------------------------------------------
503 // Shell Execute
504 // ----------------------------------------------------
506 static BOOL exec_shell(const HWND hwnd, const wchar_t *const verb, const wchar_t *const file, const wchar_t *const params, const wchar_t *const directory, HANDLE *const process)
508 SHELLEXECUTEINFOW shExecInfo;
509 SecureZeroMemory(&shExecInfo, sizeof(SHELLEXECUTEINFOW));
510 shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
511 shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
512 shExecInfo.hwnd = hwnd;
513 shExecInfo.lpVerb = verb;
514 shExecInfo.lpFile = file;
515 shExecInfo.lpParameters = params;
516 shExecInfo.lpDirectory = directory;
517 shExecInfo.nShow = SW_SHOWNORMAL;
518 const BOOL success = ShellExecuteExW(&shExecInfo);
519 if(success && (((UINT32)(UINT_PTR)shExecInfo.hInstApp) > 32U))
521 if(process)
523 *process = shExecInfo.hProcess;
525 else
527 if(shExecInfo.hProcess != NULL)
529 CloseHandle(shExecInfo.hProcess);
532 return TRUE;
534 else
536 if(process)
538 *process = NULL;
540 return FALSE;
544 static DWORD exec_shell_await(HWND *const hwnd, const wchar_t *const verb, const wchar_t *const file_name, const wchar_t *const full_path, const wchar_t *const params, const wchar_t *const directory)
546 HANDLE process = NULL;
547 for(;;)
549 const HWND owner = hwnd ? (*hwnd) : NULL;
550 PROCESS_MESSAGES(owner);
551 if(!exec_shell(owner, verb, full_path, params, directory, &process))
553 PROCESS_MESSAGES(owner);
554 if(MessageBoxW(owner, L"Failed to launch setup program. Please try again!", TITLE(file_name), (owner ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONEXCLAMATION | MB_RETRYCANCEL) != IDRETRY)
556 return 0x2E4;
559 else
561 DWORD exit_code = 0U;
562 Sleep(25);
563 if(hwnd && (*hwnd))
565 DestroyWindow(*hwnd);
566 *hwnd = NULL;
568 if(process)
570 WaitForSingleObject(process, INFINITE);
571 if(!GetExitCodeProcess(process, &exit_code))
573 exit_code = (DWORD)(-1);
575 CloseHandle(process);
577 return exit_code; /*success*/
582 // ----------------------------------------------------
583 // Miscellaneous
584 // ----------------------------------------------------
586 static void error_message(const HWND hwnd, const wchar_t *const message, const wchar_t *const title)
588 MessageBoxW(hwnd, message, TITLE(title), (hwnd ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONERROR);
591 static void show_about(const HWND hwnd, const BOOL dll)
593 wchar_t message[256U];
594 format(message, 256U, L"Setup Bootstrapper %s [%s]\n"
595 L"Copyright(c) 2016-2020 LoRd_MuldeR <mulder2@gmx.de>\n"
596 L"Please see http://muldersoft.com/ for details!\n\n"
597 L"This program is free software; you can redistribute it and/or modify it under the terms of the the MIT License.",
598 dll ? L"DLL" : L"EXE", STRINGIFY(BUILD_DATE_F));
599 MessageBoxW(hwnd, message, L"About...", (hwnd ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONINFORMATION);
602 // ==========================================================================
603 // EXE File
604 // ==========================================================================
606 #ifdef BUILD_EXE
608 static wchar_t executable_path [MAX_STRLEN] = { L'\0' };
609 static wchar_t executable_directory[MAX_STRLEN] = { L'\0' };
610 static wchar_t setup_path [MAX_STRLEN] = { L'\0' };
611 static wchar_t setup_absolute_path [MAX_STRLEN] = { L'\0' };
612 static wchar_t setup_directory [MAX_STRLEN] = { L'\0' };
613 static wchar_t library_path [MAX_STRLEN] = { L'\0' };
614 static wchar_t rundll32_path [MAX_STRLEN] = { L'\0' };
615 static wchar_t parameters [MAX_STRLEN] = { L'\0' };
617 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
619 /*get command-line arguments*/
620 if((!pCmdLine) || (!(*pCmdLine)) || (!_wcsicmp(pCmdLine, L"--help")) || (!_wcsicmp(pCmdLine, L"/?")))
622 error_message(NULL, L"Required parameters are missing!\n\nUsage:\nsetup-launcher.exe <setup.exe> [PARAMETERS]", NULL);
623 return 1;
626 /*show about screen*/
627 if((!_wcsicmp(pCmdLine, L"--about")) || (!_wcsicmp(pCmdLine, L"--version")))
629 show_about(NULL, FALSE);
630 return 0;
633 /*get executable path*/
634 if(!get_executable_path(executable_path, MAX_STRLEN))
636 error_message(NULL, L"Error: Failed to determine executable path!", NULL);
637 return 1;
640 /*get executable directory*/
641 copy(executable_directory, executable_path, MAX_STRLEN);
642 remove_file_name(executable_directory);
643 trim_trailing_separators(executable_directory, FALSE);
645 /*set working directory*/
646 SetCurrentDirectoryW(executable_directory);
648 /*get setup file path*/
649 if(!get_first_parameter(pCmdLine, setup_path, MAX_STRLEN))
651 error_message(NULL, L"Error: Failed to determine setup program path!", NULL);
654 /*get absolute path file path*/
655 const wchar_t *file_name;
656 get_absolute_path(setup_path, setup_absolute_path, MAX_STRLEN, &file_name);
658 /*check for silent mode*/
659 const wchar_t *const extra_args = get_extra_parameters(pCmdLine);
660 const BOOL silent = starts_with(extra_args, L"-ms") || starts_with(extra_args, L"/ini") || starts_with(extra_args, L"/s");
662 /*create banner window*/
663 HWND banner = (!silent) ? create_banner(hInstance, file_name, wnd_proc) : NULL;
664 if(banner != NULL)
666 show_window(banner);
669 /*make sure the setup executable exists*/
670 if(!file_exists(setup_absolute_path))
672 format(parameters, MAX_STRLEN, L"Setup executable could not be found:\n\n%s", setup_absolute_path);
673 error_message(banner, parameters, file_name);
674 return 0x490;
677 /*get setup file directory*/
678 copy(setup_directory, setup_absolute_path, MAX_STRLEN);
679 remove_file_name(setup_directory);
680 trim_trailing_separators(setup_directory, FALSE);
682 /*set working directory*/
683 SetCurrentDirectoryW(setup_directory);
685 /*take the fast path, iff already elevated (or running on pre-Vista)*/
686 if(is_elevated())
688 return exec_shell_await(&banner, NULL, file_name, setup_absolute_path, extra_args, setup_directory);
691 /*get path of RunDLL executable file*/
692 if(!get_system_path(rundll32_path, MAX_STRLEN))
694 error_message(banner, L"Error: Failed to determine system directory path!", file_name);
695 return 1;
697 trim_trailing_separators(rundll32_path, TRUE);
698 append(rundll32_path, L"\\rundll32.exe", MAX_STRLEN);
700 /*make sure the RunDLL executable exists*/
701 if(!file_exists(rundll32_path))
703 format(parameters, MAX_STRLEN, L"RUNDLL32 program could not be found:\n\n%s\n\n\nThis indicates that your Windows installation is corrupted!", rundll32_path);
704 error_message(banner, parameters, file_name);
705 return 0x485;
708 /*get path of launcher DLL*/
709 copy(library_path, executable_path, MAX_STRLEN);
710 remove_file_extension(library_path);
711 append(library_path, L".dll", MAX_STRLEN);
713 /*make sure the launcher DLL exists*/
714 if(!file_exists(library_path))
716 format(parameters, MAX_STRLEN, L"Launcher library file could not be found:\n\n%s", library_path);
717 error_message(banner, parameters, file_name);
718 return 0x485;
721 /*build parameter string for RunDLL*/
722 format(parameters, MAX_STRLEN, contains_space(library_path) ? L"\"%s\",startup" : L"%s,startup", library_path);
723 append_format(parameters, MAX_STRLEN, contains_space(setup_absolute_path) ? L"\x20%X\x20\"%s\"" : L"\x20%X\x20%s", API_VERSION, setup_absolute_path);
724 if(extra_args && (*extra_args))
726 append_format(parameters, MAX_STRLEN, L"\x20%s", extra_args);
729 /*now actually call the launcher DLL*/
730 const DWORD exit_code = exec_shell_await(&banner, L"runas", file_name, rundll32_path, parameters, setup_directory);
732 /*clean-up*/
733 if(banner != NULL)
735 DestroyWindow(banner);
738 return exit_code;
741 #endif //BUILD_EXE
743 // ==========================================================================
744 // DLL File
745 // ==========================================================================
747 #ifdef BUILD_DLL
749 static wchar_t setup_path [MAX_STRLEN] = { L'\0' };
750 static wchar_t setup_absolute_path[MAX_STRLEN] = { L'\0' };
751 static wchar_t setup_directory [MAX_STRLEN] = { L'\0' };
753 static HINSTANCE g_hinstDLL = NULL;
755 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
757 if(fdwReason == DLL_PROCESS_ATTACH)
759 g_hinstDLL = hinstDLL;
761 return TRUE;
764 void CALLBACK startupW(HWND hwnd, HINSTANCE hAppInstance, LPCWSTR lpCmdLine, int nCmdShow)
766 /*get command-line arguments*/
767 if((!lpCmdLine) || (!(*lpCmdLine)))
769 error_message(hwnd, L"Required command-line parameters are missing!", NULL);
770 ExitProcess(0x57);
771 return;
774 /*get the version tag*/
775 if(!get_first_parameter(lpCmdLine, setup_path, MAX_STRLEN))
777 error_message(hwnd, L"Error: Failed to determine the version tag!", NULL);
778 ExitProcess(0x57);
779 return;
782 /*check the version tag*/
783 if(wcstoul(setup_path, NULL, 16U) != API_VERSION)
785 error_message(hwnd, L"Error: Version tag mismatch detected!", NULL);
786 ExitProcess(0x57);
787 return;
790 /*get next command-line arguments*/
791 lpCmdLine = get_extra_parameters(lpCmdLine);
792 if((!lpCmdLine) || (!(*lpCmdLine)))
794 error_message(hwnd, L"Required command-line parameters are missing!", NULL);
795 ExitProcess(0x57);
796 return;
799 /*get setup file path*/
800 if(!get_first_parameter(lpCmdLine, setup_path, MAX_STRLEN))
802 error_message(hwnd, L"Error: Failed to determine setup program path!", NULL);
803 ExitProcess(0x57);
804 return;
807 /*get absolut setup file path*/
808 const wchar_t *file_name;
809 get_absolute_path(setup_path, setup_absolute_path, MAX_STRLEN, &file_name);
811 /*check for silent mode*/
812 const wchar_t *const extra_args = get_extra_parameters(lpCmdLine);
813 const BOOL silent = starts_with(extra_args, L"-ms") || starts_with(extra_args, L"/ini") || starts_with(extra_args, L"/s");
815 /*create banner window*/
816 HWND banner = (!silent) ? create_banner(g_hinstDLL, file_name, wnd_proc) : NULL;
817 if(banner != NULL)
819 show_window(banner);
822 /*make sure the setup executable exists*/
823 if(!file_exists(setup_absolute_path))
825 format(setup_directory, MAX_STRLEN, L"Setup executable could not be found:\n\n%s", setup_absolute_path);
826 error_message((banner != NULL) ? banner : hwnd, setup_directory, file_name);
827 ExitProcess(0x490);
828 return;
831 /*get setup file directory*/
832 copy(setup_directory, setup_absolute_path, MAX_STRLEN);
833 remove_file_name(setup_directory);
834 trim_trailing_separators(setup_directory, FALSE);
836 /*set working directory*/
837 SetCurrentDirectoryW(setup_directory);
839 /*now actually launch the executable*/
840 const DWORD exit_code = exec_shell_await(&banner, NULL, file_name, setup_absolute_path, extra_args, setup_directory);
842 /*clean-up*/
843 if(banner != NULL)
845 DestroyWindow(banner);
848 ExitProcess(exit_code);
851 void CALLBACK startup(HWND hwnd, HINSTANCE hAppInstance, LPCSTR lpCmdLine, int nCmdShow)
853 const wchar_t *const lpCmdLineW = get_extra_parameters(GetCommandLineW());
854 if(lpCmdLineW && (*lpCmdLineW))
856 startupW(hwnd, hAppInstance, (LPWSTR)get_extra_parameters(lpCmdLineW), nCmdShow);
858 else
860 startupW(hwnd, hAppInstance, L""/*no arguments*/, nCmdShow);
864 void CALLBACK aboutW(HWND hwnd, HINSTANCE hAppInstance, LPCWSTR lpCmdLine, int nCmdShow)
866 show_about(hwnd, TRUE);
869 void CALLBACK about(HWND hwnd, HINSTANCE hAppInstance, LPCSTR lpCmdLine, int nCmdShow)
871 show_about(hwnd, TRUE);
874 #endif //BUILD_DLL