1 /* ---------------------------------------------------------------------------------------------- */
2 /* Setup Bootstrapper Utility */
3 /* Copyright(c) 2016-2020 LoRd_MuldeR <mulder2@gmx.de> */
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: */
11 /* The above copyright notice and this permission notice shall be included in all copies or */
12 /* substantial portions of the Software. */
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)
24 #if defined(BUILD_EXE) && defined(BUILD_DLL)
25 #error Inconsistent build flags!
27 #if !defined(BUILD_DATE_F) || !defined(BUILD_DATE_X)
28 #error Build date is not defined!
35 // ==========================================================================
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)
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 // ----------------------------------------------------
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 \
69 (BUFF)[(SIZE) - 1U] = L'\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()!*/
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);
90 static wchar_t *format(wchar_t *const buffer
, const size_t buff_size
, const wchar_t *const format
, ...)
93 va_start(args
, format
);
94 _vsnwprintf(buffer
, buff_size
, format
, args
);
96 ENSURE_NULL_TERMINATED(buffer
, buff_size
); /*not guranteed by _vsnwprintf()!*/
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))
106 va_start(args
, format
);
107 _vsnwprintf(buffer
+ current_len
, buff_size
- current_len
, format
, args
);
109 ENSURE_NULL_TERMINATED(buffer
, buff_size
); /*not guranteed by _vsnwprintf()!*/
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
)
126 if(ptr
= wcsrchr(haystack
, needle
))
128 return ptr
- haystack
;
133 static BOOL
contains_space(const wchar_t *str
)
135 for(; *str
!= L
'\0'; ++str
)
145 static BOOL
starts_with(const wchar_t *const str
, const wchar_t *const prefix
)
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);
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); \
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
))
183 for (; *cmdLine
!= L
'\0'; ++cmdLine
)
185 if (*cmdLine
== L
'\\')
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
'\\');
201 flag_quote
= (!flag_quote
);
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
);
218 if ((!flag_quote
) && iswspace(*cmdLine
))
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
))
237 /*put the NULL terminator*/
240 arg_out
[len
] = L
'\0';
246 // ----------------------------------------------------
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
))
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
))
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);
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
);
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
);
307 static wchar_t *remove_file_extension(wchar_t *const path
)
309 wchar_t *const file_name
= skip_directory_part(path
);
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';
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
':')
330 path
[--length
] = L
'\0';
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 // ----------------------------------------------------
344 // ----------------------------------------------------
346 static BOOL
is_elevated(void)
348 const DWORD version
= GetVersion();
349 if(((DWORD
)LOBYTE(LOWORD(version
))) > 5U)
351 BOOL elevated
= FALSE
;
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
:
373 return TRUE
; /*for Windows XP support*/
377 // ----------------------------------------------------
379 // ----------------------------------------------------
381 #define IDI_ICON1 101
383 #define PROCESS_MESSAGES(X) do \
385 const HWND _hwnd = (X); \
387 process_messages(_hwnd); \
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
);
396 RECT workRect
, wndRect
;
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
);
416 static void process_messages(const HWND hwnd
)
419 for (unsigned short i
= 0U; i
< 8U; ++i
)
426 for (unsigned short k
= 0U; k
< 8192U; ++k
)
428 if (PeekMessageW(&msg
, hwnd
, 0U, 0U, PM_REMOVE
))
431 TranslateMessage(&msg
);
432 DispatchMessageW(&msg
);
439 break; /*did not process any messages*/
444 static LRESULT CALLBACK
wnd_proc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
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
);
458 return 0; /*ignore WM_CLOSE msg*/
460 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
464 static BOOL
show_window(const HWND hwnd
)
469 result
= ShowWindow(hwnd
, SW_SHOWNORMAL
);
470 process_messages(hwnd
);
472 SetForegroundWindow(hwnd
);
478 // ----------------------------------------------------
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))
499 *process
= shExecInfo
.hProcess
;
503 if(shExecInfo
.hProcess
!= NULL
)
505 CloseHandle(shExecInfo
.hProcess
);
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
;
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
)
537 DWORD exit_code
= 0U;
541 DestroyWindow(*hwnd
);
546 WaitForSingleObject(process
, INFINITE
);
547 if(!GetExitCodeProcess(process
, &exit_code
))
549 exit_code
= (DWORD
)(-1);
551 CloseHandle(process
);
553 return exit_code
; /*success*/
558 // ----------------------------------------------------
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 // ==========================================================================
587 // ==========================================================================
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
);
609 /*get command-line arguments*/
612 error_message(NULL
, L
"Required command-line parameters are missing!", NULL
);
613 show_help(NULL
, skip_directory_part(executable_path
));
617 /*show about screen*/
618 if((!_wcsicmp(pCmdLine
, L
"--about")) || (!_wcsicmp(pCmdLine
, L
"--version")))
620 show_about(NULL
, FALSE
);
625 if((!_wcsicmp(pCmdLine
, L
"--help")) || (!_wcsicmp(pCmdLine
, L
"/?")) || (!_wcsicmp(pCmdLine
, L
"-?")))
627 show_help(NULL
, skip_directory_part(executable_path
));
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
;
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
);
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)*/
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
);
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
);
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
);
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
);
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
);
726 DestroyWindow(banner
);
734 // ==========================================================================
736 // ==========================================================================
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
;
755 void CALLBACK
startupW(HWND hwnd
, HINSTANCE hAppInstance
, LPCWSTR lpCmdLine
, int nCmdShow
)
757 /*check command-line args*/
760 error_message(hwnd
, L
"Required command-line parameters are missing!", NULL
);
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
);
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
);
782 /*check remaining command-line arguments*/
785 error_message(hwnd
, L
"Required command-line parameters are missing!", NULL
);
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
);
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
;
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
);
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
);
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
);
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
);