flat assembler
Message board for the users of flat assembler.

Index > Windows > Help with menus

Author
Thread Post new topic Reply to topic
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 27 Feb 2006, 14:49
Hello,

I have created a little program that shows a menu when the user clicks on a button. I am using the "CreatePopupMenu", "AppendMenu" and "TrackPopupMenu" functions for the menu and "GetCursorPos" to tell the program where to begin showing the menu (at mouse x and y coordinates).

The problem is that the menu will still be shown at the mouse cursor coordinates, even if the user uses the enter or space keys and even if the mouse is on the other side of the screen (far from the button). Besides I do not like how it looks.

So, I would like to have the menu always begin right below the button (as the ASCII image below) whether the user clicks anywhere on the button or uses the enter and space keys, but I do not know what functions to use.

Any idea is welcome. Thank you.

Code:
 ________
| Button |
|-------------.
|Menu item 1  |
|-------------|
|Menu item 2  |
|Menu item 3  |
|_____________|
    
Post 27 Feb 2006, 14:49
View user's profile Send private message Reply with quote
wisepenguin



Joined: 30 Mar 2005
Posts: 129
wisepenguin 27 Feb 2006, 16:54
from memory use GetWindowRect to get the coordinates and position of the button

pass rect.bottom for the y parameters
and rect.left for the x

check what each function uses in terms of coordinates (screen/client)
Post 27 Feb 2006, 16:54
View user's profile Send private message Reply with quote
Reverend



Joined: 24 Aug 2004
Posts: 408
Location: Poland
Reverend 27 Feb 2006, 18:23
- GetCursorPos
- ChildWindowFromPoint
- GetWindowRect
- some_smart_calculations
- TrackPopupMenu
Post 27 Feb 2006, 18:23
View user's profile Send private message Visit poster's website Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 01 Mar 2006, 20:11
Hello,

I tried what wisepenguin proposed, but was unfortunately unable to make it work. I have programmed DOS assembler with TASM then NASM for years, but I am rather new to Win32ASM and FASM, so I may do some silly things. By the way, can structures be used with FASM?

Below is the code. I would appreciate your help in finding the error(s).

Thank you in advance.


Code:
format PE GUI 4.0
entry start

include '\fasmw164\INCLUDE\win32ax.inc'
include '\fasmw164\INCLUDE\apia\kernel32.inc'
include '\fasmw164\INCLUDE\apia\user32.inc'

section '.data' data readable writeable
winclass        db 'TestClass',0
hPopupMenu      dd 0
ButtonRect      dd 0
                dd 0
                dd 0
                dd 0

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,winclass
msg MSG


section '.code' code readable executable
start:
        invoke  GetModuleHandle,0
        mov     [wc.hInstance],eax

        invoke  LoadCursor,0,IDC_ARROW
        mov     [wc.hCursor],eax

        invoke  RegisterClass,wc

        invoke  LoadMenu,[wc.hInstance],0

        invoke  CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,winclass,'Test',WS_VISIBLE+WS_OVERLAPPEDWINDOW,0,0,200,200,0,eax,[wc.hInstance],0

msg_loop:
        invoke  GetMessage,msg,0,0,0
        or      eax,eax
        jz      end_loop
        invoke  TranslateMessage,msg
        invoke  DispatchMessage,msg
        jmp     msg_loop

end_loop:
        invoke  ExitProcess,[msg.wParam]


proc WindowProc hwnd,wmsg,wparam,lparam
        push    ebx esi edi
        cmp     [wmsg],WM_CREATE
        je      wmcreate
        cmp     [wmsg],WM_DESTROY
        je      wmdestroy
        cmp     [wmsg],WM_CLOSE
        je      wmdestroy
        cmp     [wmsg],WM_COMMAND
        je      wmcommand

defwndproc:
        invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
        jmp     finish

wmcreate:
        invoke  CreateWindowEx,0,'BUTTON','TestButton',WS_CHILD+WS_VISIBLE,10,10,80,24,[hwnd],200,[wc.hInstance],0

        invoke  CreatePopupMenu
        mov     [hPopupMenu],eax
        invoke  AppendMenu,[hPopupMenu],MF_STRING,300,'Item &1'
        invoke  AppendMenu,[hPopupMenu],MF_STRING,301,'Item &2'

        xor     eax,eax
        jmp     finish

wmdestroy:
        invoke  PostQuitMessage,0
        xor     eax,eax
        jmp     finish

