Updated icon.
[setup-launcher.git] / setup-launcher.c
blob54581d439fec6c189700eda08509185c5ba7e85d
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 : L"Setup Bootstrapper"; \
56 static const unsigned long API_VERSION = HEXLIFY(BUILD_DATE_X);
58 // ----------------------------------------------------
59 // String Functions
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 \
65 { \
66 (BUFF)[(SIZE) - 1U] = L'\0'; \
67 } \
68 while(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()!*/
74 return buffer;
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);
84 return buffer;
87 static wchar_t *format(wchar_t *const buffer, const size_t buff_size, const wchar_t *const format, ...)
89 va_list args;
90 va_start(args, format);
91 _vsnwprintf(buffer, buff_size, format, args);
92 va_end(args);
93 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
94 return buffer;
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))
102 va_list args;
103 va_start(args, format);
104 _vsnwprintf(buffer + current_len, buff_size - current_len, format, args);
105 va_end(args);
106 ENSURE_NULL_TERMINATED(buffer, buff_size); /*not guranteed by _vsnwprintf()!*/
108 return buffer;
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)
122 const wchar_t *ptr;
123 if(ptr = wcsrchr(haystack, needle))
125 return ptr - haystack;
127 return SIZE_MAX;
130 static BOOL contains_space(const wchar_t *str)
132 for(; *str != L'\0'; ++str)
134 if(iswspace(*str))
136 return TRUE;
139 return FALSE;
142 static BOOL starts_with(const wchar_t *const str, const wchar_t *const prefix)
144 if(*str)
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);
152 return FALSE;
155 // ----------------------------------------------------
156 // Path Functions
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))
164 return TRUE;
166 return FALSE;
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))
174 return TRUE;
176 return FALSE;
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);
186 return path;
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);
195 if(file_name)
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);
205 if(*file_name)
207 *file_name = L'\0';
209 return path;
212 static wchar_t *remove_file_extension(wchar_t *const path)
214 wchar_t *const file_name = skip_directory_part(path);
215 if(*file_name)
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';
223 return path;
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':')
233 break;
235 path[--length] = L'\0';
237 return path;
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); \
256 else \
258 goto exit_loop; \
261 while(0)
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))
269 ++cmdLine;
271 for (; *cmdLine != L'\0'; ++cmdLine)
273 if (*cmdLine == L'\\')
275 ++escape_count;
276 continue;
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'\\');
287 if (!modul)
289 flag_quote = (!flag_quote);
290 continue;
293 else
295 for (; escape_count; --escape_count)
297 TRY_APPEND(out, len, max_len, L'\\');
301 else if (*cmdLine == L'"')
303 flag_quote = (!flag_quote);
304 continue;
306 if ((!flag_quote) && iswspace(*cmdLine))
308 break; /*stop!*/
310 TRY_APPEND(out, len, max_len, *cmdLine);
312 for (; escape_count; --escape_count)
314 TRY_APPEND(out, len, max_len, L'\\');
316 exit_loop:
317 out[len] = L'\0';
318 return (len > 0U);
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))
327 ++cmdLine;
329 for (; *cmdLine != L'\0'; ++cmdLine)
331 if (*cmdLine == L'\\')
333 ++escape_count;
334 continue;
336 else if (escape_count)
338 if (*cmdLine == L'"')
340 if (!(escape_count % 2U))
342 escape_count = 0U;
343 flag_quote = (!flag_quote);
344 continue;
347 escape_count = 0U;
349 else if (*cmdLine == L'"')
351 flag_quote = (!flag_quote);
352 continue;
354 if ((!flag_quote) && iswspace(*cmdLine))
356 break; /*stop!*/
359 while ((*cmdLine != L'\0') && iswspace(*cmdLine))
361 ++cmdLine;
363 return cmdLine;
366 // ----------------------------------------------------
367 // UAC Functions
368 // ----------------------------------------------------
370 static BOOL is_elevated(void)
372 const DWORD version = GetVersion();
373 if(((DWORD)LOBYTE(LOWORD(version))) > 5U)
375 BOOL elevated = FALSE;
376 HANDLE hToken;
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:
387 elevated = TRUE;
388 break;
391 CloseHandle(hToken);
393 return elevated;
395 else
397 return TRUE; /*for Windows XP support*/
401 // ----------------------------------------------------
402 // Window Functions
403 // ----------------------------------------------------
405 #define IDI_ICON1 101
407 #define PROCESS_MESSAGES(X) do \
409 const HWND _hwnd = (X); \
410 if(_hwnd) \
411 process_messages(_hwnd); \
413 while(0)
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);
418 if (hwnd != NULL)
420 RECT workRect, wndRect;
421 HICON hIcon;
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);
436 return hwnd;
439 static void process_messages(const HWND hwnd)
441 MSG msg = {};
442 for (unsigned short i = 0U; i < 8U; ++i)
444 BOOL flag = FALSE;
445 if(i > 0U)
447 Sleep(1); /*delay*/
449 for (unsigned short k = 0U; k < 8192U; ++k)
451 if (PeekMessageW(&msg, hwnd, 0U, 0U, PM_REMOVE))
453 flag = TRUE;
454 TranslateMessage(&msg);
455 DispatchMessageW(&msg);
456 continue;
458 break;
460 if(!flag)
462 break; /*did not process any messages*/
467 static BOOL show_window(const HWND hwnd)
469 BOOL result = FALSE;
470 if(hwnd != NULL)
472 result = ShowWindow(hwnd, SW_SHOWNORMAL);
473 process_messages(hwnd);
474 Sleep(25);
475 SetForegroundWindow(hwnd);
476 SetCapture(hwnd);
478 return result;
481 // ----------------------------------------------------
482 // Shell Execute
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))
500 if(process)
502 *process = shExecInfo.hProcess;
504 else
506 if(shExecInfo.hProcess != NULL)
508 CloseHandle(shExecInfo.hProcess);
511 return TRUE;
513 else
515 if(process)
517 *process = NULL;
519 return FALSE;
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;
526 for(;;)
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)
535 return 0x2E4;
538 else
540 DWORD exit_code = 0U;
541 Sleep(25);
542 if(hwnd && (*hwnd))
544 DestroyWindow(*hwnd);
545 *hwnd = NULL;
547 if(process)
549 WaitForSingleObject(process, INFINITE);
550 if(!GetExitCodeProcess(process, &exit_code))
552 exit_code = (DWORD)(-1);
554 CloseHandle(process);
556 return exit_code; /*success*/
561 // ----------------------------------------------------
562 // Miscellaneous
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 // ==========================================================================
582 // EXE File
583 // ==========================================================================
585 #ifdef BUILD_EXE
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)
598 PAINTSTRUCT ps;
599 HDC hdc;
600 switch(uMsg)
602 case WM_PAINT:
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);
607 EndPaint(hwnd, &ps);
609 case WM_CLOSE:
610 return 0; /*ignore WM_CLOSE msg*/
611 default:
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);
622 return 1;
625 /*show about screen*/
626 if((!_wcsicmp(pCmdLine, L"--about")) || (!_wcsicmp(pCmdLine, L"--version")))
628 show_about(NULL, FALSE);
629 return 0;
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);
636 return 1;
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;
663 if(banner != NULL)
665 show_window(banner);
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);
673 return 0x490;
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)*/
685 if(is_elevated())
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);
694 return 1;
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);
704 return 0x485;
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);
717 return 0x485;
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);
731 /*clean-up*/
732 if(banner != NULL)
734 DestroyWindow(banner);
737 return exit_code;
740 #endif //BUILD_EXE
742 // ==========================================================================
743 // DLL File
744 // ==========================================================================
746 #ifdef BUILD_DLL
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)
754 switch (fdwReason)
756 case DLL_PROCESS_ATTACH:
757 case DLL_THREAD_ATTACH:
758 case DLL_THREAD_DETACH:
759 case DLL_PROCESS_DETACH:
760 break;
762 return TRUE;
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);
771 ExitProcess(0x57);
772 return;
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);
779 ExitProcess(0x57);
780 return;
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);
787 ExitProcess(0x57);
788 return;
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);
796 ExitProcess(0x57);
797 return;
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);
804 ExitProcess(0x57);
805 return;
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);
817 ExitProcess(0x490);
818 return;
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);
840 else
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);
856 #endif //BUILD_DLL