Updated version - Now allowing changing icons and disabling buttons

lnOption = MsgboxEx( ;
   "You have entered a wrong password for 5 times.
" + chr(13) + ;
   "For security reasons this login was suspended.", ; && main message
   0, ; && default icon info
   "Password incorrect", ; && title bar caption
   "\&Retry,&Exit,Get &new pwd", ; && new button captions
   "41.ico") && icon file

 

 

 

This is a simple function that allows us to customize the captions of buttons of the messagebox() dialog window, like in the image shown above.

Thanks to Mike gagnon and Anatolyi Mogylevetz, here's an updated version of the version that allows to change the icon and also to disable the buttons.

Basically I followed Anatolyi's instructions to allow disabling the buttons. Changing the dialog icon was also very simple, with a short research in his great site - Using Win32 functions in Visual Foxpro .

I just adapted a sample provided by Craig Boyd in his blog article - Bindevent on steroids using the VFPEX.FLL that he created and kindly provided in that article. Please refer to the original article for more details.

I called it MSGBOXEX.PRG, and it can be used very simply, to obtain the result below - notice the 4th parameter, that contains the captions of the buttons to be used, delimited by a comma:

lnOption = MsgboxEx(;
   "An unexpected error has occurred and the system needs to be restarted." + ;
   chr(13) + chr(13) + "What do you want to do ?", ;
   "X", ;
   "MsgboxEx sample", ;
   "Restart &Now,Restart &later,&Never restart")

 

 

lnOption = MsgboxEx( ;
   "Could not find the file 'Import.csv' in the selected folder.", ;
   0, ;
   "File not found", ;
   "&Abort,\&Retry,Change folder", ;
   "17.ico")

 

 

function: MsgboxEx.prg

description: Modifies the captions of messagebox buttons

parameters:

  • tcCaption - the text that appears in the dialog box.
  • tnIcon - the icon sign - can be numeric, using the default messagebox() icon values or character:
       - stop sign: 16 or "x"
       - question mark: 32 or "?"
       - exclamation point: 48 or "!"
       - information: 64 or "i"
  • tcTitle - the text that appears in the title bar of the dialog box
  • tcButtons - the captions to be used in the buttons using the comma "," delimiter
    use the "&" character to determine the hotkeys to be used - eg: "option&1,option&2,option&3" - the "\" backslash can be used to show the current button disabled.
  • tcIconFile - (optional) the icon image file

returns: The index number according to the option selected - eg. returns the value 3 if the 3rd button was selected.

 

pros:

use the same dialog interface from the messagebox() function, allowing us to easilly customize existing dialog boxes.

almost the same structure of parameters of the original function

behaves correctly in all operating systems.

allows hotkeys (thanks to thiago takehana for reminding about this possibility)

 

cons:

up to 3 buttons are allowed

size of buttons is limited to the original messagebox() buttons size, not allowing big sized buttons.

 

lparameters tccaption, tnicon, tctitle, tcbuttons, tciconfile
* msgboxex.prg
* description: modifies the captions of messagebox buttons
* prerequisites: needs vfpex.fll by craigboyd
*
http://www.sweetpotatosoftware.com/spsblog/ct.ashx?id=f7644db8-b155-4d43-8216-4cfde233edb7&url=http%3a%2f%2fwww.sweetpotatosoftware.com%2ffiles%2fvfpex.zip
* more info about vfpex.fll
*
http://www.sweetpotatosoftware.com/spsblog/2005/08/07/bindeventonsteroids.aspx
* parameters:
* tccaption - the text that appears in the dialog box.
* tnicon - the icon sign
* tctitle - the text that appears in the title bar of the dialog box
* tcbuttons - the captions to be used in the buttons using the comma "," delimiter
* use the "&" character to determine the hotkeys to be used - eg: "option&1,option&2,option&3"
* use a "\" to disable the button
* tciconfile - the icon file to replace the default from messagebox()
* returns: the index number according to the option selected - eg. returns the value 3 if the 3rd button was selected.
* sample:
* =msgboxex("this is a common text", "!", "window title", "option1,option2,option3")
if vartype(tntimeout) = "C" and (pcount
() = 4)
   tcbuttons = tntimeout
   tntimeout = 0
endif

private pnbuttoncnt, pcbuttons, pnbutttype, pciconfile, phicon
pciconfile =
iif(empty
(tciconfile),"", tciconfile)
pnbuttoncnt =
getwordcount
(tcbuttons, ",")
pcbuttons = tcbuttons
*!* stop 16
*!* question 32
*!* exclamation 48
*!* info 64
if vartype
(tnicon) = "c"
   tnicon =
upper
(tnicon)
   do case
   case
tnicon = "X"
      tnicon = 16
   case
tnicon = "?"
      tnicon = 32
   case
tnicon = "!"
      tnicon = 48
   case
