Managed MessageBox 2.0

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Managed MessageBox 2.0

Post by netmaestro »

I wrote this years ago and when I went to search for it on the forums it can't be found. So here it is again, a tool for customizing a messagebox with colors, images and timeout. You can choose the screen position too.

Code: Select all

;================================================================= 
; Library:           ManagedMessageBox 2.0 
; Author:            Lloyd Gallant (netmaestro) 
; Date:              January 9, 2008 
; Target OS:         Microsoft Windows All 
; Target Compiler:   PureBasic 4.0 and later 
; License:           Free, unrestricted, no warranty 
; 
; Last Update:       June 6, 2008 
; 
; Usage: Filling the MMMBDATA structure 
; 
; Use only the programmer-selectable options. All fields are optional. 
; If you do not fill x and y for a screenposition, the messagebox will 
; be screencentered. 
; 
; #MMB_ Constant usage: 
; 
;   If you do not fill bkContentType (or use #MMB_NOBACKGROUND) no special 
;   background options will be applied. 
; 
;   To have a background color, fill bkContent with a colorref and fill 
;   bkContentType with #MMB_COLOR 
; 
;   To have a background image, fill bkContent with the #image you want to use 
;   and fill bkContentType with #MMB_IMAGE. 
; 
;   To have a logo banner, fill bannerImage with the #image you want for a banner 
; 
;   #MMB_TEST is a special case. If you have a text in mind for the messagebox 
;   and you would like to have a background image, it is useful to know what 
;   size the client area of the message box will be. If you fill bkContentType 
;   with #MMB_TEST, the caption of the message box will be ignored and it will 
;   show the width And height. You'd only do this during development so you can 
;   easily create a nice image the right size for the message box. 
; 
; txtColor: Put a colorref here if a text color other than black is desired. 
; 
; delayTime: Leave at 0 for a non-timed message box or put a number of seconds 
; to wait before the default button is auto-selected. 
; 
; defaultButton: choose from a 1-based enumeration of the buttons on your 
; messagebox. For example, if your flags are #MB_ABORTRETRYIGNORE, you will 
; have three buttons. Filling defaultButton with 2 will make RETRY the default 
; choice. 
; 
; modalLevel: For normal application modality, leave at 0. For system-level 
; modality (the box will never allow itself to be minimized), fill with 1. 
; 
; silent: Not for use in icon message boxes (like #MB_ICONERROR, etc.), this 
; flag will remove the "ding" sound made when the message box appears. Fill with 
; 0 for normal sound or 1 to suppress the ding. 
; 
; You should compile ThreadSafe if using this library. 
; 
; Enjoy it! 
; 
;================================================================= 

#MMB_NOBACKGROUND = 0 
#MMB_COLOR        = 2 
#MMB_IMAGE        = 4 
#MMB_BANNER       = 8 
#MMB_TEST         = 16 

Structure MMBDATA 
  ;------------------------------------------------- 
  ;    Programmer-Selectable Options 
  ;------------------------------------------------- 
  x.l               ; In, desired x position on screen 
  y.l               ; In, desired y position on screen 
  bkContent.l       ; In, long value representing imageid or colorref depending on type 
  bkContentType.b   ; In, specifies whether bkContent is an image or a colorref 
  txtColor.l        ; In, specifies desired text color for message box 
  bannerImage.l     ; In, specifies a #Image to use as a banner 
  delayTime.l       ; In, specifies number of seconds to wait before auto-clicking the default button 
  defaultButton.l   ; In, specifies the default button 
  modalLevel.b      ; In, specifiels modality desired 
  silent.b          ; In, specifies no "ding" when messagebox appears. Only for non-icon messageboxes. 
  ;------------------------------------------------- 
  ;    Variables for Internal Use Only 
  ;------------------------------------------------- 
  hwndMain.l        ; reserved, do not use 
  hwndIcon.l        ; reserved, do not use 
  timerThreadID.l   ; reserved, do not use 
  textGadgetID.l    ; reserved, do not use 
  defaultHwnd.l     ; reserved, do not use 
  defaultCtrlID.l   ; reserved, do not use 
  defaultHwndName.s ; reserved, do not use 
  staticBrush.l     ; reserved, do not use 
  timingBrush.l     ; reserved, do not use 
  bkImageID.l       ; reserved, do not use  
  timingBkImageID.l ; reserved, do not use 
  iconBkImageID.l   ; reserved, do not use 
  iconBrush.l       ; reserved, do not use 
  staticBkImageID.l ; reserved, do not use 
  cx.l              ; reserved, do not use 
  cy.l              ; reserved, do not use 
EndStructure 

Global mmb_Hook, gMMB_DATA_RESERVED.MMBDATA , mmb_ForcedResult=0 

Procedure MMB_dlgProc(hwnd, msg, wparam, lparam) 
  oldproc = GetProp_(hwnd, "oldproc") 
  Select msg 
  
    Case #WM_CLOSE 
      DestroyWindow_(hwnd) 
      mmb_ForcedResult = 1 

    Case #WM_CTLCOLORSTATIC 
  
      SetBkMode_(wparam, #TRANSPARENT) 
      SetTextColor_(wParam, gMMB_DATA_RESERVED\txtColor) 
      
      Select GetDlgCtrlID_(lparam) 
        Case $FFFF 
          ProcedureReturn gMMB_DATA_RESERVED\staticBrush 
          
        Case gMMB_DATA_RESERVED\textGadgetID 
          ProcedureReturn gMMB_DATA_RESERVED\timingBrush 
          
        Case GetDlgCtrlID_(gMMB_DATA_RESERVED\hwndIcon) 
          ProcedureReturn gMMB_DATA_RESERVED\iconBrush 
          
      EndSelect 
    
    Case #WM_NCDESTROY 
      RemoveProp_(hwnd, "oldproc") 
      
      DeleteObject_(gMMB_DATA_RESERVED\staticBrush) 
      
      If gMMB_DATA_RESERVED\delayTime 
        DeleteObject_(gMMB_DATA_RESERVED\timingBrush) 
        If gMMB_DATA_RESERVED\timingBkImageID 
          If IsImage(gMMB_DATA_RESERVED\timingBkImageID) 
            FreeImage(gMMB_DATA_RESERVED\timingBkImageID) 
          EndIf 
        EndIf 
      EndIf 
      
      If gMMB_DATA_RESERVED\bkImageID 
        If IsImage(gMMB_DATA_RESERVED\bkImageID) 
          FreeImage(gMMB_DATA_RESERVED\bkImageID) 
        EndIf 
      EndIf 
      
      If gMMB_DATA_RESERVED\staticBkImageID 
        If IsImage(gMMB_DATA_RESERVED\staticBkImageID) 
          FreeImage(gMMB_DATA_RESERVED\staticBkImageID) 
        EndIf 
      EndIf      

      If gMMB_DATA_RESERVED\iconBkImageID 
        DeleteObject_(gMMB_DATA_RESERVED\iconBrush) 
        If IsImage(gMMB_DATA_RESERVED\iconBkImageID) 
          FreeImage(gMMB_DATA_RESERVED\iconBkImageID) 
        EndIf 
      EndIf      
      
      If gMMB_DATA_RESERVED\timerThreadID 
        If IsThread(gMMB_DATA_RESERVED\timerThreadID) 
          KillThread(gMMB_DATA_RESERVED\timerThreadID) 
        EndIf 
      EndIf 
        
      If gMMB_DATA_RESERVED\textGadgetID 
        If IsGadget(gMMB_DATA_RESERVED\textGadgetID) 
          FreeGadget(gMMB_DATA_RESERVED\textGadgetID) 
        EndIf 
      EndIf 
            
  EndSelect 
  
  ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam) 
  
EndProcedure 

Procedure MMB_GetDefaultHwnd(hwnd, lparam) 
  Static buttoncount = 0 
  If lparam = -1 
    buttoncount = 0 
    ProcedureReturn 0 
  EndIf 
  wc$ = Space(255) 
  GetClassName_(hwnd, @wc$, 250) 
  If UCase(wc$) = "BUTTON" 
    buttoncount+1 
    If buttoncount = gMMB_DATA_RESERVED\defaultButton 
      gMMB_DATA_RESERVED\defaultHwnd = hwnd 
      gMMB_DATA_RESERVED\defaultCtrlID = GetDlgCtrlID_(hwnd) 
      GetWindowText_(hwnd, @wc$,250) 
      gMMB_DATA_RESERVED\defaultHwndName = RemoveString(wc$,"&") 
      ProcedureReturn 0 
    EndIf 
  EndIf 
  ProcedureReturn 1 
EndProcedure 

Procedure MMB_TimerThread(secondsremaining) 
  t=ElapsedMilliseconds() 
  Repeat 
    Delay(1000) 
    secondsremaining-1 
    SetGadgetText(gMMB_DATA_RESERVED\textGadgetID, gMMB_DATA_RESERVED\defaultHwndName+" = "+Str(secondsremaining)) 
  Until secondsremaining <=0 
  PostMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_HOTKEY, gMMB_DATA_RESERVED\hwndmain) 
  Delay(200) 
  PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONDOWN,0,0) 
  Delay(200) 
  PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONUP,0,0) 
  Delay(200) 
  If IsWindow_(gMMB_DATA_RESERVED\hwndmain) 
    SendMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_CLOSE, 0) 
  EndIf 
