App with no gui - properly clean up?

I have an application that has no GUI what so ever. I do create one window to detect WM_DISPLAYCHANGE, but the window is never displayed.

Is there any way to clean up when the application is closed? It seems that my WndProc doesn't get WM_CLOSE or WM_DESTROY (assuming that's because I never display it), so my message loop just keeps running:

1
2
3
4
5
while(GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}


I'm thinking about adding add an icon into the system tray to let the user properly close the application, but that doesn't account for thing like: Logging off, restarting, shutting down the computer, or "End Task" in the task manager.

I tried atexit, but that doesn't seem to work.

The application is a Win32 App (no console), and I make use of low-level mouse and keyboard hooks. The intent is when the user moves their mouse to the edge of the desktop, it sends the control to another machine via the network. When this happens the mouse cursor is hidden by using SetSystemCursor. When the cursor comes back it is restored. If the application quits for any reason the cursor is not restored (invisible) until the user restarts/logs off. Now if the user moves the mouse back this isn't likely... But I'd still like to properly clean up the application when it quits.

I've confirmed that my application isn't cleaning up properly by writing to a file. I never get the "Closed!" text in my output file.

Luke
Unless I'm missing something, I think all you need to do is to add a case WM_CLOSE/WM_DESTROY to your routine and handle it with DestroyWindow().
Here is my WndProc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DISPLAYCHANGE:
			std::cout << "Display Change" << std::endl;
			break;
		case WM_CLOSE:
			DestroyWindow(hWnd);
	        break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}


And here is the code that creates it (most relevant part anyway):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	freopen("out.txt", "wb", stdout); // For debug only
	std::cout << "Open!" << std::endl;

	LPCTSTR szClassName = L"BackgroundWindow";
	WNDCLASSEX wc;
	MSG msg;
	
	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = NULL;
	wc.hCursor       = NULL;
	wc.hbrBackground = 0;
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szClassName;
	wc.hIconSm       = NULL;
	
	if(!RegisterClassEx(&wc))
	{
		return 0;
	}
	
	CreateWindowEx(WS_EX_NOACTIVATE, szClassName, 0, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, NULL, hInstance, NULL);

	while(GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	std::cout << "Closed!" << std::endl;
}


As you can see I'm not actually displaying the window. The window is used just for getting the WM_DISPLAYCHANGE event. I would think that I should be getting WM_CLOSE / WM_DESTROY, but I'm not. My "out.txt" file only has "Open!" and it never has "Closed!".

The test cases are:

1) Within Visual Studio click "Stop Debugging"
2) Taskmanger - End Task
3) Log off / Restart/ Shutdown

Nothing seems to trigger the WM_CLOSE / WM_DESTROY. I'm thinking this makes sense because I'm not showing the window. But I am receiving WM_DISPLAYCHANGE, so I thought I may also get WM_CLOSE at least with #3 (Logoff, etc..), but I'm not.

Is there a way to properly clean up the app in these conditions? The rest of my code (which I haven't posted) uses low level mouse/keyboard hooks and I'd like to be able to properly remove those hooks before the program exits.
Last edited on
Not sure about that but change your WndProc(); to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DISPLAYCHANGE:
			std::cout << "Display Change" << std::endl;
			break;
		case WM_CLOSE:
			DestroyWindow(hWnd);
	        break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}


maybe that might help :P
Yeah I'm pretty sure that isn't going to do it.
I've always returned 0 to WM_CLOSE and WM_DESTROY, and then instead of 0 I return DefWindowProc() at the end of the function.

In addition, if that doesn't work, you might try calling SetActiveWindow() or SetForegroundWindow() immediately before your DestroyWindow() and PostQuitMessage() calls.
I don't think you understand. WM_CLOSE and WM_DESTROY are not being received at all. The app is just being terminated.
OK I solved most of it. I found these are the messages that are sent to my application when you attempt to logout/restart/shutdown:

003B
0011 - WM_QUERYENDSESSION
0046 - WM_WINDOWPOSCHANGING
0047 - WM_WINDOWPOSCHANGED
001C - WM_ACTIVATEAPP
0086 - WM_NCACTIVATE
0006 - WM_ACTIVATE
0281 - WM_IME_SETCONTEXT
0282 - WM_IME_NOTIFY
0007 - WM_SETFOCUS
003B
0016 - WM_ENDSESSION

This, from what I can tell, is unique to an application with no GUI or console. Windows sends WM_QUERYENDSESSION top-level windows. When this happens you can return 0 to stop the Logoff/Restart/Shutdown from happening. If it continues Windows tries a variety of things to get the window active. I'm assuming that if it does, it would call WM_CLOSE or WM_QUIT (haven't tried it). If it doesn't it eventually sends WM_ENDSESSION. When you get to WM_ENDSESSION it's to late to do any type of clean up (you could, but there isn't enough time to exit the loop, according to MSDN).

From what I've observed other applications quit on WM_QUERYENDSESSION. So I've decided to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_DISPLAYCHANGE:
			std::cout << "Display Change" << std::endl;
			break;
		case WM_CLOSE:
		case WM_QUIT:
		case WM_QUERYENDSESSION:
			DestroyWindow(hWnd);
			PostQuitMessage(0);
			break;
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}


I'm not sure if WM_QUIT is even received in this function, but I put it there anyway. If a request is sent to my window to close (which isn't even displayed) it'll quit the application anyway. This seems to work well.

The only thing I haven't figured out how to do yet is clean up when someone tries to end the program task. I'm assuming that if they did it to an active window it would call one of the close/quit messages. But since I don't have a window that is visible you'd have to do it from the process list... And the message there warns that the app won't have a chance to clean up... So I think I'm out of luck on that one.
Last edited on
Cant you just use postmessage or sendmessage function to send the WM_CLOSE message to the window??
That's why I said earlier --

"In addition, if that doesn't work, you might try calling SetActiveWindow() or SetForegroundWindow() immediately before your DestroyWindow() and PostQuitMessage() calls."

I'd try SetForegroundWindow() first, and if the program is not accessing those areas beforehand, then put this function somewhere else where it will be called.
Last edited on
Windows was trying to make the window active, but the window cannot be active. The key was responding to "WM_QUERYENDSESSION", which is what my application now does, and everything works :).
Glad you got it worked out. And I've never used WM_QUERYENDSESSION, so it's good to know about for future reference.
Topic archived. No new replies allowed.