A GetWindowRectEx() for Aero and non-resizable windows

Share your advanced PureBasic knowledge/code with the community.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

A GetWindowRectEx() for Aero and non-resizable windows

Post 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.
Last edited by luis on Sun Dec 20, 2009 2:56 pm, edited 2 times in total.
"Have you tried turning it off and on again ?"
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

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

Post 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. :)
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

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

Post 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 !
"Have you tried turning it off and on again ?"
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

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

Post 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
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

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

Post 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).
"Have you tried turning it off and on again ?"
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

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

Post 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)"   ??

The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

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

Post 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.
"Have you tried turning it off and on again ?"
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

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

Post 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.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

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

Post 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).
"Have you tried turning it off and on again ?"
Al_the_dutch
User
User
Posts: 70
Joined: Mon Nov 11, 2013 11:07 am
Location: Portugal

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

Post 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
bosker
Enthusiast
Enthusiast
Posts: 105
Joined: Fri Jan 08, 2010 11:04 pm
Location: Hampshire, UK

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

Post 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
Post Reply