Author Topic: Image in menu bar  (Read 825 times)

erezpaz

  • Jr. Member
  • **
  • Posts: 62
Image in menu bar
« on: June 19, 2018, 06:50:07 am »
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

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #1 on: June 19, 2018, 07:15:33 am »
It is theoretically possible using DllCall but the process is a bit convoluted, may not actually work, and hardly seem worth the effort.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


erezpaz

  • Jr. Member
  • **
  • Posts: 62
Re: Image in menu bar
« Reply #2 on: June 19, 2018, 07:30:27 am »
Can you give me more details or point me where can I read about it? Thanks!!

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #3 on: June 19, 2018, 01:51:54 pm »
Here is an embarrassingly poorly written script that demonstrates the basics while managing to do nothing particularly useful.

Code: Winbatch
;; 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

"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #4 on: June 20, 2018, 06:46:21 am »
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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


JTaylor

  • Pundit
  • *****
  • Posts: 922
    • Data & Stuff Inc.
Re: Image in menu bar
« Reply #5 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

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #6 on: June 20, 2018, 02:08:08 pm »
Here is another poorly written mostly useless example.  This time using a static image.

Code: Winbatch
;; 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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


erezpaz

  • Jr. Member
  • **
  • Posts: 62
Re: Image in menu bar
« Reply #7 on: June 21, 2018, 07:52:44 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.

stanl

  • Pundit
  • *****
  • Posts: 796
Re: Image in menu bar
« Reply #8 on: June 21, 2018, 09:01:00 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

JTaylor

  • Pundit
  • *****
  • Posts: 922
    • Data & Stuff Inc.
Re: Image in menu bar
« Reply #9 on: June 21, 2018, 09:21:53 am »
No, because I had no idea if they can be used in this way.  Tony indicated that this is not an option :(

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.

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #10 on: June 21, 2018, 10:28:52 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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #11 on: June 21, 2018, 03:08:30 pm »
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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


erezpaz

  • Jr. Member
  • **
  • Posts: 62
Re: Image in menu bar
« Reply #12 on: July 02, 2018, 05:11:43 am »
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

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #13 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. 
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #14 on: July 02, 2018, 01:24:48 pm »
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
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


erezpaz

  • Jr. Member
  • **
  • Posts: 62
Re: Image in menu bar
« Reply #15 on: July 03, 2018, 12:43:41 am »
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?

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #16 on: July 03, 2018, 07:05:50 am »
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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


JTaylor

  • Pundit
  • *****
  • Posts: 922
    • Data & Stuff Inc.
Re: Image in menu bar
« Reply #17 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

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.

JTaylor

  • Pundit
  • *****
  • Posts: 922
    • Data & Stuff Inc.
Re: Image in menu bar
« Reply #18 on: July 07, 2018, 02:47:18 pm »
Possible?  Likely any time soon?

Jim

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #19 on: July 09, 2018, 04:02:16 pm »
User feedback is always appreciated.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


JTaylor

  • Pundit
  • *****
  • Posts: 922
    • Data & Stuff Inc.
Re: Image in menu bar
« Reply #20 on: July 09, 2018, 06:36:34 pm »
Hmmmmmmmm....feedback as in "User's generally like answers to questions" or some other type?   ;-)

Jim

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #21 on: July 10, 2018, 06:21:20 am »
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...
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


erezpaz

  • Jr. Member
  • **
  • Posts: 62
Re: Image in menu bar
« Reply #22 on: July 11, 2018, 01:36:37 am »
 :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!!

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

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.

td

  • Tech Support
  • *****
  • Posts: 2619
    • WinBatch
Re: Image in menu bar
« Reply #23 on: July 11, 2018, 06:51:43 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.
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates