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 : L"Setup Bootstrapper"; \
56 static const unsigned long API_VERSION
= HEXLIFY(BUILD_DATE_X
);
58 // ----------------------------------------------------
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 \
66 (BUFF)[(SIZE) - 1U] = L'\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()!*/
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);
87 static wchar_t *format(wchar_t *const buffer
, const size_t buff_size
, const wchar_t *const format
, ...)
90 va_start(args
, format
);
91 _vsnwprintf(buffer
, buff_size
, format
, args
);
93 ENSURE_NULL_TERMINATED(buffer
, buff_size
); /*not guranteed by _vsnwprintf()!*/
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))
103 va_start(args
, format
);
104 _vsnwprintf(buffer
+ current_len
, buff_size
- current_len
, format
, args
);
106 ENSURE_NULL_TERMINATED(buffer
, buff_size
); /*not guranteed by _vsnwprintf()!*/
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
)
123 if(ptr
= wcsrchr(haystack
, needle
))
125 return ptr
- haystack
;
130 static BOOL
contains_space(const wchar_t *str
)
132 for(; *str
!= L
'\0'; ++str
)
142 static BOOL
starts_with(const wchar_t *const str
, const wchar_t *const prefix
)
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);
155 // ----------------------------------------------------
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
))
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
))
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);
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
);
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
);
212 static wchar_t *remove_file_extension(wchar_t *const path
)
214 wchar_t *const file_name
= skip_directory_part(path
);
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';
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
':')
235 path
[--length
] = L
'\0';
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); \
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
))
271 for (; *cmdLine
!= L
'\0'; ++cmdLine
)
273 if (*cmdLine
== L
'\\')
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
'\\');
289 flag_quote
= (!flag_quote
);
295 for (; escape_count
; --escape_count
)
297 TRY_APPEND(out
, len
, max_len
, L
'\\');
301 else if (*cmdLine
== L
'"')
303 flag_quote
= (!flag_quote
);
306 if ((!flag_quote
) && iswspace(*cmdLine
))
310 TRY_APPEND(out
, len
, max_len
, *cmdLine
);
312 for (; escape_count
; --escape_count
)
314 TRY_APPEND(out
, len
, max_len
, L
'\\');
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
))
329 for (; *cmdLine
!= L
'\0'; ++cmdLine
)
331 if (*cmdLine
== L
'\\')
336 else if (escape_count
)
338 if (*cmdLine
== L
'"')
340 if (!(escape_count
% 2U))
343 flag_quote
= (!flag_quote
);
349 else if (*cmdLine
== L
'"')
351 flag_quote
= (!flag_quote
);
354 if ((!flag_quote
) && iswspace(*cmdLine
))
359 while ((*cmdLine
!= L
'\0') && iswspace(*cmdLine
))
366 // ----------------------------------------------------
368 // ----------------------------------------------------
370 static BOOL
is_elevated(void)
372 const DWORD version
= GetVersion();
373 if(((DWORD
)LOBYTE(LOWORD(version
))) > 5U)
375 BOOL elevated
= FALSE
;
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
:
397 return TRUE
; /*for Windows XP support*/
401 // ----------------------------------------------------
403 // ----------------------------------------------------
405 #define IDI_ICON1 101
407 #define PROCESS_MESSAGES(X) do \
409 const HWND _hwnd = (X); \
411 process_messages(_hwnd); \
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
);
420 RECT workRect
, wndRect
;
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
);
440 static void process_messages(const HWND hwnd
)
443 for (unsigned short i
= 0U; i
< 8U; ++i
)
450 for (unsigned short k
= 0U; k
< 8192U; ++k
)
452 if (PeekMessageW(&msg
, hwnd
, 0U, 0U, PM_REMOVE
))
455 TranslateMessage(&msg
);
456 DispatchMessageW(&msg
);
463 break; /*did not process any messages*/
468 static LRESULT CALLBACK
wnd_proc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
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
);
482 return 0; /*ignore WM_CLOSE msg*/
484 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
488 static BOOL
show_window(const HWND hwnd
)
493 result
= ShowWindow(hwnd
, SW_SHOWNORMAL
);
494 process_messages(hwnd
);
496 SetForegroundWindow(hwnd
);
502 // ----------------------------------------------------
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))
523 *process
= shExecInfo
.hProcess
;
527 if(shExecInfo
.hProcess
!= NULL
)
529 CloseHandle(shExecInfo
.hProcess
);
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
;
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
)
561 DWORD exit_code
= 0U;
565 DestroyWindow(*hwnd
);
570 WaitForSingleObject(process
, INFINITE
);
571 if(!GetExitCodeProcess(process
, &exit_code
))
573 exit_code
= (DWORD
)(-1);
575 CloseHandle(process
);
577 return exit_code
; /*success*/
582 // ----------------------------------------------------
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 // ==========================================================================
604 // ==========================================================================
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
);
626 /*show about screen*/
627 if((!_wcsicmp(pCmdLine
, L
"--about")) || (!_wcsicmp(pCmdLine
, L
"--version")))
629 show_about(NULL
, FALSE
);
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
);
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
;
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
);
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)*/
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
);
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
);
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
);
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
);
735 DestroyWindow(banner
);
743 // ==========================================================================
745 // ==========================================================================
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
;
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
);
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
);
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
);
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
);
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
);
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
;
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
);
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
);
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
);
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
);