Let me get skwire to upload the tool he wrote for me to WM_DISPLAYCHANGE events and log monitor positions, it's what we used to try to figure out what was going on..
Let me try to describe my setup:
I have 4 monitors. My pc never sleeps or hibernates, but the monitors to go to sleep and turn off after about 30 minutes. So when I wake up after 8 hours, and first come to the pc, that is when windows move all over the place. Presumably because one or more of the monitors does not wake up in time.
Importantly: The movement of windows seems NOT to happen when the monitors first go to sleep.. it happens only at the time of waking up(!)
It seems at wake up time is when windows gets confused.
Here is what we saw one day when looking at the WM_DISPLAYCHANGE events:
The situation after a few hours of sleep:
Hourly check...
2017-05-10 09:52:44 AM ------------------------------
Monitor Count: 4
Primary Monitor: 1
Monitor: #1
Name: \\.\DISPLAY1
Res: 2560 x 1440
Left: 0 (0 working)
Top: 0 (0 working)
Right: 2560 (2560 working)
Bottom: 1440 (1410 working)
Monitor: #2
Name: \\.\DISPLAY5
Res: 2560 x 1440
Left: 2560 (2560 working)
Top: 0 (0 working)
Right: 5120 (5120 working)
Bottom: 1440 (1410 working)
Monitor: #3
Name: \\.\DISPLAY6
Res: 1440 x 2560
Left: -1440 (-1440 working)
Top: -601 (-601 working)
Right: 0 (0 working)
Bottom: 1959 (1929 working)
Monitor: #4
Name: \\.\DISPLAY2
Res: 1920 x 1080
Left: -3360 (-3360 working)
Top: 180 (180 working)
Right: -1440 (-1440 working)
Bottom: 1260 (1260 working)
Everything is fine at this point.. but here is what happens when i press keyboard and "wake up" the monitors:
WM_DISPLAYCHANGE event...
2017-05-10 10:02:05 AM ------------------------------
Monitor Count: 3
Primary Monitor: 1
Monitor: #1
Name: \\.\DISPLAY1
Res: 1920 x 1080
Left: 0 (0 working)
Top: 0 (0 working)
Right: 1920 (2560 working)
Bottom: 1080 (1410 working)
Monitor: #2
Name: \\.\DISPLAY5
Res: 2560 x 1440
Left: 2560 (2560 working)
Top: 0 (0 working)
Right: 5120 (5120 working)
Bottom: 1440 (1410 working)
Monitor: #3
Name: \\.\DISPLAY6
Res: 1440 x 2560
Left: -1440 (-1440 working)
Top: -601 (-601 working)
Right: 0 (0 working)
Bottom: 1959 (1929 working)
Note that it has actually "lost" one of my monitors at this point.. And even more frustrating, another WM_DISPLAYCHANGE event is *NOT* sent when it eventually sees it a few seconds later..
SO I am guessing that the procedure will have to look something like this:
1. Save windows positions occasionally.
2. When a WM_DISPLAYCHANGE event occurs, do NOT assume it is a correct thing.. Instead, use it to start a timer, which will RECHECK monitor situation after a few seconds.
3. After the delay has passed and the monitors come back, get current real monitor locations and restore any windows locations that have changed.
So I can think of a few ways a program could work that would make me happy, perhaps the simplest would be something like this:
a) let me tell the program when my monitors are in there "normal" configuration (ie just select a menu operation).
b) when the monitors are in this state, the program can save windows locations periodically -- or in fact since we know that the OS doesn't actually have any problem while the monitors are asleep, you could simply save window positions ONCE, when the monitors fall asleep]
c) when you get a WM_DISPLAYCHANGE message, set a timer that has you check monitor configurations occasionally, and WAIT UNTIL THE "GOOD" (normal) monitor configuration comes back
d) that is when the windows should be restored.
Step C is the key part -- you are essentially detecting a WM_DISPLAYCHANGE message as a "signal" that the monitors are in an UNSTABLE state that is likely to bounce around for the next few seconds, and cannot be trusted. This is where MS Windows messes up windows positions. So then the key is to just WAIT until the monitors come back to their "normal" configuration (and don't assume you will get a WM_DISPLAYCHANGE message when they do, you just have to wait a few seconds and/or check their state). Then when the monitors are back to "normal" the window positions can be restored.
Does that make sense?