Is _WINDOWHANDLE working properly?
#1
First, I'm a complete noob to API calls so this just may be my ignorance on the subject.

@SpriggsySpriggs suggested I use GetClientRect to get the client area coordinates of a Window. So I set up some code below to investigate.

However, no matter what size the screen is set to the return values of the RECT are always 0,0 - 640,400.

This makes me think that perhaps _WINDOWHANDLE is pointing to an underlying console window instead of the currently visible window?

Am I correct in my thinking, or am I using _WINDOWHANDLE incorrectly?

Code: (Select All)
TYPE RECTAPI
    left AS LONG
    top AS LONG
    right AS LONG
    bottom AS LONG
END TYPE

DIM apirect AS RECTAPI

DECLARE DYNAMIC LIBRARY "user32"
    'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect
    FUNCTION GetClientRect% (BYVAL hWnd AS LONG, lpRect AS RECTAPI)
END DECLARE

SCREEN _NEWIMAGE(800, 600, 32) ' results the same no matter what size screen is used??

tmp = GetClientRect(_WINDOWHANDLE, apirect)

PRINT apirect.left
PRINT apirect.top
PRINT apirect.right
PRINT apirect.bottom
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#2
You've encountered an old issue with QB64 where a slight delay needs to be added after creating the screen so the _WINDOWHANDLE will return correctly.  I forget the exact reason, but just that adding a small _DELAY fixes it.

Add a _DELAY .25 right after scetting the SCREEN call and it should work.

Code: (Select All)
Screen _NewImage(800, 600, 32)
_Delay .25

EDIT: I tried using 'Do: Loop Until _ScreenExists' in the past, you may find it in some of my posted code, but I've found that it doesn't always do the trick, so I went back to adding a _delay .25 which has never failed.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#3
(08-17-2023, 08:53 PM)Dav Wrote: You've encountered an old issue with QB64 where a slight delay needs to be added after creating the screen so the _WINDOWHANDLE will return correctly.  I forget the exact reason, but just that adding a small _DELAY fixes it.

Add a _DELAY .25 right after scetting the SCREEN call and it should work.

EDIT: I tried using 'Do: Loop Until _ScreenExists' in the past, you may find it in some of my posted code, but I've found that it doesn't always do the trick, so I went back to adding a _delay .25 which never fails.

- Dav
Yep, that took care of it. Thanks Dav Smile

Perhaps a note in the Wiki under _WINDOWHANDLE about this bug and how to overcome it may be appropriate.
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#4
(08-17-2023, 09:10 PM)TerryRitchie Wrote:
(08-17-2023, 08:53 PM)Dav Wrote: You've encountered an old issue with QB64 where a slight delay needs to be added after creating the screen so the _WINDOWHANDLE will return correctly.  I forget the exact reason, but just that adding a small _DELAY fixes it.

Add a _DELAY .25 right after scetting the SCREEN call and it should work.

EDIT: I tried using 'Do: Loop Until _ScreenExists' in the past, you may find it in some of my posted code, but I've found that it doesn't always do the trick, so I went back to adding a _delay .25 which never fails.

- Dav
Yep, that took care of it. Thanks Dav Smile

Perhaps a note in the Wiki under _WINDOWHANDLE about this bug and how to overcome it may be appropriate.

Utilising SCREENEXISTS for this purpose is maybe smarter than just a dumb DELAY.

EDIT: Added a cross reference link (See Also) to the WINDOWHANDLE wiki page.
Reply
#5
I played with _SCREENEXISTS, but on my machine it didn't seem to always prevent to problem, so I went back to using _DELAY.  In Terry's code using it didn't work for me either.  Perhaps I'm calling it wrong.  Here's how I was calling it:

DO: LOOP UNTIL _SCREENEXISTS

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#6
(08-17-2023, 09:37 PM)Dav Wrote: I played with _SCREENEXISTS, but on my machine it didn't seem to always prevent to problem, so I went back to using _DELAY.  In Terry's code using it didn't work for me either.  Perhaps I'm calling it wrong.  Here's how I was calling it:

DO: LOOP UNTIL _SCREENEXISTS

- Dav

And when you combine both as shown in the SCREENEXISTS wiki example?

I mean it might be hard for the GL thread to set up the screen, if the main program does use all CPU power in a tight busy loop.
Reply
#7
Yes, the wiki example for _SCREENEXISTS below does work correctly for me - it's sets the _TITLE ok.

Code: (Select All)
SCREEN 12
DO: _LIMIT 10: LOOP UNTIL _SCREENEXISTS
_TITLE "My Title"

That works.   But using_SCREENEXISTS that way in Terry's code fails for me here.  I still have to add a small _DELAY to work. 

