Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.
Keywords: MegaPop UDF PopupMenu Popup Menu PopMenu DllCall CreatePopupMenu AppendMenuA RemoveMenu SetMenuDefaultItem CheckMenuItem EnableMenuItem ModifyMenuA InsertMenuA CreateSolidBrush LoadImageA LoadLibraryA FreeLibrary SetForegroundWindow TrackPopupMenu DestroyMenu SetMenuInfo SysTray System Tray IntControl 1007
; MegaPop UDF v2.0 - "The PopupMenu with lots of options!" This script also contains 4 examples of use. By ....IFICantBYTE 2010 ; Only tested on 32bit Windows XP and Vista, but I think it should work fine on Windows 7 and Server xxxx GoSub DEFINEUDF ; Actual UDF is below the 4 example uses :4EXAMPLES Message("MegaPop UDF Demo","The following are 4 examples using various features of the MegaPop UDF - from the most simple to more complex") ;--- Example 1 ;about the most simple example you could do: ;Store a list of items (TAB delimited list) inside a one dimension Array then call the UDF. ;Only trick is to give the simple array one extra element than you would think and put the list in element 1 [1] not [0] ;... you will understand why when you look at more complex menus later. PMArr = ArrDimension(2) PMArr[1] = StrCat("Option 1":@TAB:"Option 2":@TAB:"Option 3") Message("You clicked:",MegaPop(PMArr)) ;--- Example 2 CommandList = "SUBMENU 1 3 2 'Second List inserted here as a SUBMENU'|DEFAULT 1 4|DISABLED 1 5|GRAYED 1 6|CHECKED 1 7" L1 = StrCat("1st Item in Tab list",@TAB,"2nd Item in Tab list",@TAB,"3rd Item in Tab list",@TAB,"4th Item has DEFAULT style",@TAB,"5th Item has DISABLED style (looks the same as Grayed on Vista)",@TAB,"6th Item has GRAYED style (therefore disabled too)",@TAB,"7th Item has CHECKED style") ; Standard type of WinBatch list L2 = StrCat("Second List - Item One",@TAB,"Second list - Item Two",@TAB,"Second List - Item Three") ; Standard type of WinBatch list PMArr=ArrDimension(3) PMArr[0]=CommandList PMArr[1]=L1 PMArr[2]=L2 Message("You clicked:",MegaPop(PMArr)) ;--- Example 3 CList1 = "X 10|Y 10|DELIM 1 ','|DELIM 2 'PIPE'|DELIM 3 '/'|SUBMENU 1 1 5 'Unused Drive Letters With MAXHEIGHT restriction of 100 pixels'|SUBMENU 1 1 6 '1000+ System Directory DLLs in groups of 5 x 6 high'|SEPARATOR 6 6 repeat|BARBREAK 6 31 repeat" CList2 = "|SUBMENU 1 -1 2 'Submenus within Submenus this way...'|SUBMENU 2 2 3 'More...'|SUBMENU 3 1 4 'TAB List in another Submenu...'|SUBMENU 4 1 5 'Can reuse Submenus like this drive letter one (also used in first menu)'" CList3 = "|MAXHEIGHT 5 100" CommandList= StrCat(CList1,CList2,CList3) L1 = "CSV One,CSV Two,CSV Three,CSV Four,CSV Five"; An example Comma delimited list of items (like a CSV file) L2 = "Pipe One|Pipe Two|Pipe Three|Pipe Four" ; An example Pipe "|" delimited list - see how you must use the word 'PIPE' in the DELIM command for this one - only because the Command list is a Pipe list in itself L3 = "Slash 1/Slash 2/Slash 3/Slash 4" ; An example of a list using an unusual forward slash as the delimiter L4 = StrCat("First Item in Tab list",@TAB,"Second Item in Tab list",@TAB,"Third Item in Tab list",@TAB,"Fourth Item in Tab list") ; Standard type of WinBatch list L5 = DiskScan(0); Returns list of unused drives. L6 = FileItemize(StrCat(DirWindows(1),"\*.dll")) ; TAB list of DLLs in System directory - probably too many to see on screen, but good test for big list PMArr=ArrDimension(7) PMArr[0]=CommandList PMArr[1]=L1 PMArr[2]=L2 PMArr[3]=L3 PMArr[4]=L4 PMArr[5]=L5 PMArr[6]=L6 Message("You clicked:",MegaPop(PMArr)) ;--- Example 4 DScript = DirScript() SnapFile = StrCat(DScript,"\screenshot.bmp") DirChange(DScript) ;Taken directly from the Winbatch help file for "Snapshot" command minus the comments - used here just to get a BMP that we know exists and can show the resize function Snapshot(0) size=BinaryClipGet(0,8) bb=BinaryAlloc(size) BinaryClipGet(bb,8) bmpdatasize=14 bb2=BinaryAlloc(size + bmpdatasize) BinaryPokeStr(bb2, 0, "BM") BinaryPoke4(bb2,2,size + bmpdatasize) BinaryPoke4(bb2,6,0) headersize=BinaryPeek4(bb,0) dataoffset = headersize + bmpdatasize BinaryPoke4(bb2,10,dataoffset) BinaryCopy(bb2,bmpdatasize,bb,0,size) BinaryWrite(bb2,SnapFile);Write the screen snapshot to a BMP file in current script directory BinaryFree(bb) BinaryFree(bb2) ; OK - now we have a BMP file this script can find (you can use any BMP), so let's make a PopupMenu with it scaled inside! L1 = StrCat("Run it all again after this please!") L2 = StrCat("Page I",@TAB,"Page II",@TAB,"Page III",@TAB,"Page IV",@TAB,"Page V") DirChange(DirWindows(0)) L3 = FileItemize("*.LOG") CList1 = "BITMAP 1 1 '%snapfile%' 300 200|SUBMENUBMP 1 1 2 'ieframe.dll>551' 50 50|BITMAP 2 1 'ieframe.dll>546'|SUBMENUBMP 1 1 3 'ieframe.dll>SEARCH_120.BMP'|SEPARATOR 3 1 repeat" CList2 = "|BACKGROUND 1 250 250 80 andbelow|MENUBREAK 2 1 repeat|DEFAULT 1 1|DISABLED 2 100000001|SUBMENUBMP 1 1 4 'ieframe.dll>800'" CList3 = "|SUBMENUBMP 1 1 5 'wmploc.dll>5522' 300 20|SUBMENUBMP 1 1 6 'wmploc.dll>5534' 300 20|SUBMENUBMP 1 1 7 'wmploc.dll>5523' 300 20" CList4 = "|BACKGROUND 5 255 100 100|BACKGROUND 6 100 255 100|BACKGROUND 7 100 100 255" CommandList = StrCat(CList1,CList2,CList3,CList4) PMArr=ArrDimension(8) PMArr[0]=CommandList PMArr[1]=L1 PMArr[2]=L2 PMArr[3]=L3 PMArr[4]=L2 ;just make the following lists copies of L2 contents for this example PMArr[5]=L2 PMArr[6]=L2 PMArr[7]=L2 WhatClicked = MegaPop(PMArr) M=ItemExtract(1,WhatClicked,@TAB) I=ItemExtract(2,WhatClicked,@TAB) T=ItemExtract(3,WhatClicked,@TAB) Message("You clicked:",StrCat(WhatClicked,@CRLF,@CRLF,"Which breaks down to:",@CRLF,"List (Menu): ",M,@CRLF,"Item index: ",I,@CRLF,"Item text or name: ",T)) If T == "Run it all again after this please!" Then Goto 4EXAMPLES Display(3,"MegaPop","That's it... Bye!") Exit ; End of examples... just use the UDF below in your own script (or bits of it if you want to strip it down) Regards, ....IFICantBYTE :DEFINEUDF ;========================================================================================================================================================================= ; MegaPop UDF v2.0 - the PopupMmenu with lots of options! by ....IFICantBYTE 2010 *only tested on 32 bit XP and Vista - but should work on Win 7 and server I think ; - Creates a Popup (shortcut) menu with optional sub menus created from delimited lists stored in an array. ; The menu and items can have various styles and optional separators and bitmaps inserted. ; The popup menu will be tracked and any clicked item will return the (sub)menu it belonged to, its list index and its text in a TAB delimited string. ;------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ; ; DataIn: an ARRAY. - This is a simple one dimension array WITH AT LEAST 2 ELEMENTS. ; The first element DataIn[0] is reserved for "commands" that you can use to modify and control the appearence of menus. (see list of commands below) ; Elements [1] and beyond are used to store lists of items that you want to become the PopupMenu item choices. ; Each list becomes an individual menu. The list in element [1] is the main menu (menu 1) while the list in each element afterwards becomes a Submenu. ; ; If you only wanted a very simple menu with no submenus, then you could simply fill DataIn[1] with a TAB delimited list of items and pass it to the UDF... ; That's it, but if you want more complex Popupmenus then read on... ; ; Menu 1, being the main menu, will always "Popup" and be visible when the UDF is called, however, each Submenu needs to be told where it is to appear by ; using a special "SUBMENU" command before it will be seen. ; This SUBMENU command (and any others) are also stored in a list, but this command list is always stored in element [0] of our Array and it must also ; be a Pipe | delimited list of commands. ; There are many different commands that can be used to control and modify the appearence of the Menu and Submenus. You wont need to use them all, only the ; ones that make the Popupmenu look and act the way you require. ; Note: Don't have more than 9999 lists or more than 9999 items per list or this routine will not work properly! (What would you want that many for anyway????!) ; ; ; Command List stored inside DataIn[0] : ; - This is a PIPE (|) delimited list containing any "Commands" to modify the (Sub)menu's contents, display styles and general operation of the PopupMenu. ; Most commands have SPACE DELIMITED parameters after them. ; You can have any number of commands and repeated commands. There is some syntax checking, and some bad syntax will just be ignored, however some may cause an error. ; Any commands that act upon a submenu will not work unless the submenu has been defined (exists) first, so list your SUBMENU commands before these. ; Generally speaking, the order of commands will not affect operation, but some commands and duplicates that modify the state of items may override others. ; - Check your order and syntax if you get strange results. ; ; Current Commands: ; Commands are listed in a PIPE | delimited list where anything in square brackets [] is optional and the following SPACE delimited parameters denote... ; # = pixels, m = menu number, i = index, + = repeat for subordinates (can be any character), r g b = red green blue decimal values, t = text string, ; f = filename of BMP or Resource file, >res = BMP resource name or ordinal number to use inside the DLL - (see note below). ; Note: If using a Resource file then you must also provide the BMP resource name or number. eg: 'ieframe.dll>SEARCH_120.BMP' or 'wmploc.dll>5534' ; Seperate the filename and resource ID with a > (greater than symbol) and use quotes around paths containing spaces. ; ; X #|Y #|XCENTER|YCENTER|XRIGHT|YBOTTOM|REMOVE m i|DEFAULT m i|CHECKED m i|DISABLED m i|GRAYED m i|BARBREAK m i [+]|MENUBREAK m i [+]|SEPARATOR m i [+] ; MAXHEIGHT m # [+]|BACKGROUND m r g b [+]|BITMAP m i 'f[>res]' [#] [#]|SUBMENU m i m 't' (for text submenu)|SUBMENUBMP m i m 'f[>res]' [#] [#] (for bitmap picture submenu) ; Default values if overriding commands are not specified are: Current Mouse X,Current Mouse Y,XLEFT,YTOP,UNCHECKED,ENABLED ; ; Tips: Best to do any SUBMENU commands first, then apply styles that affect them later (they need to exist to be affected!) ; Use DISABLED and GRAYED last or they may be overridden. To apply a style like DISABLED to an inserted BITMAP, add 100000000 to the index it was inserted with! ; MAXHEIGHT can be fussy and do weird things with low values and using repeat for subordinates. BREAK commands are inserted before the item index, and can be tricky ; to get right with repeats (repeat uses the index number to increment), Also remember that the menu item index starts at One not Zero, and inserted or deleted things ; don't change those numbers. Use a resource editor to find BMP resource names and ordinals inside EXEs and DLLs. ; ; ------------------------------------------------ ; Returns: A TAB delimited string (List) containing information about the clicked item or 0 (ZERO) if no item was clicked on. ; The 3 items are: The number of the ItemList containing the clicked item, The index of the item in the ItemList, The text of the item (or "BITMAP") if the menuitem ; was a manually added BITMAP and not a "real" item in one of the origional passed lists. ; eg: "2%@TAB%14%@TAB%This is the 14th item in list 2" ;------------------------------------------------- #DefineFunction MegaPop(DataIn) MXY = MouseInfo(3) X=ItemExtract(1,MXY," ") Y=ItemExtract(2,MXY," ") User32 = DllLoad(StrCat(DirWindows(1),"User32.DLL")) hWnd = DllHwnd("") TPM_RETURNCMD = 256 TPM_LEFTBUTTON = 0 TPM_RIGHTBUTTON = 2 Align = 0 fMask = 0 cyMax = 0 hBrBack = 0 DelimDefault = @TAB ; Default delim for all other lists except Command List If VarType(DataIn) == 256 ; TRUE if Array ErrorMode(@OFF) TestInit = DataIn[0] ErrorMode(@CANCEL) If TestInit == @FALSE Then DataIn[0] = "" Lists = ArrInfo(DataIn,1)-1 ;DataIn[0] ; Any Commands are in a pipe delimited list in the first array element - (subsequent elements contain the lists of menu items) MenuArray = ArrDimension(Lists+1,2);holds memu handles in first dimension and delimiters in second dim of each element For M = 1 To Lists MenuArray[M,0] = DllCall(user32,long:"CreatePopupMenu") ;Create popup menu handles ;Add all items from each ItemList - Check for custom DELIM first (Without any DELIM command, a List's default delimeter is a TAB) MenuArray[M,1] = DelimDefault SearchDelim = StrCat("DELIM ",M," *") DelimCmd = ItemExtract(1,StrSubWild(DataIn[0],SearchDelim,StrIndexWild(DataIn[0],SearchDelim,1)),"|") ParseData(DelimCmd) If Param0 > 2 If StrUpper(Param3) == "PIPE" MenuArray[M,1] = "|" Else MenuArray[M,1] = Param3 EndIf If Param0 > 3 DelimDefault = Param3 EndIf EndIf ItemCountX = ItemCount(DataIn[M],MenuArray[M,1]) For ItemX = 1 To ItemCountX ItemText = ItemExtract(ItemX,DataIn[M],MenuArray[M,1]) DllCall(User32,long:"AppendMenuA",long:MenuArray[M,0], long:0, long:(M*10000)+ItemX, lpstr:ItemText) Next ItemX Next M ;Process any "Commands" to change the popupmenu. ItemCountX = ItemCount(DataIn[0],"|") For CommandItemX = 1 To ItemCountX CommandItem = ItemExtract(CommandItemX,DataIn[0],"|") For nx = 0 To 7 Param%nx% = 0 Next nx ParseData(CommandItem) Command = StrUpper(Param1) If Param0 > 1 && IsInt(Param2) == 0 Then Command = "GENERAL SYNTAX ERROR" ; Any Command that requires parameters has the first one as an integer - invalidate it otherwise If Param0 > 2 hMnu = MenuArray[Param2,0] ; Menu handle number to act on If IsInt(Param3) Then uPosition = (Param2*10000)+Param3 ; Real ID of item in menu EndIf Switch @TRUE Case Command == "X" && IsInt(Param2) ;Command is X and the value to set is an integer - Note: could have made a combined XY command, but separated for a bit more granular control X = Param2 Break Case Command == "Y" && IsInt(Param2) Y = Param2 Break Case Command == "XCENTER" Align = Align|4 Break Case Command == "YCENTER" Align = Align|16 Break Case Command == "XRIGHT" Align = Align|8 Break Case Command == "YBOTTOM" Align = Align|32 Break Case Command == "REMOVE" DllCall(User32,long:"RemoveMenu",long:hMnu, long:uPosition, long:0) Break Case Command == "DEFAULT" DllCall(User32,long:"SetMenuDefaultItem",long:hMnu, long:uPosition, long:0) Break Case Command == "CHECKED" DllCall(User32,long:"CheckMenuItem",long:hMnu, long:uPosition, long:0|8) Break Case Command == "DISABLED" DllCall(User32,long:"EnableMenuItem",long:hMnu, long:uPosition, long:0|2) Break Case Command == "GRAYED" DllCall(User32,long:"EnableMenuItem",long:hMnu, long:uPosition, long:0|1) Break Case Command == "BARBREAK";New Column starts with dividing line (inserts before item) If Param0 < 4 ;if there is no repeat flag DllCall(user32,long:"ModifyMenuA",long:hMnu, long:uPosition, long:0|32, long:uPosition, lpstr:ItemExtract(Param3,DataIn[Param2],MenuArray[Param2,1])) Else For Split = 0 To ItemCount(DataIn[Param2],MenuArray[Param2,1]) By Max(1,Param3-1) ; BarBreak every Param3 - 1 (or 1) items in this list DllCall(user32,long:"ModifyMenuA",long:hMnu, long:uPosition+Split, long:0|32, long:uPosition+Split, lpstr:ItemExtract(Param3+Split,DataIn[Param2],MenuArray[Param2,1])) Next Split EndIf Break Case Command == "MENUBREAK";New Column starts with no dividing line (inserts before item) If Param0 < 4 ;if there is no repeat flag DllCall(user32,long:"ModifyMenuA",long:hMnu, long:uPosition, long:0|64, long:uPosition, lpstr:ItemExtract(Param3,DataIn[Param2],MenuArray[Param2,1])) Else For Split = 0 To ItemCount(DataIn[Param2],MenuArray[Param2,1]) By Max(1,Param3-1) ; MenuBreak every Param3 - 1 (or 1) items in this list DllCall(user32,long:"ModifyMenuA",long:hMnu, long:uPosition+Split, long:0|64, long:uPosition+Split, lpstr:ItemExtract(Param3+Split,DataIn[Param2],MenuArray[Param2,1])) Next Split EndIf Break Case Command == "SEPARATOR" ;(inserts before item) If Param0 < 4 ;if there is no repeat flag DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition, long:0|2048, lpnull, lpnull) Else For Split = 0 To ItemCount(DataIn[Param2],MenuArray[Param2,1]) By Max(1,Param3-1) ; Separator every Param3 - 1 (or 1) items in this list DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition+Split, long:0|2048, lpnull, lpnull) Next Split EndIf Break Case Command == "MAXHEIGHT" cyMax = Param3 ;pixels If Param0 < 4 ;if there is no apply to submenus flag at all fMask = 1 Else fMask = 1|2147483648 ;cyMax|0MIM_APPLYTOSUBMENUS EndIf GoSub SETMENUINFO Break Case Command == "BACKGROUND" If Param0 < 6 fMask = 2 Else fMask = 2|2147483648 ;brBack|MIM_APPLYTOSUBMENUS EndIf brushColor = Param5*256*256 + Param4*256 + Param3 hBrBack = DllCall(StrCat(DirWindows(1),"GDI32.dll"), long:"CreateSolidBrush", long:brushColor) GoSub SETMENUINFO Break Case Command == "BITMAP" ;BITMAP m i 'f[>res]' [#] [#] FileX = ItemExtract(1,Param4,">") ResourceX = ItemExtract(2,Param4,">") If ResourceX <> "" If IsInt(ResourceX) Then ResourceX = StrCat("#",ResourceX);ordinal seem to need a # in front hLoadedLib = DllCall(StrCat(DirWindows(1), "Kernel32.dll"), long:"LoadLibraryA", lpstr:FileX);Load the Resource file hBMP = DllCall(User32,long:"LoadImageA",long:hLoadedLib,lpstr:ResourceX,long:0,long:Param5,long:Param6,long:0);Load the Resource DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition, long:4, long:uPosition+100000000, long:hBMP) DllCall(StrCat(DirWindows(1), "Kernel32.dll"), long:"FreeLibrary", long:hLoadedLib) Else hBMP = DllCall(User32,long:"LoadImageA",long:0,lpstr:FileX,long:0,long:Param5,long:Param6,long:16);Load BMP file DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition, long:4, long:uPosition+100000000, long:hBMP) EndIf Break Case Command == "SUBMENU" && Param0 == 5 ;SUBMENU m i m 't' DllCall(user32,long:"InsertMenuA",long:hMnu, long:uPosition, long:16, long:MenuArray[Param4,0], lpstr:Param5) Break Case Command == "SUBMENUBMP" && Param0 > 4 ;SUBMENUBMP m i m 'f[>res]' [#] [#] FileX = ItemExtract(1,Param5,">") ResourceX = ItemExtract(2,Param5,">") If ResourceX <> "" If IsInt(ResourceX) Then ResourceX = StrCat("#",ResourceX);ordinal seem to need a # in front hLoadedLib = DllCall(StrCat(DirWindows(1), "Kernel32.dll"), long:"LoadLibraryA", lpstr:FileX);Load the Resource file hBMP = DllCall(User32,long:"LoadImageA",long:hLoadedLib,lpstr:ResourceX,long:0,long:Param6,long:Param7,long:0);Load the Resource DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition, long:4|16, long:MenuArray[Param4,0], long:hBMP) DllCall(StrCat(DirWindows(1), "Kernel32.dll"), long:"FreeLibrary", long:hLoadedLib) Else hBMP = DllCall(User32,long:"LoadImageA",long:0,lpstr:FileX,long:0,long:Param6,long:Param7,long:16);Load BMP file DllCall(User32,long:"InsertMenuA",long:hMnu, long:uPosition, long:4|16, long:MenuArray[Param4,0], long:hBMP) EndIf Break EndSwitch Next CommandItemX uFlags=TPM_RETURNCMD|TPM_LEFTBUTTON|Align DllCall(User32,long:"SetForegroundWindow",long:hWnd) Selected = DllCall(User32,long:"TrackPopupMenu",long:MenuArray[1,0], long:uFlags, long:X, long:Y, long:0, long:hWnd, lpnull) ;Destroy Menus and Clean-up For M = 1 To Lists DllCall(User32,long:"DestroyMenu",long:MenuArray[M,0]) Next M DllFree(User32) ;Work out what was just clicked If Selected <> 0 MenuX = Int(Selected / 10000) ItemX = Selected mod 10000 If MenuX > 10000 MenuX = MenuX - 10000 ItemText = "Bitmap" Else ItemText = ItemExtract(ItemX,DataIn[MenuX],MenuArray[MenuX,1]) EndIf Selected = StrCat(MenuX,@TAB,ItemX,@TAB,ItemText) EndIf Return(Selected) ; Return 0 (ZERO) if nothing selected or return a string (list) of 3 items in TAB delimited form as follows: ;The Selected LIST's number (menu or sub-menu), the ITEM INDEX in that list and the TEXT OF THE ITEM. eg: "2%@TAB%4%@TAB%This is the 14th item in list 2" ;Reusable GoSubed routine :SETMENUINFO ;----- Make MenuInfo structure ------------------------------------------------------- MENUINFO=BinaryAlloc(28); Create buffer for structure http://msdn.microsoft.com/en-us/library/ms647575(v=VS.85).aspx BinaryPoke4(MENUINFO,0,28) ; cbSize BinaryPoke4(MENUINFO,4,fMask);1|2|16) ; fMask // Height|Background|Style (see MIM_???? Windows API constants) BinaryPoke4(MENUINFO,8,268435456|67108864) ; dwStyle // AutoDismiss|CheckorBMP (see MNS_???? Windows API constants) BinaryPoke4(MENUINFO,12,cyMax) ; cyMax // maximum height of menu in pixels - scroll bars used if bigger (0 is screen height) BinaryPoke4(MENUINFO,16,hBrBack) ; hbrBack // A handle to the brush to be used for the menu's background. BinaryPoke4(MENUINFO,20,0) ; dwContextHelpID // The context help identifier BinaryPoke4(MENUINFO,24,0) ; dwMenuData // An application-defined value. ;----------------------------------------------------------------------------------- DllCall(User32,long:"SetMenuInfo",long:hMnu, lpbinary:MENUINFO) BinaryFree(MENUINFO) Return ; Return for Gosub within UDF #EndFunction ;============================= END of MegaPop UDF ========================================================================================= Return
Article ID: W18249
Filename: MegaPop UDF.txt
File Created: 2013:04:02:07:38:14
Last Updated: 2013:04:02:07:38:14