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

erezpaz

  • Jr. Member
  • **
  • Posts: 58
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: 2481
    • 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: 58
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: 2481
    • 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: 2481
    • 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: 874
    • 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: 2481
    • 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: 58
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: 760
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: 874
    • 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: 2481
    • 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: 2481
    • 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