EDIT:  Here's the edited code I'm testing, with the added SCREENEXISTS loop from the wiki.  API call isn't working. (I'm using the Windows 32-bit version, btw).  

Code: (Select All)
Type RECTAPI
    left As Long
    top As Long
    right As Long
    bottom As Long
End Type

Dim apirect As RECTAPI

Declare Dynamic Library "user32"
    'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect
    Function GetClientRect% (ByVal hWnd As Long, lpRect As RECTAPI)
End Declare

Screen _NewImage(800, 600, 32) ' results the same no matter what size screen is used??

Do: _Limit 10: Loop Until _ScreenExists 'this doesn't do it for me
'_DELAY .25  'this does works for me

tmp = GetClientRect(_WindowHandle, apirect)

Print apirect.left
Print apirect.top
Print apirect.right
Print apirect.bottom

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#8
@Dav Can you give this a quick test and tell me what values it reports for you, for those handles?

Code: (Select All)
 w& = _WindowHandle
Type RECTAPI
    left As Long
    top As Long
    right As Long
    bottom As Long
End Type

Dim apirect As RECTAPI

Declare Dynamic Library "user32"
    'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect
    Function GetClientRect% (ByVal hWnd As Long, lpRect As RECTAPI)
End Declare


Screen _NewImage(800, 600, 32) ' results the same no matter what size screen is used??

'Do: _Limit 10: Loop Until _ScreenExists 'this doesn't do it for me
_Delay .25 'this does works for me
w1& = _WindowHandle
tmp = GetClientRect(_WindowHandle, apirect)

Print apirect.left
Print apirect.top
Print apirect.right
Print apirect.bottom

Print w&, w1&

Do you get the same value, or two different ones when running this?

And question 2: Are you on the latest version of Qb64PE?
Reply
#9
Yes I'm using the current version of QB64PE, and yes I get the same values running your code as posted (which is using _DELAY).  Here's the output

0
0
800
600
263499      263499

And here's what I get when running that but using _SCREENEXIST instead of _DELAY.

0
0
640
400
460002      460002

So it looks like _WINDOWHANDLE is working either way, but for some reason the API doesn't take it without a delay?  I dunno. It should return 800x600 too but isn't.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#10
(08-18-2023, 01:14 PM)Dav Wrote: Yes I'm using the current version of QB64PE, and yes I get the same values running your code as posted (which is using _DELAY).  Here's the output

0
0
800
600
263499      263499

And here's what I get when running that but using _SCREENEXIST instead of _DELAY.

0
0
640
400
460002      460002

So it looks like _WINDOWHANDLE is working either way, but for some reason the API doesn't take it without a delay?  I dunno. It should return 800x600 too but isn't.

- Dav
Your results explain what's happening perfectly, @Dav -- many thanks for those!

_SCREENEXISTS is working 100% as it should be.
_WINDOWHANDLE is working 100% as it should be.

So what's going on to cause the issue here??

Let's run down the process of what's happening step-by-step:
The program starts to run.  *ALL* QB64 programs start out in a 640x400 screen (SCREEN 0 default screen).  
As soon as this SCREEN 0 screen is created, _SCREENEXISTS is going to return a -1 flag.  (After all, the screen now *does* exist.)
_WIDOWHANDLE at this point should also exist.  Your code works without erroring out, so it *IS* indeed giving you the proper window handle.
You then call the command to change screen resolution: Screen _NewImage(800, 600, 32)
It takes a few ticks for the PC to run the image change through its dedicated thread....
While that image change takes place, you make a call to tmp = GetClientRect(_WindowHandle, apirect)
GetClientRect then returns the dimensions of the current screen -- 640 x 400 pixels. Windows hasn't changed the screen and updated its API values yet!



A pause with DO: UNTIL _SCREENEXISTS isn't going to do anything to create a pause for you at this point in your program. After all, as you can see from the very start with that initial window handle, **A** screen already exists! (It's the 640x400 SCREEN 0 that exists on start up, but it does indeed exist!)

Which is why the manual pause after the SCREEN _NEWIMAGE makes certain that everything works as expected. Windows has time to change the screen from the initial 640x400 screen to the newly resized 800x600 screen, and then it returns the proper values and everything works as you expect.

It's not a case of _SCREENEXISTS not working; nor _WINDOWHANDLE not working. It's a simple case of polling the API too quickly after making a call to SCREEN _NEWIMAGE. It's returning values back to you -- it's just returning the OLD values back to you as the system hasn't completed the race condition to change to the new screen and register those new values yet.

If any of that makes any sense. Tongue

Anywho... I don't think there's actually any glitch in the commands here. I think it's just a case where the user needs to be certain to give the OS time to complete the _NEWIMAGE screen change, before using external APIs to get values back which reference that screen. Wink
Reply




Users browsing this thread: 1 Guest(s)