Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
08-19-2023, 03:53 PM
(This post was last modified: 08-19-2023, 04:09 PM by TerryRitchie.)
(08-19-2023, 03:48 PM)Dav Wrote: The wiki code is working for me as is. Im In windows 7 32-bit using the current version of QB64-PE.
- Dav Well now, that's interesting. I'm in Windows 7 64-bit using the current version of QB64-PE. I'll fire up a VM of 32bit and see if it run there.
Update: The code works fine in a virtual machine running Windows 7 32bit and the latest 32bit version of QB64-PE. Seems to be a 64bit related issue then.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 734
Threads: 30
Joined: Apr 2022
Reputation:
43
It's not really an "issue". What it is, is the person who wrote the sample didn't take into account any architecture other than 32 bit. I try to make sure all my types are sized for both systems when I can.
Tread on those who tread on you
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
(08-19-2023, 09:10 PM)SpriggsySpriggs Wrote: It's not really an "issue". What it is, is the person who wrote the sample didn't take into account any architecture other than 32 bit. I try to make sure all my types are sized for both systems when I can. I was written by Galleon back in the 32bit .954 version of QB64.
What exactly would I need to do to bring the code to 64bit? I've studied the Microsoft docs pretty well and all but what I noted before seems in order. I've already tried changing the LONG values for handles to _OFFSETs and removing _OFFSETS as pointers to the UDT and instead passing the UDT directly but I get the same negative result.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 422
Threads: 27
Joined: Apr 2022
Reputation:
26
@ TerryRitchie
there were a number of places in your code that seemed to needed to be _offset instead of a long, plus you missed hbmpItem in the Type MENUITEMINFO
here is your altered code, it successfully adds the menu item and silently crashes or simply vanishes
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 _Offset
hbmpChecked As _Offset
hbmpUnchecked As _Offset
dwItemData As _Offset
dwTypeData As _Offset
cch As Long
hbmpItem As _Offset
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 As _Offset)
Function SetMenu& (ByVal hWnd As _Offset, Byval hMenu As _Offset)
Function InsertMenuItemA& (ByVal hMenu As _Offset, Byval uItem As _Unsigned Long, Byval fByPosition&, Byval lpmii As _Offset)
Function GetMenuItemCount& (ByVal hMenu As _Offset)
Function GetMenuItemInfoA& (ByVal hMenu As _Offset, Byval uItem As _Unsigned Long, Byval fByPosition&, Byval lpmii As _Offset)
End Declare
Dim hWnd As _Offset
Dim hMenu As _Offset
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$ = ""
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
(08-19-2023, 10:45 PM)Jack Wrote: @ TerryRitchie
there were a number of places in your code that seemed to needed to be _offset instead of a long, plus you missed hbmpItem in the Type MENUITEMINFO
here is your altered code, it successfully adds the menu item and silently crashes or simply vanishes Yeah, I pointed out that the original code was missing hbmpItem in an earlier post. The code is not mine, it's from the Wiki and was written by Galleon back around 2011.
As Dav pointed out, the code works correctly in 32bit versions of Windows and QB64.
Your code is closer than I have come to getting it to work. You got past the the first InsertMenuItemA, something I was unable to do. I'll study your changes to see if I can get it to work the rest of the way.
Thanks for changes.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 372
Threads: 23
Joined: May 2022
Reputation:
56
08-20-2023, 12:01 AM
(This post was last modified: 08-20-2023, 12:03 AM by a740g.)
Here. This should work on 64-bit compilers.
Code: (Select All)
DEFLNG A-Z
OPTION _EXPLICIT
$IF 32BIT THEN
$ERROR 32-bit compilers not supported!
$END IF
CONST NULL = 0
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
AS _UNSIGNED LONG cbSize
AS _UNSIGNED LONG fMask
AS _UNSIGNED LONG fType
AS _UNSIGNED LONG fState
AS _UNSIGNED LONG wID
AS STRING * 4 __padding1
AS _UNSIGNED _OFFSET hSubMenu
AS _UNSIGNED _OFFSET hbmpChecked
AS _UNSIGNED _OFFSET hbmpUnchecked
AS _UNSIGNED _OFFSET dwItemData
AS _UNSIGNED _OFFSET dwTypeData ' str ptr
AS _UNSIGNED LONG cch
AS STRING * 4 __padding2
AS _UNSIGNED _OFFSET hbmpItem
END TYPE
DECLARE DYNAMIC LIBRARY "user32"
FUNCTION FindWindow~%& ALIAS FindWindowA (lpClassName AS STRING, lpWindowName AS STRING)
FUNCTION CreateMenu~%&
FUNCTION DrawMenuBar& (BYVAL hWnd AS _UNSIGNED _OFFSET)
FUNCTION SetMenu& (BYVAL hWnd AS _UNSIGNED _OFFSET, BYVAL hMenu AS _UNSIGNED _OFFSET)
FUNCTION InsertMenuItem& ALIAS InsertMenuItemA (BYVAL hMenu AS _UNSIGNED _OFFSET, BYVAL item AS _UNSIGNED LONG, BYVAL fByPosition AS LONG, BYVAL lpmi AS _UNSIGNED _OFFSET)
FUNCTION GetMenuItemCount& (BYVAL hMenu AS _UNSIGNED _OFFSET)
FUNCTION GetMenuItemInfo& ALIAS GetMenuItemInfoA (BYVAL hMenu AS _UNSIGNED _OFFSET, BYVAL item AS _UNSIGNED LONG, BYVAL fByPosition AS LONG, BYVAL lpmii AS _UNSIGNED _OFFSET)
END DECLARE
DIM MenuItem AS MENUITEMINFO, BlankMenuItem AS MENUITEMINFO
DIM TypeData AS STRING * 1000
_TITLE "Menu bar API demo"
DIM hWnd AS _UNSIGNED _OFFSET: hWnd = _WINDOWHANDLE 'FindWindow(0, "Menu bar API demo" + CHR$(0))
DIM hMenu AS _UNSIGNED _OFFSET: hMenu = CreateMenu: BlankMenuItem.cbSize = LEN(BlankMenuItem)
COLOR 7, 1
'Add a separator bar
DIM count AS LONG: count = GetMenuItemCount(hMenu): PRINT "MenuItemCount:"; count
MenuItem = BlankMenuItem
MenuItem.fMask = MIIM_ID OR MIIM_TYPE
MenuItem.fType = MFT_SEPARATOR
MenuItem.wID = count
IF InsertMenuItem(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$(NULL)
MenuItem.dwTypeData = _OFFSET(TypeData)
MenuItem.cch = LEN(MenuItem.dwTypeData)
DIM MyButton AS _UNSIGNED LONG: MyButton = MenuItem.wID
IF InsertMenuItem(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
DIM AS LONG prev_state, new_state, ok
DO
_LIMIT 70
prev_state = new_state
ok = GetMenuItemInfo(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$ = ""
END
Posts: 1,272
Threads: 119
Joined: Apr 2022
Reputation:
100
(08-20-2023, 12:01 AM)a740g Wrote: Here. This should work on 64-bit compilers.
Yes it does, thank you! This example should be added to the Windows Library examples in the Wiki.
Could you explain the changes you made and why they needed to be done so I can get a better understanding of your code and why 64-bit needs to be approached differently please?
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 2,697
Threads: 327
Joined: Apr 2022
Reputation:
217
(08-20-2023, 05:47 PM)TerryRitchie Wrote: (08-20-2023, 12:01 AM)a740g Wrote: Here. This should work on 64-bit compilers.
Yes it does, thank you! This example should be added to the Windows Library examples in the Wiki.
Could you explain the changes you made and why they needed to be done so I can get a better understanding of your code and why 64-bit needs to be approached differently please?
The issue lies in data alignment and type packing. In 32 bit OSes, data is packed on a 4 byte alignment. In 64-bit OSes, it's packed on 8-byte alignments.
For example:
TYPE Foo
x AS INTEGER
y AS LONG
z AS STRING *3
END TYPE
The above type (as a windows type) would align on 4-byte break points. It'd actually use 12-bytes per record in memory as:
TRANSLATED TYPE Foo32
x AS INTEGER
buffer AS STRING *2 'complete that 4 byte block
y AS LONG 'already 4 bytes; no buffer is needed
z AS STRING * 3
buffer2 AS STRING * 1 'complete the other 4 byte block
END TYPE
On a 64-bit type, the breakpoints are 8-bytes, for 16-bytes per record in memory.
TRANSLATED TYPE Foo64
x AS INTEGER
y AS LONG
buffer AS STRING * 2 'complete the 8-byte block
z AS STRING * 3
buffer2 AS STRING * 5 'complete the second 8-byte block
END TYPE
For 32-bit windows API types, data is aligned in 4-byte segments. For 64-bit window API types, it's in 8-byte segments.
Posts: 2,697
Threads: 327
Joined: Apr 2022
Reputation:
217
TYPE MENUITEMINFO
AS _UNSIGNED LONG cbSize
AS _UNSIGNED LONG fMask << 8 bytes
AS _UNSIGNED LONG fType
AS _UNSIGNED LONG fState << 8 bytes
AS _UNSIGNED LONG wID
AS STRING * 4 __padding1 << 4 bytes + 4 bytes padding = 8 bytes
AS _UNSIGNED _OFFSET hSubMenu << *ALL* 64-bit OFFSET are 8 bytes
AS _UNSIGNED _OFFSET hbmpChecked
AS _UNSIGNED _OFFSET hbmpUnchecked
AS _UNSIGNED _OFFSET dwItemData
AS _UNSIGNED _OFFSET dwTypeData ' str ptr
AS _UNSIGNED LONG cch
AS STRING * 4 __padding2 << 4 bytes + 4 bytes padding = 8 bytes
AS _UNSIGNED _OFFSET hbmpItem
END TYPE
Posts: 422
Threads: 27
Joined: Apr 2022
Reputation:
26
with all due respect to a740g, I am not comfortable with the padding in MENUITEMINFO
this C code prints 80 as the size of MENUITEMINFO
Code: (Select All) #include <stdio.h>
#include <windows.h>
#include <winuser.h>
int main(void){
printf("%lld\n", sizeof(MENUITEMINFO));
return 0;
}
|