AutoHotkey Community

It is currently May 24th, 2012, 5:54 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: February 11th, 2007, 5:23 am 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
Is there a command (that i've missed)... or a known DLL call ... way... to add menu items to window's menu bars... (**NOT** my own GUI...)




if not... it sure seems very possible...



here is the dll list of a program that does just that...

USER32.dll
Ordinal Function Name

01be MessageBoxA
0262 SetWindowsHookExA
0258 SetWindowLongA
0015 CallNextHookEx
0286 UnhookWindowsHookEx
0122 GetMenuItemCount
01de PostMessageA
0016 CallWindowProcA
0128 GetMenuStringA
011c GetMenu
0175 InsertMenuItemA
0058 CreatePopupMenu
0007 AppendMenuA
0162 GetWindowThreadProcessId
00ab DrawMenuBar
00d5 FindWindowA


and...


see eg..

http://custom.programming-in.net/articl ... rtMenuItem

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 11th, 2007, 12:07 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
Somebody already asked it, and I answered that even if you can add items to a menu, the target program won't understand it, as it will have nothing to support this new entry. So it seems useless to me.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
PostPosted: February 11th, 2007, 11:27 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
PhiLho wrote:
Somebody already asked it, and I answered that even if you can add items to a menu, the target program won't understand it, as it will have nothing to support this new entry. So it seems useless to me.



Imagine this....

Your favorite program suddenly has a new menu... with all the commands you always wanted... no hotkeys to remember... instead... it's BUILT IN!!!


nice ?



it works AMAZINGLY WELL.



the program that clued me into this amazing possibility is XCPCMenu



have tried to understand how it is doing what it is doing...


and,

seems mostly certain that can insert WM_COMMAND values into the menu items to have the menu perform whatever functions in that program we can reach with that command... and that could be a lot!!

also...


am less certain about this.. but can't we trap for certain WM_COMMANDs ?... or isn't there a way to watch if the menu is activated ??



also...


may have over-read what is possible... but seems we can take over the processing of the entire menu...




take a look at this sample code for the dll...



Code:


' Declarations and such needed for the example:
' (Copy them to the (declarations) section of a module.)
' There's quite a few declarations for this example, but it's worth it!
Public Declare Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Long, ByVal bRevert _
   As Long) As Long
Public Declare Function GetMenuItemCount Lib "user32.dll" (ByVal hMenu As Long) As Long
Public 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 Long
   dwTypeData As String
   cch As Long
End Type
Public Const MIIM_STATE = &H1
Public Const MIIM_ID = &H2
Public Const MIIM_TYPE = &H10
Public Const MFT_SEPARATOR = &H800
Public Const MFT_STRING = &H0
Public Const MFS_ENABLED = &H0
Public Const MFS_CHECKED = &H8
Public Declare Function InsertMenuItem Lib "user32.dll" Alias "InsertMenuItemA" (ByVal _
   hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _
   As MENUITEMINFO) As Long
Public Declare Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal _
   hMenu As Long, ByVal uItem As Long, ByVal fByPosition As Long, lpmii _
   As MENUITEMINFO) As Long

Public Declare Function SetWindowPos Lib "user32.dll" (ByVal hWnd As Long, ByVal _
   hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal _
   cy As Long, ByVal wFlags As Long) As Long
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2
Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd _
   As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Const GWL_WNDPROC = -4
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal _
   lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam _
   As Long, ByVal lParam As Long) As Long
Public Const WM_SYSCOMMAND = &H112
Public Const WM_INITMENU = &H116

' Add an option to make window Form1 "Always On Top" to the bottom of its system
' menu.  A check mark appears next to this option when active.  The menu item acts as a toggle.
' Note how subclassing the window is necessary to process the two messages needed
' to give the added system menu item its full functionality.

' *** Place the following code in a module. ***

Public pOldProc As Long  ' pointer to Form1's previous window procedure
Public ontop As Boolean  ' identifies if Form1 is always on top or not

