1 /*
2 	Launch4j (http://launch4j.sourceforge.net/)
3 	Cross-platform Java application wrapper for creating Windows native executables.
4 
5 	Copyright (c) 2004, 2015 Grzegorz Kowal
6 							 Sylvain Mina (single instance patch)
7 
8 	Permission is hereby granted, free of charge, to any person obtaining a copy
9 	of this software and associated documentation files (the "Software"), to deal
10 	in the Software without restriction, including without limitation the rights
11 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 	copies of the Software, and to permit persons to whom the Software is
13 	furnished to do so, subject to the following conditions:
14 
15 	The above copyright notice and this permission notice shall be included in
16 	all copies or substantial portions of the Software.
17 
18 	Except as contained in this notice, the name(s) of the above copyright holders
19 	shall not be used in advertising or otherwise to promote the sale, use or other
20 	dealings in this Software without prior written authorization.
21 
22 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 	THE SOFTWARE.
29 */
30 
31 #include "../resource.h"
32 #include "../head.h"
33 #include "guihead.h"
34 
35 extern FILE* hLog;
36 extern PROCESS_INFORMATION processInformation;
37 
38 HWND hWnd;
39 DWORD dwExitCode = 0;
40 BOOL stayAlive = FALSE;
41 BOOL splash = FALSE;
42 BOOL splashTimeoutErr;
43 BOOL waitForWindow;
44 BOOL restartOnCrash = FALSE;
45 int splashTimeout = DEFAULT_SPLASH_TIMEOUT;
46 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)47 int APIENTRY WinMain(HINSTANCE hInstance,
48                      HINSTANCE hPrevInstance,
49                      LPSTR     lpCmdLine,
50                      int       nCmdShow)
51 {
52 	int result = prepare(lpCmdLine);
53 
54 	if (result == ERROR_ALREADY_EXISTS)
55 	{
56 		HWND handle = getInstanceWindow();
57 		ShowWindow(handle, SW_SHOW);
58 		SetForegroundWindow(handle);
59 		closeLogFile();
60 		return 2;
61 	}
62 
63 	if (result != TRUE)
64 	{
65 		signalError();
66 		return 1;
67 	}
68 
69 	splash = loadBool(SHOW_SPLASH)
70 			&& strstr(lpCmdLine, "--l4j-no-splash") == NULL;
71 	restartOnCrash = loadBool(RESTART_ON_CRASH);
72 
73 	// if we should restart on crash, we must also stay alive to check for crashes
74 	stayAlive = restartOnCrash ||
75 			  (loadBool(GUI_HEADER_STAYS_ALIVE)
76 			&& strstr(lpCmdLine, "--l4j-dont-wait") == NULL);
77 
78 	if (splash || stayAlive)
79 	{
80 		hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, "STATIC", "",
81 				WS_POPUP | SS_BITMAP,
82 				0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
83 		if (splash)
84 		{
85 			char timeout[10] = {0};
86 			if (loadString(SPLASH_TIMEOUT, timeout))
87 			{
88 				splashTimeout = atoi(timeout);
89 				if (splashTimeout <= 0 || splashTimeout > MAX_SPLASH_TIMEOUT)
90 				{
91 					splashTimeout = DEFAULT_SPLASH_TIMEOUT;
92 				}
93 			}
94 			splashTimeoutErr = loadBool(SPLASH_TIMEOUT_ERR)
95 					&& strstr(lpCmdLine, "--l4j-no-splash-err") == NULL;
96 			waitForWindow = loadBool(SPLASH_WAITS_FOR_WINDOW);
97 			HANDLE hImage = LoadImage(hInstance,	// handle of the instance containing the image
98 					MAKEINTRESOURCE(SPLASH_BITMAP),	// name or identifier of image
99 					IMAGE_BITMAP,					// type of image
100 					0,								// desired width
101 					0,								// desired height
102 					LR_DEFAULTSIZE);
103 			if (hImage == NULL)
104 			{
105 				signalError();
106 				return 1;
107 			}
108 			SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hImage);
109 			RECT rect;
110 			GetWindowRect(hWnd, &rect);
111 			int x = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
112 			int y = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
113 			SetWindowPos(hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
114 			ShowWindow(hWnd, nCmdShow);
115 			UpdateWindow (hWnd);
116 		}
117 	}
118 
119 	do
120 	{
121 		if (splash || stayAlive)
122 		{
123 			if (!SetTimer (hWnd, ID_TIMER, 1000 /* 1s */, TimerProc))
124 			{
125 				signalError();
126 				return 1;
127 			}
128 		}
129 
130 		if (!execute(FALSE, &dwExitCode))
131 		{
132 			signalError();
133 			return 1;
134 		}
135 
136 		if (!(splash || stayAlive))
137 		{
138 			debug("Exit code:\t0\n");
139 			closeProcessHandles();
140 			closeLogFile();
141 			return 0;
142 		}
143 
144 		MSG msg;
145 		while (GetMessage(&msg, NULL, 0, 0))
146 		{
147 			TranslateMessage(&msg);
148 			DispatchMessage(&msg);
149 		}
150 
151 		if (restartOnCrash && dwExitCode != 0)
152 		{
153 	  		debug("Exit code:\t%d, restarting the application!\n", dwExitCode);
154   		}
155 
156   		closeProcessHandles();
157 	} while (restartOnCrash && dwExitCode != 0);
158 
159 	debug("Exit code:\t%d\n", dwExitCode);
160 	closeLogFile();
161 	return dwExitCode;
162 }
163 
getInstanceWindow()164 HWND getInstanceWindow()
165 {
166 	char windowTitle[STR];
167 	char instWindowTitle[STR] = {0};
168 	if (loadString(INSTANCE_WINDOW_TITLE, instWindowTitle))
169 	{
170 		HWND handle = FindWindowEx(NULL, NULL, NULL, NULL);
171 		while (handle != NULL)
172 		{
173 			GetWindowText(handle, windowTitle, STR - 1);
174 			if (strstr(windowTitle, instWindowTitle) != NULL)
175 			{
176 				return handle;
177 			}
178 			else
179 			{
180 				handle = FindWindowEx(NULL, handle, NULL, NULL);
181 			}
182 		}
183 	}
184 	return NULL;
185 }
186 
enumwndfn(HWND hwnd,LPARAM lParam)187 BOOL CALLBACK enumwndfn(HWND hwnd, LPARAM lParam)
188 {
189 	DWORD processId;
190 	GetWindowThreadProcessId(hwnd, &processId);
191 	if (processInformation.dwProcessId == processId)
192 	{
193 		LONG styles = GetWindowLong(hwnd, GWL_STYLE);
194 		if ((styles & WS_VISIBLE) != 0)
195 		{
196 			splash = FALSE;
197 			ShowWindow(hWnd, SW_HIDE);
198 			return FALSE;
199 		}
200 	}
201 	return TRUE;
202 }
203 
TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)204 VOID CALLBACK TimerProc(
205 	HWND hwnd,			// handle of window for timer messages
206 	UINT uMsg,			// WM_TIMER message
207 	UINT idEvent,		// timer identifier
208 	DWORD dwTime) 		// current system time
209 {
210 	if (splash)
211 	{
212 		if (splashTimeout == 0)
213 		{
214 			splash = FALSE;
215 			ShowWindow(hWnd, SW_HIDE);
216 			if (waitForWindow && splashTimeoutErr)
217 			{
218 				KillTimer(hwnd, ID_TIMER);
219 				signalError();
220 				PostQuitMessage(0);
221 			}
222 		}
223 		else
224 		{
225 			splashTimeout--;
226 			if (waitForWindow)
227 			{
228 				EnumWindows(enumwndfn, 0);
229 			}
230 		}
231 	}
232 
233 	GetExitCodeProcess(processInformation.hProcess, &dwExitCode);
234 	if (dwExitCode != STILL_ACTIVE
235 			|| !(splash || stayAlive))
236 	{
237 		KillTimer(hWnd, ID_TIMER);
238 		PostQuitMessage(0);
239 	}
240 }
241