1 /* ---------------------------------------------------------------------------------------------- */
2 /* Setup Launcher 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!
30 //---------------------------------------------------------------------------
32 //---------------------------------------------------------------------------
34 #define MAX_PATHLEN 32768U
35 #define MAX_CMDNLEN 131072U
39 const __typeof__((A)) _a = (A); \
40 const __typeof__((B)) _b = (B); \
44 #define APPEND(BUFF,STR,BUFF_SIZE) do \
46 if(contains_space((STR))) \
48 append((BUFF), L"\"", (BUFF_SIZE)); \
49 append((BUFF), STR, (BUFF_SIZE)); \
50 append((BUFF), L"\"", (BUFF_SIZE)); \
54 append((BUFF), STR, (BUFF_SIZE)); \
59 static wchar_t *append(wchar_t *const buffer
, const wchar_t *const str
, const size_t buff_size
)
61 const size_t current_len
= wcslen(buffer
);
62 if(current_len
< buff_size
)
64 wcsncat(buffer
, str
, buff_size
- current_len
);
65 buffer
[buff_size
- 1U] = L
'\0';
70 static size_t last_index(const wchar_t *const haystack
, const wchar_t needle
)
73 if(ptr
= wcsrchr(haystack
, needle
))
75 return ptr
- haystack
;
80 static BOOL
contains_space(const wchar_t *str
)
82 for(; *str
!= L
'\0'; ++str
)
92 static void get_absolut_path(const wchar_t *const path
, wchar_t *const full_path
, const size_t max_len
)
94 const DWORD ret
= GetFullPathNameW(path
, max_len
, full_path
, NULL
);
95 if(!((ret
> 0U) && (ret
< max_len
)))
97 wcsncpy(full_path
, path
, max_len
);
98 full_path
[max_len
- 1U] = L
'\0';
102 static BOOL
file_exists(const wchar_t *const path
)
104 const DWORD attributes
= GetFileAttributesW(path
);
105 return ((attributes
!= INVALID_FILE_ATTRIBUTES
) && (!(attributes
& FILE_ATTRIBUTE_DIRECTORY
)));
108 static BOOL
is_elevated(void)
110 BOOL elevated
= FALSE
;
112 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
114 TOKEN_ELEVATION elevation
;
115 DWORD cbSize
= sizeof(TOKEN_ELEVATION
);
116 if(GetTokenInformation(hToken
, TokenElevation
, &elevation
, sizeof(elevation
), &cbSize
))
118 elevated
= elevation
.TokenIsElevated
;
125 static BOOL
get_executable_path(const wchar_t *ptr
, wchar_t *const out
, const size_t max_len
)
128 const size_t limit
= max_len
- 1U;
130 while ((*ptr
!= L
'\0') && iswspace(*ptr
))
134 for (; *ptr
!= L
'\0'; ++ptr
)
142 if((!flag
) && iswspace(*ptr
))
161 static const wchar_t *get_parameters(const wchar_t *cmdLine
)
168 while ((*cmdLine
!= L
'\0') && iswspace(*cmdLine
))
172 for (; *cmdLine
!= L
'\0'; ++cmdLine
)
180 if((!flag
) && iswspace(*cmdLine
))
186 while ((*cmdLine
!= L
'\0') && iswspace(*cmdLine
))
193 static void remove_file_extension(wchar_t *const path
)
195 const size_t pos_dot
= last_index(path
, L
'.');
196 const size_t pos_sep
= MAX(last_index(path
, L
'/'), last_index(path
, L
'\\'));
197 if((pos_dot
> 0U) && ((pos_sep
== 0U) || (pos_dot
> pos_sep
)))
199 path
[pos_dot
] = L
'\0';
203 static BOOL
exec_shell(const wchar_t *const verb
, const wchar_t *const file
, const wchar_t *const params
, const BOOL await
, DWORD
*const exit_code
)
205 SHELLEXECUTEINFOW shExecInfo
;
206 SecureZeroMemory(&shExecInfo
, sizeof(SHELLEXECUTEINFOW
));
207 shExecInfo
.cbSize
= sizeof(SHELLEXECUTEINFOW
);
208 shExecInfo
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
209 shExecInfo
.lpVerb
= verb
;
210 shExecInfo
.lpFile
= file
;
211 shExecInfo
.lpParameters
= params
;
212 shExecInfo
.nShow
= SW_SHOW
;
213 if(ShellExecuteExW(&shExecInfo
))
219 if(await
&& (shExecInfo
.hProcess
!= NULL
))
221 WaitForSingleObject(shExecInfo
.hProcess
, INFINITE
);
224 GetExitCodeProcess(shExecInfo
.hProcess
, exit_code
);
226 CloseHandle(shExecInfo
.hProcess
);
237 static void error_message(const wchar_t *const message
)
239 MessageBoxW(NULL
, message
, L
"Setup Launcher", MB_ICONERROR
|MB_SYSTEMMODAL
);
242 //---------------------------------------------------------------------------
244 //---------------------------------------------------------------------------
248 static wchar_t executable_path
[MAX_PATHLEN
];
249 static wchar_t executable_absolut_path
[MAX_PATHLEN
];
250 static wchar_t library_path
[MAX_PATHLEN
];
251 static wchar_t rundll32_path
[MAX_PATHLEN
];
252 static wchar_t parameters
[MAX_CMDNLEN
];
254 int WINAPI
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, PSTR pCmdLine
, int nCmdShow
)
256 /*get command-line arguments*/
257 const wchar_t *const cmdLineArgs
= get_parameters(GetCommandLineW());
258 if((!cmdLineArgs
) || (!(*cmdLineArgs
)))
260 error_message(L
"Required parameters are missing!\n\nUsage:\nsetup-launcher.exe <setup.exe> [PARAMETERS]");
264 /*get executable path*/
265 if(!get_executable_path(cmdLineArgs
, executable_path
, MAX_PATHLEN
))
267 error_message(L
"Error: Failed to determine the executable path!");
270 /*get absolout executable path*/
271 get_absolut_path(executable_path
, executable_absolut_path
, MAX_PATHLEN
);
273 /*make sure the executable exists*/
274 if(!file_exists(executable_absolut_path
))
276 error_message(L
"Error: Setup executable could not be found!");
280 /*take the fast path, iff already elevated*/
284 if(!exec_shell(NULL
, executable_absolut_path
, get_parameters(cmdLineArgs
), TRUE
, &exit_code
))
286 error_message(L
"Error: Failed to launch the setup program!");
292 /*get path of RunDLL EXE file*/
293 DWORD ret
= GetSystemDirectoryW(rundll32_path
, MAX_PATHLEN
);
294 if((ret
< 1U) || (ret
>= MAX_PATHLEN
))
296 error_message(L
"Error: Failed to determine system directory path!");
299 append(rundll32_path
, L
"\\rundll32.exe", MAX_PATHLEN
);
301 /*get path of launcher DLL*/
302 ret
= GetModuleFileNameW(NULL
, library_path
, MAX_PATHLEN
);
303 if((ret
< 1U) || (ret
>= MAX_PATHLEN
))
305 error_message(L
"Error: Failed to determine executable path!");
308 remove_file_extension(library_path
);
309 append(library_path
, L
".dll", MAX_PATHLEN
);
311 /*make sure the launcher DLL exists*/
312 if(!file_exists(library_path
))
314 error_message(L
"Error: Launcher library file could not be found!");
318 /*build parameter string for RunDLL*/
319 parameters
[0U] = L
'\0';
320 APPEND(parameters
, library_path
, MAX_CMDNLEN
);
321 append(parameters
, L
",startup ", MAX_CMDNLEN
);
322 APPEND(parameters
, executable_absolut_path
, MAX_CMDNLEN
);
324 /*append additional parameters, if any*/
325 const wchar_t *const extraArgs
= get_parameters(cmdLineArgs
);
326 if(extraArgs
&& (*extraArgs
))
328 append(parameters
, L
" ", MAX_CMDNLEN
);
329 append(parameters
, extraArgs
, MAX_CMDNLEN
);
332 /*now actually call the launcher DLL*/
336 if(!exec_shell(L
"runas", rundll32_path
, parameters
, TRUE
, &exit_code
))
338 if(MessageBoxW(NULL
, L
"Failed to launch installer. Please try again!", L
"Setup Launcher", MB_SYSTEMMODAL
| MB_ICONEXCLAMATION
| MB_RETRYCANCEL
) != IDRETRY
)
345 return exit_code
; /*success*/
352 //---------------------------------------------------------------------------
354 //---------------------------------------------------------------------------
358 static wchar_t executable_path
[MAX_PATHLEN
];
359 static wchar_t executable_absolut_path
[MAX_PATHLEN
];
361 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
365 case DLL_PROCESS_ATTACH
:
366 case DLL_THREAD_ATTACH
:
367 case DLL_THREAD_DETACH
:
368 case DLL_PROCESS_DETACH
:
374 void CALLBACK
startup(HWND hwnd
, HINSTANCE hAppInstance
, LPSTR lpCmdLine
, int nCmdShow
)
376 error_message(L
"ANSI entry-point not supported. Please use Unicode entry-point!");
377 ExitProcess((DWORD
)(-1));
380 void CALLBACK
startupW(HWND hwnd
, HINSTANCE hAppInstance
, LPWSTR lpCmdLine
, int nCmdShow
)
382 /*get executable path*/
383 if(!get_executable_path(lpCmdLine
, executable_path
, MAX_PATHLEN
))
385 error_message(L
"Error: Failed to determine the executable path!");
388 /*get absolout executable path*/
389 get_absolut_path(executable_path
, executable_absolut_path
, MAX_PATHLEN
);
391 /*make sure the executable exists*/
392 if(!file_exists(executable_absolut_path
))
394 error_message(L
"Error: Setup executable could not be found!");
398 /*now actually launch the executable*/
400 if(!exec_shell(NULL
, executable_absolut_path
, get_parameters(lpCmdLine
), TRUE
, &exit_code
))
402 error_message(L
"Error: Failed to launch the setup program!");
406 ExitProcess(exit_code
);