tnicon = "I"
      tnicon = 64
   otherwise
      tnicon = 0
   endcase
endif

* check if an icon will be shown
* if an icon file was passed, we need to ensure that messagebox() will
* show an icon, that will be changed further.

#define image_bitmap 0
#
define
image_icon 1
#
define
lr_loadfromfile 0x0010
#
define
lr_defaultsize 0x0040
phicon = 0
if not empty(pciconfile) and ;
   (not (bittest(tnicon, 4) or bittest(tnicon, 5) or bittest
(tnicon, 6)))
   tnicon = tnicon + 16
   phicon = xmbloadimage(0, fullpath(pciconfile), image_icon,;
0,0, lr_loadfromfile + lr_defaultsize)
endif


* windows hook constants
#define wh_cbt 5

* set library so bindeventex and unbindeventex can be used in vfp
local
lcoldsetlib
lcoldsetlib =
set
("library")
set library to (locfile
("vfpex.fll"))
bindeventex('wineventhandler()', wh_cbt)
&& setwindowshookex

* this messagebox will be modified before it is shown
local
lnoption, lnindex
do case
case
pnbuttoncnt = 1
   pnbutttype = 0
&& ok
case
pnbuttoncnt = 2
   pnbutttype = 4
&& yes / no
case
pnbuttoncnt = 3
   pnbutttype = 2
&& abort / retry / ignore
otherwise
endcase

lnoption = messagebox(tccaption, tnicon + pnbutttype, tctitle)

local lnoffset
lnoffset =
icase
(pnbuttoncnt = 3, 2, pnbuttoncnt = 2, 5 , 0)
lnindex = lnoption - lnoffset

if phicon <> 0
   =xmbdeleteobject(phicon) && clear icon handle
endif

if not empty(lcoldsetlib)
   set library to
(lcoldsetlib)
endif
return
lnindex


procedure wineventhandler
#
define
dlg_ctrlid_icon 0x0014
#
define
stm_seticon 0x0170
#
define
stm_setimage 0x0172
if ncode == 5
   if not empty(phicon
)
      * changing the dialog icon
      local
lhiconwindow
      lhiconwindow = xmbgetdlgitem(wparam, dlg_ctrlid_icon)
      if
lhiconwindow <> 0
         if
phicon <> 0
            =xmbsendmessage(lhiconwindow, stm_seticon, phicon, 0)
         endif
      endif
   endif

   * change button attributes
   local
n, lnoffset, lccaption
   lnoffset =
icase
(pnbuttoncnt = 3, 2, pnbuttoncnt = 2, 5 , 0)
   for n = 1 to
pnbuttoncnt
      lccaption =
getwordnum
(pcbuttons, n, ",")
      * disable current button
      if left
(lccaption, 1) = "\"
         lccaption =
substr(lccaption, 2)
&& get the rest of the string
         local
lnbtnhwnd
         lnbtnhwnd = xmbgetdlgitem(wparam, lnoffset + n)
         =xmbenablewindow(lnbtnhwnd, 0)
      endif

      * change the caption
      =xmbsetdlgitemtext(wparam, lnoffset + n, lccaption)
   endfor

   =xmbcallnexthookex(hhook, ncode, wparam, lparam) && all 4 variables exist
   unbindeventex()
else
   =xmbcallnexthookex(hhook, ncode, wparam, lparam)
&& all 4 variables created by fll
endif

release ncode, wparam, lparam, hhook
endproc

 

*********************************************************************
function
xmbsetdlgitemtext(hdlg, niddlgitem, lpstring)
*********************************************************************
declare integer SetDlgItemText in user32 as
xmbsetdlgitemtext ;
   long
hdlg,;
   long
niddlgitem,;
   string
lpstring
return
xmbsetdlgitemtext(hdlg, niddlgitem, lpstring)
endfunc

*********************************************************************
function
xmbcallnexthookex(hhook, ncode, wparam, lparam)
*********************************************************************
declare long CallNextHookEx in user32 as
xmbcallnexthookex ;
   long hhook, long ncode, long wparam, long
lparam
return
xmbcallnexthookex(hhook, ncode, wparam, lparam)
endfunc

*********************************************************************
function
xmbgetdlgitem(hdlg, niddlgitem)
*********************************************************************
* hdlg [in] handle to the dialog box that contains the control.
* niddlgitem [in] specifies the identifier of the control to be retrieved.
*
http://msdn.microsoft.com/en-us/library/ms645481(vs.85).aspx
declare integer GetDlgItem in user32 as xmbgetdlgitem ;
   long
hdlg,;
   long
niddlgitem
return
xmbgetdlgitem(hdlg, niddlgitem)
endfunc

*********************************************************************
function xmbenablewindow(hwnd
, fenable)
*********************************************************************
declare integer EnableWindow in user32 as xmbenablewindow integer hwnd, integer
fenable
return xmbenablewindow(hwnd
, fenable)
endfunc