' The following function acts as Form1's window procedure to process messages.
Public Function WindowProc (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam _
      As Long, ByVal lParam As Long) As Long
   Dim hSysMenu As Long     ' handle to Form1's system menu
   Dim mii As MENUITEMINFO  ' menu item information for Always On Top
   Dim retval As Long       ' return value
   
   Select Case uMsg
   Case WM_INITMENU
      ' Before displaying the system menu, make sure that the Always On Top
      ' option is properly checked.
      hSysMenu = GetSystemMenu(hwnd, 0)
      With mii
         ' Size of the structure.
         .cbSize = Len(mii)
         ' Only use what needs to be changed.
         .fMask = MIIM_STATE
         ' If Form1 is now always on top, check the item.
         .fState = MFS_ENABLED Or IIf(ontop, MFS_CHECKED, 0)
      End With
      retval = SetMenuItemInfo(hSysMenu, 1, 0, mii)
      WindowProc = 0
   Case WM_SYSCOMMAND
      ' If Always On Top (ID = 1) was selected, change the on top/not on top
      ' setting of Form1 to match.
      If wParam = 1 Then
         ' Reverse the setting and make it the current one.
         ontop = Not ontop
         retval = SetWindowPos(hwnd, IIf(ontop, HWND_TOPMOST, HWND_NOTOPMOST), _
            0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
         WindowProc = 0
      Else
         ' Some other item was selected.  Let the previous window procedure
         ' process it.
         WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam)
      End If
   Case Else
      ' If this is some other message, let the previous procedure handle it.
      WindowProc = CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam)
   End Select
End Function

' *** Place the following code inside Form1. ***

' When Form1 loads, add Always On Top to the system menu and set up the
' new window procedure.
Private Sub Form_Load()
   Dim hSysMenu As Long     ' handle to the system menu
   Dim count As Long        ' the number of items initially on the menu
   Dim mii As MENUITEMINFO  ' describes a menu item to add
   Dim retval As Long       ' return value
   
   ' Get a handle to the system menu.
   hSysMenu = GetSystemMenu(Form1.hWnd, 0)
   ' See how many items are currently in it.
   count = GetMenuItemCount(hSysMenu)
   
   ' Add a separator bar and then Always On Top to the system menu.
   With mii
      ' The size of the structure.
      .cbSize = Len(mii)
      ' What parts of the structure to use.
      .fMask = MIIM_ID Or MIIM_TYPE
      ' This is a separator.
      .fType = MFT_SEPARATOR
      ' It has an ID of 0.
      .wID = 0
   End With
   ' Add the separator to the end of the system menu.
   retval = InsertMenuItem(hSysMenu, count, 1, mii)
   
   ' Likewise, add the Always On Top command.
   With mii
      .fMask = MIIM_STATE Or MIIM_ID Or MIIM_TYPE
      ' This is a regular text item.
      .fType = MFT_STRING
      ' The option is enabled.
      .fState = MFS_ENABLED
      ' It has an ID of 1 (this identifies it in the window procedure).
      .wID = 1
      ' The text to place in the menu item.
      .dwTypeData = "&Always On Top"
      .cch = Len(.dwTypeData)
   End With
   ' Add this to the bottom of the system menu.
   retval = InsertMenuItem(hSysMenu, count + 1, 1, mii)
   
   ' Set the custom window procedure to process Form1's messages.
   ontop = False
   pOldProc = SetWindowLong(Form1.hWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

' Before unloading, restore the default system menu and remove the
' custom window procedure.
Private Sub Form_Unload(Cancel As Integer)
   Dim retval As Long  ' return value
   
   ' Replace the previous window procedure to prevent crashing.
   retval = SetWindowLong(Form1.hWnd, GWL_WNDPROC, pOldProc)
   ' Remove the modifications made to the system menu.
   retval = GetSystemMenu(Form1.hWnd, 1)
End Sub








looks to me (you tell me if correct or not...)


that SetWindowLong allows us to use GWL_WNDPROC to take over the menu procedure....


see eg,

http://www.answers.com/topic/setwindowlong



finally,

since another program is DOING THIS... (inserting a working menu it controls inside another program)... is CAN BE DONE....

maybe it can be done fairly easily with DLL calls (and later added as a ahk feature)...


help sought... :)



ps:

also...

known what SetWindowsHookExA can do with menus ?

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 12th, 2007, 4:19 am 
Offline
User avatar

Joined: December 20th, 2004, 12:19 pm
Posts: 794
Location: LooseChange911.com Ask Questions, Demand Answers █ The WTC bldgs █ shouldn't have fallen █ that fast
I'm




sorry




I've




ignored




it




long




enough




...Joy2DWorld could you PLEASE stop pressing enter so much???

