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