Added Makefile + implemented waiting for the child window to appear.

This commit is contained in:
LoRd_MuldeR 2020-09-26 22:17:23 +02:00
parent 2e8e6df7a2
commit 0355bcbaef
6 changed files with 174 additions and 34 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/bin
/obj

51
Makefile Normal file
View File

@ -0,0 +1,51 @@
############################################################
# Launch5j, by LoRd_MuldeR <MuldeR2@GMX.de> #
# Java JAR wrapper for creating Windows native executables #
# https://github.com/lordmulder/ #
# #
# This work has been released under the MIT license. #
# Please see LICENSE.TXT for details! #
# #
# ACKNOWLEDGEMENT #
# This project is partly inspired by the Launch4j project: #
# https://sourceforge.net/p/launch4j/ #
############################################################
MARCH ?= i586
MTUNE ?= intel
CFLAGS = -O3 -municode -mwindows -march=$(MARCH) -mtune=$(MTUNE)
.PHONY: all init headers resources clean
all: headers
init:
mkdir -p bin
mkdir -p obj
resources: init
windres -o obj/icon.o res/icon.rc
windres -o obj/splash_screen.o res/splash_screen.rc
headers: init resources
$(CC) $(CFLAGS) -o bin/head.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o
$(CC) $(CFLAGS) -o bin/head_nosplash.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o
$(CC) $(CFLAGS) -o bin/head_nowait.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o
$(CC) $(CFLAGS) -o bin/head_nowait_nosplash.exe -DJAR_FILE_WRAPPED=0 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o
$(CC) $(CFLAGS) -o bin/head_wrapped.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o
$(CC) $(CFLAGS) -o bin/head_wrapped_nosplash.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=1 -DENABLE_SPLASH=0 src/head.c obj/icon.o
$(CC) $(CFLAGS) -o bin/head_wrapped_nowait.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=1 src/head.c obj/icon.o obj/splash_screen.o
$(CC) $(CFLAGS) -o bin/head_wrapped_nowait_nosplash.exe -DJAR_FILE_WRAPPED=1 -DSTAY_ALIVE=0 -DENABLE_SPLASH=0 src/head.c obj/icon.o
strip bin/head.exe
strip bin/head_nosplash.exe
strip bin/head_nowait.exe
strip bin/head_nowait_nosplash.exe
strip bin/head_wrapped.exe
strip bin/head_wrapped_nosplash.exe
strip bin/head_wrapped_nowait.exe
strip bin/head_wrapped_nowait_nosplash.exe
clean: init
rm -f bin/*.exe
rm -f obj/*.o

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

17
res/icon.rc Normal file
View File

@ -0,0 +1,17 @@
/************************************************************/
/* Launch5j, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* Java JAR wrapper for creating Windows native executables */
/* https://github.com/lordmulder/ */
/* */
/* This work has been released under the MIT license. */
/* Please see LICENSE.TXT for details! */
/* */
/* ACKNOWLEDGEMENT */
/* This project is partly inspired by the Launch4j project: */
/* https://sourceforge.net/p/launch4j/ */
/************************************************************/
#include "../src/resource.h"
// ICON
ID_APP_ICON ICON "icon.ico"

View File

@ -13,8 +13,5 @@
#include "../src/resource.h" #include "../src/resource.h"
// ICON
ID_APP_ICON ICON "launcher.ico"
// BITMAP // BITMAP
ID_SPLASH_BITMAP BITMAP "splash_screen.bmp" ID_SPLASH_BITMAP BITMAP "splash_screen.bmp"

View File

