Blog
SetWindowPlacement
Date: 8/11/2006
The seemingly useful SetWindowPlacement Windows API call has been the bane of my life the last 2 days. In that it looks exactly like what I want it to do but it fails under the circumstances that I want to call it, which is inside the WM_CREATE message handler.

A little background, I want to add better window position save/restore functionality to Scribe, and I thought, well most of my apps will want this so why not patch it into LGI's GWindow object! So I did, but that also means it has to work. On my machine. On Joe Average's machine... and on Uber Cool Designer's machine with 3 monitors. You'd think that saving your window position and restoring it on the next session was easy right? Well aren't you in for a nasty surprise.

Windows makes it well, difficult to get it right all the time. It's easy to write a 95% solution. But hard to get the edge cases working. One spectacular edge case is where you have a window mazimised. Not only do you need to save the fact it's mazimized but also where the window will restore to. This isn't so important on a single monitor machine but on a multi-monitor machine it controls where a window will maximize to. For instance, if you shut down an application maximized on the 2nd montior, and store only "was maximized" then when you open it again it'll be maximized on the first monitor. From what I can deduce, the restore position controls which monitor the SW_MAXIMIZE showCmd will send the window to.

So enter GetWindowPlacement and SetWindowPlacement. They let you get the current minimized/maxmimized/normal state as well as the restored window position in workspace coordinates. Workspace coordinates are NOT screen coordinates, so they are not compatible with SetWindowPos or its ilk. So you'd be thinking now... yes yes... lets just save the WINDOWPLACEMENT structure to our settings hive and use that to restore the window on restart. Well thats good in theory but one runs into trouble in getting the settings to stick when using SetWindowPlacement inside the WM_CREATE handler. In the case that the window was maximized and you call SetWindowPlacement the call succeeds and your window maximized to the correct display. However when you restore the window during normal use you discover that the restore position has been lost and the window remains in the same position as it was when maximized.

Nice.

So after pulling it down to a bare test application and confirming this as behaviour built into Windows what do you do about it? How can we work around this?

The best I've come up with so far is, call SetWindowPlacement once inside the WM_CREATE, and then at the end of your WM_CREATE post yourself a WM_USER message with a copy of the WINDOWPLACEMENT structure (dynamically allocated) and then when you receive that message, call SetWindowPlacement AGAIN to "fix" the restore position corrdinates. This is a bit of a kludge... but welcome to Windows.

I might run into new and more difficult problems in saving/restoring window position/state as this code gets more field testing but at least for all the test cases I know about now it's good.
Comments:
Josh
08/11/2006 9:03am
Well, works till Vista comes out anyways. Gotta love Micro$osft.
 
Reply
From:
Email (optional): (Will be HTML encoded to evade harvesting)
Message:
 
Remember username and/or email in a cookie.
Notify me of new posts in this thread via email.
BBcode:
[q]text[/q]
[url=link]description[/url]
[img]url_to_image[/img]
[pre]some_code[/pre]
[b]bold_text[/b]