Improved help screen + fixed minor bug in get_executable_path() function.
[setup-launcher.git] / setup-launcher.c
blob3d83b78fbcc75acaf3d6ed3aed185ff56207ebcc
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 : PROGRAM_NAME; \
56 static const wchar_t *const PROGRAM_NAME = L"Setup Bootstrapper";
57 static const unsigned long API_VERSION = HEXLIFY(BUILD_DATE_X);
59 // ----------------------------------------------------
60 // String Functions
61 // ----------------------------------------------------
63 /*Note: Cannot use wcsncpy_s() or wcsncat_s(), because they were NOT available in Windows XP yet!*/
65 #define EMPTY(STR) ((!(STR)) || (!(*(STR))))
67 #define ENSURE_NULL_TERMINATED(BUFF,SIZE) do \
68 { \
69 (BUFF)[(SIZE) - 1U] = L'\0'; \
70 } \
71 while(0)
73 static wchar_t *copy(wchar_t *const buffer, const wchar_t *const str, const size_t buff_size)
75 wcsncpy(buffer, str, buff_size);
76 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by wcsncpy()!*/
77 return buffer;
80 static wchar_t *append(wchar_t *const buffer, const wchar_t *const str, const size_t buff_size)
82 const size_t current_len = wcslen(buffer);
83 if(current_len < (buff_size - 1U))
85 wcsncat(buffer, str, buff_size - current_len - 1U);
87 return buffer;
90 static wchar_t *format(wchar_t *const buffer, const size_t buff_size, const wchar_t *const format, ...)
92 va_list args;
93 va_start(args, format);
94 _vsnwprintf(buffer, buff_size, format, args);
95 va_end(args);
96 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
97 return buffer;
100 static wchar_t *append_format(wchar_t *const buffer, const size_t buff_size, const wchar_t *const format, ...)
102 const size_t current_len = wcslen(buffer);
103 if(current_len < (buff_size - 1U))
105 va_list args;
106 va_start(args, format);
107 _vsnwprintf(buffer + current_len, buff_size - current_len, format, args);
108 va_end(args);
109 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
111 return buffer;
114 static size_t max_index(const size_t pos_a, const size_t pos_b)
116 if((pos_a != SIZE_MAX) && (pos_b != SIZE_MAX))
118 return pos_a > pos_b ? pos_a : pos_b;
120 return (pos_a != SIZE_MAX) ? pos_a : pos_b;
123 static size_t last_index(const wchar_t *const haystack, const wchar_t needle)
125 const wchar_t *ptr;
126 if(ptr = wcsrchr(haystack, needle))
128 return ptr - haystack;
130 return SIZE_MAX;
133 static BOOL contains_space(const wchar_t *str)
135 for(; *str != L'\0'; ++str)
137 if(iswspace(*str))
139 return TRUE;
142 return FALSE;
145 static BOOL starts_with(const wchar_t *const str, const wchar_t *const prefix)
147 if(*str)
149 const size_t len_str = wcslen(str), len_prefix = wcslen(prefix);
150 if(len_str >= len_prefix)
152 return (_wcsnicmp(str, prefix, len_prefix) == 0);
155 return FALSE;
158 // ----------------------------------------------------
159 // Command-line Functions
160 // ----------------------------------------------------
162 #define TRY_APPEND(OUT,LEN,MAX_LEN,CHR) do \
164 if((OUT) && ((LEN) < ((MAX_LEN) - 1U))) \
166 (OUT)[(LEN)++] = (CHR); \
169 while(0)
171 static const wchar_t *get_next_arg(const wchar_t *cmdLine, wchar_t *const arg_out, const size_t max_len)
173 size_t len = 0U, escape_count = 0U;
174 BOOL flag_quote = FALSE;
176 /*skip leading spaces*/
177 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
179 ++cmdLine;
182 /*process token*/
183 for (; *cmdLine != L'\0'; ++cmdLine)
185 if (*cmdLine == L'\\')
187 ++escape_count;
188 continue;
190 else if (escape_count)
192 if (*cmdLine == L'"')
194 const size_t modul = escape_count % 2U;
195 for (escape_count /= 2U; escape_count; --escape_count)
197 TRY_APPEND(arg_out, len, max_len, L'\\');
199 if (!modul)
201 flag_quote = (!flag_quote);
202 continue;
205 else
207 for (; escape_count; --escape_count)
209 TRY_APPEND(arg_out, len, max_len, L'\\');
213 else if (*cmdLine == L'"')
215 flag_quote = (!flag_quote);
216 continue;
218 if ((!flag_quote) && iswspace(*cmdLine))
220 break; /*stop!*/
222 TRY_APPEND(arg_out, len, max_len, *cmdLine);
225 /*flush pending backslashes*/
226 for (; escape_count; --escape_count)
228 TRY_APPEND(arg_out, len, max_len, L'\\');
231 /*skip trailing spaces*/
232 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
234 ++cmdLine;
237 /*put the NULL terminator*/
238 if (arg_out)
240 arg_out[len] = L'\0';
243 return cmdLine;
246 // ----------------------------------------------------
247 // Path Functions
248 // ----------------------------------------------------
250 static BOOL get_executable_path(wchar_t *const path, const size_t max_len)
252 const DWORD ret = GetModuleFileNameW(NULL, path, max_len);
253 if((ret > 0U) && (ret < max_len))
255 return TRUE;
257 else
259 get_next_arg(GetCommandLineW(), path, max_len);
260 return (!EMPTY(path));
264 static BOOL get_system_path(wchar_t *const path, const size_t max_len)
266 const DWORD ret = GetSystemDirectoryW(path, max_len);
267 if((ret > 0U) || (ret < max_len))
269 return TRUE;
271 return FALSE;
274 static wchar_t *skip_directory_part(wchar_t *const path)
276 const size_t pos_sep = max_index(last_index(path, L'/'), last_index(path, L'\\'));
277 if (pos_sep != SIZE_MAX)
279 return path + (pos_sep + 1U);
281 return path;
284 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)
286 const DWORD ret = GetFullPathNameW(path, max_len, full_path, (LPWSTR*)file_name);
287 if(!((ret > 0U) && (ret < max_len)))
289 copy(full_path, path, max_len);
290 if(file_name)
292 *file_name = skip_directory_part(full_path);
297 static wchar_t *remove_file_name(wchar_t *const path)
299 wchar_t *const file_name = skip_directory_part(path);
300 if(*file_name)
302 *file_name = L'\0';
304 return path;
307 static wchar_t *remove_file_extension(wchar_t *const path)
309 wchar_t *const file_name = skip_directory_part(path);
310 if(*file_name)
312 const size_t pos_ext = last_index(file_name, L'.');
313 if((pos_ext != SIZE_MAX) && (pos_ext > 0U))
315 file_name[pos_ext] = L'\0';
318 return path;
321 static wchar_t *trim_trailing_separators(wchar_t *const path, const BOOL force)
323 size_t length = wcslen(path);
324 while ((length > (force ? 0U : 1U)) && ((path[length - 1U] == L'/') || (path[length - 1U] == L'\\')))
326 if((!force) && path[length - 2U] == L':')
328 break;
330 path[--length] = L'\0';
332 return path;
335 static BOOL file_exists(const wchar_t *const path)
337 const DWORD attributes = GetFileAttributesW(path);
338 return ((attributes != INVALID_FILE_ATTRIBUTES) && (!(attributes & FILE_ATTRIBUTE_DIRECTORY)));
341 // ----------------------------------------------------
342 // ----------------------------------------------------
343 // UAC Functions
344 // ----------------------------------------------------
346 static BOOL is_elevated(void)
348 const DWORD version = GetVersion();
349 if(((DWORD)LOBYTE(LOWORD(version))) > 5U)
351 BOOL elevated = FALSE;
352 HANDLE hToken;
353 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
355 DWORD cbSize = sizeof(TOKEN_ELEVATION_TYPE);
356 TOKEN_ELEVATION_TYPE elevation_type;
357 if(GetTokenInformation(hToken, TokenElevationType, &elevation_type, sizeof(TOKEN_ELEVATION_TYPE), &cbSize))
359 switch(elevation_type)
361 case TokenElevationTypeFull:
362 case TokenElevationTypeDefault:
363 elevated = TRUE;
364 break;
367 CloseHandle(hToken);
369 return elevated;
371 else
373 return TRUE; /*for Windows XP support*/
377 // ----------------------------------------------------
378 // Window Functions
379 // ----------------------------------------------------
381 #define IDI_ICON1 101
383 #define PROCESS_MESSAGES(X) do \
385 const HWND _hwnd = (X); \
386 if(_hwnd) \
387 process_messages(_hwnd); \
389 while(0)
391 static HWND create_banner(const HINSTANCE hInstance, const wchar_t *const title, WNDPROC wndproc)
393 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);
394 if (hwnd != NULL)
396 RECT workRect, wndRect;
397 HICON hIcon;
398 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc);
399 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
400 if (SystemParametersInfoW(SPI_GETWORKAREA, 0, &workRect, 0) && GetWindowRect(hwnd, &wndRect))
402 MoveWindow(hwnd, (RECT_W(workRect)-RECT_W(wndRect))/2, (RECT_H(workRect)-RECT_H(wndRect))/2, RECT_W(wndRect), RECT_H(wndRect), TRUE);
404 if((hIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_ICON1), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED)) != NULL)
406 SendMessage(hwnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
408 if((hIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCEW(IDI_ICON1), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR | LR_SHARED)) != NULL)
410 SendMessage(hwnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
413 return hwnd;
416 static void process_messages(const HWND hwnd)
418 MSG msg = {};
419 for (unsigned short i = 0U; i < 8U; ++i)
421 BOOL flag = FALSE;
422 if(i > 0U)
424 Sleep(1); /*delay*/
426 for (unsigned short k = 0U; k < 8192U; ++k)
428 if (PeekMessageW(&msg, hwnd, 0U, 0U, PM_REMOVE))
430 flag = TRUE;
431 TranslateMessage(&msg);
432 DispatchMessageW(&msg);
433 continue;
435 break;
437 if(!flag)
439 break; /*did not process any messages*/
444 static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
446 PAINTSTRUCT ps;
447 HDC hdc;
448 switch(uMsg)
450 case WM_PAINT:
451 if(hdc = BeginPaint(hwnd, &ps))
453 FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
454 DrawTextExW(hdc, L"Setup is launching, please stay tuned...", -1, &ps.rcPaint, DT_CENTER|DT_SINGLELINE|DT_VCENTER, NULL);
455 EndPaint(hwnd, &ps);
457 case WM_CLOSE:
458 return 0; /*ignore WM_CLOSE msg*/
459 default:
460 return DefWindowProc(hwnd, uMsg, wParam, lParam);
464 static BOOL show_window(const HWND hwnd)
466 BOOL result = FALSE;
467 if(hwnd != NULL)
469 result = ShowWindow(hwnd, SW_SHOWNORMAL);
470 process_messages(hwnd);
471 Sleep(25);
472 SetForegroundWindow(hwnd);
473 SetCapture(hwnd);
475 return result;
478 // ----------------------------------------------------
479 // Shell Execute
480 // ----------------------------------------------------
482 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)
484 SHELLEXECUTEINFOW shExecInfo;
485 SecureZeroMemory(&shExecInfo, sizeof(SHELLEXECUTEINFOW));
486 shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
487 shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
488 shExecInfo.hwnd = hwnd;
489 shExecInfo.lpVerb = verb;
490 shExecInfo.lpFile = file;
491 shExecInfo.lpParameters = params;
492 shExecInfo.lpDirectory = directory;
493 shExecInfo.nShow = SW_SHOWNORMAL;
494 const BOOL success = ShellExecuteExW(&shExecInfo);
495 if(success && (((UINT32)(UINT_PTR)shExecInfo.hInstApp) > 32U))
497 if(process)
499 *process = shExecInfo.hProcess;
501 else
503 if(shExecInfo.hProcess != NULL)
505 CloseHandle(shExecInfo.hProcess);
508 return TRUE;
510 else
512 if(process)
514 *process = NULL;
516 return FALSE;
520 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)
522 HANDLE process = NULL;
523 for(;;)
525 const HWND owner = hwnd ? (*hwnd) : NULL;
526 PROCESS_MESSAGES(owner);
527 if(!exec_shell(owner, verb, full_path, params, directory, &process))
529 PROCESS_MESSAGES(owner);
530 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)
532 return 0x2E4;
535 else
537 DWORD exit_code = 0U;
538 Sleep(25);
539 if(hwnd && (*hwnd))
541 DestroyWindow(*hwnd);
542 *hwnd = NULL;
544 if(process)
546 WaitForSingleObject(process, INFINITE);
547 if(!GetExitCodeProcess(process, &exit_code))
549 exit_code = (DWORD)(-1);
551 CloseHandle(process);
553 return exit_code; /*success*/
558 // ----------------------------------------------------
559 // Miscellaneous
560 // ----------------------------------------------------
562 static void error_message(const HWND hwnd, const wchar_t *const message, const wchar_t *const title)
564 MessageBoxW(hwnd, message, TITLE(title), (hwnd ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONERROR);
567 static void show_help(const HWND hwnd, const wchar_t *const executable_name)
569 wchar_t message[256U];
570 format(message, 256U, L"Usage:\n\n%s <setup.exe> [PARAMETERS]", executable_name);
571 MessageBoxW(hwnd, message, PROGRAM_NAME, (hwnd ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONINFORMATION);
574 static void show_about(const HWND hwnd, const BOOL dll)
576 wchar_t message[256U];
577 format(message, 256U, L"%s %s [%s]\n"
578 L"Copyright(c) 2016-2020 LoRd_MuldeR <mulder2@gmx.de>\n"
579 L"Please see http://muldersoft.com/ for details!\n\n"
580 L"This program is free software; you can redistribute it and/or modify it under the terms of the the MIT License.",
581 PROGRAM_NAME, dll ? L"DLL" : L"EXE", STRINGIFY(BUILD_DATE_F));
582 MessageBoxW(hwnd, message, L"About...", (hwnd ? MB_TOPMOST : MB_SYSTEMMODAL) | MB_ICONINFORMATION);
585 // ==========================================================================
586 // EXE File
587 // ==========================================================================
589 #ifdef BUILD_EXE
591 static wchar_t executable_path [MAX_STRLEN] = { L'\0' };
592 static wchar_t executable_directory[MAX_STRLEN] = { L'\0' };
593 static wchar_t setup_path [MAX_STRLEN] = { L'\0' };
594 static wchar_t setup_absolute_path [MAX_STRLEN] = { L'\0' };
595 static wchar_t setup_directory [MAX_STRLEN] = { L'\0' };
596 static wchar_t library_path [MAX_STRLEN] = { L'\0' };
597 static wchar_t rundll32_path [MAX_STRLEN] = { L'\0' };
598 static wchar_t parameters [MAX_STRLEN] = { L'\0' };
600 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR pCmdLine, int nCmdShow)
602 /*get executable path*/
603 if(!get_executable_path(executable_path, MAX_STRLEN))
605 error_message(NULL, L"Error: Failed to determine executable path!", NULL);
606 return 1;
609 /*get command-line arguments*/
610 if(EMPTY(pCmdLine))
612 error_message(NULL, L"Required command-line parameters are missing!", NULL);
613 show_help(NULL, skip_directory_part(executable_path));
614 return 1;
617 /*show about screen*/
618 if((!_wcsicmp(pCmdLine, L"--about")) || (!_wcsicmp(pCmdLine, L"--version")))
620 show_about(NULL, FALSE);
621 return 0;
624 /*show help screen*/
625 if((!_wcsicmp(pCmdLine, L"--help")) || (!_wcsicmp(pCmdLine, L"/?")) || (!_wcsicmp(pCmdLine, L"-?")))
627 show_help(NULL, skip_directory_part(executable_path));
628 return 0;
631 /*get executable directory*/
632 copy(executable_directory, executable_path, MAX_STRLEN);
633 remove_file_name(executable_directory);
634 trim_trailing_separators(executable_directory, FALSE);
636 /*set working directory*/
637 SetCurrentDirectoryW(executable_directory);
639 /*get setup file path*/
640 const wchar_t *const cmd_args = get_next_arg(pCmdLine, setup_path, MAX_STRLEN);
641 if(EMPTY(setup_path))
643 error_message(NULL, L"Error: Failed to determine setup program path!", NULL);
646 /*get absolute path file path*/
647 const wchar_t *file_name;
648 get_absolute_path(setup_path, setup_absolute_path, MAX_STRLEN, &file_name);
650 /*check for silent mode*/
651 const BOOL silent = starts_with(cmd_args, L"-ms") || starts_with(cmd_args, L"/ini") || starts_with(cmd_args, L"/s");
653 /*create banner window*/
654 HWND banner = (!silent) ? create_banner(hInstance, file_name, wnd_proc) : NULL;
655 if(banner != NULL)
657 show_window(banner);
660 /*make sure the setup executable exists*/
661 if(!file_exists(setup_absolute_path))
663 format(parameters, MAX_STRLEN, L"Setup executable could not be found:\n\n%s", setup_absolute_path);
664 error_message(banner, parameters, file_name);
665 return 0x490;
668 /*get setup file directory*/
669 copy(setup_directory, setup_absolute_path, MAX_STRLEN);
670 remove_file_name(setup_directory);
671 trim_trailing_separators(setup_directory, FALSE);
673 /*set working directory*/
674 SetCurrentDirectoryW(setup_directory);
676 /*take the fast path, iff already elevated (or running on pre-Vista)*/
677 if(is_elevated())
679 return exec_shell_await(&banner, NULL, file_name, setup_absolute_path, cmd_args, setup_directory);
682 /*get path of RunDLL executable file*/
683 if(!get_system_path(rundll32_path, MAX_STRLEN))
685 error_message(banner, L"Error: Failed to determine system directory path!", file_name);
686 return 1;
688 trim_trailing_separators(rundll32_path, TRUE);
689 append(rundll32_path, L"\\rundll32.exe", MAX_STRLEN);
691 /*make sure the RunDLL executable exists*/
692 if(!file_exists(rundll32_path))
694 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);
695 error_message(banner, parameters, file_name);
696 return 0x485;
699 /*get path of launcher DLL*/
700 copy(library_path, executable_path, MAX_STRLEN);
701 remove_file_extension(library_path);
702 append(library_path, L".dll", MAX_STRLEN);
704 /*make sure the launcher DLL exists*/
705 if(!file_exists(library_path))
707 format(parameters, MAX_STRLEN, L"Launcher library file could not be found:\n\n%s", library_path);
708 error_message(banner, parameters, file_name);
709 return 0x485;
712 /*build parameter string for RunDLL*/
713 format(parameters, MAX_STRLEN, contains_space(library_path) ? L"\"%s\",startup" : L"%s,startup", library_path);
714 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);
715 if(!EMPTY(cmd_args))
717 append_format(parameters, MAX_STRLEN, L"\x20%s", cmd_args);
720 /*now actually call the launcher DLL*/
721 const DWORD exit_code = exec_shell_await(&banner, L"runas", file_name, rundll32_path, parameters, setup_directory);
723 /*clean-up*/
724 if(banner != NULL)
726 DestroyWindow(banner);
729 return exit_code;
732 #endif //BUILD_EXE
734 // ==========================================================================
735 // DLL File
736 // ==========================================================================
738 #ifdef BUILD_DLL
740 static wchar_t setup_path [MAX_STRLEN] = { L'\0' };
741 static wchar_t setup_absolute_path[MAX_STRLEN] = { L'\0' };
742 static wchar_t setup_directory [MAX_STRLEN] = { L'\0' };
744 static HINSTANCE g_hinstDLL = NULL;
746 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
748 if(fdwReason == DLL_PROCESS_ATTACH)
750 g_hinstDLL = hinstDLL;
752 return TRUE;
755 void CALLBACK startupW(HWND hwnd, HINSTANCE hAppInstance, LPCWSTR lpCmdLine, int nCmdShow)
757 /*check command-line args*/
758 if(EMPTY(lpCmdLine))
760 error_message(hwnd, L"Required command-line parameters are missing!", NULL);
761 ExitProcess(0x57);
762 return;
765 /*get the version tag*/
766 lpCmdLine = get_next_arg(lpCmdLine, setup_path, MAX_STRLEN); /*use 'setup_path' to store version tag!*/
767 if(EMPTY(setup_path))
769 error_message(hwnd, L"Error: Failed to determine the version tag!", NULL);
770 ExitProcess(0x57);
771 return;
774 /*check the version tag*/
775 if(wcstoul(setup_path, NULL, 16U) != API_VERSION)
777 error_message(hwnd, L"Error: Version tag mismatch detected!", NULL);
778 ExitProcess(0x57);
779 return;
782 /*check remaining command-line arguments*/
783 if(EMPTY(lpCmdLine))
785 error_message(hwnd, L"Required command-line parameters are missing!", NULL);
786 ExitProcess(0x57);
787 return;
790 /*get setup file path*/
791 lpCmdLine = get_next_arg(lpCmdLine, setup_path, MAX_STRLEN);
792 if(EMPTY(setup_path))
794 error_message(hwnd, L"Error: Failed to determine setup program path!", NULL);
795 ExitProcess(0x57);
796 return;
799 /*get absolut setup file path*/
800 const wchar_t *file_name;
801 get_absolute_path(setup_path, setup_absolute_path, MAX_STRLEN, &file_name);
803 /*check for silent mode*/
804 const BOOL silent = starts_with(lpCmdLine, L"-ms") || starts_with(lpCmdLine, L"/ini") || starts_with(lpCmdLine, L"/s");
806 /*create banner window*/
807 HWND banner = (!silent) ? create_banner(g_hinstDLL, file_name, wnd_proc) : NULL;
808 if(banner != NULL)
810 show_window(banner);
813 /*make sure the setup executable exists*/
814 if(!file_exists(setup_absolute_path))
816 format(setup_directory, MAX_STRLEN, L"Setup executable could not be found:\n\n%s", setup_absolute_path);
817 error_message((banner != NULL) ? banner : hwnd, setup_directory, file_name);
818 ExitProcess(0x490);
819 return;
822 /*get setup file directory*/
823 copy(setup_directory, setup_absolute_path, MAX_STRLEN);
824 remove_file_name(setup_directory);
825 trim_trailing_separators(setup_directory, FALSE);
827 /*set working directory*/
828 SetCurrentDirectoryW(setup_directory);
830 /*now actually launch the executable*/
831 const DWORD exit_code = exec_shell_await(&banner, NULL, file_name, setup_absolute_path, lpCmdLine, setup_directory);
833 /*clean-up*/
834 if(banner != NULL)
836 DestroyWindow(banner);
839 ExitProcess(exit_code);
842 void CALLBACK startup(HWND hwnd, HINSTANCE hAppInstance, LPCSTR lpCmdLine, int nCmdShow)
844 const wchar_t *const lpCmdLineW = get_next_arg(GetCommandLineW(), NULL, 0U);
845 if(!EMPTY(lpCmdLineW))
847 startupW(hwnd, hAppInstance, (LPWSTR)get_next_arg(lpCmdLineW, NULL, 0U), nCmdShow);
849 else
851 startupW(hwnd, hAppInstance, L""/*no arguments*/, nCmdShow);
855 void CALLBACK aboutW(HWND hwnd, HINSTANCE hAppInstance, LPCWSTR lpCmdLine, int nCmdShow)
857 show_about(hwnd, TRUE);
860 void CALLBACK about(HWND hwnd, HINSTANCE hAppInstance, LPCSTR lpCmdLine, int nCmdShow)
862 show_about(hwnd, TRUE);
865 #endif //BUILD_DLL