aboutsummaryrefslogtreecommitdiff
path: root/tests/server
diff options
context:
space:
mode:
authorMarc Hoersken <info@marc-hoersken.de>2020-04-12 18:38:12 +0200
committerMarc Hoersken <info@marc-hoersken.de>2020-04-12 18:38:12 +0200
commitac1e206278b98fbe762f4b554803c64e8b562156 (patch)
tree3e996f00ff15b3c13fb291d99d8d3cefcb61eb7f /tests/server
parent30c8ef7d636ea060e690b4959280d05f2587d882 (diff)
tests/server: add hidden window to gracefully handle WM_CLOSE
Forward Window events as signals to existing signal event handler.
Diffstat (limited to 'tests/server')
-rw-r--r--tests/server/util.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/server/util.c b/tests/server/util.c
index c8bc32945..65d491c0b 100644
--- a/tests/server/util.c
+++ b/tests/server/util.c
@@ -544,6 +544,12 @@ static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
#endif
+#ifdef WIN32
+static DWORD thread_main_id = 0;
+static HANDLE thread_main_window = NULL;
+static HWND hidden_main_window = NULL;
+#endif
+
/* var which if set indicates that the program should finish execution */
volatile int got_exit_signal = 0;
@@ -606,6 +612,78 @@ static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType)
}
return TRUE;
}
+/* Window message handler for Windows applications to add support
+ * for graceful process termination via taskkill (without /f) which
+ * sends WM_CLOSE to all Windows of a process (even hidden ones).
+ *
+ * Therefore we create and run a hidden Window in a separate thread
+ * to receive and handle the WM_CLOSE message as SIGTERM signal.
+ */
+static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+{
+ int signum = 0;
+ if(hwnd == hidden_main_window) {
+ switch(uMsg) {
+#ifdef SIGTERM
+ case WM_CLOSE: signum = SIGTERM; break;
+#endif
+ case WM_DESTROY: PostQuitMessage(0); break;
+ }
+ if(signum) {
+ logmsg("main_window_proc: %d -> %d", uMsg, signum);
+ exit_signal_handler(signum);
+ }
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+/* Window message queue loop for hidden main window, details see above.
+ */
+static DWORD WINAPI main_window_loop(LPVOID lpParameter)
+{
+ WNDCLASS wc;
+ BOOL ret;
+ MSG msg;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.lpfnWndProc = (WNDPROC)main_window_proc;
+ wc.hInstance = (HINSTANCE)lpParameter;
+ wc.lpszClassName = "MainWClass";
+ if(!RegisterClass(&wc)) {
+ perror("RegisterClass failed");
+ return (DWORD)-1;
+ }
+
+ hidden_main_window = CreateWindowEx(0, "MainWClass", "Recv WM_CLOSE msg",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ (HWND)NULL, (HMENU)NULL,
+ wc.hInstance, (LPVOID)NULL);
+ if(!hidden_main_window) {
+ perror("CreateWindowEx failed");
+ return (DWORD)-1;
+ }
+
+ do {
+ ret = GetMessage(&msg, NULL, 0, 0);
+ if(ret == -1) {
+ perror("GetMessage failed");
+ return (DWORD)-1;
+ }
+ else if(ret) {
+ if(msg.message == WM_APP) {
+ DestroyWindow(hidden_main_window);
+ }
+ else if(msg.hwnd && !TranslateMessage(&msg)) {
+ DispatchMessage(&msg);
+ }
+ }
+ } while(ret);
+
+ hidden_main_window = NULL;
+ return (DWORD)msg.wParam;
+}
#endif
void install_signal_handlers(bool keep_sigalrm)
@@ -659,6 +737,12 @@ void install_signal_handlers(bool keep_sigalrm)
#ifdef WIN32
if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
logmsg("cannot install CTRL event handler");
+ thread_main_window = CreateThread(NULL, 0,
+ &main_window_loop,
+ (LPVOID)GetModuleHandle(NULL),
+ 0, &thread_main_id);
+ if(!thread_main_window || !thread_main_id)
+ logmsg("cannot start main window loop");
#endif
}
@@ -694,5 +778,9 @@ void restore_signal_handlers(bool keep_sigalrm)
#endif
#ifdef WIN32
(void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);
+ if(thread_main_window && thread_main_id) {
+ if(PostThreadMessage(thread_main_id, WM_APP, 0, 0))
+ (void)WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE);
+ }
#endif
}