API Questions
#1
Since I've started diving into API calls I figured a dedicated thread for API related questions would be better.

Here is my first question.

In the Wiki here: https://qb64phoenix.com/qb64wiki/index.p...ndow_Focus

It's shown how to determine the foreground window (the one in focus).

The Microsoft docs for GetForegroundWindow are located here: https://learn.microsoft.com/en-us/window...oundwindow

I noticed in the Wiki example that GetForegroundWindow is declared as an _OFFSET (%&). How was this determined? Looking at the Microsoft docs there is no indication of the type of variable returned. With other window handle (hWnd) related functions I've noticed a variable type of LONG is used. Why was _OFFSET needed here instead of LONG?

This has me confused. Any clarification would be greatly appreciated.
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#2
(08-18-2023, 07:35 PM)TerryRitchie Wrote: Since I've started diving into API calls I figured a dedicated thread for API related questions would be better.

Here is my first question.

In the Wiki here: https://qb64phoenix.com/qb64wiki/index.p...ndow_Focus

It's shown how to determine the foreground window (the one in focus).

The Microsoft docs for GetForegroundWindow are located here: https://learn.microsoft.com/en-us/window...oundwindow

I noticed in the Wiki example that GetForegroundWindow is declared as an _OFFSET (%&). How was this determined? Looking at the Microsoft docs there is no indication of the type of variable returned. With other window handle (hWnd) related functions I've noticed a variable type of LONG is used. Why was _OFFSET needed here instead of LONG?

This has me confused. Any clarification would be greatly appreciated.
HWND is 4 bytes in 32 bit and 8 bytes in 64. The reason you probably see it often declared as a LONG is because many people use 32 bit QB64. Using OFFSET makes it automatically the right size for either system. From Microsoft, the declaration for GetForegroundWindow is: HWND GetForegroundWindow();
The HWND is a handle to the window. Most handles in Win32 are going to be translated best to OFFSET in QB64.
Ask me about Windows API and maybe some Linux stuff
Reply
#3
(08-18-2023, 07:51 PM)SpriggsySpriggs Wrote:
(08-18-2023, 07:35 PM)TerryRitchie Wrote: Since I've started diving into API calls I figured a dedicated thread for API related questions would be better.

Here is my first question.

In the Wiki here: https://qb64phoenix.com/qb64wiki/index.p...ndow_Focus

It's shown how to determine the foreground window (the one in focus).

The Microsoft docs for GetForegroundWindow are located here: https://learn.microsoft.com/en-us/window...oundwindow

I noticed in the Wiki example that GetForegroundWindow is declared as an _OFFSET (%&). How was this determined? Looking at the Microsoft docs there is no indication of the type of variable returned. With other window handle (hWnd) related functions I've noticed a variable type of LONG is used. Why was _OFFSET needed here instead of LONG?

This has me confused. Any clarification would be greatly appreciated.
HWND is 4 bytes in 32 bit and 8 bytes in 64. The reason you probably see it often declared as a LONG is because many people use 32 bit QB64. Using OFFSET makes it automatically the right size for either system. From Microsoft, the declaration for GetForegroundWindow is: HWND GetForegroundWindow();
The HWND is a handle to the window. Most handles in Win32 are going to be translated best to OFFSET in QB64.
Ah, ok, so basically it's acting like an _INTEGER64 in this sense. So the rule of thumb is if a handle is returned best practice is to use _OFFSET.

Thank you for the quick reply and explanation. Smile
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#4
In a lot of cases, like in the wiki example you reference, the return type really isn't that important.  Think of making a function like so:

FUNCTION Foo&& 
   'Stuff
END FUNCTION

Now that function returns a value which is an Integer64...  Yet, you'll see folks write code like:

DIM whatever AS INTEGER
whatever = Foo

And, it works!  Well, it works as long as the return value is less than 32536, otherwise you get overflow results as you can't put values larger than that in an INTEGER.