_________________
AutoHotkey-Hotstring.ahk - Helping the world spell "AutoHotkey" correctly! (btw, it's a lowercase k!)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 12th, 2007, 8:03 am 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
@JSLover,


sorry...


i use a speach-to-text program that I wrote myself.......


and,



when I pause....


it enters returns.............



That was the part of the code I wrote first..........


in machine code...........


and now....


I can't for the life of me debug it.............


believe me i've tried!!!




but if it bothers you so much....


just write a javascript routine to 'compress' returns in posts....

and i'll be happy to press the 'compress double line' button, or whatever.



sorry....

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 12th, 2007, 9:13 am 
I will just add that it can be done. I've seen an example script by AutoIt members using Notepad. AutoHotkey should be able to do it too.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: February 12th, 2007, 9:19 am 
Offline
User avatar

Joined: December 20th, 2004, 12:19 pm
Posts: 794
Location: LooseChange911.com Ask Questions, Demand Answers █ The WTC bldgs █ shouldn't have fallen █ that fast
Joy2DWorld wrote:
i use a speach-to-text program...

...oh, ok at least there's a reason...is it a disability?...or you just want to use speech-to-text? I could write an AutoHotkey Script to pre-process your messages...you could speech-to-text into it, then press a button & it would remove the extra lines...then you paste that in the forum post box...or actually just a hotkey...press the hotkey before you click post...
Joy2DWorld wrote:
...that I wrote myself

...is there any freeware one out there that don't push enter on pause?...do you have to keep using yours?

_________________
AutoHotkey-Hotstring.ahk - Helping the world spell "AutoHotkey" correctly! (btw, it's a lowercase k!)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 12th, 2007, 12:25 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
So the solution is to hook the message loop of the target program? Doesn't look like a simple solution, and I don't know if it can be done in pure AHK.

I can be wrong (I only glanced at the VB code), but your snippet seems to only add a menu item to its own system menu (the menu behind the icon in the title bar). No hook here.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
PostPosted: February 16th, 2007, 7:43 am 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
There are 3 levels of functionality. At least the first should be EASY, maybe they all are.


1) Simply insert/modify a MENU in another window. Seems like straightforward DLL calls. Should allow inserting WM+COMMANDs directly to the target window.

CAN WE WORK THIS OUT ?


2) same as above PLUS, use AHK to watch for event (ie. clicking on any menu item created). Too complex to do ?? (watching for control.. ?)


3) same as #1, BUT adding hook to take control over the message box. Adding hook seems to be straightforward DLL call. Seems like simple watch message/send message pass thru.. is all it takes after that..

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 20th, 2007, 8:25 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
was looking at http://msdn2.microsoft.com/en-us/library/ms646977.aspx

and if not mistaken,

indeed we can

1) add/delete/modify another programs menu,

2) trap the invocation of the menu, and INVOKE IT via the AHK script--> so the RETURN VALUE IS SENT TO our AHK script!!!,

and,

3) after we process/and if we choose, can send command to original program as if menu was selected there......



unless have missed something, (which is possible),


kind of cool!

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 20th, 2007, 11:22 pm 
Online
User avatar

Joined: August 30th, 2005, 8:43 pm
Posts: 8640
Location: Salem, MA
cool link

Code:
IDM_TEST = 1337
STR_TEST = Testing

hNotepad := WinExist("Untitled - Notepad")

;http://msdn2.microsoft.com/en-us/library/ms647640.aspx
hMenu := Dllcall("GetMenu", "int", hNotepad)

;http://msdn2.microsoft.com/en-us/library/ms647616.aspx
Result := DllCall("AppendMenu"
  , "int", hMenu
  , "int", 0                 ;MF_STRING := 0x0
  , "int", IDM_TEST
  , "str", STR_TEST)

Exitapp


I have not looked at how to remove it or how to tell when it's been triggered...

EDIT:
Code:
IDM_TEST = 1337
STR_TEST = Testing
run, Notepad.exe

WinWait, Untitled - Notepad
hNotepad := WinExist("Untitled - Notepad")

;http://msdn2.microsoft.com/en-us/library/ms647640.aspx
hMenu := Dllcall("GetMenu", "int", hNotepad)

;http://msdn2.microsoft.com/en-us/library/ms647616.aspx
Result := DllCall("AppendMenu"
  , "int", hMenu
  , "int", 0                 ;MF_STRING := 0x0
  , "int", IDM_TEST
  , "str", STR_TEST)

WindowProcNew := RegisterCallback("WindowProc", ""  ; "" to avoid fast-mode for subclassing.
    , 4, IDM_TEST)  ; Must specify exact ParamCount when EventInfo parameter is present.
WindowProcOld := DllCall("SetWindowLong", UInt, hNotepad, Int, -4  ; -4 is GWL_WNDPROC
    , Int, WindowProcNew, UInt)  ; Return value must be set to UInt vs. Int.



return

Esc::Exitapp


WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global IDM_TEST, WindowProcOld
    if (uMsg = 0x111)  && lParam = IDM_TEST)  ; WM_COMMAND := 0x111
    {
      Msgbox, Bingo!
    }
    ; Otherwise (since above didn't return), pass all unhandled events to the original WindowProc.
    return DllCall("CallWindowProcA", UInt, WindowProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
}


Too bad in XP you cannot change the GWL_WNDPROC of another process via SetWindoLong or SetWindowLongPtr :(

_________________
Image
(Common Answers) - New Tutorials Forum - Humongous FAQ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 24th, 2007, 10:00 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
or,

if AHK could compile into a dll,

SetWindowsHookEx seems simple enough...


edit: SWHE likely will take took CB's to process, but seems like creates huge stability risk if our process crashes... (or maybe am missing something).

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 21st, 2008, 11:47 pm 
Offline

Joined: November 8th, 2004, 12:46 am
Posts: 1271
I'm trying to get this to work on 2k. Winspector returns the WM_COMMAND when I click the added menu item, but it seems the script isn't receiving anything, the msgbox in WindowProc() never shows. I've tried it with Metapad and got the same.

Code:
#SingleInstance Force
#Persistent
SetBatchLines, -1
IDM_TEST := 1337, STR_TEST := "Testing"
Run, Notepad,,, pid
WinWait, Untitled - Notepad
hWnd := WinExist("ahk_pid" . pid), hMenu := DllCall("GetMenu", Int, hWnd)
Result := DllCall("AppendMenu", Int,hMenu, Int,0x0, Int,IDM_TEST, Str,STR_TEST)

; menu item not showing immediately
; WinSet, Redraw
WinHide
WinShow

WindowProcNew := RegisterCallback("WindowProc", "" ; "" to avoid fast-mode for subclassing.
   , 4, IDM_TEST)  ; Must specify exact ParamCount when EventInfo parameter is present.
WindowProcOld := DllCall("SetWindowLong", UInt, hWnd, Int, -4  ; -4 is GWL_WNDPROC
   , Int, WindowProcNew, UInt)  ; Return value must be set to UInt vs. Int.
Return

Esc::
WinClose, ahk_id %hWnd%
Exitapp
Return

WindowProc(hwnd, uMsg, wParam, lParam)
{
   Critical
   Global IDM_TEST, WindowProcOld
   Msgbox % "lParam: " . lParam

   /*
   ; with this commented out notepad menu still responds to selections
   ; surely this would not be the case if the subclassing worked?
   if (uMsg = 0x111 && lParam = IDM_TEST)  ; WM_COMMAND := 0x111
   {
      Msgbox, Bingo!
   }
   ; Otherwise (since above didn't return), pass all unhandled events to the original WindowProc.
   return DllCall("CallWindowProcA", UInt, WindowProcOld, UInt, hwnd, UInt, uMsg, UInt, wParam, UInt, lParam)
   */
}

_________________
"Anything worth doing is worth doing slowly." - Mae West
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject: check this
PostPosted: February 12th, 2011, 4:31 pm 
Offline

Joined: August 12th, 2010, 7:05 am
Posts: 13
http://www.autohotkey.com/forum/topic56 ... appendmenu


Report this post
Top
 Profile  
Reply with quote  
 Post subject: maybe helpful
PostPosted: February 12th, 2011, 4:48 pm 
Offline

Joined: August 12th, 2010, 7:05 am
Posts: 13
hSysMenu := DllCall("GetSystemMenu", "Int", GUIhWnd, "Int", False) ;Systeemmenu oproepen
DllCall("AppendMenu", "Int", hSysMenu, "Int", MF_SEPARATOR, "Int", 0, "Int", "") ;Item aan systeemmenu toevoegen
DllCall("AppendMenu", "Int", hSysMenu, "Int", MF_STRING, "Int", SC_MyMenuItem1, "Str", sMyMenuCaption1) ;Item aan systeemmenu toevoegen
DllCall("DrawMenuBar", "Int", GUIhWnd) ;Toegevoegde items aan systeemmenu weergeven
OnMessage(0x112, "ManageSysCommand") ; WM_SYSCOMMAND

ManageSysCommand(wParam, lParam)
{
global
If (wParam = SC_MyMenuItem1)
ShowAbout()
}
Return

----
from:http://www.autohotkey.com/forum/viewtopic.php?t=23425&highlight=appendmenu


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: engunneer, Google Feedfetcher, KenC, Klark92, kwfine, Rathgar2 and 73 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group