*********************************************************************
function
xmbsendmessage(hwindow, msg, wparam, lparam)
*********************************************************************
*
http://msdn.microsoft.com/en-us/library/bb760780(vs.85).aspx
*
http://www.news2news.com/vfp/?group=-1&function=312
declare integer SendMessage in user32 as
xmbsendmessage;
   integer hwindow, integer
msg,;
   integer wparam, integer
lparam
return
xmbsendmessage(hwindow, msg, wparam, lparam)
endfunc

*********************************************************************
function
xmbloadimage(hinst, lpszname, utype, cxdesired, cydesired, fuload)
*********************************************************************
declare integer LoadImage in user32 as
xmbloadimage;
   integer
hinst,;
   string
lpszname,;
   integer
utype,;
   integer
cxdesired,;
   integer
cydesired,;
   integer
fuload
return
xmbloadimage(hinst, lpszname, utype, cxdesired, cydesired, fuload)
endfunc

 

*********************************************************************
function
xmbdeleteobject(hobject)
*********************************************************************
declare integer DeleteObject in gdi32 as xmbdeleteobject integer
hobject
return
xmbdeleteobject(hobject)
endfunc
 

download the vfpex.fll here, created by craig boyd, directly from the sps weblog.

download the MessageboxEx function  

History:

2009-10-19 original version (change captions)

2009-10-23 updated, allowing icon change and disabling buttons

 

8 Responses to Extended MessageBox function – Updated ! – change button captions, main icon, disable buttons

  • magicjack says:

    Very neat man, loving this. Keep up the great work.

  • John Koziol says:

    Nice VFP example.  Good to see the language extended.

    Thanks !

  • Anatoliy Mogylevets says:

    It is just a coincidence that I’m working on the same kind of extension to the MessageBox function. The difference is that I decided to put everything into an FLL, which I hope I will complete soon.

    The SetWindowsHookEx function does the trick. Once the hook is set, the creation of a window within the current VFP session becomes detectable. The MessageBox window has a distinctive class name, which is #32770, so it is possible to tell whether the new window is a dialog. Alas some other VFP dialogs, like GetPrinter(), share the same class name. That makes the detecting process just a bit more intricate.

    Once the MessageBox window gets detected and its Window procedure is re-routed, many of the settings can be adjusted before the dialog first appears on the screen.

    From my current experience, this is what can be tweaked:
    – initial position of the dialog and its dimensions
    – message font
    – dialog background color and/or pattern, and message font color
    – button captions
    – button fonts
    – button sizes
    – the dialog’s icon

    As far as I know, the background color and the font color of the MessageBox buttons cannot be changed just because the system prohibits such change for windows having the BS_PUSHBUTTON attribute.

    It is possible to customize the MessageBox dialog even further. And the choice between the further customization and between writing a custom-made MessageBox based on VFP form is never obvious.

    Hi Anatolyi,

    Thanks for your detailed comments. I’m a big fan of your work. Keep rock’n rolling ! Next step that I want to implement is to allow to disable some buttons, and also to show a timeout message, showing how much time it is left till the dialog will close.

    Regards

    Cesar

  • Anatoliy Mogylevets says:

    Hi Cesar,

    Once you obtain the HWND for the dialog, each button can be detected via calling the GetDlgItem() API. There are 11 different dialog buttons, and their CtrlIds coincidentally 🙂 are from 1 to 11. Disabling buttons can be done by calling the EnableWindow() API.

    Showing the elapsed time or the time left will probably be more difficult. First of all, a timer is required. Then it has to be decided on the way of displaying the time: creating a child static window, or may be just re-drawing the string on each timer tick.

    Anyway, I’m very glad that we can share ideas and experience. Thank you!

    Thanks again, I hope to play with these very soon. My pleasure to meet you here !

  • Allen Pollard says:

    nice, how about allowing a picture ?

    Hi Allen,

    As Anatoliy previously said, that’s totally possible too. But I’m not so sure if it’s worth the efforts. In my case, as I did not use a customized dialog form, I was looking for a quick alternative to change the captions of some of the buttons, in order to make it clearer for my users what options they have in every situation.

    Please have a look at the thread in Foxite forum – http://www.foxite.com/archives/0000243908.htm and have a look at Marat Chariev’s messages, showing what you can get using a custom dialog form. Very teasing pictures !

    Anyway, as an exercise I hope to allow changing the dialog icon for this too.

    Thanks for your comment !

  • dharm says:

    very nice .

  • Pingback: Extended Messagebox() function reviewed | | Foxite.COM Community Weblog - VFPIMAGINGFoxite.COM Community Weblog – VFPIMAGING

  • Edson says:

    It needs VC + + runtime.
    It worked on my computer but not on my client. I shame.

  • Leave a Reply

    Your email address will not be published. Required fields are marked *