Posts: 1,270
Threads: 118
Joined: Apr 2022
Reputation:
100
Just a head's up for everyone. I've just spent an hour cursing at my code until I figured out what was going on.
SCREEN _NEWIMAGE(640, 480, 32)
hWnd&& = _WINDOWHANDLE
The above code will not return the correct window handle.
SCREEN _NEWIMAGE(640, 480, 32)
_DELAY .25
hWnd&& = _WINDOWHANDLE
This code above will. Very frustrating.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 2,710
Threads: 328
Joined: Apr 2022
Reputation:
219
06-05-2024, 10:11 PM
(This post was last modified: 06-05-2024, 10:51 PM by SMcNeill.)
(06-05-2024, 09:57 PM)TerryRitchie Wrote: Just a head's up for everyone. I've just spent an hour cursing at my code until I figured out what was going on.
SCREEN _NEWIMAGE(640, 480, 32)
hWnd&& = _WINDOWHANDLE
The above code will not return the correct window handle.
SCREEN _NEWIMAGE(640, 480, 32)
_DELAY .25
hWnd&& = _WINDOWHANDLE
This code above will. Very frustrating.
I've wrote about this before. Here's the basic issue:
<QB64 starts, assigns a window handle to that SCREEN 0 startup screen you see.>
SCREEN _NEWIMAGE is called. Starts to make a new window... asks system for a handle...
hWnd tries to get the current handle. It gets one.
But what's the only handle available to get?? The one associated with the SCREEN 0 startup screen!
Adding that _DELAY after the call to _NEWIMAGE gives the system time to create and assign a handle to the new screen, so it can return that handle to you, as you intended.
Edit: Matt's right (see below). We fixed the issue I was thinking of. This really shouldn't be such an issue with the current versions of QB64PE. Any chance you can share some test code which reproduces the issue. And share with us which OS and QB64PE version you're testing with?
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
Are you sure the _Delay is necessary in newer versions of QB64-PE? I briefly tested it and it doesn't appear to be, and it really shouldn't be after changes I made in 3.5.0 QB64-PE version. Before 3.5.0 there is a race that would cause it to be zero at the beginning of the program.
The `_WINDOWHANDLE` is not related to the `SCREEN`, changing the `SCREEN` does not change the `_WINDOWHANDLE`. In `3.13.0` this prints a non-zero value on start-up and the same value for all three prints:
Code: (Select All)
Print _WindowHandle
Sleep
Screen _NewImage(640, 480, 32)
_delay 1
Print _WindowHandle
Sleep
Screen 0
_delay 1
Print _WindowHandle
I don't think there are any commands that would make the window handle change, but I'd be curious to know what your program is doing before the `SCREEN`, and also what you're using the `_WINDOWHANDLE` for.
Posts: 1,270
Threads: 118
Joined: Apr 2022
Reputation:
100
Here's some tinkering code I've been working on. When the _DELAY is removed you can see you get different results.
Code: (Select All)
$RESIZE:ON
OPTION _EXPLICIT
TYPE TYPE_IPOINT
x AS LONG
y AS LONG
END TYPE
TYPE TYPE_RECT
left AS LONG
top AS LONG
right AS LONG
bottom AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "user32"
'get current mouse x/y position
'http://allapi.mentalis.org/apilist/GetCursorPos.shtml
FUNCTION GetCursorPos% (lpPoint AS TYPE_IPOINT)
'system window metrics in pixels
'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics
FUNCTION GetSystemMetrics% (BYVAL nIndex AS INTEGER)
FUNCTION GetWindowRect% (BYVAL hWnd AS _INTEGER64, lpRect AS TYPE_RECT) ' returns desktop coordinates (_SCREENX, _SCREENY)-(x2, y2)
FUNCTION GetClientRect% (BYVAL hWnd AS _INTEGER64, lpRect AS TYPE_RECT) ' returns (0, 0)-(_WIDTH, _HEIGHT)
FUNCTION IsZoomed% (BYVAL hWnd AS _INTEGER64) ' reports a maximized window (_FULLSCREEN)
END DECLARE
TYPE TYPE_PROGRAMWINDOW
HWND AS _INTEGER64 ' operating system window handle (_WINDOWHANDLE)
Main AS TYPE_RECT ' window coordinates (absolute to desktop)
Client AS TYPE_RECT ' client coordinates (absolute to desktop)
Caption AS TYPE_RECT ' caption coordinates (absolute to desktop)
Border AS INTEGER ' border width/height
MainWidth AS INTEGER
MainHeight AS INTEGER
ClientWidth AS INTEGER
ClientHeight AS INTEGER
CaptionWidth AS INTEGER
CaptionHeight AS INTEGER ' height of caption
END TYPE
DIM MOUSE_Window AS TYPE_PROGRAMWINDOW
DIM HWND AS _INTEGER64
DIM rect AS TYPE_RECT
DIM Test AS INTEGER
SCREEN _NEWIMAGE(640, 480, 32)
_DELAY .25
HWND = _WINDOWHANDLE
Test = GetWindowRect(HWND, MOUSE_Window.Main) ' get program window desktop coordinates
MOUSE_Window.MainWidth = MOUSE_Window.Main.right - MOUSE_Window.Main.left ' calculate program window width
MOUSE_Window.MainHeight = MOUSE_Window.Main.bottom - MOUSE_Window.Main.top ' calculate program window height
MOUSE_Window.ClientWidth = _WIDTH
MOUSE_Window.ClientHeight = _HEIGHT
MOUSE_Window.Border = (MOUSE_Window.MainWidth - _WIDTH) \ 2
MOUSE_Window.CaptionWidth = _WIDTH
MOUSE_Window.CaptionHeight = MOUSE_Window.MainHeight - _HEIGHT - MOUSE_Window.Border * 2
MOUSE_Window.Client.left = MOUSE_Window.Main.left + MOUSE_Window.Border
MOUSE_Window.Client.top = MOUSE_Window.Main.top + MOUSE_Window.Border + MOUSE_Window.CaptionHeight
PRINT
PRINT " Left :"; MOUSE_Window.Main.left
PRINT " Top :"; MOUSE_Window.Main.top
PRINT " Right :"; MOUSE_Window.Main.right
PRINT " Bottom :"; MOUSE_Window.Main.bottom
PRINT " Main Width :"; MOUSE_Window.MainWidth
PRINT " Main Height :"; MOUSE_Window.MainHeight
PRINT " Client Width :"; MOUSE_Window.ClientWidth
PRINT " Client Height :"; MOUSE_Window.ClientHeight
PRINT " Caption Width :"; MOUSE_Window.CaptionWidth
PRINT " Caption Height :"; MOUSE_Window.CaptionHeight
PRINT " Border Size :"; MOUSE_Window.Border
PRINT
PRINT " Client Left :"; MOUSE_Window.Client.left
PRINT " Client Top :"; MOUSE_Window.Client.top
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 2,710
Threads: 328
Joined: Apr 2022
Reputation:
219
(06-05-2024, 11:21 PM)TerryRitchie Wrote: Here's some tinkering code I've been working on. When the _DELAY is removed you can see you get different results.
Code: (Select All)
$RESIZE:ON
OPTION _EXPLICIT
TYPE TYPE_IPOINT
x AS LONG
y AS LONG
END TYPE
TYPE TYPE_RECT
left AS LONG
top AS LONG
right AS LONG
bottom AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "user32"
'get current mouse x/y position
'http://allapi.mentalis.org/apilist/GetCursorPos.shtml
FUNCTION GetCursorPos% (lpPoint AS TYPE_IPOINT)
'system window metrics in pixels
'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics
FUNCTION GetSystemMetrics% (BYVAL nIndex AS INTEGER)
FUNCTION GetWindowRect% (BYVAL hWnd AS _INTEGER64, lpRect AS TYPE_RECT) ' returns desktop coordinates (_SCREENX, _SCREENY)-(x2, y2)
FUNCTION GetClientRect% (BYVAL hWnd AS _INTEGER64, lpRect AS TYPE_RECT) ' returns (0, 0)-(_WIDTH, _HEIGHT)
FUNCTION IsZoomed% (BYVAL hWnd AS _INTEGER64) ' reports a maximized window (_FULLSCREEN)
END DECLARE
TYPE TYPE_PROGRAMWINDOW
HWND AS _INTEGER64 ' operating system window handle (_WINDOWHANDLE)
Main AS TYPE_RECT ' window coordinates (absolute to desktop)
Client AS TYPE_RECT ' client coordinates (absolute to desktop)
Caption AS TYPE_RECT ' caption coordinates (absolute to desktop)
Border AS INTEGER ' border width/height
MainWidth AS INTEGER
MainHeight AS INTEGER
ClientWidth AS INTEGER
ClientHeight AS INTEGER
CaptionWidth AS INTEGER
CaptionHeight AS INTEGER ' height of caption
END TYPE
DIM MOUSE_Window AS TYPE_PROGRAMWINDOW
DIM HWND AS _INTEGER64
DIM rect AS TYPE_RECT
DIM Test AS INTEGER
SCREEN _NEWIMAGE(640, 480, 32)
_DELAY .25
HWND = _WINDOWHANDLE
Test = GetWindowRect(HWND, MOUSE_Window.Main) ' get program window desktop coordinates
MOUSE_Window.MainWidth = MOUSE_Window.Main.right - MOUSE_Window.Main.left ' calculate program window width
MOUSE_Window.MainHeight = MOUSE_Window.Main.bottom - MOUSE_Window.Main.top ' calculate program window height
MOUSE_Window.ClientWidth = _WIDTH
MOUSE_Window.ClientHeight = _HEIGHT
MOUSE_Window.Border = (MOUSE_Window.MainWidth - _WIDTH) \ 2
MOUSE_Window.CaptionWidth = _WIDTH
MOUSE_Window.CaptionHeight = MOUSE_Window.MainHeight - _HEIGHT - MOUSE_Window.Border * 2
MOUSE_Window.Client.left = MOUSE_Window.Main.left + MOUSE_Window.Border
MOUSE_Window.Client.top = MOUSE_Window.Main.top + MOUSE_Window.Border + MOUSE_Window.CaptionHeight
PRINT
PRINT " Left :"; MOUSE_Window.Main.left
PRINT " Top :"; MOUSE_Window.Main.top
PRINT " Right :"; MOUSE_Window.Main.right
PRINT " Bottom :"; MOUSE_Window.Main.bottom
PRINT " Main Width :"; MOUSE_Window.MainWidth
PRINT " Main Height :"; MOUSE_Window.MainHeight
PRINT " Client Width :"; MOUSE_Window.ClientWidth
PRINT " Client Height :"; MOUSE_Window.ClientHeight
PRINT " Caption Width :"; MOUSE_Window.CaptionWidth
PRINT " Caption Height :"; MOUSE_Window.CaptionHeight
PRINT " Border Size :"; MOUSE_Window.Border
PRINT
PRINT " Client Left :"; MOUSE_Window.Client.left
PRINT " Client Top :"; MOUSE_Window.Client.top
You certain this is with v3.13? Can you do a quick "HELP/ABOUT" and get the version number there?
I can't reproduce any issues with this -- at least not on my laptop.
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
Now I get it - I can't run your code at the moment but I'm assuming the difference is in the reported size of the window, correct?
Your issue is not the `_WINDOWHANDLE` changing, it's the size of the window changing. Basically, `SCREEN` does not currently wait for the window to change in size before continuing in your code, instead it queues that up to happen on the next window refresh (60 FPS). When you call `GetWindowRect()` with no delay, the screen is still the old size. You should be able to test this by placing the `HWND = _WINDOWHANDLE` before the `_Delay`.
We've talked about potentially changing `SCREEN` to wait for the resize, but in most cases this distinction doesn't matter because the program doesn't notice it - I don't believe there are any commands that return the current window height/width, commands like `_WIDTH` and `_HEIGHT` return the size of the current QB64 SCREEN regardless of the actual size of the window. You're skipping this by going to Windows with the `_WINDOWHANDLE` though and thus can notice the delay.
Posts: 1,270
Threads: 118
Joined: Apr 2022
Reputation:
100
06-06-2024, 12:42 AM
(This post was last modified: 06-06-2024, 12:44 AM by TerryRitchie.)
Yes, version 3.13.1
Ok, so if I get the _WINDOWHANDLE before any screen changes I'll be good then?
(nope, that doesn't work either)
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(06-06-2024, 12:42 AM)TerryRitchie Wrote: Yes, version 3.13.1
Ok, so if I get the _WINDOWHANDLE before any screen changes I'll be good then?
(nope, that doesn't work either) The issue isn't with the `_WINDOWHANDLE`, the `_WINDOWHANDLE` does not change while your program is running, but the window size that it reports does.
`SCREEN _NEWIMAGE(640, 480, 32)` does not change the size of the window until the next screen refresh, and that will happen after `SCREEN` is done and your QB64 code continues on to run the next lines. As far as regular QB64 code is concerned it doesn't know the real size of the window anyway, so this behavior has no direct impact on pure QB64 code. Your `GetWindowRect()` call bypasses the QB64 logic though and thus notices the delay in changing the window size.
This issue is known to impact `_SCREENMOVE _MIDDLE` so we'll probably fix it so that `SCREEN` waits for a redraw, but I would also say that your results may be surprising when using `_WINDOWHANDLE` to directly call Windows functions. The state of things according to QB64 may not always match the state of things according to Windows, we don't make any guarantees in that regard and the details may change from version to version as things change around how we interact with the OS.
Posts: 1,270
Threads: 118
Joined: Apr 2022
Reputation:
100
(06-06-2024, 01:44 AM)DSMan195276 Wrote: (06-06-2024, 12:42 AM)TerryRitchie Wrote: Yes, version 3.13.1
Ok, so if I get the _WINDOWHANDLE before any screen changes I'll be good then?
(nope, that doesn't work either) The issue isn't with the `_WINDOWHANDLE`, the `_WINDOWHANDLE` does not change while your program is running, but the window size that it reports does.
`SCREEN _NEWIMAGE(640, 480, 32)` does not change the size of the window until the next screen refresh, and that will happen after `SCREEN` is done and your QB64 code continues on to run the next lines. As far as regular QB64 code is concerned it doesn't know the real size of the window anyway, so this behavior has no direct impact on pure QB64 code. Your `GetWindowRect()` call bypasses the QB64 logic though and thus notices the delay in changing the window size.
This issue is known to impact `_SCREENMOVE _MIDDLE` so we'll probably fix it so that `SCREEN` waits for a redraw, but I would also say that your results may be surprising when using `_WINDOWHANDLE` to directly call Windows functions. The state of things according to QB64 may not always match the state of things according to Windows, we don't make any guarantees in that regard and the details may change from version to version as things change around how we interact with the OS. Yeah, I realized that after thinking about it a bit. I remember a while back when the need for a _DELAY was removed for many situations and that's why adding a _DELAY to fix this issue frustrated and confused me. I happened to stumble across a new one.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
|