AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Menu Icons v2 (stdlib)
Goto page Previous  1, 2, 3, 4, 5, 6
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Mon Feb 02, 2009 2:20 pm    Post subject: Reply with quote

animeaime wrote:
When AHK recreates the menu, it doesn't save ALL the info
Technically, none of the properties of the Win32 menu are retained. AutoHotkey keeps all of the properties it knows about in its internal UserMenu and UserMenuItem structures.
Quote:
Thus, if you could add the ability to retain the dwItem/MenuData when recreating the menu, that would be AWE-SOME.
As I meant to suggest in my previous post, if there were some built-in method to associate user-data with a menu or menu item, dwItem/MenuData would not be necessary. Item data would be stored in the UserMenuItem structure, along with item text, submenu, icon, etc. This might be easier to implement than some method of retaining dwItem/MenuData, or any other properties associated with the menu handle.
Quote:
so you don't need to worry about the ability to associate data with a menu, because I have that covered.
That is, apart from the pitfalls we have discussed?
Quote:
Right now, I have a "hack" of adding a menu separator, storing the old size, deleting the "temp" separator (and decreasing the old size by one), adding the item, comparing the old/new size, and then, from that, knowing if the menu item was added or only updated.
Is the separator merely because the menu may be empty or non-existent, and therefore not have a valid menu handle? Otherwise, why not simply compare the item count before and after Add?
Quote:
MIIM_ID (do you know what this is for?).
"Application-defined 16-bit value that identifies the menu item. Set fMask to MIIM_ID to use wID." I believe AutoHotkey uses the ID's internally.
Quote:
just need to find a way to remove a submenu without AHK destroying it on me Wink
If you mean remove a menu item without destroying its associated submenu, what about the workaround I already demonstrated? Specifically, modify the item to remove the sub-menu before removing the item. Actually, there was a comment in the AutoHotkey source indicating the Win32 API may delete the sub-menu as an undocumented side-effect, but this does not seem to be the case on my system.
Quote:
This way, AHK doesn't know about the menu (and thus, can't destroy it).
Are you sure? AutoHotkey uses DeleteMenu() to remove a menu item. It is documented to destroy any sub-menu associated with the menu item. (This is at the Win32 API level, not at the AutoHotkey level.) I'm fairly certain AutoHotkey does not explicitly/intentionally delete the sub-menu.
Back to top
View user's profile Send private message Visit poster's website
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Mon Feb 02, 2009 3:16 pm    Post subject: Reply with quote

Lexikos wrote:
As I meant to suggest in my previous post, if there were some built-in method to associate user-data with a menu or menu item

Oh, so there would be a way to retrieve/set this value (to a UInt, let's say) so that the user could then store what they might in the dwMenu/ItemData in there instead? If so, yeah, that sounds great.

Lexikos wrote:
That is, apart from the pitfalls we have discussed?

Well, actually, I think I "hacked" out the pitfalls. I'm testing the code now, but it looks fine. Deleting the entire menu doesn't work right yet, but I'm checking it out. Deleting items with submenus works fine with the "double hack" (first don't store submenus in the labels, then use RemoveMenu before Menu, delete - without either it won't work right, or I can't seem to get it to - looking into it though).

Granted there are quite a few "hacks" to get around AHK's syntax, but it works. The menus are never recreated (going to add a hack in for Menu, NoStandard/Standard); Also, icons, menu data, the "goto label", etc. are retained when menu items are inserted (at the end or middle of a menu), moved within the same menu (or to another menu), and all data is cleared on delete (both the menu icon as well as my menu/menu item data structure). So, besides the number of hacks that are going on in the background, the code will work as expected - no loss in functionality that I can see (well, unless you count recreating the menu to do anything "functionality").

Lexikos wrote:
Is the separator merely because the menu may be empty or non-existent, and therefore not have a valid menu handle?

