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)