1

I am trying to get the width and height of all the windows. I did this easily with GetWindowRect however the styling in Win8.1+ seems such that there is a border on some windows and thats not being included. When I move/drag the window, this area moves with the window, so I expected it would be apart of its geometry. Is this known? Is there away to include the border width?

New Example

I created a second screenshot to explain after I see some confusion in the comments.

I have two windows side by side as seen in this image here:

Now if I take the GetWindowRect of the left and right windows, it should be a continuous rectangle around both of thse windows. However in the below we see this is not the case. I put a black fade over the whole desktop and cut out just the parts of the GetWindowRect for each window, we see the left window GetWindowRect is a bit smaller, this is my problem.

Old Example

For example this is a screenshot, using the cleared/non-black curtain area is what GetWindowRect identified as the width height, x and y:

We see there is some area of the window not included, I think this is the border? I used photoshop here to put a blue border around what all should have been:

And just for clarity I put an inner red border to show that the area between the red and blue borders was what should have been included, but was not:

Does anyone know how to include this "border" in the GetWindowRect?

Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 2
    Based on what specification should the area between the red and blue rectangle be part of the area returned by `GetWindowRect`? It's **clearly** not part of the window rectangle. – IInspectable Aug 08 '15 at 19:44
  • Thanks @IInspectable man is there some geometry function that includes that part? – Noitidart Aug 08 '15 at 19:57
  • 1
    I have no idea. Maybe you should explain what makes that area so special to you, that you want to account for it. It doesn't appear to be any more special than the area outside the blue rectangle. – IInspectable Aug 08 '15 at 20:02
  • Ah its just that when I drag the window, it drags that part with it, so I think this is a good way to put it thanks @IInspectable for getting me to phrase that right i have hard time with that! :P I want to get geometry of the whole area that moves when I drag the window please. – Noitidart Aug 08 '15 at 20:08
  • Are you talking about the drop shadows that later version of Windows display? They aren't part of the window, they're just rendered by the DWM when the window is drawn to the screen. – Jonathan Potter Aug 08 '15 at 22:04
  • Thanks @JonathanPotter it seems there is more yellow and more to the X button, not the drop shadows. – Noitidart Aug 08 '15 at 22:11
  • I cannot make any sense of this either. This does feel like an XY question. – David Heffernan Aug 09 '15 at 08:22
  • Thanks for the note @DavidHeffernan I added a "new example" to the topic post, please have see if you have some time. – Noitidart Aug 09 '15 at 08:42
  • It's still an XY question. It would help to know why you are asking. – David Heffernan Aug 09 '15 at 08:43

1 Answers1

3

Yes, GetWindowRect() lies to you. As you found out. It is a necessary lie. Goes back to Vista, the first Windows version that gave resizable windows their fat border. A pretty necessary feature, high screen resolutions were getting pretty common and the traditional 2-pixel border was getting too hard to hit with a mouse.

That created a massive compatibility problem however, many programs that create a window use CreateWindowEx(), you specify the outer window size. And don't use AdjustWindowRectEx(), the function that you must use to calculate the window size you need. Necessary because almost every window actually cares about the client size of the window. The part you fill with content. If they would have done nothing then legacy programs would end up creating windows with a client area that is too small, no longer fitting the content or aligning it out of whack. Very, very ugly.

So GetWindowRect() lies and pretends that the window has the traditional 2-pixel border. Pretty consistent lie, if you ask for the border size with GetSystemMetrics() then you get 2 back, even though it is 5. All works pretty well, until you start caring about positioning windows next to each other. Impossible to lie about that.

Turning off the lies requires letting Windows know that you are aware of the consequences of the fat borders. And know how to deal with Aero being turned off, possible on Vista and Win7. You must select the sub-system version number in the EXE file header and pick at least 6.00. The vast majority of programs use the legacy value, 4.00. Exactly how that's done depends on your tooling, for the Microsoft linker it is the /SUBSYSTEM option. It can be changed after the program was built with Editbin.exe, /SUBSYSTEM option. The program will no longer run on XP and earlier.

Windows 10 took an interesting new approach to this problem. The skinny borders are back. But now with a much bigger drop-shadow, the mouse is active beyond the border, even for windows that don't have a shadow. Works pretty well, hopefully we can all forget about this appcompat detail soon :)

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks so much for this awesome reply! My app is a screenshot app so is it possible to identify the sub-system version number by hwnd? And then figure out if to add 5px (sometimes it seems to be 4px). Like in my "new example" that is two window from the same app, the right one has no issue, but the left one has a 4px fat around it. – Noitidart Aug 09 '15 at 17:15
  • 1
    @Noitidart: If I understand Hans correctly, you don't need to fiddle with those other applications. Simply set **your** application's subsystem version to 6.0 or above, and the call to `GetWindowRect` will stop lying to **your** application. – IInspectable Aug 09 '15 at 17:32
  • Ahh thanks @IInspectable ! :) My issue was I can't change the subsystem version on my app, as its an addon for Firefox :( – Noitidart Aug 09 '15 at 17:34
  • 1
    @Noitidart: One solution for that scenario would be to write an additional executable, that calls `GetWindowRect`, and have it executed from your plugin. If Firefox plugins are allowed to launch executables. – IInspectable Aug 09 '15 at 17:36
  • Ah that's a good idea thanks @IInspectable I can have it do that but have to request extra permission which users typically don't like Ill definitely keep that as like last resort option though :D Thanks man! – Noitidart Aug 09 '15 at 17:38
  • If I set the subsystem version in a DLL, will code in that DLL honor the subsystem, or will the EXE subsystem be preferred? – andlabs Aug 09 '15 at 19:53
  • 1
    @andlabs this will be a process wide property, value in dll ignored – David Heffernan Aug 10 '15 at 06:39