wmcommand:
        mov     eax,[wparam]
        cmp     eax,200
        je      ChannelButtonCommand
        jmp     wmcommandend

    ChannelButtonCommand:
        invoke  GetWindowRect,200,ButtonRect
        invoke  TrackPopupMenu,[hPopupMenu],TPM_RIGHTALIGN,[ButtonRect],[ButtonRect+12],0,[hwnd],0
        jmp     wmcommandend

wmcommandend:
        xor     eax,eax
        jmp     finish

finish:
        pop     edi esi ebx
        ret
endp


section '.idata' import data readable writeable
library kernel32,'KERNEL32.DLL',user32,'USER32.DLL'
    
Post 01 Mar 2006, 20:11
View user's profile Send private message Reply with quote
vbVeryBeginner



Joined: 15 Aug 2004
Posts: 884
Location: \\world\asia\malaysia
vbVeryBeginner 02 Mar 2006, 08:36
check this man of steel :p
Code:
format PE GUI 4.0 
entry start 

include '%fasminc%\win32ax.inc' 

section '.data' data readable writeable 
winclass        db 'TestClass',0 
hPopupMenu      dd 0 
ButtonRect      RECT
button.h        dd ?

wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,winclass 
msg MSG 


section '.code' code readable executable 
start: 
        invoke  GetModuleHandle,0 
                mov  [wc.hInstance],eax 

        invoke  LoadCursor,0,IDC_ARROW 
                mov  [wc.hCursor],eax 

        invoke  RegisterClass,wc 

        invoke  LoadMenu,[wc.hInstance],0 

        invoke  CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,winclass,'Test',WS_VISIBLE+WS_OVERLAPPEDWINDOW,100,100,200,200,0,eax,[wc.hInstance],0 

msg_loop: 
        invoke  GetMessage,msg,0,0,0 
        or      eax,eax 
        jz      end_loop 
        invoke  TranslateMessage,msg 
        invoke  DispatchMessage,msg 
        jmp     msg_loop 

end_loop: 
        invoke  ExitProcess,[msg.wParam] 


proc WindowProc hwnd,wmsg,wparam,lparam 
        push    ebx esi edi 
        cmp     [wmsg],WM_CREATE 
        je      wmcreate 
        cmp     [wmsg],WM_DESTROY 
        je      wmdestroy 
        cmp     [wmsg],WM_CLOSE 
        je      wmdestroy 
        cmp     [wmsg],WM_COMMAND 
        je      wmcommand 

defwndproc: 
        invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam] 
        jmp     finish 

wmcreate: 
        invoke  CreateWindowEx,0,'BUTTON','TestButton',WS_CHILD+WS_VISIBLE,10,10,100,24,[hwnd],200,[wc.hInstance],0 
                mov  [button.h],eax
        invoke  CreatePopupMenu 
        mov     [hPopupMenu],eax 
        invoke  AppendMenu,[hPopupMenu],MF_STRING,300,'Item &1' 
        invoke  AppendMenu,[hPopupMenu],MF_STRING,301,'Item &2' 

        xor     eax,eax 
        jmp     finish 

wmdestroy: 
        invoke  PostQuitMessage,0 
        xor     eax,eax 
        jmp     finish 

wmcommand: 
        mov     eax,[wparam] 
        cmp     eax,200 
        je      ChannelButtonCommand 
        jmp     wmcommandend 

    ChannelButtonCommand: 
        ;invoke  GetWindowRect,200,ButtonRect 
        invoke  GetWindowRect,[button.h],ButtonRect      ; we get screen cordinate in ButtonRect
                ; assume u want TPM_LEFTALIGN + TPM_TOPALIGN
                mov  eax,[ButtonRect.left]
                mov  edx,[ButtonRect.bottom]
        invoke  TrackPopupMenu,[hPopupMenu],TPM_LEFTALIGN+TPM_TOPALIGN,eax,edx,0,[button.h],0 
        jmp     wmcommandend 

wmcommandend: 
        xor     eax,eax 
        jmp     finish 

finish: 
        pop     edi esi ebx 
        ret 
endp 


section '.idata' import data readable writeable 
library kernel32,'KERNEL32.DLL',user32,'USER32.DLL'
include '%fasminc%\apia\kernel32.inc' 
include '%fasminc%\apia\user32.inc' 
    

Image
Post 02 Mar 2006, 08:36
View user's profile Send private message Visit poster's website Reply with quote
Crukko



