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
= LoadIcon((HINSTANCE
)GetModuleHandle(NULL
), MAKEINTRESOURCE(IDI_ICON1
))) != NULL
)
430 for(DWORD k
= ICON_SMALL
; k
<= ICON_BIG
; ++k
)
432 SendMessage(hwnd
, WM_SETICON
, (WPARAM
)k
, (LPARAM
)hIcon
);
439 static void process_messages(const HWND hwnd
)
442 for (unsigned short i
= 0U; i
< 8U; ++i
)
449 for (unsigned short k
= 0U; k
< 8192U; ++k
)
451 if (PeekMessageW(&msg
, hwnd
, 0U, 0U, PM_REMOVE
))
454 TranslateMessage(&msg
);
455 DispatchMessageW(&msg
);
462 break; /*did not process any messages*/
467 static BOOL
show_window(const HWND hwnd
)
472 result
= ShowWindow(hwnd
, SW_SHOWNORMAL
);
473 process_messages(hwnd
);
475 SetForegroundWindow(hwnd
);
481 // ----------------------------------------------------
483 // ----------------------------------------------------
485 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
)
487 SHELLEXECUTEINFOW shExecInfo
;
488 SecureZeroMemory(&shExecInfo
, sizeof(SHELLEXECUTEINFOW
));
489 shExecInfo
.cbSize
= sizeof(SHELLEXECUTEINFOW
);
490 shExecInfo
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
491 shExecInfo
.hwnd
= hwnd
;
492 shExecInfo
.lpVerb
= verb
;
493 shExecInfo
.lpFile
= file
;
494 shExecInfo
.lpParameters
= params
;
495 shExecInfo
.lpDirectory
= directory
;
496 shExecInfo
.nShow
= SW_SHOWNORMAL
;
497 const BOOL success
= ShellExecuteExW(&shExecInfo
);
498 if(success
&& (((UINT32
)(UINT_PTR
)shExecInfo
.hInstApp
) > 32U))
502 *process
= shExecInfo
.hProcess
;
506 if(shExecInfo
.hProcess
!= NULL
)
508 CloseHandle(shExecInfo
.hProcess
);
523 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
)
525 HANDLE process
= NULL
;
528 const HWND owner
= hwnd
? (*hwnd
) : NULL
;
529 PROCESS_MESSAGES(owner
);
530 if(!exec_shell(owner
, verb
, full_path
, params
, directory
, &process
))
532 PROCESS_MESSAGES(owner
);
533 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
)
540 DWORD exit_code
= 0U;
544 DestroyWindow(*hwnd
);
549 WaitForSingleObject(process
, INFINITE
);
550 if(!GetExitCodeProcess(process
, &exit_code
))
552 exit_code
= (DWORD
)(-1);
554 CloseHandle(process
);
556 return exit_code
; /*success*/
561 // ----------------------------------------------------
563 // ----------------------------------------------------
565 static void error_message(const HWND hwnd
, const wchar_t *const message
, const wchar_t *const title
)
567 MessageBoxW(hwnd
, message
, TITLE(title
), (hwnd
? MB_TOPMOST
: MB_SYSTEMMODAL
) | MB_ICONERROR
);
570 static void show_about(const HWND hwnd
, const BOOL dll
)
572 wchar_t message
[256U];
573 format(message
, 256U, L
"Setup Bootstrapper %s [%s]\n"
574 L
"Copyright(c) 2016-2020 LoRd_MuldeR <mulder2@gmx.de>\n"
575 L
"Please see http://muldersoft.com/ for details!\n\n"
576 L
"This program is free software; you can redistribute it and/or modify it under the terms of the the MIT License.",
577 dll
? L
"DLL" : L
"EXE", STRINGIFY(BUILD_DATE_F
));
578 MessageBoxW(hwnd
, message
, L
"About...", (hwnd
? MB_TOPMOST
: MB_SYSTEMMODAL
) | MB_ICONINFORMATION
);
581 // ==========================================================================
583 // ==========================================================================
587 static wchar_t executable_path
[MAX_STRLEN
] = { L
'\0' };
588 static wchar_t executable_directory
[MAX_STRLEN
] = { L
'\0' };
589 static wchar_t setup_path
[MAX_STRLEN
] = { L
'\0' };
590 static wchar_t setup_absolute_path
[MAX_STRLEN
] = { L
'\0' };
591 static wchar_t setup_directory
[MAX_STRLEN
] = { L
'\0' };
592 static wchar_t library_path
[MAX_STRLEN
] = { L
'\0' };
593 static wchar_t rundll32_path
[MAX_STRLEN
] = { L
'\0' };
594 static wchar_t parameters
[MAX_STRLEN
] = { L
'\0' };
596 static LRESULT CALLBACK
WndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
603 if(hdc
= BeginPaint(hwnd
, &ps
))
605 FillRect(hdc
, &ps
.rcPaint
, (HBRUSH
)(COLOR_WINDOW
+ 1));
606 DrawTextExW(hdc
, L
"Setup is launching, please stay tuned...", -1, &ps
.rcPaint
, DT_CENTER
|DT_SINGLELINE
|DT_VCENTER
, NULL
);
610 return 0; /*ignore WM_CLOSE msg*/
612 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
616 int WINAPI
wWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, PWSTR pCmdLine
, int nCmdShow
)
618 /*get command-line arguments*/
619 if((!pCmdLine
) || (!(*pCmdLine
)) || (!_wcsicmp(pCmdLine
, L
"--help")) || (!_wcsicmp(pCmdLine
, L
"/?")))
621 error_message(NULL
, L
"Required parameters are missing!\n\nUsage:\nsetup-launcher.exe <setup.exe> [PARAMETERS]", NULL
);
625 /*show about screen*/
626 if((!_wcsicmp(pCmdLine
, L
"--about")) || (!_wcsicmp(pCmdLine
, L
"--version")))
628 show_about(NULL
, FALSE
);
632 /*get executable path*/
633 if(!get_executable_path(executable_path
, MAX_STRLEN
))
635 error_message(NULL
, L
"Error: Failed to determine executable path!", NULL
);
639 /*get executable directory*/
640 copy(executable_directory
, executable_path
, MAX_STRLEN
);
641 remove_file_name(executable_directory
);
642 trim_trailing_separators(executable_directory
, FALSE
);
644 /*set working directory*/
645 SetCurrentDirectoryW(executable_directory
);
647 /*get setup file path*/
648 if(!get_first_parameter(pCmdLine
, setup_path
, MAX_STRLEN
))
650 error_message(NULL
, L
"Error: Failed to determine setup program path!", NULL
);
653 /*get absolute path file path*/
654 const wchar_t *file_name
;
655 get_absolute_path(setup_path
, setup_absolute_path
, MAX_STRLEN
, &file_name
);
657 /*check for silent mode*/
658 const wchar_t *const extra_args
= get_extra_parameters(pCmdLine
);
659 const BOOL silent
= starts_with(extra_args
, L
"-ms") || starts_with(extra_args
, L
"/ini") || starts_with(extra_args
, L
"/s");
661 /*create banner window*/
662 HWND banner
= (!silent
) ? create_banner(hInstance
, file_name
, WndProc
) : NULL
;
668 /*make sure the setup executable exists*/
669 if(!file_exists(setup_absolute_path
))
671 format(parameters
, MAX_STRLEN
, L
"Setup executable could not be found:\n\n%s", setup_absolute_path
);
672 error_message(banner
, parameters
, file_name
);
676 /*get setup file directory*/
677 copy(setup_directory
, setup_absolute_path
, MAX_STRLEN
);
678 remove_file_name(setup_directory
);
679 trim_trailing_separators(setup_directory
, FALSE
);
681 /*set working directory*/
682 SetCurrentDirectoryW(setup_directory
);
684 /*take the fast path, iff already elevated (or running on pre-Vista)*/
687 return exec_shell_await(&banner
, NULL
, file_name
, setup_absolute_path
, extra_args
, setup_directory
);
690 /*get path of RunDLL executable file*/
691 if(!get_system_path(rundll32_path
, MAX_STRLEN
))
693 error_message(banner
, L
"Error: Failed to determine system directory path!", file_name
);
696 trim_trailing_separators(rundll32_path
, TRUE
);
697 append(rundll32_path
, L
"\\rundll32.exe", MAX_STRLEN
);
699 /*make sure the RunDLL executable exists*/
700 if(!file_exists(rundll32_path
))
702 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
);
703 error_message(banner
, parameters
, file_name
);
707 /*get path of launcher DLL*/
708 copy(library_path
, executable_path
, MAX_STRLEN
);
709 remove_file_extension(library_path
);
710 append(library_path
, L
".dll", MAX_STRLEN
);
712 /*make sure the launcher DLL exists*/
713 if(!file_exists(library_path
))
715 format(parameters
, MAX_STRLEN
, L
"Launcher library file could not be found:\n\n%s", library_path
);
716 error_message(banner
, parameters
, file_name
);
720 /*build parameter string for RunDLL*/
721 format(parameters
, MAX_STRLEN
, contains_space(library_path
) ? L
"\"%s\",startup" : L
"%s,startup", library_path
);
722 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
);
723 if(extra_args
&& (*extra_args
))
725 append_format(parameters
, MAX_STRLEN
, L
"\x20%s", extra_args
);
728 /*now actually call the launcher DLL*/
729 const DWORD exit_code
= exec_shell_await(&banner
, L
"runas", file_name
, rundll32_path
, parameters
, setup_directory
);
734 DestroyWindow(banner
);
742 // ==========================================================================
744 // ==========================================================================
748 static wchar_t setup_path
[MAX_STRLEN
] = { L
'\0' };
749 static wchar_t setup_absolute_path
[MAX_STRLEN
] = { L
'\0' };
750 static wchar_t setup_directory
[MAX_STRLEN
] = { L
'\0' };
752 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
756 case DLL_PROCESS_ATTACH
:
757 case DLL_THREAD_ATTACH
:
758 case DLL_THREAD_DETACH
:
759 case DLL_PROCESS_DETACH
:
765 void CALLBACK
startupW(HWND hwnd
, HINSTANCE hAppInstance
, LPCWSTR lpCmdLine
, int nCmdShow
)
767 /*get command-line arguments*/
768 if((!lpCmdLine
) || (!(*lpCmdLine
)))
770 error_message(hwnd
, L
"Required command-line parameters are missing!", NULL
);
775 /*get the version tag*/
776 if(!get_first_parameter(lpCmdLine
, setup_path
, MAX_STRLEN
))
778 error_message(hwnd
, L
"Error: Failed to determine the version tag!", NULL
);
783 /*check the version tag*/
784 if(wcstoul(setup_path
, NULL
, 16U) != API_VERSION
)
786 error_message(hwnd
, L
"Error: Version tag mismatch detected!", NULL
);
791 /*get next command-line arguments*/
792 lpCmdLine
= get_extra_parameters(lpCmdLine
);
793 if((!lpCmdLine
) || (!(*lpCmdLine
)))
795 error_message(hwnd
, L
"Required command-line parameters are missing!", NULL
);
800 /*get setup file path*/
801 if(!get_first_parameter(lpCmdLine
, setup_path
, MAX_STRLEN
))
803 error_message(hwnd
, L
"Error: Failed to determine setup program path!", NULL
);
808 /*get absolut setup file path*/
809 const wchar_t *file_name
;
810 get_absolute_path(setup_path
, setup_absolute_path
, MAX_STRLEN
, &file_name
);
812 /*make sure the setup executable exists*/
813 if(!file_exists(setup_absolute_path
))
815 format(setup_directory
, MAX_STRLEN
, L
"Setup executable could not be found:\n\n%s", setup_absolute_path
);
816 error_message(hwnd
, setup_directory
, file_name
);
821 /*get setup file directory*/
822 copy(setup_directory
, setup_absolute_path
, MAX_STRLEN
);
823 remove_file_name(setup_directory
);
824 trim_trailing_separators(setup_directory
, FALSE
);
826 /*set working directory*/
827 SetCurrentDirectoryW(setup_directory
);
829 /*now actually launch the executable*/
830 ExitProcess(exec_shell_await(&hwnd
, NULL
, file_name
, setup_absolute_path
, get_extra_parameters(lpCmdLine
), setup_directory
));
833 void CALLBACK
startup(HWND hwnd
, HINSTANCE hAppInstance
, LPCSTR lpCmdLine
, int nCmdShow
)
835 const wchar_t *const lpCmdLineW
= get_extra_parameters(GetCommandLineW());
836 if(lpCmdLineW
&& (*lpCmdLineW
))
838 startupW(hwnd
, hAppInstance
, (LPWSTR
)get_extra_parameters(lpCmdLineW
), nCmdShow
);
842 startupW(hwnd
, hAppInstance
, L
""/*no arguments*/, nCmdShow
);
846 void CALLBACK
aboutW(HWND hwnd
, HINSTANCE hAppInstance
, LPCWSTR lpCmdLine
, int nCmdShow
)
848 show_about(hwnd
, TRUE
);
851 void CALLBACK
about(HWND hwnd
, HINSTANCE hAppInstance
, LPCSTR lpCmdLine
, int nCmdShow
)
853 show_about(hwnd
, TRUE
);