EndProcedure 

Procedure ThemesEnabled() 
  dlv.DLLVERSIONINFO 
  dlv\cbsize=SizeOf(DLLVERSIONINFO) 
  lib=OpenLibrary(#PB_Any,"comctl32.dll") 
  If lib 
    CallFunction(lib,"DllGetVersion",@dlv) 
    DLLVersion = dlv\dwMajorVersion 
    CloseLibrary(lib) 
  EndIf 
  If DLLVersion = 6 
    ProcedureReturn 1 
  Else 
    ProcedureReturn 0 
  EndIf 
EndProcedure 

Procedure MMB_CBTHookProc(nCode, wParam, lParam) 

  Static hwndmain 
  Select nCode 
  
    Case #HCBT_CREATEWND 
      *pcbt.CBT_CREATEWND = lParam 
      *pcs.CREATESTRUCT = *pcbt\lpcs 
      
      Select *pcs\lpszClass 
      
        Case 32770  ; Dialog Window 
          hwndmain = wParam 
          gMMB_DATA_RESERVED\hwndmain = wParam 
  
          If Not (gMMB_DATA_RESERVED\x=0 And gMMB_DATA_RESERVED\y=0) 
            *pcs\x = gMMB_DATA_RESERVED\x    
            *pcs\y = gMMB_DATA_RESERVED\y 
          EndIf    
          If gMMB_DATA_RESERVED\delayTime 
            *pcs\cy + 20 
          EndIf 
          If gMMB_DATA_RESERVED\bannerImage 
            *pcs\cy + ImageHeight(gMMB_DATA_RESERVED\bannerImage) 
          EndIf          
          gMMB_DATA_RESERVED\cx = *pcs\cx - 2*GetSystemMetrics_(#SM_CXFIXEDFRAME) 
          gMMB_DATA_RESERVED\cy = *pcs\cy - 2*GetSystemMetrics_(#SM_CYFIXEDFRAME)-GetSystemMetrics_(#SM_CYCAPTION) 
          SetProp_(wparam, "oldproc", SetWindowLong_(wparam,#GWL_WNDPROC,@MMB_dlgProc())) 
          
        Case 49177 ; Static Control 
          If GetWindowLong_(wParam, #GWL_STYLE) & #SS_BITMAP 
            gMMB_DATA_RESERVED\hwndIcon = wParam 
          EndIf 
          
          If gMMB_DATA_RESERVED\bannerImage 
            *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage) 
          EndIf        
          
        Default 
          If gMMB_DATA_RESERVED\bannerImage 
            *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage) 
          EndIf 
            
      EndSelect 
      
    Case #HCBT_ACTIVATE 
  
      If wParam = hwndmain 
      
        UnhookWindowsHookEx_(mmb_Hook) 
        
        MMB_GetDefaultHwnd(0, -1) ; clear the static buttoncount var before enumerating the controls 
        EnumChildWindows_(hwndmain, @MMB_GetDefaultHwnd(), 0) 
          
        Select gMMB_DATA_RESERVED\bkContentType 
        
          Case #MMB_COLOR 
            img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32) 
            StartDrawing(ImageOutput(img)) 
              Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, gMMB_DATA_RESERVED\bkContent) 
            StopDrawing() 
            gMMB_DATA_RESERVED\bkImageID = img 
            
          Case #MMB_IMAGE 
            If IsImage(gMMB_DATA_RESERVED\bkContent) 
              tmp = CopyImage(gMMB_DATA_RESERVED\bkContent, #PB_Any) 
              ResizeImage(tmp,gMMB_DATA_RESERVED\cx,gMMB_DATA_RESERVED\cy) 
              gMMB_DATA_RESERVED\bkImageID = tmp 
            Else 
              gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32) 
              StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID)) 
                Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE)) 
              StopDrawing() 
            EndIf 
            
          Case #MMB_TEST 
            img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32) 
            StartDrawing(ImageOutput(img)) 
              Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE)) 
            StopDrawing()        
            gMMB_DATA_RESERVED\bkImageID = img  
            tmp$ = "w"+Str(gMMB_DATA_RESERVED\cx)+",h"+Str(gMMB_DATA_RESERVED\cy) 
            SetWindowText_(hwndmain, @tmp$) 
                        
          Case #MMB_NOBACKGROUND 
            gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32) 
            StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID)) 
              Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE)) 
            StopDrawing() 
            
        EndSelect 
        
        If gMMB_DATA_RESERVED\bannerImage 
          ; Create left and right extension brushes 
          lbrush = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any,0,0,1,ImageHeight(gMMB_DATA_RESERVED\bannerImage)) 
          rbrush = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any,ImageWidth(gMMB_DATA_RESERVED\bannerImage)-1,0,1,ImageHeight(gMMB_DATA_RESERVED\bannerImage)) 
          leftbrush = CreatePatternBrush_(ImageID(lbrush)) 
          rightbrush = CreatePatternBrush_(ImageID(rbrush)) 
          
          ; Create and draw the banner image 
          banner = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, ImageHeight(gMMB_DATA_RESERVED\bannerImage), #PB_Image_DisplayFormat) 
          lpos = ImageWidth(banner)/2 - ImageWidth(gMMB_DATA_RESERVED\bannerImage)/2 
          rpos = lpos + ImageWidth(gMMB_DATA_RESERVED\bannerImage) 
          With lbr.RECT 
            \left=0 : \top=0 : \right=lpos : \bottom=ImageHeight(gMMB_DATA_RESERVED\bannerImage) 
          EndWith 
          With rbr.RECT 
            \left=rpos : \top=0 : \right=ImageWidth(banner) : \bottom=ImageHeight(gMMB_DATA_RESERVED\bannerImage) 
          EndWith 
          hdc = StartDrawing(ImageOutput(banner)) 
            FillRect_(hdc, lbr, leftbrush) 
            FillRect_(hdc, rbr, rightbrush) 
            DrawImage(ImageID(gMMB_DATA_RESERVED\bannerImage),lpos,0) 
            Line(0,0,ImageWidth(banner)-1,0,RGB(157,157,161)) 
            Line(0,0,0,ImageHeight(banner)-1,RGB(157,157,161)) 
            Line(1,1,ImageWidth(banner)-3,0,RGB(113,111,100)) 
            Line(1,1,0,ImageHeight(banner)-3,RGB(113,111,100)) 
            Line(ImageWidth(banner)-1,0,0,ImageHeight(banner),#White) 
            Line(0,ImageHeight(banner)-1,ImageWidth(banner),0,#White) 
            Line(ImageWidth(banner)-2,1,0,ImageHeight(banner)-2,RGB(241,239,226)) 
            Line(1,ImageHeight(banner)-2,ImageWidth(banner)-2,0,RGB(241,239,226)) 
          StopDrawing() 
          DeleteObject_(leftbrush) 
          DeleteObject_(rightbrush) 
          FreeImage(lbrush) 
          FreeImage(rbrush)  
          StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID)) 
            DrawImage(ImageID(banner),0,0) 
          StopDrawing() 
          FreeImage(banner)      
        EndIf 
        
        CompilerIf #PB_Compiler_Version < 430 
          CreateGadgetList(wParam)
        CompilerElse
          UseGadgetList(wParam)
        CompilerEndIf
        ig = ImageGadget(#PB_Any, 0,0,0,0,ImageID(gMMB_DATA_RESERVED\bkImageID)) 
        SetWindowPos_(GadgetID(ig), #HWND_BOTTOM,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE) 
        SetWindowLong_(GadgetID(ig),#GWL_STYLE,GetWindowLong_(GadgetID(ig),#GWL_STYLE)|#WS_CLIPSIBLINGS) 
        DisableGadget(ig, #True) 
        
        ; Icon background brush 
        If gMMB_DATA_RESERVED\hwndIcon 
          If Not ThemesEnabled() 
            gMMB_DATA_RESERVED\iconBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID)) 
          Else 
            GetWindowRect_(gMMB_DATA_RESERVED\hwndIcon, wr.RECT) 
            MapWindowPoints_(0, gMMB_DATA_RESERVED\hwndMain, wr, 2) 
            gMMB_DATA_RESERVED\iconBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID, #PB_Any,wr\left,wr\top,wr\right-wr\left,wr\bottom-wr\top) 
            gMMB_DATA_RESERVED\iconBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\iconBkImageID)) 
          EndIf 
        EndIf 
        
        ; Messagebox text background brush 
        If Not ThemesEnabled() 
          gMMB_DATA_RESERVED\staticBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID)) 
        Else 
          GetWindowRect_(GetDlgItem_(wparam, $FFFF), @wr.RECT) 
          MapWindowPoints_(0,gMMB_DATA_RESERVED\hwndMain,@wr,2) 
          gMMB_DATA_RESERVED\staticBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID,#PB_Any,wr\left,wr\top,gMMB_DATA_RESERVED\cx-wr\left,wr\bottom-wr\top)      
          gMMB_DATA_RESERVED\staticBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\staticBkImageID)) 
        EndIf 
        
        If gMMB_DATA_RESERVED\delayTime 
          gMMB_DATA_RESERVED\textGadgetID = TextGadget(#PB_Any, 0,gMMB_DATA_RESERVED\cy-22,gMMB_DATA_RESERVED\cx,20, gMMB_DATA_RESERVED\defaultHwndName+" = "+Str(gMMB_DATA_RESERVED\delayTime),#SS_CENTER) 
          exstyle = GetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE)    
          SetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE, exstyle | #WS_EX_NOPARENTNOTIFY) 
            
          ; Seconds remaining text background brush 
          If Not ThemesEnabled() 
            gMMB_DATA_RESERVED\timingBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID)) 
          Else 
            GetWindowRect_(GadgetID(gMMB_DATA_RESERVED\textGadgetID), @wr.RECT) 
            MapWindowPoints_(0,gMMB_DATA_RESERVED\hwndMain,@wr,2) 
            gMMB_DATA_RESERVED\timingBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID,#PB_Any,wr\left,wr\top,gMMB_DATA_RESERVED\cx-wr\left,wr\bottom-wr\top)      
            gMMB_DATA_RESERVED\timingBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\timingBkImageID)) 
          EndIf 
          
          ; Start the countdown timer 
          If Not IsThread(gMMB_DATA_RESERVED\timerThreadID)          
            gMMB_DATA_RESERVED\timerThreadID = CreateThread(@MMB_TimerThread(), gMMB_DATA_RESERVED\delayTime) 
          EndIf 
        EndIf 
        
        ProcedureReturn 0 
      EndIf 
      
  EndSelect 
  
  ProcedureReturn CallNextHookEx_(mmb_Hook, nCode, wParam, lParam) 
  
 EndProcedure 