Joined: 26 Nov 2005
Posts: 118
Crukko 02 Mar 2006, 08:53
Remember:
1. Store the handle of the button
2. use it to find the x, y
3. Track the Menu

vbVeryBeginner: This was my solution too Wink
Post 02 Mar 2006, 08:53
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 03 Mar 2006, 10:34
Thank you very much, that is exactly what I wanted.

But I still have a problem/question. Just imagine that the program lets the user add buttons at will, with, let us say some menu command. Now, in the program you corrected, you suggest to save the button handle, but how can you save the handle of each button the user has created and then how can you know which button was clicked so that you can retrieve the right handle? Right now, handles of old buttons get crushed by the handles of new buttons, so if you add new buttons, when you click any (old) button, the menu obviously only appears below the last one created.

So, do you have any idea on how I could store all the handles of all the buttons the user creates, and then retrieve the right one when any button is clicked?
Or better... is there any way to automatically retrieve the handle of any button without storing any handle? In other words, is there any API(s) I can invoke that will detect what button was clicked and automatically retrieve and store its handle at a precise memory location?
Post 03 Mar 2006, 10:34
View user's profile Send private message Reply with quote
Crukko



Joined: 26 Nov 2005
Posts: 118
Crukko 04 Mar 2006, 08:57
You can find the Button Handle in 'lparam'

invoke GetWindowRect,[lparam],ButtonRect ; we get screen cordinate in ButtonRect

so every time you get the exact x, y of the clicked button.

If you want to store every button you can create/reserve memory for it
Remeber: in the line
invoke CreateWindowEx,0,'BUTTON','TestButton',WS_CHILD+WS_VISIBLE,10,10,100,24,[hwnd],200,[wc.hInstance],0

You use the ButtonID=200, so at line
cmp eax,200
you find its message....
so
1. Reserve memory
2. use Dword for ButtonID created or handle of the button
+ Dword handle menu created
3. find the right button handle in the Mem
4. get the handle menu
5. show the menu

If the user delete the button simply mov dword 0 into the corresponding memory Wink

Hope this will be ok.
Post 04 Mar 2006, 08:57
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 05 Mar 2006, 01:29
So, the handle can be retrieved from lparam and the ID can be retrieved as easily from the low-word of wparam, but there is still a problem: while the Windows-generated handle is different for each button, the ID is always the same (200 in the example) unless I am missing something here.
The result here is that we can get the handle to use it with GetWindowRect as you said, but if one of the menu items uses, let us say, SetDlgItemText to change the button caption, we will need the ID (200 invariably for all the buttons) and not the handle, so even though the menu will be correctly shown under the button we click, only the first button caption will be modified when the menu item is clicked.
So we still have a problem, unless there is some way to dynamically increase the ID before creating a new button.
Post 05 Mar 2006, 01:29
View user's profile Send private message Reply with quote
Crukko



Joined: 26 Nov 2005
Posts: 118
Crukko 05 Mar 2006, 23:01
Siply use:

Code:
ButtonID dd 0

CreateWindowEx,0,'BUTTON','TestButton',WS_CHILD+WS_VISIBLE,10,10,100,24,[hwnd], [ButtonID], [wc.hInstance], 0
    


Remember to increase the ButtonID.
Now you have different ID for each button you create.
Remember to put it in the memory you reserved Wink
Post 05 Mar 2006, 23:01
View user's profile Send private message Reply with quote
ManOfSteel



Joined: 02 Feb 2005
Posts: 1154
ManOfSteel 07 Mar 2006, 18:44
Of course! I had already tried something like that but it did not work because I had made an error. But now it works like a charm.

Thank you for all your help, it was very valuable.
Post 07 Mar 2006, 18:44
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 10 Mar 2008, 19:41
hi guys,
How to show up & symbol as is?

Code:
menuitem 'Up & Down',IDM_LEVEL5
    

_________________
Hobby BASIC Interpreter
Post 10 Mar 2008, 19:41
View user's profile Send private message Visit poster's website Reply with quote
wisepenguin



Joined: 30 Mar 2005
Posts: 129
wisepenguin 10 Mar 2008, 19:57
hi thimis,
Code:
menuitem "Up && Down", IDM_LEVEL5
    


have a good day
Post 10 Mar 2008, 19:57
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 10 Mar 2008, 20:04
Oh Gosh, i didn't try this, thank you wisepenguin, have a nice day too.

_________________
Hobby BASIC Interpreter
Post 10 Mar 2008, 20:04
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.