Since a lot of windows API calls just return simple error/success codes, it often doesn't matter what the return type is.  Nearly any variable type can successfully receive a value of 1 for success, 0 for failure.  Wink
Reply
#5
Such as here:


DECLARE DYNAMIC LIBRARY "kernel32"
FUNCTION QueryDosDeviceA~& (BYVAL lpDeviceName AS _UNSIGNED _OFFSET, BYVAL lpTargetPath AS _UNSIGNED _OFFSET, BYVAL ucchMax AS _UNSIGNED LONG)
FUNCTION GetLastError~& ()
END DECLARE

DIM sizeofbuffer AS _UNSIGNED LONG
DIM buffer AS STRING
DIM i AS _UNSIGNED LONG
DIM x AS _UNSIGNED LONG
DIM n AS _UNSIGNED LONG
sizeofbuffer = 1024
buffer = SPACE$(sizeofbuffer)

DO
x = 0
IF QueryDosDeviceA~&(0, _OFFSET(buffer), sizeofbuffer) = 0 THEN
x = GetLastError~&
IF x = &H7A THEN


GetLastError is defined as an offset to return values, but x is defined as an Unsigned Long, and yet it works perfectly fine. Why? Because we only care if the return value in this case is &H7A -- which would fit properly in an Unsigned Byte! Wink

(Snippet taken from wiki for Window Ports in the windows dll examples.)

It's not the *PROPER* return type, but it'll work a lot of times with any glitches. Wink
Reply
#6
As our one-eyed friend put, it doesn't often matter about return types. However, it makes the most sense to do your best to match up sizes and types, for professionalism and consistency.
Ask me about Windows API and maybe some Linux stuff
Reply
#7
Can anyone figure out why the Windows Menu code here in the wiki: https://qb64phoenix.com/qb64wiki/index.p...ndows_Menu

does not work?

I went extensively through the Microsoft docs and found two things that may be a problem.

First, the UDT MENUITEMINFO:

TYPE MENUITEMINFO
    cbSize AS LONG
    fMask AS LONG
    fType AS LONG
    fState AS LONG
    wID AS LONG
    hSubMenu AS LONG
    hbmpChecked AS LONG
    hbmpUnchecked AS LONG
    dwItemData AS _OFFSET
    dwTypeData AS _OFFSET
    cch AS LONG
    'hbmpItem AS LONG <--- this not in original but specified in Microsoft docs.
END TYPE

seems to be missing hbmpItem (I added it above remmed out).

Second, the function DrawMenuBar is not used anywhere in the code to actually generate the menu. I'm wondering if somehow some of the code has been omitted during a copy/paste into this Wiki?

CreateMenu is returning a valid hMenu handle value. I believe the problem is with the first InsertMenuItemA function encountered, but according to what I've read in the docs it's structure appears fine.

Code: (Select All)
DEFLNG A-Z

CONST MIIM_STATE = &H1
CONST MIIM_ID = &H2
CONST MIIM_TYPE = &H10
CONST MFT_SEPARATOR = &H800
CONST MFT_STRING = &H0
CONST MFS_ENABLED = &H0
CONST MFS_CHECKED = &H8

CONST HWND_TOPMOST = -1
CONST HWND_NOTOPMOST = -2
CONST SWP_NOMOVE = &H2
CONST SWP_NOSIZE = &H1
'-----------------------------------------------------------------------------------

TYPE MENUITEMINFO
    cbSize AS LONG
    fMask AS LONG
    fType AS LONG
    fState AS LONG
    wID AS LONG
    hSubMenu AS LONG
    hbmpChecked AS LONG
    hbmpUnchecked AS LONG
    dwItemData AS _OFFSET
    dwTypeData AS _OFFSET
    cch AS LONG
END TYPE

DECLARE LIBRARY
    FUNCTION FindWindow& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
END DECLARE

