guihead.c 6.1 KB

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