Right, I need a way to see if the menu item was added or only updated. This is the only way I could think of. I can't just call the menu API because I need the menu handle, and if the menu doesn't exist, your code will then error (like it should). I can (just thought of this), however, keep track of the Menu, UseErrorLevel value internally. Then, the user would call a wrapper function to change this value. The code can then have UseErrorLevel on, run your MI_getMenuHandle function (returning 0 means the menu doesn't exist - or shouldn't... as long as I keep AHK from destroying menus), then set the UserErrorLevel to the previous value - that would work (and I'll use it, thanks).

Lexikos wrote:
"Application-defined 16-bit value that identifies the menu item. Set fMask to MIIM_ID to use wID." I believe AutoHotkey uses the ID's internally.

Oh, ok. I'll definetely add it back in then (and make sure whatever bug I saw before doesn't still exist). I thought of using it to store the menu object, but I saw that you used dwItemData so I thought you knew what you were doing, so I just followed suit.

Lexikos wrote:
If you mean remove a menu item without destroying its associated submenu, what about the workaround I already demonstrated?

It changes the menu handle (which I'll test, but as you said before - this means that AHK is recreating the menu).

Code:
Menu, Sub, Add, Item 1, _
Menu, Main1, Add, Sub-Menu, :Sub
Menu, Main1, Add, Plain old item, _
Menu, Main2, Add, Sub-Menu, :Sub
Menu, Main2, Add, Plain old item, _

hMenu := MI_GetMenuHandle("Main1")

MsgBox, % "SubMenu handle: " . MI_GetMenuHandle("Sub")
Menu, Main1, Show
; should fix problem
; however, changes the menu handle
Menu, Main1, Add, Sub-Menu, _
Menu, Main1, Delete, Sub-Menu

MsgBox, % "SubMenu handle: " . MI_GetMenuHandle("Sub")
Menu, Main1, Show
Menu, Main2, Show
Menu, Sub, Show
ExitApp
_:
return

MI_GetMenuHandle(menu_name)
{
    static   h_menuDummy
    ; v2.2: Check for !h_menuDummy instead of h_menuDummy="" in case init failed last time.
    If !h_menuDummy
    {
        Menu, menuDummy, Add
        Menu, menuDummy, DeleteAll

        Gui, 99:Menu, menuDummy
        ; v2.2: Use LastFound method instead of window title. [Thanks animeaime.]
        Gui, 99:+LastFound

        h_menuDummy := DllCall("GetMenu", "uint", WinExist())

        Gui, 99:Menu
        Gui, 99:Destroy

        ; v2.2: Return only after cleaning up. [Thanks animeaime.]
        if !h_menuDummy
            return 0
    }

    Menu, menuDummy, Add, :%menu_name%

    h_menu := DllCall( "GetSubMenu", "uint", h_menuDummy, "int", 0 )

    DllCall( "RemoveMenu", "uint", h_menuDummy, "uint", 0, "uint", 0x400)
    Menu, menuDummy, Delete, :%menu_name%

    return h_menu
}


Lexikos wrote:
Are you sure? AutoHotkey uses DeleteMenu() to remove a menu item. It is documented to destroy any sub-menu associated with the menu item. (This is at the Win32 API level, not at the AutoHotkey level.) I'm fairly certain AutoHotkey does not explicitly/intentionally delete the sub-menu.

Ohhh... that's why if I don't use RemoveMenu first, there's a problem - that explains it. Yeah, I "fixed" that be first removing the item, then using AHK menu, delete. This way, AHK still sees it as "gone" (so if I add the item later it doesn't try to update, but actually adds the value), and it can't delete the submenu. Good thing the code doesn't crash or produce an error when removing a menu item that doesn't exist anymore...

Like always, thank you SO MUCH for your help - without you I wouldn't have been able to make these libraries of mine work.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Mon Feb 02, 2009 7:33 pm    Post subject: Reply with quote

I have a some quick questios about your Menu test (trying to figure what's required and what's not).

Code:
if (A_OSVersion != "WIN_VISTA")
{   ; It is necessary to hook the tray icon for owner-drawing to work.
    ; (Owner-drawing is not used on Windows Vista.)
    OnMessage(0x404, "AHK_NOTIFYICON")
    OnMessage(0x111, "WM_COMMAND") ; To track "pause" status.
    MI_SetMenuStyle(hTM, 0x4000000) ; MNS_CHECKORBMP (optional)
}


1) Is calling WM_COMMAND only to track "pause" status, or is there another use (i.e. is it required - in the general case)?

