double WM_ACTIVATE on task-bar minimize

Started by
3 comments, last by Stephany 9 years, 2 months ago

edit: sorry, the title was supposed to be double WM_ACTIVATEAPP rather than double WM_ACTIVATE, but my application is getting two of both so I guess it doesn't matter much.

I'm having some issues trying to maintain the window focus state for my game engine. While messing around with debugging today, I noticed that I'm receiving two WM_ACTIVATEAPP messages when I click the windows task bar to minimize my game's (non-full-screen) windowed application.

The first message looks correct, with w_param being false. But then, immediately after, I get another copy of that same message, with w_param set to true. This makes my app think its focused throughout the time it's minimized. And when I click my application in the taskbar to re-focus it, windows doesn't send a WM_ACTIVATEAPP at all - I'm assuming because it already believes my app is focused.

I've googled this to death, and I've found several people posting about the same issue (such as http://forums.indiegamer.com/showthread.php?2058-Getting-two-WM_ACTIVATEAPP-messages), but no one posting any type of solution. edit: After testing, I've found that I also get two WM_ACTIVATE messages as well.

Has anyone found a solution to this? Or perhaps someone else is aware of what I may be doing wrong to cause it? Such as calling some focus-like function, which is forcing my window to regain focus?

Thanks for any advice

edit: when I click the task bar of my window, the flow of related messages goes..

+ WM_ACTIVATE=0
+ WM_ACTIVATEAPP=0
+ KILLFOCUS
+ ACTIVATEAPP=1
+ ACTIVATE=1

Advertisement

This makes my app think its focused throughout the time it's minimized.

You should be using WM_SETFOCUS and WM_KILLFOCUS to determine if your window has the focus.

With regard to WM_ACTIVEATEAPP, both wParam (TRUE/FALSE) and lParam (thread id) are important to the interpretation of that message. Review the docs, which also state "The message is sent to the application whose window is being activated and to the application whose window is being deactivated." So, under certain circumstances, you can expect to receive two WM_ACTIVATEAPP messages - but only one applicable to your thread.

Under certain circumstances, WM_ACTIVATE may also be sent twice, but, similar to WM_ACTIVATEAPP, you must look at all applicable parameters, i.e., wParam AND lParam, to determine the applicability to your app. EDIT: wParam and lParam do NOT have the same meaning for those messages.

As an example, I was able to duplicate the situation by having both App1 and notepad open on the desktop. App1 has the focus. Following a click of the taskbar icon, App1 is minimized and receives:

[columns = message, wParam, lParam]

WM_ACTIVATEAPP False 6856 // window in thread 6856 deactivated. I.e., App1
WM_KILLFOCUS
WM_ACTIVATEAPP True 0 // window in thread 0 activated - I assume notepad. In any case, not applicable to App1??

EDIT: I think the docs are confused (or, at least, confusing). They state: wParam is TRUE if the window is being activated; FALSE if deactivated. That part appears correct.

However, for lParam, the docs say if wParam is TRUE, lParam is the thread that owns the window being deactivated; and if wParam is FALSE, lParam is the thread that owns the window being activated. It appears that the interpretation of lParam should be the thread owner. Period. Without regard to wParam.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


You should be using WM_SETFOCUS and WM_KILLFOCUS to determine if your window has the focus.

I was aware of these and thought I tried to go this route once, but I can't remember what went wrong. After trying again, it seems to be working correctly so far. Thanks a bunch for recommending it.

Two things I was curious about. First, when researching these issues, I came across someone that mentioned using WM_ENTERSIZEMOVE (to call SetFocus(Hwnd)) and WM_EXITSIZEMOVE (to call SetFocus(null)) with WM_SETFOCUS and WM_KILLFOCUS. They mentioned that DirectX (maybe samples?) used this approach. Is there a good reason for this? Perhaps because resizing/moving is disabled or causes issues with full screen focus? Second, is there any reason to catch/use the WM_ACTIVATE(APP) messages when using these two messages? Something it is still needed for, or can I just ditch them?


With regard to WM_ACTIVEATEAPP, both wParam (TRUE/FALSE) and lParam (thread id) are important to the interpretation of that message.

Wow, thank you so much for clearing that up for me. You have no idea how long I've been struggling/ignoring window focus issues in my application because I didn't know this.


I came across someone that mentioned using WM_ENTERSIZEMOVE (to call SetFocus(Hwnd)) and WM_EXITSIZEMOVE (to call SetFocus(null)) with WM_SETFOCUS and WM_KILLFOCUS. They mentioned that DirectX (maybe samples?) used this approach. Is there a good reason for this?

Don't know of any specific reason to tie set/kill focus to sizing, unless the app uses focus as a flag for other purposes. For instance, I don't tie the sizemove messages to focus, but I do use WM_ENTER/EXITSIZEMOVE to pause/resume (if not previously paused) rendering. I resize the buffers (Direct3D 11) on WM_EXITSIZEMOVE (as well as WM_SIZE moves only when related to restoring/maximizing - ignored otherwise), rather than resizing the buffers for each small increment of a size move. I.e., if the user drags the window frame, there's a steady stream of WM_SIZE messages between the ENTER and EXITSIZEMOVE messages which you may want to ignore.


is there any reason to catch/use the WM_ACTIVATE(APP) messages when using these two messages?

If you mean by "these two messages" - WM_SET/KILL_FOCUS - none specifically related to Windows functionality. However, depending on how you want your app to behave, you can use WM_ACTIVATE, WM_SET/KILL_FOCUS, WM_SIZE, etc., to determine (for instance) when the app should be running/rendering or be paused. When a user minimizes a game, it may indicate the user's expectation that the game will pause until the user wants to resume. Even if your app doesn't pause, there's no reason to render while minimized. That condition is different for WM_KILLFOCUS, which can occur if the game is running un-minimized and rendering, and the user opens another app to log something, or opens a messaging service, with the expectation that the game will continue running.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


Don't know of any specific reason to tie set/kill focus to sizing, unless the app uses focus as a flag for other purposes. For instance, I don't tie the sizemove messages to focus, but I do use WM_ENTER/EXITSIZEMOVE to pause/resume (if not previously paused) rendering. I resize the buffers (Direct3D 11) on WM_EXITSIZEMOVE (as well as WM_SIZE moves only when related to restoring/maximizing - ignored otherwise), rather than resizing the buffers for each small increment of a size move. I.e., if the user drags the window frame, there's a steady stream of WM_SIZE messages between the ENTER and EXITSIZEMOVE messages which you may want to ignore.

I think you probably layed out the answer, right there. I'm guessing, but their re-focus code may have checked for reasons to reallocate/resize video resources, and by calling SetFocus(null/hWnd), they're just forcing their app to lose (on resize-start) and regain (on resize-exit) focus, to reuse the same restoration code. Basically like having a CheckVideoResources()-type function, and calling it from WM_SETFOCUS as well as WM_EXITSIZEMOVE.

Anyway, thanks again for your help. I haven't run into any window focus problems since I switched to WM_SET/KILLFOCUS.

This topic is closed to new replies.

Advertisement