Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
_WINDOWHANDLE
#1
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
Reply
#2
(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.  Smile



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?
Reply
#3
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.
Reply
#4
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
Reply
#5
(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.  Sad
Reply
#6
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.
Reply
#7
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
Reply
#8
(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.
Reply
#9
(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
Reply




Users browsing this thread: 14 Guest(s)