2) In AHK_NotifyIcon, you call MI_ShowMenu. On vista which is the prefered call - Menu, tray, show or MI_ShowMenu("tray")?

3) You say the below call is optional, when (or if) would you call it (i.e. what are the benefits/disadvantages and uses for it)?

Code:
MI_SetMenuStyle(hTM, 0x4000000) ; MNS_CHECKORBMP (optional)


Thanks again.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Mon Feb 02, 2009 9:33 pm    Post subject: Reply with quote

animeaime wrote:
It changes the menu handle
Right, it happens when the sub-menu is removed from "Sub-Menu" via Menu, Add. I could swear this didn't happen in my previous tests (which did use MI_GetMenuHandle), but it is now. Must be the undocumented side-effect I mentioned.
Quote:
1) Is calling WM_COMMAND only to track "pause" status
Yes.
Quote:
2) In AHK_NotifyIcon, you call MI_ShowMenu. On vista which is the prefered call - Menu, tray, show or MI_ShowMenu("tray")?
AHK_NotifyIcon is not called on Vista. Generally, it does not matter either way.
Quote:
3) You say the below call is optional, when (or if) would you call it (i.e. what are the benefits/disadvantages and uses for it)?
Aesthetics.
Quote:
Source: MSDN: MENUINFO Structure ()
The same space is reserved for the check mark and the bitmap. If the check mark is drawn, the bitmap is not. All checkmarks and bitmaps are aligned. Used for menus where some items use checkmarks and some use bitmaps.
Back to top
View user's profile Send private message Visit poster's website
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Tue Feb 03, 2009 12:15 pm    Post subject: Reply with quote

Cases when a menu handle is destroyed include, but may not be limited to:
  • Menu,,[No]MainWindow destroys the menu handle if the menu includes the standard menu items. Next time the menu handle is created, only the relevant standard menu items are added.

  • Menu,,DeleteAll destroys the menu handle.

  • If a pop-up menu is used with Gui, Menu, it has to be destroyed and recreated to convert it to the correct type of menu.
    Quote:
    Source: AutoHotkey Documentation: Gui, Menu
    Once a menu has been used as a menu bar, it should not be used as a popup menu or a submenu. This is because menu bars internally require a different format (however, this restriction applies only to the menu bar itself, not its submenus).

  • If a menu item which has a sub-menu is given a different sub-menu or converted into a normal menu item, the old sub-menu is destroyed by SetMenuItemInfo. Although this is undocumented for SetMenuItemInfo, it was documented for its predecessor:
    Quote:
    Source: MSDN: ModifyMenu Function ()
    If ModifyMenu replaces a menu item that opens a drop-down menu or submenu, the function destroys the old drop-down menu or submenu and frees the memory used by it.

  • If a menu handle is destroyed, its sub-menus' handles are also destroyed. There doesn't seem to be a way around this:
    Quote:
    Source: MSDN: DestroyMenu Function ()
    DestroyMenu is recursive, that is, it will destroy the menu and all its submenus.

  • Any menus containing the destroyed menu are also destroyed. This is done so that the sub-menu itself is automatically recreated when the parent menu is next shown.
Back to top
View user's profile Send private message Visit poster's website
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Tue Feb 03, 2009 12:42 pm    Post subject: Reply with quote

Hmmm... I'll have to check into those, thanks. Also, why not use RemoveMenu instead of DeleteMenu when deleting an item? This way the menu won't be recreated next time - which should be more efficient anyway, right?

Also, now I see what you mean, a built-in value would be MUCH better than the dwMenu/ItemData value. This way, when the menu / menu item is destroyed and recreated, the behavior, is as expected, that nothing happens. If both the menu icons could be restored and this built-in value, then that would be great. If that built-in value stored a Class, then it would remain valid (because it's destroy function was never called), also, any other values which may be stored in that space are preserved. This way, only when the user calls something like Menu: delete, deleteAll, etc. where the menu SHOULD be destroyed, will the menu wrapper actually destroy anything (which will help fight potential memory leaks). Right now it's safe for delete and deleteAll, although I'm going to keep testing. I didn't test [No]MainWindow or Guis - never even crossed my mind that those would destroy the menu - so thank you a bunch for that information.

Edit:
I just thought of something. Since AHK has its own data structure that holds the menu data, is it destroyed automatically when the the menu / menu item handle is invalid? For example, when you call Menu, MenuName, delete, won't that remove each item that has MenuName as its submenu? That would mean that each of those item's data structures need to be removed, right? Is there a way to have a function run on the menu item's data at that time (likewise a function, or the same function, when deleting a menu). For example, both the Menu and MenuItem objects can be destroyed automatically by a call to Class_DestroyThis(Object) - where Object is the value stored in the dwMenu/ItemData (which hopefully can be instead stored as part of the UserMenu[Item] data structure). This function, then dynamically calls the destroy function for the Class object (either Menu_destroy for a Menu object or MenuItem_destroy for a MenuItem object). If you could add the ability to call a user-specified function when AHK destroys the menu/menu item's AHK data - that would be GREAT (although not sure if plausible). This way, only when AHK destroys the menu/menu item its Class object destroyed. Like I said, not sure if it's possible, but just a thought. Of course, since the function is user-specified it won't limit the use of the menu/menu item's data to solely a Class object.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Last edited by animeaime on Tue Feb 03, 2009 1:42 pm; edited 2 times in total
Back to top
View user's profile Send private message Send e-mail
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Tue Feb 03, 2009 1:38 pm    Post subject: Reply with quote

animeaime wrote:
Also, why not use RemoveMenu instead of DeleteMenu when deleting an item?
I already suggested that in the bug report thread, and implemented it in my working copy of AutoHotkey_L.
Quote:
This way the menu won't be recreated next time - which should be more efficient anyway, right?
As I explained in the bug report, the sub-menu is not recreated as AutoHotkey does not expect the sub-menu handle to be destroyed. However, your argument is valid when considering the alternative, which is to clear the sub-menu handle and allow it to be recreated. Smile


Edit in response to your last-minute edit: Laughing
Quote:
Since AHK has its own data structure that holds the menu data, is it destroyed automatically when the the menu / menu item handle is invalid?
No, with the exception below.
Quote:
For example, when you call Menu, MenuName, delete, won't that remove each item that has MenuName as its submenu?
It will remove the individual menu items which use the sub-menu, as documented. I don't see any problem with this.
Quote:
That would mean that each of those item's data structures need to be removed, right?
It would be part of the UserMenuItem structure, and would be deleted automatically when the item is deleted.
Quote:
Is there a way to have a function run on the menu item's data at that time
I have thought of this. I can see its uses, and will consider it for AutoHotkey_L. However, a UserMenuItem structure is only deleted when the item is removed explicitly by some Menu command, so it wouldn't be entirely necessary.
Back to top
View user's profile Send private message Visit poster's website
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Tue Feb 03, 2009 4:27 pm    Post subject: Reply with quote

I hope I'm not a bother with all these questions - I'm going to you because you seem able to answer them. If I ever become a bother, please tell, that's not my intent.

Right now I'm trying to add functionality to "save" the menu so when NoStandard and other operations need to be done that recreate the menu, the previous values are restored. I know that the menu items have their wid (and menu item handle) which can be used to see that they are part of the "standard menu", but is there any characteristics on the menu separators? Or, does the code just "know" that they are there. I'm testing different configurations to reverse enginer the algorith used, but I thought since you were familiar with the AHK source code, you might have an idea.

Edit:
This might clear up my question: how does AHK know that what items are part of the standard menu? I know I can use the handle for the menu items; do the separators have any value associated with them to say that they are part of the standard menu? Or, does AHK just know that menu items X to Y in the structure are for the standard menu, and when NoStandard is called, those items are removed (and not used in the menu rebuild)?

Thanks for any help you can provide.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Tue Feb 03, 2009 9:22 pm    Post subject: Reply with quote

animeaime wrote:
how does AHK know that what items are part of the standard menu?
It doesn't need to. Item ID's tell which item was activated. As already mentioned, AutoHotkey simply destroys and recreates the whole menu if it needs to modify the standard items. They do not have corresponding UserMenuItem structures, like user-created items.

Separator items have the MFT_SEPARATOR flag for fType.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page Previous  1, 2, 3, 4, 5, 6
Page 6 of 6

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group