Posts: 1,006
Threads: 330
Joined: Mar 2007
Hi All,
I created this to add Menu/Toolbar dlg in exe. It works pretty well but I am sure Gintaras could class it up!!
Function TestExeDlgMenu
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages
CloseWindowsOf("DlgMenu" "#32770");err
run "$system$\notepad.exe" "" "" "" 0x1800 win("Notepad" "Notepad")
if(!ShowDialog("TestExeDlgMenu" &TestExeDlgMenu 0)) ret
;BEGIN DIALOG
;0 "" 0x80000840 0x90 0 0 385 11 "DlgMenu"
;3 Button 0x54032000 0x0 0 0 48 11 "Button1"
;4 Button 0x54032000 0x0 48 0 48 11 "Button2"
;5 Button 0x54032000 0x0 96 0 48 11 "Button3"
;6 Button 0x54032000 0x0 144 0 48 11 "Button4"
;7 Button 0x54032000 0x0 192 0 48 11 "Button5"
;8 Button 0x54032000 0x0 240 0 48 11 "Button6"
;9 Button 0x54032000 0x0 288 0 48 11 "Button7"
;10 Button 0x54032000 0x0 336 0 48 11 "Button8"
;1 Button 0x54030001 0x4 64 402 48 11 "OK"
;2 Button 0x54030000 0x4 118 402 48 11 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2030502 "*" "" "" ""
ret
;messages
sel message
,case WM_INITDIALOG
,__GdiHandle-- hb=CreateSolidBrush(0xff00)
,Transparent hDlg 255 0xff00
,int+ NotePadHwnd = win("Notepad" "Notepad")
,SetWindowLong hDlg GWL_HWNDPARENT NotePadHwnd
,SetTimer hDlg 1 100 0
,;SendMessage hDlg WM_COMMAND 5 0 ;;execute gButton code. Or use function instead.
,SendMessage hDlg WM_TIMER 1 0 ;;execute gTimer code. Or use function instead.
,case WM_TIMER
,sel wParam
,,case 1 goto gTimer
,case WM_DESTROY
,case WM_CTLCOLORDLG ret hb
,case WM_COMMAND goto messages2
,
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
;gButton
ret
;gTimer
Zorder hDlg HWND_TOP SWP_NOACTIVATE
int x_NotePad y_NotePad cx_NotePad cy_NotePad;
ifi(NotePadHwnd)
,GetWinXY NotePadHwnd x_NotePad y_NotePad cx_NotePad cy_NotePad
else
,CloseWindowsOf("DlgMenu" "#32770");err
,ret
int x_Dlg y_Dlg cx_Dlg cy_Dlg
GetWinXY hDlg x_Dlg y_Dlg cx_Dlg cy_Dlg
MoveWindow hDlg x_NotePad+25 y_NotePad+3 cx_NotePad-100 cy_Dlg 1;;need to leave enough room for max/min/close app dlg frame buttons and enough of frame to grab for moving/resizing
Posts: 12,092
Threads: 142
Joined: Dec 2002
It works. Improving would be endless.
Posts: 1,006
Threads: 330
Joined: Mar 2007
Yes, recreating all the things you already natively support in QM in Toolbars and menu's would indeed be endless. But this works for anyone who has QM dialog making skills to add anything they want into exe....Thanks for looking at it and giving it your blessing! :-)
S
Posts: 769
Threads: 263
Joined: Jul 2012
Sorry to kick this topic up, but I do not understand something.
The settimer line:
The "gTimer SendMessage" line
SendMessage hDlg WM_TIMER 1 0
If I disable the "gTimer SendMessage" line, the function seems to work exactly the same as with the "gTimer SendMessage" line enabled.
From:
https://msdn.microsoft.com/en-us/librar ... 85%29.aspx
UINT_PTR WINAPI SetTimer(
_In_opt_ HWND hWnd,
_In_ UINT_PTR nIDEvent,
_In_ UINT uElapse,
_In_opt_ TIMERPROC lpTimerFunc
);
nIDEvent [in]
Type: UINT_PTR
A nonzero timer identifier. If the hWnd parameter is NULL, and the nIDEvent does not match an existing timer then it is ignored and a new timer ID is generated. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored. If the call is not intended to replace an existing timer, nIDEvent should be 0 if the hWnd is NULL.
The timer identifier has already been set in:
So the below code always catches the timer id "1"
case WM_TIMER
sel wParam
case 1 goto gTimer
QUESTION:
Am I correct that I can safely remove the "gTimer SendMessage" line: SendMessage hDlg WM_TIMER 1 0 ?
Posts: 12,092
Threads: 142
Joined: Dec 2002
After SetTimer, the first WM_TIMER arrives after the timer period time, in this case 100 ms. But often we want it immediately. Then we can:
1. SendMessage, like here. It calls the dialog procedure.
2. Directly call the dialog procedure: TestExeDlgMenu hDlg WM_TIMER 1 0
3. goto gTimer. But then it must be the last statement under WM_INITDIALOG.
4. Put gTimer code in a function and call it on WM_TIMER and WM_INITDIALOG.
Posts: 769
Threads: 263
Joined: Jul 2012
Thank you for the explanation!
Posts: 769
Threads: 263
Joined: Jul 2012
What could be the cause when the window that has the button-dialog attached to it stays on top? (does not "wants" to be put at the back of the z order)
What I mean:
If I attach the buttons to notepad, sometimes notepad does not "wants" to be set to the back when I click a window that is behind it (partly overlapped by notepad). Notepad just stays on top and refuses to be set to the the back.
When close notepad (and the macro attached to it) and then restart the macro, notepad behaves noramally (with the dialogbuttons attached).
It may be a thing that can not be prevented because it is inherent to the timer code?
But if there is something there could be done about then it would be greatly appreciated.
(I use this code as a template for many executables, I can enhance about any application with a single executable containing this code!)
Posts: 12,092
Threads: 142
Joined: Dec 2002
Add flag SWP_NOOWNERZORDER when calling Zorder.
Zorder hDlg HWND_TOP SWP_NOACTIVATE|SWP_NOOWNERZORDER
See also:
Insert buttons into a window's caption area
Posts: 769
Threads: 263
Joined: Jul 2012
Posts: 769
Threads: 263
Joined: Jul 2012
Sorry to bother you with another question about this, but if have the following situation (extracted from code above):
Where the first "int+ ApplicationHwnd=..." does not work because of the regex addition.
The line directly below does work, but targets the wrong window (if there are multiple).
Function tcmd_extension
,,int+ ApplicationHwnd=win(F"^{ini_winname_main_app}" ini_winclass_main_app 0x200) ;; Does not work
,,int+ ApplicationHwnd=win(F"{ini_winname_main_app}" ini_winclass_main_app) ;; Works
,,;.
,,;.
,,;.
,,;
,,ifi(ApplicationHwnd) ;; Code below in 'gTimer'
Is there a way around this?
The window names are:
- "Total Commander" , for the first window
- "[#] Total Commander" for all the other windows (#=number beginning with '2' then '3' etc....)
It always needs to attach dialog-buttons to "Total Commander" not the one starting with "[#] "
Posts: 12,092
Threads: 142
Joined: Dec 2002
int+ ApplicationHwnd=win(F"^/Q{ini_winname_main_app}/E" ini_winclass_main_app "" 0x200)
or use flag 1 and wildcard characters
Posts: 769
Threads: 263
Joined: Jul 2012
Posts: 726
Threads: 99
Joined: Mar 2018
I added a menu bar definition, how to cancel the display button, only display the menu bar, and the position of the menu bar is always placed in the middle of the title bar.
Some code, can't understand , I hope someone can provide an example, thanks in advance
Function TestExeDlgMenu
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages
CloseWindowsOf("DlgMenu" "#32770");err
run "$system$\notepad.exe" "" "" "" 0x1800 win("Notepad" "Notepad")
str md=
;BEGIN MENU
;>&File
;,&Open :501 0x0 0x0 Co
;,&Save :502 0x0 0x0 Cs
;,>Submenu
;,,Item1 :551
;,,Item2 :552
;,,<
;,-
;,E&xit :2
;,<
;>&Edit
;,Cu&t :601
;,&Copy :602
;,&Paste :603
;,<
;>&Help
;,&About :901
;,<
;END MENU
;;menu bar example:
;if(!ShowDialog(dd &sub.DlgProc &controls 0 0 0 0 0 0 0 0 md)) ret
;;popup menu example:
;int i=ShowMenu(md); out i
if(!ShowDialog("TestExeDlgMenu" &TestExeDlgMenu 0)) ret
;BEGIN DIALOG
;0 "" 0x80000840 0x90 0 0 385 11 "DlgMenu"
;3 Button 0x54032000 0x0 0 0 48 11 "Button1"
;4 Button 0x54032000 0x0 48 0 48 11 "Button2"
;5 Button 0x54032000 0x0 96 0 48 11 "Button3"
;6 Button 0x54032000 0x0 144 0 48 11 "Button4"
;7 Button 0x54032000 0x0 192 0 48 11 "Button5"
;8 Button 0x54032000 0x0 240 0 48 11 "Button6"
;9 Button 0x54032000 0x0 288 0 48 11 "Button7"
;10 Button 0x54032000 0x0 336 0 48 11 "Button8"
;1 Button 0x54030001 0x4 64 402 48 11 "OK"
;2 Button 0x54030000 0x4 118 402 48 11 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2030502 "*" "" "" ""
ret
;messages
sel message
,case WM_INITDIALOG
,__GdiHandle-- hb=CreateSolidBrush(0xff00)
,Transparent hDlg 255 0xff00
,int+ NotePadHwnd = win("Notepad" "Notepad")
,SetWindowLong hDlg GWL_HWNDPARENT NotePadHwnd
,SetTimer hDlg 1 100 0
,;SendMessage hDlg WM_COMMAND 5 0 ;;execute gButton code. Or use function instead.
,SendMessage hDlg WM_TIMER 1 0 ;;execute gTimer code. Or use function instead.
,case WM_TIMER
,sel wParam
,,case 1 goto gTimer
,case WM_DESTROY
,case WM_CTLCOLORDLG ret hb
,case WM_COMMAND goto messages2
,
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
;gButton
ret
;gTimer
Zorder hDlg HWND_TOP SWP_NOACTIVATE
int x_NotePad y_NotePad cx_NotePad cy_NotePad;
ifi(NotePadHwnd)
,GetWinXY NotePadHwnd x_NotePad y_NotePad cx_NotePad cy_NotePad
else
,CloseWindowsOf("DlgMenu" "#32770");err
,ret
int x_Dlg y_Dlg cx_Dlg cy_Dlg
GetWinXY hDlg x_Dlg y_Dlg cx_Dlg cy_Dlg
MoveWindow hDlg x_NotePad+25 y_NotePad+3 cx_NotePad-100 cy_Dlg 1;;need to leave enough room for max/min/close app dlg frame buttons and enough of frame to grab for moving/resizing
Posts: 12,092
Threads: 142
Joined: Dec 2002
Macro Macro362
CloseWindowsOf("DlgMenu" "#32770");err
int w
run "$system$\notepad.exe" "" "" "" 0x1800 win("Notepad" "Notepad") w
str md=
;BEGIN MENU
;>&File
;,&Open :501 0x0 0x0 Co
;,&Save :502 0x0 0x0 Cs
;,>Submenu
;,,Item1 :551
;,,Item2 :552
;,,<
;,-
;,E&xit :2
;,<
;>&Edit
;,Cu&t :601
;,&Copy :602
;,&Paste :603
;,<
;>&Help
;,&About :901
;,<
;END MENU
str dd=
;BEGIN DIALOG
;0 "" 0x80000840 0x90 0 0 385 11 "DlgMenu"
;END DIALOG
;DIALOG EDITOR: "" 0x2030502 "*" "" "" ""
if(!ShowDialog(dd &sub.DlgProc 0 0 128 0 0 0 0 0 0 md)) ret
#sub DlgProc v
function# hDlg message wParam lParam
sel message
,case WM_INITDIALOG
,__GdiHandle-- hb=CreateSolidBrush(0xff00)
,Transparent hDlg 255 0xff00
,SetWindowLong hDlg GWL_HWNDPARENT w
,SetTimer hDlg 1 100 0
,;SendMessage hDlg WM_COMMAND 5 0 ;;execute gButton code. Or use function instead.
,SendMessage hDlg WM_TIMER 1 0 ;;execute gTimer code. Or use function instead.
,hid- hDlg
,case WM_TIMER
,sel wParam
,,case 1 goto gTimer
,case WM_DESTROY
,case WM_CTLCOLORDLG ret hb
,case WM_COMMAND goto messages2
,
ret
;messages2
sel wParam
,case 501
,out "Open"
,case IDCANCEL
,out "Exit"
act w; err
ret 1
;gTimer
Zorder hDlg HWND_TOP SWP_NOACTIVATE
int x_NotePad y_NotePad cx_NotePad cy_NotePad;
if !IsWindow(w)
,CloseWindowsOf("DlgMenu" "#32770");err
,ret
GetWinXY w x_NotePad y_NotePad cx_NotePad cy_NotePad
int x_Dlg y_Dlg cx_Dlg cy_Dlg
GetWinXY hDlg x_Dlg y_Dlg cx_Dlg cy_Dlg
MoveWindow hDlg x_NotePad+150 y_NotePad+3 cx_NotePad-300 cy_Dlg 1;;need to leave enough room for max/min/close app dlg frame buttons and enough of frame to grab for moving/resizing
The last line sets dialog position relative to the window.
Posts: 726
Threads: 99
Joined: Mar 2018
04-06-2019, 09:24 PM
(This post was last modified: 04-06-2019, 11:26 PM by win.)
Thanks for your help, the effect is great, but the hotkeys in the menu are not available.
When I click on the menu and then press the hotkey is in effect, in addition, I found a problem, use the hotkey ctrl+p to exit Notepad, the menu will delay for a few seconds to disappear
Is there a way to make the hotkeys Directly effective in the notpad?
I have an idea,
When I press ctrl, the menu will be activated. Then, when I press ctrl+p, the hotkey in the menu will take effect.
If these functions can be implemented, I think that almost all functions of QM, such as toolbars, menus, context menus, hotkeys, and AutoText, can be used after generating exe files. I hope developers can continue to improve it.
Macro Macro3
CloseWindowsOf("DlgMenu" "#32770");err
int w
run "$system$\notepad.exe" "" "" "" 0x1800 win("" "Notepad") w
str md=
;BEGIN MENU
;>&File
;,&Open :501 0x0 0x0 Co
;,&Save :502 0x0 0x0 Cs
;,>Submenu
;,,Item1 :551
;,,Item2 :552
;,,<
;,-
;,E&xit :555 0x0 0x0 Cp
;,<
;>&Edit
;,Cu&t :601
;,&Copy :602
;,&Paste :603
;,<
;>&Help
;,&About :901
;,<
;END MENU
str dd=
;BEGIN DIALOG
;0 "" 0x80000840 0x90 0 0 385 11 "DlgMenu"
;END DIALOG
;DIALOG EDITOR: "" 0x2030502 "*" "" "" ""
if(!ShowDialog(dd &sub.DlgProc 0 0 128 0 0 0 0 0 0 md)) ret
#sub DlgProc v
function# hDlg message wParam lParam
sel message
,case WM_INITDIALOG
,__GdiHandle-- hb=CreateSolidBrush(0xff00)
,Transparent hDlg 255 0xff00
,SetWindowLong hDlg GWL_HWNDPARENT w
,SetTimer hDlg 1 100 0
,;SendMessage hDlg WM_COMMAND 5 0 ;;execute gButton code. Or use function instead.
,SendMessage hDlg WM_TIMER 1 0 ;;execute gTimer code. Or use function instead.
,hid- hDlg
,case WM_TIMER
,sel wParam
,,case 1 goto gTimer
,case WM_DESTROY
,case WM_CTLCOLORDLG ret hb
,case WM_COMMAND goto messages2
,
ret
;messages2
sel wParam
,case 501
,out "Open"
,case IDCANCEL
,out "Exit"
,case 555 ;;E&xit
,int w1=win("" "Notepad")
,clo w1
act w; err
ret 1
;gTimer
Zorder hDlg HWND_TOP SWP_NOACTIVATE
int x_NotePad y_NotePad cx_NotePad cy_NotePad;
if !IsWindow(w)
,CloseWindowsOf("DlgMenu" "#32770");err
,ret
GetWinXY w x_NotePad y_NotePad cx_NotePad cy_NotePad
int x_Dlg y_Dlg cx_Dlg cy_Dlg
GetWinXY hDlg x_Dlg y_Dlg cx_Dlg cy_Dlg
MoveWindow hDlg x_NotePad+150 y_NotePad+3 cx_NotePad-300 cy_Dlg 1;;need to leave enough room for max/min/close app dlg frame buttons and enough of frame to grab for moving/resizing
|