DECLARE DYNAMIC LIBRARY "user32"
  FUNCTION CreateMenu& ()
  FUNCTION DrawMenuBar (BYVAL hWnd&)
  FUNCTION SetMenu& (BYVAL hWnd&, BYVAL hMenu&)
  FUNCTION InsertMenuItemA& (BYVAL hMenu&, BYVAL uItem&, BYVAL fByPosition&, BYVAL lpmii AS _OFFSET)
  FUNCTION GetMenuItemCount& (BYVAL hMenu&)
  FUNCTION GetMenuItemInfoA& (BYVAL hMenu&, BYVAL uItem&, BYVAL fByPosition&, BYVAL lpmii AS _OFFSET)
END DECLARE

DIM hWnd AS LONG
DIM hMenu AS LONG
DIM MenuItem AS MENUITEMINFO, BlankMenuItem AS MENUITEMINFO
DIM TypeData AS STRING * 1000

_TITLE "Menu bar API demo"
hWnd = _WINDOWHANDLE 'FindWindow(0, "Menu bar API demo" + CHR$(0))

hMenu = CreateMenu: BlankMenuItem.cbSize = LEN(BlankMenuItem)

COLOR 7, 1: CLS

'Add a separator bar
count = GetMenuItemCount(hMenu): PRINT "MenuItemCount:"; count
MenuItem = BlankMenuItem
MenuItem.fMask = MIIM_ID OR MIIM_TYPE
MenuItem.fType = MFT_SEPARATOR
MenuItem.wID = count
IF InsertMenuItemA(hMenu, count, 1, _OFFSET(MenuItem)) THEN PRINT "Successfully added menu item!" ELSE PRINT "Failed to add menu item!": END

'Add a button
MenuItem = BlankMenuItem
count = GetMenuItemCount(hMenu): PRINT "MenuItemCount:"; count
MenuItem.fMask = MIIM_STATE OR MIIM_ID OR MIIM_TYPE
MenuItem.fType = MFT_STRING
MenuItem.fState = MFS_ENABLED
MenuItem.wID = count
TypeData = "&Fire Laser!" + CHR$(0)
MenuItem.dwTypeData = _OFFSET(TypeData)
MenuItem.cch = LEN(MenuItem.dwTypeData)
MyButton = MenuItem.wID
IF InsertMenuItemA(hMenu, count, 1, _OFFSET(MenuItem)) THEN PRINT "Successfully added menu item!" ELSE PRINT "Failed to add menu item!": END

IF SetMenu(hWnd, hMenu) THEN PRINT "Successfully set menu!": PRINT "Menu handle is:"; hMenu ELSE PRINT "Failed to set menu!": END

DO: _LIMIT 70
    prev_state = new_state
    ok = GetMenuItemInfoA(hMenu, MyButton, 1, _OFFSET(MenuItem))
    new_state = MenuItem.fState AND 128
    IF prev_state = 0 AND new_state <> 0 THEN PRINT "Ouch! ";
LOOP WHILE INKEY$ = ""
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#8
I think this was due to the padding and such. I wrote code that worked for 64 bit a while back but I think I lost it. I'd need to look at it again to check the offsets of each member.
Ask me about Windows API and maybe some Linux stuff
Reply
#9
(08-19-2023, 04:32 AM)SpriggsySpriggs Wrote: I think this was due to the padding and such. I wrote code that worked for 64 bit a while back but I think I lost it. I'd need to look at it again to check the offsets of each member.
I was going through my code archives and found a copy of the menu library I copied back in 2012 when version .954 of QB64 was still the latest. Aside from the change to using _WINDOWHANDLE in the version in the Wiki the code is identical. It appears a change in QB64 somewhere along the line broke the code.
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#10
The wiki code is working for me as is.  Im In windows 7 32-bit using the current version of QB64-PE. 

- Dav

Find my programs here in Dav's QB64 Corner
Reply




Users browsing this thread: 5 Guest(s)