@ -23,13 +23,22 @@
#include "resource.h" #include "resource.h"
// Const // Const
static const DWORD SPLASH_SCREEN_TIMEOUT = 30U; static const DWORD SPLASH_SCREEN_TIMEOUT = 30000U;
static const wchar_t *const JRE_RELATIVE_PATH = L"runtime\\bin\\javaw.exe"; static const wchar_t *const JRE_RELATIVE_PATH = L"runtime\\bin\\javaw.exe";
// Options // Options
#define ENABLE_SPLASH 1 #ifndef ENABLE_SPLASH
#define WAIT_FOR_INPUT_IDLE 1 #define ENABLE_SPLASH 1
//#define JAR_FILE_WRAPPED 1 #endif
#ifndef JAR_FILE_WRAPPED
#define JAR_FILE_WRAPPED 0
#endif
#ifndef WAIT_FOR_WINDOW
#define WAIT_FOR_WINDOW 1
#endif
#ifndef STAY_ALIVE
#define STAY_ALIVE 1
#endif
/* ======================================================================== */ /* ======================================================================== */
/* String routines */ /* String routines */
@ -177,7 +186,9 @@ static const wchar_t *get_executable_directory(const wchar_t *const executable_p
static const wchar_t *get_jarfile_path(const wchar_t *const executable_path, const wchar_t *const executable_directory) static const wchar_t *get_jarfile_path(const wchar_t *const executable_path, const wchar_t *const executable_directory)
{ {
#ifndef JAR_FILE_WRAPPED #if JAR_FILE_WRAPPED
return wcsdup(executable_path); /*JAR file is wrapped*/
#else
const wchar_t *jarfile_path = NULL; const wchar_t *jarfile_path = NULL;
const wchar_t *const path_prefix = remove_file_extension(executable_path); const wchar_t *const path_prefix = remove_file_extension(executable_path);
@ -197,8 +208,6 @@ static const wchar_t *get_jarfile_path(const wchar_t *const executable_path, con
free((void*)path_prefix); free((void*)path_prefix);
return jarfile_path; return jarfile_path;
#else
return wcsdup(executable_path); /*JAR file is wrapped*/
#endif #endif
} }
@ -269,6 +278,77 @@ static BOOL process_window_messages(const HWND hwnd)
return result; return result;
} }
/* ======================================================================== */
/* Find window functions */
/* ======================================================================== */
typedef struct
{
DWORD process_id;
HWND hwnd;
}
find_window_t;
static BOOL CALLBACK enum_windows_callback(const HWND hwnd, const LPARAM lparam)
{
DWORD process_id = MAXDWORD;
find_window_t *const ptr = (find_window_t*) lparam;
if(IsWindowVisible(hwnd))
{
GetWindowThreadProcessId(hwnd, &process_id);
if(process_id == ptr->process_id)
{
ptr->hwnd = hwnd;
return FALSE;
}
}
return TRUE;
}
static HWND find_window_by_process_id(const DWORD process_id)
{
find_window_t find_window_data;
find_window_data.process_id = process_id;
find_window_data.hwnd = NULL;
EnumWindows(enum_windows_callback, (LONG_PTR)&find_window_data);
return find_window_data.hwnd;
}
/* ======================================================================== */
/* Wait for process */
/* ======================================================================== */
static BOOL signaled_or_failed(const DWORD wait_result)
{
return (wait_result == WAIT_OBJECT_0) || (wait_result == WAIT_FAILED);
}
static BOOL wait_for_process_ready(const HWND hwnd, const HANDLE process_handle, const DWORD process_id)
{
const DWORD ticks_start = GetTickCount();
for (;;)
{
const HWND child_hwnd = find_window_by_process_id(process_id);
if (child_hwnd)
{
SwitchToThisWindow(child_hwnd, TRUE);
return TRUE;
}
if (signaled_or_failed(WaitForSingleObject(process_handle, 13U)))
{
break;
}
const DWORD ticks_delta = GetTickCount() - ticks_start;
if(ticks_delta > SPLASH_SCREEN_TIMEOUT)
{
break;
}
process_window_messages(hwnd);
}
return FALSE;
}
/* ======================================================================== */ /* ======================================================================== */
/* Message box */ /* Message box */
/* ======================================================================== */ /* ======================================================================== */
@ -344,7 +424,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
int result = -1; int result = -1;
const wchar_t *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, *java_runtime_path = NULL, *command_line = NULL; const wchar_t *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, *java_runtime_path = NULL, *command_line = NULL;
HGDIOBJ splash_image = NULL; HGDIOBJ splash_image = NULL;
DWORD exit_code = 0U;
PROCESS_INFORMATION process_info; PROCESS_INFORMATION process_info;
STARTUPINFOW startup_info; STARTUPINFOW startup_info;
@ -356,7 +435,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, L"STATIC", L"", WS_POPUP | SS_BITMAP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, L"STATIC", L"", WS_POPUP | SS_BITMAP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
// Show the splash screen // Show the splash screen
#ifdef ENABLE_SPLASH #if ENABLE_SPLASH
if(splash_image = LoadImage(hInstance, MAKEINTRESOURCE(ID_SPLASH_BITMAP), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE)) if(splash_image = LoadImage(hInstance, MAKEINTRESOURCE(ID_SPLASH_BITMAP), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE))
{ {
if(create_splash_screen(hwnd, splash_image)) if(create_splash_screen(hwnd, splash_image))
@ -401,7 +480,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
} }
// Does the JAR file exist? // Does the JAR file exist?
#ifndef JAR_FILE_WRAPPED #if !JAR_FILE_WRAPPED
if(!file_exists(jarfile_path)) if(!file_exists(jarfile_path))
{ {
show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, L"JAR not found", L"The required JAR file could not be found:\n\n%ls\n\n\nRe-installing the application may fix the problem!", jarfile_path); show_message_format(hwnd, MB_ICONERROR | MB_TOPMOST, L"JAR not found", L"The required JAR file could not be found:\n\n%ls\n\n\nRe-installing the application may fix the problem!", jarfile_path);
@ -425,7 +504,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
} }
// Process pending window messages // Process pending window messages
#ifdef ENABLE_SPLASH #if ENABLE_SPLASH
process_window_messages(hwnd); process_window_messages(hwnd);
#endif #endif
@ -446,33 +525,27 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
} }
// Process pending window messages // Process pending window messages
#ifdef ENABLE_SPLASH #if ENABLE_SPLASH
process_window_messages(hwnd); process_window_messages(hwnd);
#ifdef WAIT_FOR_INPUT_IDLE #if WAIT_FOR_WINDOW
for (DWORD t = 0U; t < SPLASH_SCREEN_TIMEOUT; ++t) wait_for_process_ready(hwnd, process_info.hProcess, process_info.dwProcessId);
{
if (WaitForInputIdle(process_info.hProcess, 1000U) != WAIT_TIMEOUT)
{
break; /*child-process is ready!*/
}
if (WaitForSingleObject(process_info.hProcess, 1U) != WAIT_TIMEOUT)
{
break; /*child process terminated!*/
}
process_window_messages(hwnd);
}
#endif #endif
destroy_window(&hwnd); destroy_window(&hwnd);
#endif #endif
// Wait for process to exit // Wait for process to exit, then get exit code
WaitForSingleObject(process_info.hProcess, INFINITE); #if STAY_ALIVE
if(WaitForSingleObject(process_info.hProcess, INFINITE) == WAIT_OBJECT_0)
// Get the exit code
if(GetExitCodeProcess(process_info.hProcess, &exit_code))
{ {
result = (int) exit_code; DWORD exit_code = 0U;
if(GetExitCodeProcess(process_info.hProcess, &exit_code))
{
result = (int) exit_code;
}
} }
#else
result = 0;
#endif
cleanup: cleanup: