Hi
I wonder if there is a way to insert a small image in the left side before text in the menu-bar dynamic dialog. Something like the attached.
Thanks
It is theoretically possible using DllCall but the process is a bit convoluted, may not actually work, and hardly seem worth the effort.
Can you give me more details or point me where can I read about it? Thanks!!
Here is an embarrassingly poorly written script that demonstrates the basics while managing to do nothing particularly useful.
;; Define UDFs.
gosub defineudps
MenuBitmapFormat=`WWWDLGED,6.2`
MenuBitmapCaption=`WIL Dialog 1`
MenuBitmapX=001
MenuBitmapY=001
MenuBitmapWidth=352
MenuBitmapHeight=241
MenuBitmapNumControls=005
MenuBitmapProcedure=`MenuBitmapProc`
MenuBitmapFont=`DEFAULT`
MenuBitmapTextColor=`DEFAULT`
MenuBitmapBackground=`DEFAULT,DEFAULT`
MenuBitmapConfig=0
MenuBitmap001=`095,226,032,011,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,10,@csDefButton,DEFAULT,DEFAULT,DEFAULT`
MenuBitmap002=`223,226,032,011,PUSHBUTTON,"PushButton_Cancel",DEFAULT,"Cancel",0,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MenuBitmap003=`000,000,000,000,MENUBAR,"Dialog_Bar"`
MenuBitmap004=`000,000,000,000,MENUITEM,"mbi1_MyDialog","Dialog_Bar","Bitmap",DEFAULT,10,DEFAULT`
MenuBitmap005=`000,000,000,000,MENUITEM,"mbi2_MenuBitmap","mbi1_MyDialog","Has One",DEFAULT,10,DEFAULT`
ButtonPushed=Dialog("MenuBitmap")
exit
:defineudps
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Simple way to create a dummy menu item bitmap for testing
;; purposes.
;;
;; Returns a Windows bitmap handle.
#definefunction CreateMenuBitmap()
hUser32 = DllLoad('user32.dll')
hwndDesktop = DllCall(hUser32, long:'GetDesktopWindow')
hdcDesktop = DllCall(hUser32, long:'GetDC', long:hwndDesktop)
; Determine the required bitmap size.
SM_CXMENUCHECK = 71
SM_CYMENUCHECK = 72
nX = WinMetrics(SM_CXMENUCHECK)
nY = WinMetrics(SM_CYMENUCHECK)
; Create a monochrome bitmap and select it.
hGdi32 = DllLoad('Gdi32.dll')
hdcMem = DllCall(hGdi32, long:'CreateCompatibleDC', long:hdcDesktop)
hbm = DllCall(hGdi32, long:'CreateBitmap',long:nX, long:nY, long:1, long:1, lpnull)
hbmOld = DllCall(hGdi32, long:'SelectObject',long:hdcMem, long:hbm)
WHITENESS = 16711778 ; 0x00FF0062
DllCall(hGdi32, long:'PatBlt', long:hdcMem, long:0, long:0, long:nX, long:nY, long:WHITENESS);
; Clean up.
DllCall(hGdi32, long:'SelectObject', long:hdcMem, long:hbmOld)
DllCall(hGdi32, long:'DeleteDC',long:hdcMem)
DllCall(hUser32, long:'ReleaseDC',long:hwndDesktop, long:hdcDesktop)
DllFree(hUser32)
DllFree(hGdi32)
return hbm
#endfunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Creates a structure descript string for use with DllStructAlloc.
;;
;; Returns a string description of the Wub 32 MENUITEMINFOW structure.
#DefineFunction GetMiiStructStr()
return $"
uint::cbSize;
uint::fMask;
uint::fType;
uint::fStat;
uint::wID;
HMENU::hSubMenu;
HBITMAP::hbmpChecked;
HBITMAP::hbmpUnchecked;
DWORD_PTR::dwItemData;
LPWSTR::dwTypeData;
uint::cch;
HBITMAP::hbmpItem;$"
#EndFunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User defined dialog callback function
;;
;; Adds and destroys a menu item's bitmap.
#DefineFunction MenuBitmapProc(Bm_Handle,Bm_Event,Bm_Name,Bm_EventInfo,Bm_ChangeInfo)
switch Bm_Event
case @deInit
DialogProcOptions(Bm_Handle, @dePbPush, 1)
hUser32 = DllLoad('user32.dll')
hMenuBar = DllCall(hUser32, long:'GetMenu', long:Bm_Handle)
mii = DllStructAlloc(GetMiiStructStr())
DllStructPoke(mii, 'cbSize', IntControl(98, mii, 1, 0, 0))
MIIM_SUBMENU = 4
DllStructPoke(mii, 'fMask', MIIM_SUBMENU)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hMenuBar, long:0, long:@True, lpstruct:mii)
hmenuPopup = DllStructPeek(mii, 'hSubMenu')
hbm = CreateMenuBitmap()
MF_BYPOSITION = 1024 ;0x00000400L
DllCall(hUser32, long:'SetMenuItemBitmaps',long:hmenuPopup, long:0, long:MF_BYPOSITION, long:hbm, long:hbm);
; aError = DllLastError()
DllStructFree(mii)
DllFree(hUser32)
return(@retDefault)
case @dePbPush
; Destroy bitmaps as system won't.
hUser32 = DllLoad('user32.dll')
hMenuBar = DllCall(hUser32, long:'GetMenu', long:Bm_Handle)
mii = DllStructAlloc(GetMiiStructStr())
DllStructPoke(mii, 'cbSize', IntControl(98, mii, 1, 0, 0))
MIIM_SUBMENU = 4
DllStructPoke(mii, 'fMask', MIIM_SUBMENU)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hMenuBar, long:0, long:@True, lpstruct:mii)
hmenuPopup = DllStructPeek(mii, 'hSubMenu')
MIIM_CHECKMARKS = 8
DllStructPoke(mii, 'fMask', MIIM_CHECKMARKS)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hmenuPopup, long:0, long:@True, lpstruct:mii)
hGdi32 = DllLoad('Gdi32.dll')
DllCall(hGdi32,long:'DeleteObject', long:DllStructPeek(mii, 'hbmpChecked'))
DllCall(hGdi32,long:'DeleteObject', long:DllStructPeek(mii, 'hbmpUnchecked'))
DllStructFree(mii)
DllFree(hUser32)
DllFree(hGdi32)
break
; case @deMiSelect
; case @deMiInit
; case @deClose
endswitch
return(@retDefault)
#EndFunction
return
The above example only scratches the surface. You can also create bitmap menu items where you would need to draw the menu's text on the bitmap.
Just out of curiosity...would my ComControl Extender be any use? That is, the creation and use of an "Image List"?
Jim
Here is another poorly written mostly useless example. This time using a static image.
;; Define UDFs.
gosub defineudps
MenuBitmapFormat=`WWWDLGED,6.2`
MenuBitmapCaption=`WIL Dialog 1`
MenuBitmapX=001
MenuBitmapY=001
MenuBitmapWidth=352
MenuBitmapHeight=241
MenuBitmapNumControls=005
MenuBitmapProcedure=`MenuBitmapProc`
MenuBitmapFont=`DEFAULT`
MenuBitmapTextColor=`DEFAULT`
MenuBitmapBackground=`DEFAULT,DEFAULT`
MenuBitmapConfig=0
MenuBitmap001=`095,226,032,011,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,10,@csDefButton,DEFAULT,DEFAULT,DEFAULT`
MenuBitmap002=`223,226,032,011,PUSHBUTTON,"PushButton_Cancel",DEFAULT,"Cancel",0,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MenuBitmap003=`000,000,000,000,MENUBAR,"Dialog_Bar"`
MenuBitmap004=`000,000,000,000,MENUITEM,"mbi1_MyDialog","Dialog_Bar","Bitmap",DEFAULT,10,DEFAULT`
MenuBitmap005=`000,000,000,000,MENUITEM,"mbi2_MenuBitmap","mbi1_MyDialog","Has One",DEFAULT,10,DEFAULT`
ButtonPushed=Dialog("MenuBitmap")
exit
:defineudps
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Simple way to create a dummy menu item bitmap for testing
;; purposes.
;;
;; Returns a Windows bitmap handle.
#definefunction CreateMenuBitmap(_strFile)
; Determine the required bitmap size.
SM_CXMENUCHECK = 71
SM_CYMENUCHECK = 72
nX = WinMetrics(SM_CXMENUCHECK)
nY = WinMetrics(SM_CYMENUCHECK)
IMAGE_BITMAP = 0
LR_LOADFROMFILE = 16
hBitmap = DllCall('user32.dll', long:'LoadImageA', lpnull, lpstr:_strFile, long:IMAGE_BITMAP, LONG:nX, long:nY, long:LR_LOADFROMFILE)
return hBitmap
#endfunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Creates a MENUITEMINFOW structure with DllStructAlloc.
;;
;; Returns a structure handle to a Win2 MENUITEMINFOW structure.
#DefineFunction GetMiiStruct()
strMii = $"
uint::cbSize;
uint::fMask;
uint::fType;
uint::fStat;
uint::wID;
HMENU::hSubMenu;
HBITMAP::hbmpChecked;
HBITMAP::hbmpUnchecked;
DWORD_PTR::dwItemData;
LPWSTR::dwTypeData;
uint::cch;
HBITMAP::hbmpItem;$"
mii = DllStructAlloc(strMii)
DllStructPoke(mii, 'cbSize', IntControl(98, mii, 1, 0, 0)) ; Always set the size
return mii
#EndFunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User defined dialog callback function
;;
;; Adds and destroys a menu item's bitmap.
#DefineFunction MenuBitmapProc(Bm_Handle,Bm_Event,Bm_Name,Bm_EventInfo,Bm_ChangeInfo)
switch Bm_Event
case @deInit
DialogProcOptions(Bm_Handle, @dePbPush, 1)
hUser32 = DllLoad('user32.dll')
hMenuBar = DllCall(hUser32, long:'GetMenu', long:Bm_Handle)
mii = GetMiiStruct()
MIIM_SUBMENU = 4
DllStructPoke(mii, 'fMask', MIIM_SUBMENU)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hMenuBar, long:0, long:@True, lpstruct:mii)
hmenuPopup = DllStructPeek(mii, 'hSubMenu')
hbm = CreateMenuBitmap(DirScript():'WBPrgn.bmp')
MIIM_BITMAP = 128 ;0x00000080
DllStructPoke(mii, 'fMask', MIIM_BITMAP)
DllStructPoke(mii, 'fType', 0)
DllStructPoke(mii, 'hbmpItem', hbm)
MF_BYPOSITION = 1024 ;0x00000400L
az = DllCall(hUser32, long:'SetMenuItemInfoW',long:hmenuPopup, long:0, long:MF_BYPOSITION, lpstruct:mii);
;aError = DllLastError()
DllStructFree(mii)
DllFree(hUser32)
return(@retDefault)
case @dePbPush
; Destroy bitmaps as system won't.
hUser32 = DllLoad('user32.dll')
hMenuBar = DllCall(hUser32, long:'GetMenu', long:Bm_Handle)
mii = GetMiiStruct()
MIIM_SUBMENU = 4
DllStructPoke(mii, 'fMask', MIIM_SUBMENU)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hMenuBar, long:0, long:@True, lpstruct:mii)
hmenuPopup = DllStructPeek(mii, 'hSubMenu')
MIIM_BITMAP = 128 ;0x00000080
DllStructPoke(mii, 'fMask', MIIM_BITMAP)
DllCall(hUser32, long:'GetMenuItemInfoW', long:hmenuPopup, long:0, long:@True, lpstruct:mii)
hGdi32 = DllLoad('Gdi32.dll')
DllCall(hGdi32,long:'DeleteObject', long:DllStructPeek(mii, 'hbmpItem'))
DllStructFree(mii)
DllFree(hUser32)
DllFree(hGdi32)
break
; case @deMiSelect
; case @deMiInit
; case @deClose
endswitch
return(@retDefault)
#EndFunction
return
Don't believe menu items can use image lists directly.
Quote from: JTaylor on June 20, 2018, 07:11:32 AM
Just out of curiosity...would my ComControl Extender be any use? That is, the creation and use of an "Image List"?
Jim
Do you have any example for a solution base on the com control?
Also i tried it in Windows 10. I didn't see any image just blank. see image.
Quote from: erezpaz on June 21, 2018, 07:52:44 AM
Do you have any example for a solution base on the com control?
Also i tried it in Windows 10. I didn't see any image just blank. see image.
I posted a link from the Tech DB, but removed it. Back around 2006 we did a lot with images [pre-WB Menus], using MSCI control, Treeview, or a neat OCX called TopicList. All worked pretty well on XP, but you can't even find them to download anymore and it would be a little insane to try stuff like that in Win10. There is excellent C# code out there to do what you want, but it can't be leveraged into WB due to event processing. And I agree with what Tony said, lot a work maybe not really that satisfying.
As usual I post this as somewhat controversial and to be proven wrong. ;D
No, because I had no idea if they can be used in this way. Tony indicated that this is not an option :(
Jim
Quote from: erezpaz on June 21, 2018, 07:52:44 AM
Do you have any example for a solution base on the com control?
Also i tried it in Windows 10. I didn't see any image just blank. see image.
Quote from: erezpaz on June 21, 2018, 07:52:44 AM
Do you have any example for a solution base on the com control?
Also i tried it in Windows 10. I didn't see any image just blank. see image.
Whatever your problem is it is not because you are testing on Windows 10. Both scripts I posted were written and worked on Windows 10.
Completely forgot to add that the first script posted will not show a bitmap until you click because of the way checkbox images work in Win32. However, this is not an issue with the second script. If you want to understand why the first script works the way it does and how to make it fully functional, you will need to read Microsoft's online documentation for the menu functions used in the script. Pay special attention to the documentation for the "SetMenuItemBitmaps" function.
Hi
I was able to successfully create an image for the menu item but not to a context menu. Cant find the context menu handle to load in the dllcall:
hMenuBar = DllCall(hUser32, long:'GetMenu', long:WindowHandler)
I need the image to appeared to a context menu on top a report view contro (see image attched)l. Is there something i am missing?
Thanks
You are missing the fact that a context menu is not attached to a window until a user causes a context menu message to be sent to the dialog window procedure. The user creates the context menu message by right-clicking the control, using a menu key, or using a shortcut key combination.
Here is Tech DB article that illustrates how to create your own sorta like a context menu that you can modify in any way you choose.
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/Dialog~Editor/Dialog~Editor~version~6.X+Dialogs~-~Menus~in~dialogs.txt (http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/Dialog~Editor/Dialog~Editor~version~6.X+Dialogs~-~Menus~in~dialogs.txt)
Cant i use in the dialog function:
case @deMiSelect
if ControlNum == "cmi5_ReportView_JobSelect" then...
to capture the context manue handle and pass it to the SetMenuItemImage function?
The @deMiSelect notification is not sent until the menu is already displayed unless a hotkey is used to activate the command without using the menu at all. When the @deMiInit notification is sent, the menu has not yet been associated with the Window handle in such a way that the Windows menu API can obtain the menu handle.
Maybe your previous post answered this but if not, would it be a difficult enhancement to have a "ContextMenuCreated" event which passed the context menu handle to the script so it could be used to add images to context menus?
Jim
Quote from: td on July 02, 2018, 08:17:15 AM
You are missing the fact that a context menu is not attached to a window until a user causes a context menu message to be sent to the dialog window procedure. The user creates the context menu message by right-clicking the control, using a menu key, or using a shortcut key combination.
Possible? Likely any time soon?
Jim
User feedback is always appreciated.
Hmmmmmmmm....feedback as in "User's generally like answers to questions" or some other type? ;-)
Jim
Not all questions are answerable at the time they are asked and some may never be answered. I can remember trying to explain this to my children during their formative years. I think it may have sunk in a little bit as they are chasing their curiosity and thirst for discovery through carriers in science. But then I could be giving myself to much credit...
:o
Let go back to the question asked please...
Is there a way to do what Jim asked? How can we capture the handle of the context menu? Thanks!!
Quote from: JTaylor on July 03, 2018, 03:06:56 PM
Maybe your previous post answered this but if not, would it be a difficult enhancement to have a "ContextMenuCreated" event which passed the context menu handle to the script so it could be used to add images to context menus?
Jim
Quote from: td on July 02, 2018, 08:17:15 AM
You are missing the fact that a context menu is not attached to a window until a user causes a context menu message to be sent to the dialog window procedure. The user creates the context menu message by right-clicking the control, using a menu key, or using a shortcut key combination.
Quote from: erezpaz on July 11, 2018, 01:36:37 AM
:o
Let go back to the question asked please...
There isn't much to add but if you insist.
Quote
Is there a way to do what Jim asked? How can we capture the handle of the context menu? Thanks!!
As has already been mentioned in previous posts in this topic, currently there is no way to access the context menu handles in scripts. As to the future, prophecy is difficult particularly when it is about the future but also as previously mentioned, we appreciate the suggestion.