ProcedureDLL.l ManagedMessageBox(title$, text$, *mmb_data_in.MMBDATA, flags=0) 

  With gMMB_DATA_RESERVED 
    \x               = *mmb_data_in\x          
    \y               = *mmb_data_in\y              
    \bkContent       = *mmb_data_in\bkContent      
    \bkContentType   = *mmb_data_in\bkContentType    
    \txtColor        = *mmb_data_in\txtColor      
    \bannerImage     = *mmb_data_in\bannerImage 
    \delayTime       = *mmb_data_in\delayTime        
    \defaultButton   = *mmb_data_in\defaultButton    
    \modalLevel      = *mmb_data_in\modalLevel      
    \silent          = *mmb_data_in\silent 
    \hwndMain        = 0 
    \hwndIcon        = 0 
    \timerThreadID   = 0 
    \textGadgetID    = 0    
    \defaultHwnd     = 0      
    \defaultCtrlID   = 0 
    \defaultHwndName = "" 
    \staticBrush     = 0 
    \timingBrush     = 0 
    \iconBrush       = 0  
    \bkImageID       = 0 
    \staticBkImageID = 0 
    \timingBkImageID = 0        
    \iconBkImageID   = 0 
    \cx              = 0 
    \cy              = 0 
  EndWith 
  
  If gMMB_DATA_RESERVED\delayTime 
    gMMB_DATA_RESERVED\modalLevel = 1 
  EndIf 
  
  Select gMMB_DATA_RESERVED\defaultButton 
    Case 0 
      gMMB_DATA_RESERVED\defaultButton = 1 
      flags = flags|#MB_DEFBUTTON1 
    Case 2 
      flags = flags|#MB_DEFBUTTON2 
    Case 3 
      flags = flags|#MB_DEFBUTTON3 
    Default 
      flags = flags|#MB_DEFBUTTON1 
  EndSelect 
  If gMMB_DATA_RESERVED\BkContent 
    If Not gMMB_DATA_RESERVED\BkContentType 
      gMMB_DATA_RESERVED\BkContentType = #MMB_COLOR 
    EndIf 
  EndIf  
  If gMMB_DATA_RESERVED\modalLevel 
    flags = flags | #MB_SYSTEMMODAL 
  EndIf 
  If gMMB_DATA_RESERVED\silent 
    flags = flags | $C0 
  EndIf 
  mmb_Hook = SetWindowsHookEx_(#WH_CBT, @MMB_CBTHookProc(), #Null, GetCurrentThreadId_()) 
  result = MessageBox_(0, text$, title$, flags) 
  If mmb_ForcedResult 
    result = gMMB_DATA_RESERVED\defaultCtrlID 
    mmb_ForcedResult = 0 
  EndIf 
  
  ProcedureReturn result 
  
EndProcedure 

; Little test
; Here we will make the box come out at location 200,100 on your desktop
; We place a custom banner image and a custom background image
; The messagebox will time out at ten seconds

LoadFont(0, "comic sans", 20, #PB_Font_Bold)
CreateImage(11, 400,200,24,#White)
CreateImage(22, 400,60,24,#Blue)
StartDrawing(ImageOutput(22))
DrawingFont(FontID(0))
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(110,16,"Banner Text",#Black,#Blue)
DrawText(106,12,"Banner Text",#Yellow,#Blue)
StopDrawing()


With this.MMBDATA
  \bkContenttype=#MMB_IMAGE
  \bkContent=11
  \bkImageID=ImageID(11)
  \bannerImage=22
  \x=200
  \y=100
  \delayTime=10
EndWith

ManagedMessageBox("Notice", "Important message; Hickory Dickery Dock, and all that.",this.MMBDATA) 

BERESHEIT
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4941
Joined: Sun Apr 12, 2009 6:27 am

Re: Managed MessageBox 2.0

Post by RASHAD »

Hi NM :)
Glad to know that you still have a sharp mind as always :)
Next is your missing snippet

Code: Select all

;=================================================================
; Library:           ManagedMessageBox 2.0
; Author:            Lloyd Gallant (netmaestro)
; Date:              January 9, 2008
; Target OS:         Microsoft Windows All
; Target Compiler:   PureBasic 4.0 and later
; License:           Free, unrestricted, no warranty
;
; Last Update:       June 6, 2008
;
; Usage: Filling the MMMBDATA structure
;
; Use only the programmer-selectable options. All fields are optional.
; If you do not fill x and y for a screenposition, the messagebox will
; be screencentered.
;
; #MMB_ Constant usage:
;
;   If you do not fill bkContentType (or use #MMB_NOBACKGROUND) no special
;   background options will be applied.
;
;   To have a background color, fill bkContent with a colorref and fill
;   bkContentType with #MMB_COLOR
;
;   To have a background image, fill bkContent with the #image you want to use
;   and fill bkContentType with #MMB_IMAGE.
;
;   To have a logo banner, fill bannerImage with the #image you want for a banner
;
;   #MMB_TEST is a special case. If you have a text in mind for the messagebox
;   and you would like to have a background image, it is useful to know what
;   size the client area of the message box will be. If you fill bkContentType
;   with #MMB_TEST, the caption of the message box will be ignored and it will
;   show the width And height. You'd only do this during development so you can
;   easily create a nice image the right size for the message box.
;
; txtColor: Put a colorref here if a text color other than black is desired.
;
; delayTime: Leave at 0 for a non-timed message box or put a number of seconds
; to wait before the default button is auto-selected.
;
; defaultButton: choose from a 1-based enumeration of the buttons on your
; messagebox. For example, if your flags are #MB_ABORTRETRYIGNORE, you will
; have three buttons. Filling defaultButton with 2 will make RETRY the default
; choice.
;
; modalLevel: For normal application modality, leave at 0. For system-level
; modality (the box will never allow itself to be minimized), fill with 1.
;
; silent: Not for use in icon message boxes (like #MB_ICONERROR, etc.), this
; flag will remove the "ding" sound made when the message box appears. Fill with
; 0 for normal sound or 1 to suppress the ding.
;
; You should compile ThreadSafe if using this library.
;
; Enjoy it!
;
;=================================================================

#MMB_NOBACKGROUND = 0
#MMB_COLOR        = 2
#MMB_IMAGE        = 4
#MMB_BANNER       = 8
#MMB_TEST         = 16

Structure MMBDATA
  ;-------------------------------------------------
  ;    Programmer-Selectable Options
  ;-------------------------------------------------
  x.l               ; In, desired x position on screen
  y.l               ; In, desired y position on screen
  bkContent.l       ; In, long value representing imageid or colorref depending on type
  bkContentType.b   ; In, specifies whether bkContent is an image or a colorref
  txtColor.l        ; In, specifies desired text color for message box
  bannerImage.l     ; In, specifies a #Image to use as a banner
  delayTime.l       ; In, specifies number of seconds to wait before auto-clicking the default button
  defaultButton.l   ; In, specifies the default button
  modalLevel.b      ; In, specifiels modality desired
  silent.b          ; In, specifies no "ding" when messagebox appears. Only for non-icon messageboxes.
                    ;-------------------------------------------------
                    ;    Variables for Internal Use Only
                    ;-------------------------------------------------
  hwndMain.l        ; reserved, do not use
  hwndIcon.l        ; reserved, do not use
  timerThreadID.l   ; reserved, do not use
  textGadgetID.l    ; reserved, do not use
  defaultHwnd.l     ; reserved, do not use
  defaultCtrlID.l   ; reserved, do not use
  defaultHwndName.s ; reserved, do not use
  staticBrush.l     ; reserved, do not use
  timingBrush.l     ; reserved, do not use
  bkImageID.l       ; reserved, do not use 
  timingBkImageID.l ; reserved, do not use
  iconBkImageID.l   ; reserved, do not use
  iconBrush.l       ; reserved, do not use
  staticBkImageID.l ; reserved, do not use
  cx.l              ; reserved, do not use
  cy.l              ; reserved, do not use
EndStructure

Global mmb_Hook, gMMB_DATA_RESERVED.MMBDATA , mmb_ForcedResult=0

Procedure MMB_dlgProc(hwnd, msg, wparam, lparam)
  oldproc = GetProp_(hwnd, "oldproc")
  Select msg
      
    Case #WM_CLOSE
      DestroyWindow_(hwnd)
      mmb_ForcedResult = 1
      
    Case #WM_CTLCOLORSTATIC
      
      SetBkMode_(wparam, #TRANSPARENT)
      SetTextColor_(wParam, gMMB_DATA_RESERVED\txtColor)
      
      Select GetDlgCtrlID_(lparam)
        Case $FFFF
          ProcedureReturn gMMB_DATA_RESERVED\staticBrush
          
        Case gMMB_DATA_RESERVED\textGadgetID
          ProcedureReturn gMMB_DATA_RESERVED\timingBrush
          
        Case GetDlgCtrlID_(gMMB_DATA_RESERVED\hwndIcon)
          ProcedureReturn gMMB_DATA_RESERVED\iconBrush
          
      EndSelect
      
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")
      
      DeleteObject_(gMMB_DATA_RESERVED\staticBrush)
      
      If gMMB_DATA_RESERVED\delayTime
        DeleteObject_(gMMB_DATA_RESERVED\timingBrush)
        If gMMB_DATA_RESERVED\timingBkImageID
          If IsImage(gMMB_DATA_RESERVED\timingBkImageID)
            FreeImage(gMMB_DATA_RESERVED\timingBkImageID)
          EndIf
        EndIf
      EndIf
      
      If gMMB_DATA_RESERVED\bkImageID
        If IsImage(gMMB_DATA_RESERVED\bkImageID)
          FreeImage(gMMB_DATA_RESERVED\bkImageID)
        EndIf
      EndIf
      
      If gMMB_DATA_RESERVED\staticBkImageID
        If IsImage(gMMB_DATA_RESERVED\staticBkImageID)
          FreeImage(gMMB_DATA_RESERVED\staticBkImageID)
        EndIf
      EndIf     
      
      If gMMB_DATA_RESERVED\iconBkImageID
        DeleteObject_(gMMB_DATA_RESERVED\iconBrush)
        If IsImage(gMMB_DATA_RESERVED\iconBkImageID)
          FreeImage(gMMB_DATA_RESERVED\iconBkImageID)
        EndIf
      EndIf     
      
      If gMMB_DATA_RESERVED\timerThreadID
        If IsThread(gMMB_DATA_RESERVED\timerThreadID)
          KillThread(gMMB_DATA_RESERVED\timerThreadID)
        EndIf
      EndIf
      
      If gMMB_DATA_RESERVED\textGadgetID
        If IsGadget(gMMB_DATA_RESERVED\textGadgetID)
          FreeGadget(gMMB_DATA_RESERVED\textGadgetID)
        EndIf
      EndIf
      
  EndSelect
  
  ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
  
EndProcedure

Procedure MMB_GetDefaultHwnd(hwnd, lparam)
  Static buttoncount = 0
  If lparam = -1
    buttoncount = 0
    ProcedureReturn 0
  EndIf
  wc$ = Space(255)
  GetClassName_(hwnd, @wc$, 250)
  If UCase(wc$) = "BUTTON"
    buttoncount+1
    If buttoncount = gMMB_DATA_RESERVED\defaultButton
      gMMB_DATA_RESERVED\defaultHwnd = hwnd
      gMMB_DATA_RESERVED\defaultCtrlID = GetDlgCtrlID_(hwnd)
      GetWindowText_(hwnd, @wc$,250)
      gMMB_DATA_RESERVED\defaultHwndName = RemoveString(wc$,"&")
      ProcedureReturn 0
    EndIf
  EndIf
  ProcedureReturn 1
EndProcedure

Procedure MMB_TimerThread(secondsremaining)
  t=ElapsedMilliseconds()
  Repeat
    Delay(1000)
    secondsremaining-1
    SetGadgetText(gMMB_DATA_RESERVED\textGadgetID, gMMB_DATA_RESERVED\defaultHwndName+" = "+Str(secondsremaining))
  Until secondsremaining <=0
  PostMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_HOTKEY, gMMB_DATA_RESERVED\hwndmain)
  Delay(200)
  PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONDOWN,0,0)
  Delay(200)
  PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONUP,0,0)
  Delay(200)
  If IsWindow_(gMMB_DATA_RESERVED\hwndmain)
    SendMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_CLOSE, 0)
  EndIf
EndProcedure

Procedure ThemesEnabled()
  dlv.DLLVERSIONINFO
  dlv\cbsize=SizeOf(DLLVERSIONINFO)
  lib=OpenLibrary(#PB_Any,"comctl32.dll")
  If lib
    CallFunction(lib,"DllGetVersion",@dlv)
    DLLVersion = dlv\dwMajorVersion
    CloseLibrary(lib)
  EndIf
  If DLLVersion = 6
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure MMB_CBTHookProc(nCode, wParam, lParam)
  
  Static hwndmain
  Select nCode
      
    Case #HCBT_CREATEWND
      *pcbt.CBT_CREATEWND = lParam
      *pcs.CREATESTRUCT = *pcbt\lpcs
      
      Select *pcs\lpszClass
          
        Case 32770  ; Dialog Window
          hwndmain = wParam
          gMMB_DATA_RESERVED\hwndmain = wParam
          
          If Not (gMMB_DATA_RESERVED\x=0 And gMMB_DATA_RESERVED\y=0)
            *pcs\x = gMMB_DATA_RESERVED\x   
            *pcs\y = gMMB_DATA_RESERVED\y
          EndIf   
          If gMMB_DATA_RESERVED\delayTime
            *pcs\cy + 20
          EndIf
          If gMMB_DATA_RESERVED\bannerImage
            *pcs\cy + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
          EndIf         
          gMMB_DATA_RESERVED\cx = *pcs\cx - 2*GetSystemMetrics_(#SM_CXFIXEDFRAME)
          gMMB_DATA_RESERVED\cy = *pcs\cy - 2*GetSystemMetrics_(#SM_CYFIXEDFRAME)-GetSystemMetrics_(#SM_CYCAPTION)
          SetProp_(wparam, "oldproc", SetWindowLong_(wparam,#GWL_WNDPROC,@MMB_dlgProc()))
          
        Case 49177 ; Static Control
          If GetWindowLong_(wParam, #GWL_STYLE) & #SS_BITMAP
            gMMB_DATA_RESERVED\hwndIcon = wParam
          EndIf
          
          If gMMB_DATA_RESERVED\bannerImage
            *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
          EndIf       
          
        Default
          If gMMB_DATA_RESERVED\bannerImage
            *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
          EndIf
          
      EndSelect
      
    Case #HCBT_ACTIVATE
      
      If wParam = hwndmain
        
        UnhookWindowsHookEx_(mmb_Hook)
        
        MMB_GetDefaultHwnd(0, -1) ; clear the static buttoncount var before enumerating the controls
        EnumChildWindows_(hwndmain, @MMB_GetDefaultHwnd(), 0)
        
        Select gMMB_DATA_RESERVED\bkContentType
            
          Case #MMB_COLOR
            img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
            StartDrawing(ImageOutput(img))
            Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, gMMB_DATA_RESERVED\bkContent)
            StopDrawing()
            gMMB_DATA_RESERVED\bkImageID = img
            
          Case #MMB_IMAGE
            If IsImage(gMMB_DATA_RESERVED\bkContent)
              tmp = CopyImage(gMMB_DATA_RESERVED\bkContent, #PB_Any)
              ResizeImage(tmp,gMMB_DATA_RESERVED\cx,gMMB_DATA_RESERVED\cy)
              gMMB_DATA_RESERVED\bkImageID = tmp
            Else
              gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
              StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
              Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
              StopDrawing()
            EndIf
            
          Case #MMB_TEST
            img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
            StartDrawing(ImageOutput(img))
            Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
            StopDrawing()       
            gMMB_DATA_RESERVED\bkImageID = img 
            tmp$ = "w"+Str(gMMB_DATA_RESERVED\cx)+",h"+Str(gMMB_DATA_RESERVED\cy)
            SetWindowText_(hwndmain, @tmp$)
            
          Case #MMB_NOBACKGROUND
            gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
            StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
            Box(0,0,gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
            StopDrawing()
            
        EndSelect
        
        If gMMB_DATA_RESERVED\bannerImage
          ; Create left and right extension brushes
          lbrush = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any,0,0,1,ImageHeight(gMMB_DATA_RESERVED\bannerImage))
          rbrush = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any,ImageWidth(gMMB_DATA_RESERVED\bannerImage)-1,0,1,ImageHeight(gMMB_DATA_RESERVED\bannerImage))
          leftbrush = CreatePatternBrush_(ImageID(lbrush))
          rightbrush = CreatePatternBrush_(ImageID(rbrush))
          
          ; Create and draw the banner image
          banner = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, ImageHeight(gMMB_DATA_RESERVED\bannerImage), #PB_Image_DisplayFormat)
          lpos = ImageWidth(banner)/2 - ImageWidth(gMMB_DATA_RESERVED\bannerImage)/2
          rpos = lpos + ImageWidth(gMMB_DATA_RESERVED\bannerImage)
          With lbr.RECT
            \left=0 : \top=0 : \right=lpos : \bottom=ImageHeight(gMMB_DATA_RESERVED\bannerImage)
          EndWith
          With rbr.RECT
            \left=rpos : \top=0 : \right=ImageWidth(banner) : \bottom=ImageHeight(gMMB_DATA_RESERVED\bannerImage)
          EndWith
          hdc = StartDrawing(ImageOutput(banner))
          FillRect_(hdc, lbr, leftbrush)
          FillRect_(hdc, rbr, rightbrush)
          DrawImage(ImageID(gMMB_DATA_RESERVED\bannerImage),lpos,0)
          Line(0,0,ImageWidth(banner)-1,0,RGB(157,157,161))
          Line(0,0,0,ImageHeight(banner)-1,RGB(157,157,161))
          Line(1,1,ImageWidth(banner)-3,0,RGB(113,111,100))
          Line(1,1,0,ImageHeight(banner)-3,RGB(113,111,100))
          Line(ImageWidth(banner)-1,0,0,ImageHeight(banner),#White)
          Line(0,ImageHeight(banner)-1,ImageWidth(banner),0,#White)
          Line(ImageWidth(banner)-2,1,0,ImageHeight(banner)-2,RGB(241,239,226))
          Line(1,ImageHeight(banner)-2,ImageWidth(banner)-2,0,RGB(241,239,226))
          StopDrawing()
          DeleteObject_(leftbrush)
          DeleteObject_(rightbrush)
          FreeImage(lbrush)
          FreeImage(rbrush) 
          StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
          DrawImage(ImageID(banner),0,0)
          StopDrawing()
          FreeImage(banner)     
        EndIf
        
        CompilerIf #PB_Compiler_Version < 430
          CreateGadgetList(wParam)
        CompilerElse
          UseGadgetList(wParam)
        CompilerEndIf
        ig = ImageGadget(#PB_Any, 0,0,0,0,ImageID(gMMB_DATA_RESERVED\bkImageID))
        SetWindowPos_(GadgetID(ig), #HWND_BOTTOM,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE)
        SetWindowLong_(GadgetID(ig),#GWL_STYLE,GetWindowLong_(GadgetID(ig),#GWL_STYLE)|#WS_CLIPSIBLINGS)
        DisableGadget(ig, #True)
        
        ; Icon background brush
        If gMMB_DATA_RESERVED\hwndIcon
          If Not ThemesEnabled()
            gMMB_DATA_RESERVED\iconBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
          Else
            GetWindowRect_(gMMB_DATA_RESERVED\hwndIcon, wr.RECT)
            MapWindowPoints_(0, gMMB_DATA_RESERVED\hwndMain, wr, 2)
            gMMB_DATA_RESERVED\iconBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID, #PB_Any,wr\left,wr\top,wr\right-wr\left,wr\bottom-wr\top)
            gMMB_DATA_RESERVED\iconBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\iconBkImageID))
          EndIf
        EndIf
        
        ; Messagebox text background brush
        If Not ThemesEnabled()
          gMMB_DATA_RESERVED\staticBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
        Else
          GetWindowRect_(GetDlgItem_(wparam, $FFFF), @wr.RECT)
          MapWindowPoints_(0,gMMB_DATA_RESERVED\hwndMain,@wr,2)
          gMMB_DATA_RESERVED\staticBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID,#PB_Any,wr\left,wr\top,gMMB_DATA_RESERVED\cx-wr\left,wr\bottom-wr\top)     
          gMMB_DATA_RESERVED\staticBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\staticBkImageID))
        EndIf
        
        If gMMB_DATA_RESERVED\delayTime
          gMMB_DATA_RESERVED\textGadgetID = TextGadget(#PB_Any, 0,gMMB_DATA_RESERVED\cy-22,gMMB_DATA_RESERVED\cx,20, gMMB_DATA_RESERVED\defaultHwndName+" = "+Str(gMMB_DATA_RESERVED\delayTime),#SS_CENTER)
          exstyle = GetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE)   
          SetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE, exstyle | #WS_EX_NOPARENTNOTIFY)
          
          ; Seconds remaining text background brush
          If Not ThemesEnabled()
            gMMB_DATA_RESERVED\timingBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
          Else
            GetWindowRect_(GadgetID(gMMB_DATA_RESERVED\textGadgetID), @wr.RECT)
            MapWindowPoints_(0,gMMB_DATA_RESERVED\hwndMain,@wr,2)
            gMMB_DATA_RESERVED\timingBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID,#PB_Any,wr\left,wr\top,gMMB_DATA_RESERVED\cx-wr\left,wr\bottom-wr\top)     
            gMMB_DATA_RESERVED\timingBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\timingBkImageID))
          EndIf
          
          ; Start the countdown timer
          If Not IsThread(gMMB_DATA_RESERVED\timerThreadID)         
            gMMB_DATA_RESERVED\timerThreadID = CreateThread(@MMB_TimerThread(), gMMB_DATA_RESERVED\delayTime)
          EndIf
        EndIf
        
        ProcedureReturn 0
      EndIf
      
  EndSelect
  
  ProcedureReturn CallNextHookEx_(mmb_Hook, nCode, wParam, lParam)
  
EndProcedure

ProcedureDLL.l ManagedMessageBox(title$, text$, *mmb_data_in.MMBDATA, flags=0)
  
  With gMMB_DATA_RESERVED
    \x               = *mmb_data_in\x         
    \y               = *mmb_data_in\y             
    \bkContent       = *mmb_data_in\bkContent     
    \bkContentType   = *mmb_data_in\bkContentType   
    \txtColor        = *mmb_data_in\txtColor     
    \bannerImage     = *mmb_data_in\bannerImage
    \delayTime       = *mmb_data_in\delayTime       
    \defaultButton   = *mmb_data_in\defaultButton   
    \modalLevel      = *mmb_data_in\modalLevel     
    \silent          = *mmb_data_in\silent
    \hwndMain        = 0
    \hwndIcon        = 0
    \timerThreadID   = 0
    \textGadgetID    = 0   
    \defaultHwnd     = 0     
    \defaultCtrlID   = 0
    \defaultHwndName = ""
    \staticBrush     = 0
    \timingBrush     = 0
    \iconBrush       = 0 
    \bkImageID       = 0
    \staticBkImageID = 0
    \timingBkImageID = 0       
    \iconBkImageID   = 0
    \cx              = 0
    \cy              = 0
  EndWith
  
  If gMMB_DATA_RESERVED\delayTime
    gMMB_DATA_RESERVED\modalLevel = 1
  EndIf
  
  Select gMMB_DATA_RESERVED\defaultButton
    Case 0
      gMMB_DATA_RESERVED\defaultButton = 1
      flags = flags|#MB_DEFBUTTON1
    Case 2
      flags = flags|#MB_DEFBUTTON2
    Case 3
      flags = flags|#MB_DEFBUTTON3
    Default
      flags = flags|#MB_DEFBUTTON1
  EndSelect
  If gMMB_DATA_RESERVED\BkContent
    If Not gMMB_DATA_RESERVED\BkContentType
      gMMB_DATA_RESERVED\BkContentType = #MMB_COLOR
    EndIf
  EndIf 
  If gMMB_DATA_RESERVED\modalLevel
    flags = flags | #MB_SYSTEMMODAL
  EndIf
  If gMMB_DATA_RESERVED\silent
    flags = flags | $C0
  EndIf
  mmb_Hook = SetWindowsHookEx_(#WH_CBT, @MMB_CBTHookProc(), #Null, GetCurrentThreadId_())
  result = MessageBox_(0, text$, title$, flags)
  If mmb_ForcedResult
    result = gMMB_DATA_RESERVED\defaultCtrlID
    mmb_ForcedResult = 0
  EndIf
  
  ProcedureReturn result
  
EndProcedure

; Test program:
; Code:
; IncludeFile "ManagedMessageBox20.pbi"

myimage = CreateImage(#PB_Any,257,95) ; got the size using #MMB_TEST
StartDrawing(ImageOutput(myimage))
Box(0,0,257,95, #White)
Circle(257/2, 95/2, 90/2, RGB(235,245,235))
StopDrawing()

With mmb_data.MMBDATA
  \x = 100
  \y = 100
  \BkContent = myimage
  \BkContentType = #MMB_IMAGE
  \txtcolor = #Red
  \defaultButton = 2
  \delayTime = 5
  \modalLevel = 1
  \silent = 1
EndWith

Debug ManagedMessageBox("Announcement:", "Holy insect bites, Batman! It's the Green Hornet!", mmb_data, #MB_ABORTRETRYIGNORE )
Egypt my love
Mesa
Enthusiast
Enthusiast
Posts: 433
Joined: Fri Feb 24, 2012 10:19 am

Re: Managed MessageBox 2.0

Post by Mesa »

Hi, i've just made a module.

Code: Select all

;=================================================================
; Library:           ManagedMessageBox 2.0
; Author:            Lloyd Gallant (netmaestro)
; Date:              January 9, 2008
; Target OS:         Microsoft Windows All
; Target Compiler:   PureBasic 4.0 and later
; License:           Free, unrestricted, no warranty
;
; Last Update:       June 6, 2008
;
; Usage: Filling the MMMBDATA structure
;
; Use only the programmer-selectable options. All fields are optional.
; If you do not fill x and y for a screenposition, the messagebox will
; be screencentered.
;
; #MMB_ Constant usage:
;
;   If you do not fill bkContentType (or use #MMB_NOBACKGROUND) no special
;   background options will be applied.
;
;   To have a background color, fill bkContent with a colorref and fill
;   bkContentType with #MMB_COLOR
;
;   To have a background image, fill bkContent with the #image you want to use
;   and fill bkContentType with #MMB_IMAGE.
;
;   To have a logo banner, fill bannerImage with the #image you want for a banner
;
;   #MMB_TEST is a special case. If you have a text in mind for the messagebox
;   and you would like to have a background image, it is useful to know what
;   size the client area of the message box will be. If you fill bkContentType
;   with #MMB_TEST, the caption of the message box will be ignored and it will
;   show the width And height. You'd only do this during development so you can
;   easily create a nice image the right size for the message box.
;
; txtColor: Put a colorref here if a text color other than black is desired.
;
; delayTime: Leave at 0 for a non-timed message box or put a number of seconds
; to wait before the default button is auto-selected.
;
; defaultButton: choose from a 1-based enumeration of the buttons on your
; messagebox. For example, if your flags are #MB_ABORTRETRYIGNORE, you will
; have three buttons. Filling defaultButton with 2 will make RETRY the default
; choice.
;
; modalLevel: For normal application modality, leave at 0. For system-level
; modality (the box will never allow itself to be minimized), fill with 1.
;
; silent: Not for use in icon message boxes (like #MB_ICONERROR, etc.), this
; flag will remove the "ding" sound made when the message box appears. Fill with
; 0 for normal sound or 1 to suppress the ding.
;
; You should compile ThreadSafe if using this library.
;
; Enjoy it!
;
;=================================================================

;WINDOWS ONLY
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  
  ;- DeclareModule ManagedMessageBox
  DeclareModule ManagedMessageBox
    
    #MMB_NOBACKGROUND = 0
    #MMB_COLOR        = 2
    #MMB_IMAGE        = 4
    #MMB_BANNER       = 8
    #MMB_TEST         = 16
    
    Structure MMBDATA
      ;-------------------------------------------------
      ;    Programmer-Selectable Options
      ;-------------------------------------------------
      x.i               ; In, desired x position on screen
      y.i               ; In, desired y position on screen
      bkContent.i       ; In, long value representing imageid or colorref depending on type
      bkContentType.b   ; In, specifies whether bkContent is an image or a colorref
      txtColor.i        ; In, specifies desired text color for message box
      bannerImage.i     ; In, specifies a #Image to use as a banner
      delayTime.i       ; In, specifies number of seconds to wait before auto-clicking the default button
      defaultButton.i   ; In, specifies the default button
      modalLevel.b      ; In, specifiels modality desired
      silent.b          ; In, specifies no "ding" when messagebox appears. Only for non-icon messageboxes.
                        ;-------------------------------------------------
                        ;    Variables for Internal Use Only
                        ;-------------------------------------------------
      hwndMain.i        ; reserved, do not use
      hwndIcon.i        ; reserved, do not use
      timerThreadID.i   ; reserved, do not use
      textGadgetID.i    ; reserved, do not use
      defaultHwnd.i     ; reserved, do not use
      defaultCtrlID.i   ; reserved, do not use
      defaultHwndName.s ; reserved, do not use
      staticBrush.i     ; reserved, do not use
      timingBrush.i     ; reserved, do not use
      bkImageID.i       ; reserved, do not use
      timingBkImageID.i ; reserved, do not use
      iconBkImageID.i   ; reserved, do not use
      iconBrush.i       ; reserved, do not use
      staticBkImageID.i ; reserved, do not use
      cx.i              ; reserved, do not use
      cy.i              ; reserved, do not use
    EndStructure
    Declare.i ManagedMessageBox(title$, text$, *mmb_data_in.MMBDATA, flags = 0)
    Declare.i ManagedMessageBox2(title$, text$, x = 0, y = 0, defaultButton = 0, delayTime = 0, txtColor = 0,
                                 bkContent = 0, bkContentType = 0, bannerImage = 0, modalLevel = 0, silent = 0,
                                 flags = 0)
  EndDeclareModule
  
  Module ManagedMessageBox
    
    
    CompilerIf #PB_Compiler_Thread
    CompilerElse
      DebuggerWarning("You should compile ThreadSafe if using ManagedMessageBox module !")
      Debug "You should compile ThreadSafe if using ManagedMessageBox module !"
    CompilerEndIf
    
    
    
    
    
    Global mmb_Hook, gMMB_DATA_RESERVED.MMBDATA , mmb_ForcedResult = 0
    
    Procedure MMB_dlgProc(hwnd, msg, wparam, lparam)
      oldproc = GetProp_(hwnd, "oldproc")
      Select msg
          
        Case #WM_CLOSE
          DestroyWindow_(hwnd)
          mmb_ForcedResult = 1
          
        Case #WM_CTLCOLORSTATIC
          
          SetBkMode_(wparam, #TRANSPARENT)
          SetTextColor_(wParam, gMMB_DATA_RESERVED\txtColor)
          
          Select GetDlgCtrlID_(lparam)
            Case $FFFF
              ProcedureReturn gMMB_DATA_RESERVED\staticBrush
              
            Case gMMB_DATA_RESERVED\textGadgetID
              ProcedureReturn gMMB_DATA_RESERVED\timingBrush
              
            Case GetDlgCtrlID_(gMMB_DATA_RESERVED\hwndIcon)
              ProcedureReturn gMMB_DATA_RESERVED\iconBrush
              
          EndSelect
          
        Case #WM_NCDESTROY
          RemoveProp_(hwnd, "oldproc")
          
          DeleteObject_(gMMB_DATA_RESERVED\staticBrush)
          
          If gMMB_DATA_RESERVED\delayTime
            DeleteObject_(gMMB_DATA_RESERVED\timingBrush)
            If gMMB_DATA_RESERVED\timingBkImageID
              If IsImage(gMMB_DATA_RESERVED\timingBkImageID)
                FreeImage(gMMB_DATA_RESERVED\timingBkImageID)
              EndIf
            EndIf
          EndIf
          
          If gMMB_DATA_RESERVED\bkImageID
            If IsImage(gMMB_DATA_RESERVED\bkImageID)
              FreeImage(gMMB_DATA_RESERVED\bkImageID)
            EndIf
          EndIf
          
          If gMMB_DATA_RESERVED\staticBkImageID
            If IsImage(gMMB_DATA_RESERVED\staticBkImageID)
              FreeImage(gMMB_DATA_RESERVED\staticBkImageID)
            EndIf
          EndIf
          
          If gMMB_DATA_RESERVED\iconBkImageID
            DeleteObject_(gMMB_DATA_RESERVED\iconBrush)
            If IsImage(gMMB_DATA_RESERVED\iconBkImageID)
              FreeImage(gMMB_DATA_RESERVED\iconBkImageID)
            EndIf
          EndIf
          
          If gMMB_DATA_RESERVED\timerThreadID
            If IsThread(gMMB_DATA_RESERVED\timerThreadID)
              KillThread(gMMB_DATA_RESERVED\timerThreadID)
            EndIf
          EndIf
          
          If gMMB_DATA_RESERVED\textGadgetID
            If IsGadget(gMMB_DATA_RESERVED\textGadgetID)
              FreeGadget(gMMB_DATA_RESERVED\textGadgetID)
            EndIf
          EndIf
          
      EndSelect
      
      ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
      
    EndProcedure
    
    Procedure MMB_GetDefaultHwnd(hwnd, lparam)
      Static buttoncount = 0
      If lparam = -1
        buttoncount = 0
        ProcedureReturn 0
      EndIf
      wc$ = Space(255)
      GetClassName_(hwnd, @wc$, 250)
      If UCase(wc$) = "BUTTON"
        buttoncount + 1
        If buttoncount = gMMB_DATA_RESERVED\defaultButton
          gMMB_DATA_RESERVED\defaultHwnd   = hwnd
          gMMB_DATA_RESERVED\defaultCtrlID = GetDlgCtrlID_(hwnd)
          GetWindowText_(hwnd, @wc$, 250)
          gMMB_DATA_RESERVED\defaultHwndName = RemoveString(wc$, "&")
          ProcedureReturn 0
        EndIf
      EndIf
      ProcedureReturn 1
    EndProcedure
    
    Procedure MMB_TimerThread(secondsremaining)
      t = ElapsedMilliseconds()
      Repeat
        Delay(1000)
        secondsremaining - 1
        SetGadgetText(gMMB_DATA_RESERVED\textGadgetID, gMMB_DATA_RESERVED\defaultHwndName + " = " + Str(secondsremaining))
      Until secondsremaining <= 0
      PostMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_HOTKEY, gMMB_DATA_RESERVED\hwndmain)
      Delay(200)
      PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONDOWN, 0, 0)
      Delay(200)
      PostMessage_(gMMB_DATA_RESERVED\defaultHwnd, #WM_LBUTTONUP, 0, 0)
      Delay(200)
      If IsWindow_(gMMB_DATA_RESERVED\hwndmain)
        SendMessage_(gMMB_DATA_RESERVED\hwndmain, #WM_SYSCOMMAND, #SC_CLOSE, 0)
      EndIf
    EndProcedure
    
    Procedure ThemesEnabled()
      dlv.DLLVERSIONINFO
      dlv\cbsize = SizeOf(DLLVERSIONINFO)
      lib        = OpenLibrary(#PB_Any, "comctl32.dll")
      If lib
        CallFunction(lib, "DllGetVersion", @dlv)
        DLLVersion = dlv\dwMajorVersion
        CloseLibrary(lib)
      EndIf
      If DLLVersion = 6
        ProcedureReturn 1
      Else
        ProcedureReturn 0
      EndIf
    EndProcedure
    
    Procedure MMB_CBTHookProc(nCode, wParam, lParam)
      
      Static hwndmain
      Select nCode
          
        Case #HCBT_CREATEWND
          *pcbt.CBT_CREATEWND = lParam
          *pcs.CREATESTRUCT   = *pcbt\lpcs
          
          Select *pcs\lpszClass
              
            Case 32770  ; Dialog Window
              hwndmain                    = wParam
              gMMB_DATA_RESERVED\hwndmain = wParam
              
              If Not (gMMB_DATA_RESERVED\x = 0 And gMMB_DATA_RESERVED\y = 0)
                *pcs\x = gMMB_DATA_RESERVED\x
                *pcs\y = gMMB_DATA_RESERVED\y
              EndIf
              If gMMB_DATA_RESERVED\delayTime
                *pcs\cy + 20
              EndIf
              If gMMB_DATA_RESERVED\bannerImage
                *pcs\cy + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
              EndIf
              gMMB_DATA_RESERVED\cx = *pcs\cx - 2*GetSystemMetrics_(#SM_CXFIXEDFRAME)
              gMMB_DATA_RESERVED\cy = *pcs\cy - 2*GetSystemMetrics_(#SM_CYFIXEDFRAME) - GetSystemMetrics_(#SM_CYCAPTION)
              SetProp_(wparam, "oldproc", SetWindowLong_(wparam, #GWL_WNDPROC, @MMB_dlgProc()))
              
            Case 49177 ; Static Control
              If GetWindowLong_(wParam, #GWL_STYLE) & #SS_BITMAP
                gMMB_DATA_RESERVED\hwndIcon = wParam
              EndIf
              
              If gMMB_DATA_RESERVED\bannerImage
                *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
              EndIf
              
            Default
              If gMMB_DATA_RESERVED\bannerImage
                *pcs\y + ImageHeight(gMMB_DATA_RESERVED\bannerImage)
              EndIf
              
          EndSelect
          
        Case #HCBT_ACTIVATE
          
          If wParam = hwndmain
            
            UnhookWindowsHookEx_(mmb_Hook)
            
            MMB_GetDefaultHwnd(0, - 1) ; clear the static buttoncount var before enumerating the controls
            EnumChildWindows_(hwndmain, @MMB_GetDefaultHwnd(), 0)
            
            Select gMMB_DATA_RESERVED\bkContentType
                
              Case #MMB_COLOR
                img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
                StartDrawing(ImageOutput(img))
                Box(0, 0, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, gMMB_DATA_RESERVED\bkContent)
                StopDrawing()
                gMMB_DATA_RESERVED\bkImageID = img
                
              Case #MMB_IMAGE
                If IsImage(gMMB_DATA_RESERVED\bkContent)
                  tmp = CopyImage(gMMB_DATA_RESERVED\bkContent, #PB_Any)
                  ResizeImage(tmp, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy)
                  gMMB_DATA_RESERVED\bkImageID = tmp
                Else
                  gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
                  StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
                  Box(0, 0, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
                  StopDrawing()
                EndIf
                
              Case #MMB_TEST
                img = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
                StartDrawing(ImageOutput(img))
                Box(0, 0, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
                StopDrawing()
                gMMB_DATA_RESERVED\bkImageID = img
                tmp$                         = "w" + Str(gMMB_DATA_RESERVED\cx) + ",h" + Str(gMMB_DATA_RESERVED\cy)
                SetWindowText_(hwndmain, @tmp$)
                
              Case #MMB_NOBACKGROUND
                gMMB_DATA_RESERVED\bkImageID = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, 32)
                StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
                Box(0, 0, gMMB_DATA_RESERVED\cx, gMMB_DATA_RESERVED\cy, GetSysColor_(#COLOR_BTNFACE))
                StopDrawing()
                
            EndSelect
            
            If gMMB_DATA_RESERVED\bannerImage
              ; Create left and right extension brushes
              lbrush     = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any, 0, 0, 1, ImageHeight(gMMB_DATA_RESERVED\bannerImage))
              rbrush     = GrabImage(gMMB_DATA_RESERVED\bannerImage, #PB_Any, ImageWidth(gMMB_DATA_RESERVED\bannerImage) - 1, 0, 1, ImageHeight(gMMB_DATA_RESERVED\bannerImage))
              leftbrush  = CreatePatternBrush_(ImageID(lbrush))
              rightbrush = CreatePatternBrush_(ImageID(rbrush))
              
              ; Create and draw the banner image
              banner = CreateImage(#PB_Any, gMMB_DATA_RESERVED\cx, ImageHeight(gMMB_DATA_RESERVED\bannerImage), #PB_Image_DisplayFormat)
              lpos   = ImageWidth(banner) / 2 - ImageWidth(gMMB_DATA_RESERVED\bannerImage) / 2
              rpos   = lpos + ImageWidth(gMMB_DATA_RESERVED\bannerImage)
              With lbr.RECT
                \left = 0 : \top = 0 : \right = lpos : \bottom = ImageHeight(gMMB_DATA_RESERVED\bannerImage)
              EndWith
              With rbr.RECT
                \left = rpos : \top = 0 : \right = ImageWidth(banner) : \bottom = ImageHeight(gMMB_DATA_RESERVED\bannerImage)
              EndWith
              hdc = StartDrawing(ImageOutput(banner))
              FillRect_(hdc, lbr, leftbrush)
              FillRect_(hdc, rbr, rightbrush)
              DrawImage(ImageID(gMMB_DATA_RESERVED\bannerImage), lpos, 0)
              Line(0, 0, ImageWidth(banner) - 1, 0, RGB(157, 157, 161))
              Line(0, 0, 0, ImageHeight(banner) - 1, RGB(157, 157, 161))
              Line(1, 1, ImageWidth(banner) - 3, 0, RGB(113, 111, 100))
              Line(1, 1, 0, ImageHeight(banner) - 3, RGB(113, 111, 100))
              Line(ImageWidth(banner) - 1, 0, 0, ImageHeight(banner), #White)
              Line(0, ImageHeight(banner) - 1, ImageWidth(banner), 0, #White)
              Line(ImageWidth(banner) - 2, 1, 0, ImageHeight(banner) - 2, RGB(241, 239, 226))
              Line(1, ImageHeight(banner) - 2, ImageWidth(banner) - 2, 0, RGB(241, 239, 226))
              StopDrawing()
              DeleteObject_(leftbrush)
              DeleteObject_(rightbrush)
              FreeImage(lbrush)
              FreeImage(rbrush)
              StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID))
              DrawImage(ImageID(banner), 0, 0)
              StopDrawing()
              FreeImage(banner)
            EndIf
            
            CompilerIf #PB_Compiler_Version < 430
              CreateGadgetList(wParam)
            CompilerElse
              UseGadgetList(wParam)
            CompilerEndIf
            ig = ImageGadget(#PB_Any, 0, 0, 0, 0, ImageID(gMMB_DATA_RESERVED\bkImageID))
            SetWindowPos_(GadgetID(ig), #HWND_BOTTOM, 0, 0, 0, 0, #SWP_NOMOVE | #SWP_NOSIZE)
            SetWindowLong_(GadgetID(ig), #GWL_STYLE, GetWindowLong_(GadgetID(ig), #GWL_STYLE) | #WS_CLIPSIBLINGS)
            DisableGadget(ig, #True)
            
            ; Icon background brush
            If gMMB_DATA_RESERVED\hwndIcon
              If Not ThemesEnabled()
                gMMB_DATA_RESERVED\iconBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
              Else
                GetWindowRect_(gMMB_DATA_RESERVED\hwndIcon, wr.RECT)
                MapWindowPoints_(0, gMMB_DATA_RESERVED\hwndMain, wr, 2)
                gMMB_DATA_RESERVED\iconBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID, #PB_Any, wr\left, wr\top, wr\right - wr\left, wr\bottom - wr\top)
                gMMB_DATA_RESERVED\iconBrush     = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\iconBkImageID))
              EndIf
            EndIf
            
            ; Messagebox text background brush
            If Not ThemesEnabled()
              gMMB_DATA_RESERVED\staticBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
            Else
              GetWindowRect_(GetDlgItem_(wparam, $FFFF), @wr.RECT)
              MapWindowPoints_(0, gMMB_DATA_RESERVED\hwndMain, @wr, 2)
              gMMB_DATA_RESERVED\staticBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID, #PB_Any, wr\left, wr\top, gMMB_DATA_RESERVED\cx - wr\left, wr\bottom - wr\top)
              gMMB_DATA_RESERVED\staticBrush     = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\staticBkImageID))
            EndIf
            
            If gMMB_DATA_RESERVED\delayTime
              gMMB_DATA_RESERVED\textGadgetID = TextGadget(#PB_Any, 0, gMMB_DATA_RESERVED\cy - 22, gMMB_DATA_RESERVED\cx, 20, gMMB_DATA_RESERVED\defaultHwndName + " = " + Str(gMMB_DATA_RESERVED\delayTime), #SS_CENTER)
              exstyle                         = GetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE)
              SetWindowLong_(gMMB_DATA_RESERVED\textGadgetID, #GWL_EXSTYLE, exstyle | #WS_EX_NOPARENTNOTIFY)
              
              ; Seconds remaining text background brush
              If Not ThemesEnabled()
                gMMB_DATA_RESERVED\timingBrush = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\bkImageID))
              Else
                GetWindowRect_(GadgetID(gMMB_DATA_RESERVED\textGadgetID), @wr.RECT)
                MapWindowPoints_(0, gMMB_DATA_RESERVED\hwndMain, @wr, 2)
                gMMB_DATA_RESERVED\timingBkImageID = GrabImage(gMMB_DATA_RESERVED\bkImageID, #PB_Any, wr\left, wr\top, gMMB_DATA_RESERVED\cx - wr\left, wr\bottom - wr\top)
                gMMB_DATA_RESERVED\timingBrush     = CreatePatternBrush_(ImageID(gMMB_DATA_RESERVED\timingBkImageID))
              EndIf
              
              ; Start the countdown timer
              If Not IsThread(gMMB_DATA_RESERVED\timerThreadID)
                gMMB_DATA_RESERVED\timerThreadID = CreateThread(@MMB_TimerThread(), gMMB_DATA_RESERVED\delayTime)
              EndIf
            EndIf
            
            ProcedureReturn 0
          EndIf
          
      EndSelect
      
      ProcedureReturn CallNextHookEx_(mmb_Hook, nCode, wParam, lParam)
      
    EndProcedure
    
    Procedure.i ManagedMessageBox(title$, text$, *mmb_data_in.MMBDATA, flags = 0)
      
      With gMMB_DATA_RESERVED
        \x               = *mmb_data_in\x
        \y               = *mmb_data_in\y
        \bkContent       = *mmb_data_in\bkContent
        \bkContentType   = *mmb_data_in\bkContentType
        \txtColor        = *mmb_data_in\txtColor
        \bannerImage     = *mmb_data_in\bannerImage
        \delayTime       = *mmb_data_in\delayTime
        \defaultButton   = *mmb_data_in\defaultButton
        \modalLevel      = *mmb_data_in\modalLevel
        \silent          = *mmb_data_in\silent
        \hwndMain        = 0
        \hwndIcon        = 0
        \timerThreadID   = 0
        \textGadgetID    = 0
        \defaultHwnd     = 0
        \defaultCtrlID   = 0
        \defaultHwndName = ""
        \staticBrush     = 0
        \timingBrush     = 0
        \iconBrush       = 0
        \bkImageID       = 0
        \staticBkImageID = 0
        \timingBkImageID = 0
        \iconBkImageID   = 0
        \cx              = 0
        \cy              = 0
      EndWith
      
      If gMMB_DATA_RESERVED\delayTime
        gMMB_DATA_RESERVED\modalLevel = 1
      EndIf
      
      Select gMMB_DATA_RESERVED\defaultButton
        Case 0
          gMMB_DATA_RESERVED\defaultButton = 1
          flags                            = flags | #MB_DEFBUTTON1
        Case 2
          flags = flags | #MB_DEFBUTTON2
        Case 3
          flags = flags | #MB_DEFBUTTON3
        Default
          flags = flags | #MB_DEFBUTTON1
      EndSelect
      If gMMB_DATA_RESERVED\BkContent
        If Not gMMB_DATA_RESERVED\BkContentType
          gMMB_DATA_RESERVED\BkContentType = #MMB_COLOR
        EndIf
      EndIf
      If gMMB_DATA_RESERVED\modalLevel
        flags = flags | #MB_SYSTEMMODAL
      EndIf
      If gMMB_DATA_RESERVED\silent
        flags = flags | $C0
      EndIf
      mmb_Hook = SetWindowsHookEx_(#WH_CBT, @MMB_CBTHookProc(), #Null, GetCurrentThreadId_())
      result   = MessageBox_(0, text$, title$, flags)
      If mmb_ForcedResult
        result           = gMMB_DATA_RESERVED\defaultCtrlID
        mmb_ForcedResult = 0
      EndIf
      
      ProcedureReturn result
      
    EndProcedure
    
    Procedure.i ManagedMessageBox2(title$, text$, x = 0, y = 0, defaultButton = 0, delayTime = 0, txtColor = 0,
                                   bkContent = 0, bkContentType = 0, bannerImage = 0, modalLevel = 0, silent = 0,
                                   flags = 0)
      With this.MMBDATA
        \bkContenttype = bkContenttype
        \bkContent     = bkContent
        \bkImageID     = bkImageID
        \bannerImage   = bannerImage
        \x             = x
        \y             = y
        \delayTime     = delayTime
        \defaultButton = defaultButton
        \modalLevel    = modalLevel
        \silent        = silent
        ManagedMessageBox(title$, text$, this.MMBDATA, flags)
      EndWith
      
      
    EndProcedure
    
  EndModule
  
CompilerElse
  DebuggerWarning("ManagedMessageBox module is WINDOWS ONLY !")
  Debug "ManagedMessageBox module is WINDOWS ONLY !"
CompilerEndIf

CompilerIf #PB_Compiler_IsMainFile
  ;- Test
  ; Little test
  ; Here we will make the box come out at location 200,100 on your desktop
  ; We place a custom banner image and a custom background image
  ; The messagebox will time out at ten seconds
  
  LoadFont(0, "comic sans", 20, #PB_Font_Bold)
  CreateImage(11, 400, 200, 24, #White)
  CreateImage(22, 400, 60, 24, #Blue)
  StartDrawing(ImageOutput(22))
  DrawingFont(FontID(0))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(110, 16, "Banner Text", #Black, #Blue)
  DrawText(106, 12, "Banner Text", #Yellow, #Blue)
  StopDrawing()
  
  UseModule ManagedMessageBox
  
  
  With this.MMBDATA
    \bkContenttype = #MMB_IMAGE
    \bkContent     = 11
    \bkImageID     = ImageID(11)
    \bannerImage   = 22
    \x             = 200
    \y             = 100
    \delayTime     = 10
  EndWith
  
  ManagedMessageBox("Notice", "Important message: Hickory Dickery Dock, and all that.", this.MMBDATA)
  ManagedMessageBox2("Notice2", "Important message2")
  ManagedMessageBox2("Notice3", "Important message3", 200, 200, 0, 5)
  ManagedMessageBox2("Notice4", "Important message: Hickory Dickery Dock, and all that.", 200, 100, 0, 10,0,11,#MMB_IMAGE,22)
CompilerEndIf

M.
Last edited by Mesa on Thu Apr 10, 2025 1:36 pm, edited 2 times in total.
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Managed MessageBox 2.0

Post by Caronte3D »

Nice! :D
P.D: Not working with x64 compiler?
BarryG
Addict
Addict
Posts: 4118
Joined: Thu Apr 18, 2019 8:17 am

Re: Managed MessageBox 2.0

Post by BarryG »

Confirmed that it doesn't compile on 6.10 x64 due to an image error on line 360:

Code: Select all

StartDrawing(ImageOutput(gMMB_DATA_RESERVED\bkImageID)) ; The specified #Image is not initialised.
Little John
Addict
Addict
Posts: 4770
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Managed MessageBox 2.0

Post by Little John »

Caronte3D wrote: Thu Apr 10, 2025 9:07 am P.D: Not working with x64 compiler?
Several variables are defined as Long, but should be defind as Integer, in oder to work on x64.
Mesa
Enthusiast
Enthusiast
Posts: 433
Joined: Fri Feb 24, 2012 10:19 am

Re: Managed MessageBox 2.0

Post by Mesa »

Module updated for x64.

M.
PBJim
Enthusiast
Enthusiast
Posts: 293
Joined: Fri Jan 19, 2024 11:56 pm

Re: Managed MessageBox 2.0

Post by PBJim »

Thanks for posting, Metmaestro, Mesa and other contributors.

I wondered — might this be a good basis for developing a non-blocking error dialogue box? For a system we're prototyping, I created dialogue boxes as windows, in order to allow the main event loop to continue and thus continue to update screen contents.

Your code is obviously creating the box at a lower lever, but it occurred to me that the code might lend itself well to the requirement. I appreciate you have a timeout, which is useful but not so good when you need processing to continue during the timeout period.
Post Reply