Page 1 of 1

A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 1:10 am
by luis
Under Windows 7 (and Vista too I believe) with Aero enabled, GetWindowRect_ does not include the full non-client area for non-resizable windows.
One way to solve the problem is to call DwmGetWindowAttribute() with #DWMWA_EXTENDED_FRAME_BOUNDS when Aero is enabled.

This code is an example of that and if I didn't do something wrong (!) GetWindowRectEx() should return the right size in any condition (vista/7 with/without aero and winxp or lower).

Code: Select all

EnableExplicit 

Enumeration
    #DWMWA_NCRENDERING_ENABLED = 1
    #DWMWA_NCRENDERING_POLICY
    #DWMWA_TRANSITIONS_FORCEDISABLED
    #DWMWA_ALLOW_NCPAINT
    #DWMWA_CAPTION_BUTTON_BOUNDS
    #DWMWA_NONCLIENT_RTL_LAYOUT
    #DWMWA_FORCE_ICONIC_REPRESENTATION
    #DWMWA_FLIP3D_POLICY
    #DWMWA_EXTENDED_FRAME_BOUNDS
    #DWMWA_HAS_ICONIC_BITMAP
    #DWMWA_DISALLOW_PEEK
    #DWMWA_EXCLUDED_FROM_PEEK
    #DWMWA_LAST
EndEnumeration

Procedure.i IsThemeActive()
; Do not call this function during DllMain or global objects contructors.

Protected *IsThemeActive
Protected iRetVal = 0 ; Themes not active
Protected hDll

If OSVersion() >= #PB_OS_Windows_XP
    hDll = OpenLibrary(#PB_Any, "UxTheme.dll")
    If hDll 
        *IsThemeActive = GetFunction(hDll, "IsThemeActive")
        If *IsThemeActive
            iRetVal = CallFunctionFast(*IsThemeActive) ; #True / #False
        EndIf   
        CloseLibrary(hDll)
    EndIf    
EndIf

ProcedureReturn iRetVal
EndProcedure

Procedure.i IsAeroActive()
Protected *DwmIsCompositionEnabled
Protected iRetVal = 0 ; Aero is not active
Protected hDll
Protected flgBool
 
If OSVersion() >= #PB_OS_Windows_Vista
    hDll = OpenLibrary(#PB_Any, "dwmapi.dll")
    If hDll
        *DwmIsCompositionEnabled = GetFunction(hDll, "DwmIsCompositionEnabled")

        If *DwmIsCompositionEnabled
            If CallFunctionFast(*DwmIsCompositionEnabled, @flgBool)  = #S_OK
                iRetVal = flgBool ; #True / #False
            EndIf       
        EndIf
        CloseLibrary(hDll)
    EndIf
EndIf

ProcedureReturn  iRetVal
EndProcedure

Procedure GetWindowRectEx (hWnd, *tRECT.RECT)
Protected hDll
Protected iRetVal = 0 ; 0 if fail
Protected *DwmGetWindowAttribute
Protected tRECT.RECT

If OSVersion() >= #PB_OS_Windows_Vista
    If IsAeroActive()
        hDll = OpenLibrary(#PB_Any, "dwmapi.dll")
        If hDll
            *DwmGetWindowAttribute = GetFunction(hDll, "DwmGetWindowAttribute")
            If *DwmGetWindowAttribute                 
                If CallFunctionFast(*DwmGetWindowAttribute, hWnd,  #DWMWA_EXTENDED_FRAME_BOUNDS, *tRECT, SizeOf(RECT)) = #S_OK
                    iRetVal = 1               
                EndIf           
            EndIf           
            CloseLibrary(hDLL)
        EndIf
    Else
        iRetVal = GetWindowRect_(hWnd, *tRECT) ; 0 if fail       
    EndIf
Else
    iRetVal = GetWindowRect_(hWnd, *tRECT) ; 0 if fail
EndIf

ProcedureReturn iRetVal
EndProcedure



; TEST

Procedure Main()
  Protected tRECT.RECT
 
  Debug "Aero = " + Str(IsAeroActive())
  Debug "Themes = " + Str(IsThemeActive())
 
  OpenWindow(0, 150,150, 640, 480, "TEST", #PB_Window_SystemMenu)

  Debug "GetWindowRectEx = " + Str( GetWindowRectEx (WindowID(0), @tRECT) )
   
  Debug "x = " + Str(tRECT\left)
  Debug "y = " + Str(tRECT\top)
  Debug "w = " + Str(tRECT\right - tRECT\left)
  Debug "h = " + Str(tRECT\bottom - tRECT\top)
 
  Debug "GetWindowRect_ = " + Str( GetWindowRect_ (WindowID(0), @tRECT) )
   
  Debug "x = " + Str(tRECT\left)
  Debug "y = " + Str(tRECT\top)
  Debug "w = " + Str(tRECT\right - tRECT\left)
  Debug "h = " + Str(tRECT\bottom - tRECT\top)
   
  While WaitWindowEvent() <> #PB_Event_CloseWindow :  Wend
 
EndProcedure

Main()
It's not optimized for efficiency obviously, you can do many of the test at startup and then call the appropriate code in your program, or whatever.

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 10:39 am
by Rescator
Pst!
The dll will only be closed if it's Windows XP or later.
Not actually an issue as 2K does not have it, just a little bad programming behavior I'd like to point out. :)

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 12:08 pm
by luis
Rescator wrote:Pst!
The dll will only be closed if it's Windows XP or later.
It was late and I was tired :)

But you are right and now the dll close should be fixed, thanks !

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 4:40 pm
by SFSxOI
should 'GetWindowRect_(WindowID(0), @tRECT)' and 'GetWindowRectEx(WindowID(0), @tRECT)' both return the same thing with aero enabled? i'm showing this:

Code: Select all

Aero = 1
Themes = 1
GetWindowRectEx = 1
x = 150
y = 150
w = 646
h = 508
GetWindowRect_ = 1
x = 150
y = 150
w = 646
h = 508

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 5:07 pm
by luis
I'm getting this:

Code: Select all

[16:58:28] Aero = 1
[16:58:28] Themes = 1
[16:58:28] GetWindowRectEx = 1
[16:58:28] x = 145
[16:58:28] y = 145
[16:58:28] w = 656
[16:58:28] h = 518
[16:58:28] GetWindowRect_ = 1
[16:58:28] x = 150
[16:58:28] y = 150
[16:58:28] w = 646
[16:58:28] h = 508
and the first one is the one correct.

Are you telling me the Ex() functions on your system return the wrong value as GetWindowRect_ does ?

I've copied/pasted the window in a paint program and the size in pixels is 656x518 (using the default theme in win7 when aero is enabled).

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 5:34 pm
by SFSxOI
Are you telling me the Ex() functions on your system return the wrong value as GetWindowRect_ does ?

[/quote]

Running your code as you posted it. I'm not telling you either one is wrong, i'm saying that they both return the same here with just running your code. I believe the values I posted are correct.

Code: Select all

If CallFunctionFast(*DwmGetWindowAttribute, hWnd,  #DWMWA_EXTENDED_FRAME_BOUNDS, *tRECT, SizeOf(RECT)) = #S_OK

should that be "SizeOf(tRECT)"  and not "SizeOf(RECT)"   ??


Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 5:44 pm
by luis
SFSxOI wrote: I believe the values I posted are correct.
Have you tried to measure the actual size in pixels of the window ?
Does it match with the values returned to you ?
If the answer is yes then I don't know what to say! I read about the problem on some forum about c/c++ and I tried to see if it was really the case. Certainly it was in my test!

Hence I cooked up the GetWindowRectEx().
SFSxOI wrote:
should that be "SizeOf(tRECT)" and not "SizeOf(RECT)" ??
Nope, sizeof works with data types, even if in PB (and usually in many languages) it work with instances of data types too. I prefer the former ! tRECT is of type RECT so it's the same thing.

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 6:04 pm
by SFSxOI
luis wrote: Have you tried to measure the actual size in pixels of the window ?
Does it match with the values returned to you ?
If the answer is yes then I don't know what to say! I read about the problem on some forum about c/c++ and I tried to see if it was really the case. Certainly it was in my test!

Hence I cooked up the GetWindowRectEx().
SFSxOI wrote:
should that be "SizeOf(tRECT)" and not "SizeOf(RECT)" ??
Nope, sizeof works with data types, even if in PB (and usually in many languages) it work with instances of data types too. I prefer the former ! tRECT is of type RECT so it's the same thing.
Yep, actual size matches. Using Windows 7 Ultimate.

I'm puzzled. This is the second thing you posted based upon activity you saw with Windows 7 that I can't see going on here. I wonder if there is some sort of interaction with graphics cards or DirectX or even drivers for graphics cards going on here? Maybe compliant type of thing with full DirectX 10 compliant at least? How odd.

The SizeOf thing was just something I was thinking that wasn't correct, it is the way you have it.

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Sun Dec 20, 2009 6:20 pm
by luis
SFSxOI wrote: I'm puzzled. This is the second thing you posted based upon activity you saw with Windows 7 that I can't see going on here.
I am too, and consider both the things are quite widespread if you try to look for them on google, especially the first one (this last one probably it's not so immediate to spot).

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Fri Jun 05, 2015 10:59 am
by Al_the_dutch
GetWindowRect_ worked fine for me under Win7. When I tried my application under Win8.1 GetWindowRect_ gave me problems (with sizeble windows too) and in an Internet search I found your post. Thx a lot, your code cleared the issue.

KR Al

Re: A GetWindowRectEx() for Aero and non-resizable windows

Posted: Fri Jun 05, 2015 8:38 pm
by bosker
Well, I get the same results as luis with Aero on.
I normally run with Aero off, and in that case, the numbers are the same for both GetWindowRect..
My results...

Code: Select all

<20:25:01.94>test_windowsize   #AERO off
[Debugger]  Aero = 0
[Debugger]  Themes = 1
[Debugger]  GetWindowRectEx = 1
[Debugger]  x = 150
[Debugger]  y = 150
[Debugger]  w = 646
[Debugger]  h = 508
[Debugger]  GetWindowRect_ = 1
[Debugger]  x = 150
[Debugger]  y = 150
[Debugger]  w = 646
[Debugger]  h = 508

<20:25:07.94>test_windowsize  #AERO on
[Debugger]  Aero = 1
[Debugger]  Themes = 1
[Debugger]  GetWindowRectEx = 1
[Debugger]  x = 145
[Debugger]  y = 145
[Debugger]  w = 656
[Debugger]  h = 518
[Debugger]  GetWindowRect_ = 1
[Debugger]  x = 150
[Debugger]  y = 150
[Debugger]  w = 646
[Debugger]  h = 508