Click here to Skip to main content
Email Password   helpLost your password?

Sample custom message box

Contents

Introduction

Sometime ago, I was musing about current user interface design trends. I had been doing a lot of development at that time and VSS was one frequently used app, I started thinking about the VSS message box, you know the one which has six buttons like "Replace", "Merge", "Leave" etc. and the "Apply to all items" checkbox. If we need to implement something like that today, we would have to roll our own message box for each such message box, well, that's just a waste of time. So I started thinking about a reusable message box that supported stuff like custom buttons, "Don't ask me again" feature, etc. I did find some articles about custom message boxes but most of them were implemented using hooks. Well, I didn't like that too much and would never use such solutions in a production environment. So I decided to create a message box from scratch and provide the functionality that I needed. I also wanted to expose the functionality in an easy to use manner. This article describes some of the hurdles and interesting things I discovered while implementing this custom message box. The source code accompanying this article implements a custom message box that:

The MessageBoxEx component can be used as is in your applications to show message boxes where the standard message box won't do. Also, it can be used as a starting point for creating your own custom message box.

What does it take to replicate the MessageBox?

Let's take a look at what all is required if you need to implement a message box that duplicates the functionality provided by default.

Size and Position

The message box dynamically resizes itself to best fit its content. The factors that determine the size of the message box are message text, caption text and number of buttons. Also, I discovered that it imposes some limits on its size, both horizontally and vertically. So no matter how long the text of the message box is, the message box will never extend beyond your screen area, in fact, it does not even come close to covering the entire screen area. The message box also displays itself in the center of the screen.

So we need to first determine the maximum size for the message box. This can be done by using the SystemInformation class.

_maxWidth = (int)(SystemInformation.WorkingArea.Width * 0.60);
_maxHeight = (int)(SystemInformation.WorkingArea.Height * 0.90);

So the message box has a max width of 60% of the screen width and max height of 90% of the screen height.

For fitting the size of the message box to its contents, we can make use of the Graphics.MeasureString() method.

/// <summary>

/// Measures a string using the Graphics object for this form with

/// the specified font

/// </summary>

/// <param name="str">The string to measure</param>

/// <param name="maxWidth">The maximum width

///          available to display the string</param>

/// <param name="font">The font with which to measure the string</param>

/// <returns></returns>

private Size MeasureString(string str, int maxWidth, Font font)
{
    Graphics g = this.CreateGraphics();
    SizeF strRectSizeF = g.MeasureString(str, font, maxWidth);
    g.Dispose();

    return new Size((int)Math.Ceiling(strRectSizeF.Width), 
               (int)Math.Ceiling(strRectSizeF.Height));
}

The above code is used to determine the size of the various elements in the message box. Once we have the size required by each of the elements, we determine the optimal size for the form and then layout all the elements in the form. The code for determining the optimal size is in the method MessageBoxExForm.SetOptimumSize(), and the code for laying out the various elements is in MessageBoxExForm.LayoutControls().

One interesting thing is that the font of the caption is determined by the system. Thus we cannot use the Form's Font property to measure the size of the caption string. To get the font of the caption, we can use the Win32 API SystemParametersInfo.

private Font GetCaptionFont()
{
    
    NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
    ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS));
    try
    {
        bool result = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 
                                           ncm.cbSize, ref ncm, 0);
    
        if(result)
        {
            return Font.FromLogFont(ncm.lfCaptionFont);
        }
        else
        {
            int lastError = Marshal.GetLastWin32Error();
            return null;
        }
    }
    catch(Exception /*ex*/)
    {
        //System.Console.WriteLine(ex.Message);

    }
    
    return null;
}

private const int SPI_GETNONCLIENTMETRICS = 41;
private const int LF_FACESIZE = 32;

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct LOGFONT
{ 
    public int lfHeight; 
    public int lfWidth; 
    public int lfEscapement; 
    public int lfOrientation; 
    public int lfWeight; 
    public byte lfItalic; 
    public byte lfUnderline; 
    public byte lfStrikeOut; 
    public byte lfCharSet; 
    public byte lfOutPrecision; 
    public byte lfClipPrecision; 
    public byte lfQuality; 
    public byte lfPitchAndFamily; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string lfFaceSize;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct NONCLIENTMETRICS
{
    public int cbSize;
    public int iBorderWidth;
    public int iScrollWidth;
    public int iScrollHeight;
    public int iCaptionWidth;
    public int iCaptionHeight;
    public LOGFONT lfCaptionFont;
    public int iSmCaptionWidth;
    public int iSmCaptionHeight;
    public LOGFONT lfSmCaptionFont;
    public int iMenuWidth;
    public int iMenuHeight;
    public LOGFONT lfMenuFont;
    public LOGFONT lfStatusFont;
    public LOGFONT lfMessageFont;
} 

[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
private static extern bool SystemParametersInfo(int uiAction, 
   int uiParam, ref NONCLIENTMETRICS ncMetrics, int fWinIni);

One interesting thing that happened while I was working on getting the caption font was with the definition of the LOGFONT structure. You see in MSDN documentation, the first five fields of the LOGFONT structure were declared as type long. I blindly copied the definition from the MSDN documentation and my call to SystemParametersInfo always returned false. After banging my head for four hours trying to figure out what the problem was, I came across a code snippet that used SystemParametersInfo. I downloaded that snippet and it worked perfectly on my machine. On further inspection, I noticed that the size of the structure I was passing to SystemParametersInfo was different from what the code snippet had. And then the lights came on, long should have been mapped to int...aaaargh.

Disabling the Close button

Another interesting thing that I had never really noticed about the message box was that if you don't have a Cancel button in your message box, the Close button on the top right is disabled. You can check this by showing a message box with "Yes", "No" buttons only. Not only is the Close button disabled but the system menu also does not show a Close option. So, that called for some more P/Invoke magic to disable the Close button if more than one button was present and there were no Cancel buttons. Of course, since the buttons themselves are custom, each button has a IsCancelButton property that you can set if you want to make the button a Cancel button.

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem,
uint uEnable);

private const int SC_CLOSE  = 0xF060;
private const int MF_BYCOMMAND  = 0x0;
private const int MF_GRAYED  = 0x1;
private const int MF_ENABLED  = 0x0;

private void DisableCloseButton(Form form)
{
    try
    {
        EnableMenuItem(GetSystemMenu(form.Handle, false), 
                   SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
    }
    catch(Exception /*ex*/)
    {
//System.Console.WriteLine(ex.Message);

    }
}

The above code disables the Close button, and also disables the Alt+F4 and Close option from the system menu.

Icons

Initially, I had obtained all the standard message box icons from various system files, using ResHacker. After I had posted the article, Carl pointed out the SystemIcons enumeration which provides all the standard system icons. So now, instead of embedding the standard icons into the message box, I am using the SystemIcons enumeration to draw the standard icons. Which means that on Windows XP, instead of , the real system icon is shown. An interesting problem that came up was that initially I was using a PictureBox control to display the icon. Now since it can only take Image objects, I tried converting the icon returned by SystemIcons to a Bitmap via the Icon.ToBitmap() method. This worked alright for Win2K icons, but on XP where the icons had an alpha channel, the icons came out looking terrible. Next, I tried manually creating a bitmap and then painting the icon onto the bitmap using Graphics.DrawIcon(), that too gave the same results. So finally, I had to draw the icon directly on the surface of the message box and drop the picture box.

Another interesting thing that I noticed was that out of the eight enumeration values in MessageBoxIcon, only four had unique values. Thus, Asterisk = Information, Error = Hand, Exclamation = Warning and Hand = Stop. The difference I believe is in the support for Compact Framework.

Alerts

When I was almost finished with my implementation, I realized that my message box made no sound when it displayed. I knew that the sounds were configurable via the Control Panel so I could not embed the sounds in the library. Fortunately, there is an API called MessageBeep which is exactly what I required. It takes only one parameter which is an integer representing the icon that is being displayed for the message box.

Below is the code that plays the alerts whenever a message box is popped:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern bool MessageBeep(uint type);

if(_playAlert)
{
    if(_standardIcon != MessageBoxIcon.None)
    {
        MessageBeep((uint)_standardIcon);
    }
    else
    {
        MessageBeep(0 /*MB_OK*/);
    }
}

Design of the component

The interesting part in the design was how to implement the "Don't ask me again" a.k.a. SaveUserResponse feature. I didn't want that the client code be littered with if statements checking if a saved response was available. So I decided that the client code should always call MessageBoxEx.Show() and if the user had saved a response then that response should be returned by the call rather than the dialog actually popping up. The next problem to handle was message box identity, how do I identify that the same message box is being invoked so that I can lookup if a user has saved a response to that message box? One solution would have been to create a hash of the message text, caption text, buttons etc. to identify the message box. The problem here was that in cases where we didn't want to use the response saved by the user, this approach would fail. Another big disadvantage was that there was no way to undo the saved response; once a user made a choice, he had to stick to it for the entire process lifetime.

The approach I have used is to have a MessageBoxExManager that manages all message boxes. Basically, all message boxes are created with a name. The name can be used to retrieve the message box at a later stage and invoke it. The name can also be used to reset the saved response of the user. One other functionality which I have exposed via the MessageBoxExManager is the ability to persist saved responses. Although there is no implementation for this right now, it can be implemented very easily, only the hashtable containing the saved responses need to be serialized.

This means that a message box once created can be reused. If it is not required anymore, then it can be disposed using the MessageBoxExManager.DeleteMessageBox() method; or if you want to create and show a one time message box, then you can pass null in the call to MessageBoxExManager.CreateMessageBox(). If a message box is created with a null name, then it is automatically disposed after the first call to MessageBoxEx.Show().

Below is the public interface for the MessageBoxExManager, along with explanations:

/// <summary>

/// Manages a collection of MessageBoxes. Basically manages the

/// saved response handling for messageBoxes.

/// </summary>

public class MessageBoxExManager
{
    /// <summary>

    /// Creates a new message box with the specified name. If null is specified

    /// in the message name then the message

    /// box is not managed by the Manager and

    /// will be disposed automatically after a call to Show()

    /// </summary>

    /// <param name="name">The name of the message box</param>

    /// <returns>A new message box</returns>

    public static MessageBoxEx CreateMessageBox(string name);

    
    /// <summary>

    /// Gets the message box with the specified name

    /// </summary>

    /// <param name="name">The name of the message box to retrieve</param>

    /// <returns>The message box

    /// with the specified name or null if a message box

    /// with that name does not exist</returns>

    public static MessageBoxEx GetMessageBox(string name);
    
    
    /// <summary>

    /// Deletes the message box with the specified name

    /// </summary>

    /// <param name="name">The name of the message box to delete</param>

    public static void DeleteMessageBox(string name);
    
    
    /// <summary>

    /// Persists the saved user responses to the stream

    /// </summary>

    public static void WriteSavedResponses(Stream stream);
    

    /// <summary>

    /// Reads the saved user responses from the stream

    /// </summary>

    public static void ReadSavedResponses(Stream stream)
    

    /// <summary>

    /// Reset the saved response for the message box with the specified name.

    /// </summary>

    /// <param name="messageBoxName">The name of the message box

    ///         whose response is to be reset.</param>

    public static void ResetSavedResponse(string messageBoxName);
    

    /// <summary>

    /// Resets the saved responses for all message boxes

    /// that are managed by the manager.

    /// </summary>

    public static void ResetAllSavedResponses();

}

Another design decision was regarding how to expose the MessageBoxEx class itself. Although the MessageBoxEx is a Form, I did not want to expose it as a Form for two reasons: one was to abstract away the implementation details and the second was to reduce intellisense clutter while working with the class. Thus, MessageBoxEx is a proxy to the real Form which is implemented in MessageBoxExForm.

Below is the public interface for MessageBoxEx:

/// <summary>

/// An extended MessageBox with lot of customizing capabilities.

/// </summary>

public class MessageBoxEx
{
    /// <summary>

    /// Sets the caption of the message box

    /// </summary>

    public string Caption


    /// <summary>

    /// Sets the text of the message box

    /// </summary>

    public string Text


    /// <summary>

    /// Sets the icon to show in the message box

    /// </summary>

    public Icon CustomIcon


    /// <summary>

    /// Sets the icon to show in the message box

    /// </summary>

    public MessageBoxExIcon Icon


    /// <summary>

    /// Sets the font for the text of the message box

    /// </summary>

    public Font Font

    /// <summary>

    /// Sets or Gets the ability of the  user to save his/her response

    /// </summary>

    public bool AllowSaveResponse


    /// <summary>

    /// Sets the text to show to the user when saving his/her response

    /// </summary>

    public string SaveResponseText


    /// <summary>

    /// Sets or Gets wether the saved response if available should be used

    /// </summary>

    public bool UseSavedResponse


    /// <summary>

    /// Sets or Gets wether an alert sound

    /// is played while showing the message box

    /// The sound played depends on the the Icon selected for the message box

    /// </summary>

    public bool PlayAlsertSound

    /// <summary>

    /// Sets or Gets the time in milliseconds

    /// for which the message box is displayed

    /// </summary>

    public int Timeout
    
    /// <summary>

    /// Controls the result that will be returned when the message box times out

    /// </summary>

    public TimeoutResult TimeoutResult
   
    /// <summary>

    /// Shows the message box

    /// </summary>

    /// <returns></returns>

    public string Show()

    /// <summary>

    /// Shows the messsage box with the specified owner

    /// </summary>

    /// <param name="owner"></param>

    /// <returns></returns>

    public string Show(IWin32Window owner)


    /// <summary>

    /// Add a custom button to the message box

    /// </summary>

    /// <param name="button">The button to add</param>

    public void AddButton(MessageBoxExButton button)


    /// <summary>

    /// Add a custom button to the message box

    /// </summary>

    /// <param name="text">The text of the button</param>

    /// <param name="val">The return value

    ///         in case this button is clicked</param>

    public void AddButton(string text, string val)


    /// <summary>

    /// Add a standard button to the message box

    /// </summary>

    /// <param name="buttons">The standard button to add</param>

    public void AddButton(MessageBoxExButtons button)


    /// <summary>

    /// Add standard buttons to the message box.

    /// </summary>

    /// <param name="buttons">The standard buttons to add</param>

    public void AddButtons(MessageBoxButtons buttons)
}

Also for convenience, the standard message box buttons are available as an enumeration which can be used in AddButton().

/// <summary>

/// Standard MessageBoxEx buttons

/// </summary>

public enum MessageBoxExButtons
{
    Ok = 0,
    Cancel = 1,
    Yes = 2,
    No = 4,
    Abort = 8,
    Retry = 16,
    Ignore = 32,
}

Also, the results of these standard buttons are available as constants.

/// <summary>

/// Standard MessageBoxEx results

/// </summary>

public struct MessageBoxExResult
{
    public const string Ok = "Ok";
    public const string Cancel = "Cancel";
    public const string Yes = "Yes";
    public const string No = "No";
    public const string Abort = "Abort";
    public const string Retry = "Retry";
    public const string Ignore = "Ignore";
    public const string Timeout = "Timeout";
}

Using the code

Using the code is pretty straightforward. Just add the MessageBoxExLib project to your application, and you're ready to go. Below is some code that shows how to create and display a standard message box with the option to save the user's response.

MessageBoxEx msgBox = MessageBoxExManager.CreateMessageBox("Test");
msgBox.Caption = "Question";
msgBox.Text = "Do you want to save the data?";

msgBox.AddButtons(MessageBoxButtons.YesNo);
msgBox.Icon = MessageBoxIcon.Question;

msgBox.SaveResponseText = "Don't ask me again";
msgBox.Font = new Font("Tahoma",11);

string result = msgBox.Show();

Here is the resulting message box:

Here is some code that demonstrates how you can use your own custom buttons with tooltips in your message box:

MessageBoxEx msgBox = MessageBoxExManager.CreateMessageBox("Test2");
msgBox.Caption = "Question";
msgBox.Text = "Do you want to save the data?";

MessageBoxExButton btnYes = new MessageBoxExButton();
btnYes.Text = "Yes";
btnYes.Value = "Yes";
btnYes.HelpText = "Save the data";

MessageBoxExButton btnNo = new MessageBoxExButton();
btnNo.Text = "No";
btnNo.Value = "No";
btnNo.HelpText = "Do not save the data";

msgBox.AddButton(btnYes);
msgBox.AddButton(btnNo);

msgBox.Icon = MessageBoxExIcon.Question;

msgBox.SaveResponseText = "Don't ask me again";
msgBox.AllowSaveResponse = true;

msgBox.Font = new Font("Tahoma",8);

string result = msgBox.Show();

Here is the resulting message box:

Timeouts

While showing the message box, a timeout value can be specified; if the user does not select a response within the specified time frame, then the message box will be automatically dismissed. The result that is returned when the message box times out can be specified using the enumeration shown below:

/// <summary>

/// Enumerates the kind of results that can be returned when a

/// message box times out

/// </summary>

public enum TimeoutResult
{
    /// <summary>

    /// On timeout the value associated with

    /// the default button is set as the result.

    /// This is the default action on timeout.

    /// </summary>

    Default,

    /// <summary>

    /// On timeout the value associated with

    /// the cancel button is set as the result. 

    /// If the messagebox does not have a cancel button

    /// then the value associated with 

    /// the default button is set as the result.

    /// </summary>

    Cancel,

    /// <summary>

    /// On timeout MessageBoxExResult.Timeout is set as the result.

    /// </summary>

    Timeout
}

Here is a code snippet that shows how you can use the timeout feature:

MessageBoxEx msgBox = MessageBoxExManager.CreateMessageBox(null);
msgBox.Caption = "Question";
msgBox.Text = "Do you want to save the data?";

msgBox.AddButtons(MessageBoxButtons.YesNo);
msgBox.Icon = MessageBoxExIcon.Question;

//Wait for 30 seconds for the user to respond

msgBox.Timeout = 30000;
msgBox.TimeoutResult = TimeoutResult.Timeout;

string result = msgBox.Show();
if(result == MessageBoxExResult.Timeout)
{
    //Take action to handle the timeout

}

Localization

After my initial posting of this article, Carl and Frank pointed out that the message box could also be useful in localized applications. Now, initially I had thought that I would be able to access the localized strings for standard buttons like "OK", "Cancel" etc. from the OS itself, it seems that there is no such documented way, I even talked to Michael Kaplan and he confirmed that there is no way to get those strings. Now instead of thinking of some hack to get the strings from the OS, I decided to use a simple solution, I moved the strings into a .resx file and used that to show the text for standard buttons based on the CurrentUICulture property of the current thread. I've included resources for French and German using BabelFish. Here is an example of a message box that was created after setting the CurrentUICulture to "fr".

MessageBoxEx msgBox = MessageBoxExManager.CreateMessageBox(null);
msgBox.Caption = "Question";
msgBox.Text = "Voulez-vous sauver les donn�es ?";
msgBox.AddButtons(MessageBoxButtons.YesNoCancel);
msgBox.Icon = MessageBoxExIcon.Question;

msgBox.Show();

The resulting message box is shown below:

Things to remember

To do

  1. Add support for RTF or HTML text in message box text.
  2. Add support for gradient backgrounds and background images.
  3. Add support for showing detailed help.
  4. Add support to choose default button, i.e., the button that is selected by default. Currently, this is the first button that is added.
  5. Add support for persisting saved user responses.
  6. Make a Buttons custom collection that allows insertion of buttons at specified indexes.
  7. Workaround for tooltip bug. See below.

Known Issues

  1. The tooltips don't display the second time a message box is shown. This happens because of a known issue in the .NET framework. See this thread for more info.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralGreat job!...but small bug in sample code
Ant Waters
11:26 19 Feb '10  
I think the 5th line in the code for "Using the code" should read:

msgBox.Icon = MessageBoxExIcon.Question;

(note the "Ex" before "Icon")

Otherwise, thanks!!!
GeneralVery Useful
Tom Delany
4:31 3 Sep '09  
This has helped me tremendously on a project that I have been working on. You saved me many hours of work! Thank you.


GeneralRe: Very Useful
Sijin
6:53 3 Sep '09  
Glad it helped. Smile



I always think that the idea of a compiler that compiles another compiler or itself is rather incestuous in a binary way. - Colin Davies
My Blog


GeneralNo handler for the ESC key
CosmoMaster
17:48 31 Jan '09  
One function that is lost in relation to MessageBox is the ability to emulate cancel by clicking the ESC key. What is the best way to restore that functionality?
GeneralRe: No handler for the ESC key
Tyler Collier
12:51 8 Jan '10  
I too find the ESC key functionality a must-have feature!

Here's what I did to enable ESC key functionality:

1. Add a button named EscButton to the MessageBoxExForm form.
2. Double click on the button to add code to its Click method hander, like so:
private void EscButton_Click(object sender, EventArgs e)
{
if (_allowCancel)
{
SetResultAndClose(_cancelButton.Value);
}
}
3. Make sure it IS visible but set its Location so it won't show, such as -100,-100.
4. Set the MessageBoxExForm's CancelButton property to EscButton.
Generalbox positioning
bilalso
7:21 5 Aug '08  
How do I position the box at the center of the parent window instead of the screen? The library does'nt provide any flexibilty to position the dialog. It does'nt really let consumer of the dll to set the parameters of dialog box position.
GeneralRe: box positioning
Sijin
10:08 5 Aug '08  
Hi,

MessageBox API doesn't allow the user to specify position as well. But you have the source for the dialog, it should be trivial to add an additional property to set the initial position of the dialog as well.



I always think that the idea of a compiler that compiles another compiler or itself is rather incestuous in a binary way. - Colin Davies
My Blog


GeneralSijin Joseph Code Licensing Question...
plexar
6:39 18 Sep '07  
Sijin,

I am looking for the license for this code. Do you have license text you could send me for its use.

Thank you,
Gregory Simeone
GeneralGreat Article but few issues
amit_logicon
5:34 10 Jul '07  
Hi,

Thanks for writing such a great article. Its really helpfull. But can you tell me few things (I have converted your code to VS2005), -

1) What if don't need any buttons at all. How to do this?
2) Form Size is larg at runtime. How to srink it?

Thanks again for writing such an excellent code. It must be voted a 5.

Regards,
Kumar
GeneralThanks a lot!
Hautzendorfer
2:39 29 Jun '07  
Hi Sijin,

that's what I've been looking for,
aditionally I integrated a detail message display functionality.
I would like you to take a look at it and if its ok please share it for the others too ...

Is it ok to send an email to you with the sources?

Regards,
Martin
GeneralRe: Thanks a lot!
Sijin
4:07 2 Jul '07  
Sure.



I always think that the idea of a compiler that compiles another compiler or itself is rather incestuous in a binary way. - Colin Davies
My Blog

QuestionPossible to kill MessageBox?
xoninhas
3:52 8 Jun '07  
Hi! Excelent work! Thanks!

Anyway I have a need of killing message boxes locally! I need to launch a messagebox in a new thread so my program can continue running. The message box is purely informative. When I get to a certain state of my program I want to kill all message boxes launched so far, is it possible with your implementation?

Thanks again,
André
GeneralExcellent job - very helpful - small bug and suggestion
SBendBuckeye
4:24 27 Apr '07  
Hello,

1. Thanks for some excellent work!

2. I added the following code in the AddButtons method to clear the form's buttons collection in case the method was called twice. It is the first code executed in the method before the Case logic.

// Clear any existing buttons before proceeding.
_MessageBoxForm.Buttons.Clear()

3. If you inherited your manager from System.ComponentModel.Component you could provide Design time exposure.

Have a great day!

j2associates_NO_SPAM_@yahoo.com

QuestionActiveX
Roebie
4:29 12 Dec '06  
Can you make this into an ActiveX component so that VB6 developers can use your magnificent MessageBox too?
Thanks,
Roebie
AnswerRe: ActiveX
Badprop7
23:24 3 Sep '08  
Has there been any reply to this request. I would also use this if it where a activeX component. This is exactly what I need for my code. Anybody know of anything similar I can use in VB6?
AnswerRe: ActiveX
Roebie
23:46 3 Sep '08  
I'm sorry Badprop7, I never had any reply to my question.
As the only thing I needed from Sijin's concept was the part described under "Timeouts" I wrote a class myself. The rest I have never implemented.
I don't know what features you need, but if I remember well CCRP has a messegebox too that is partly configurable.
Good luck
GeneralGreat job!!
omar.vera
13:54 8 Nov '06  
It is really a great Custom Message Box. It really help me a lot!! I just made a customization. The position of the checkbox for me should be better under the message text, I also saw that in some application but I don't know if that is the windows standard.

-Omar
GeneralButtons grouped virtically
FredSP
12:56 4 Nov '06  
I have used MessageBoxEx successfully in a number of my projects.
The latest project requires a MessageBoxEx to have nine (9) buttons.
Is it possible to have the Buttons grouped vertically?
As an alternative, can the Buttons be made larger to allow for 2 or more lines of Text?

Fred S. Parker

GeneralInvalidOperationException On NetworkChange event
jonnni12xyz
1:04 14 Oct '06  
Hi,
When I use the MessageBoxEx.Show(...) inside event callback of NetworkChange.NetworkAddressChanged it throw :
System.InvalidOperationException was unhandled
Message="The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone)."
Source="mscorlib"
StackTrace:
at System.Threading.SynchronizationContextSwitcher.Undo()
at System.Threading.ExecutionContextSwitcher.Undo()
at System.Threading.ExecutionContext.runFinallyCode(Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.NetworkInformation.NetworkChange.AddressChangeListener.AddressChangedCallback(Object stateObject, Boolean signaled)
at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)

any suggestion ?
thanks
GeneralRe: InvalidOperationException On NetworkChange event
Sijin
9:22 16 Oct '06  
I guess it has something to do with the fact that the callback is happening on a non-UI thread i.e a thread that does not have a message loop associated with it.

Can you marshall the call across to the UI thread from the NetworkAddressChanged event handler?



I always think that the idea of a compiler that compiles another compiler or itself is rather incestuous in a binary way. - Colin Davies
My .Net Blog

GeneralUpdated version?
dan neely
10:06 8 Sep '06  
It's been almost a year and a half since you last uploaded a new version here. From the forum I see that you've done several minor enhancements/bug fixes since then. Could you post a new zip with that version?
GeneralRe: Updated version?
Sijin
18:06 9 Sep '06  
I haven't yet incorporated the changes mentioned in the forums to the source yet. Will probably be doing it this week, I guess it's about time I updated Smile



I always think that the idea of a compiler that compiles another compiler or itself is rather incestuous in a binary way. - Colin Davies
My .Net Blog

GeneralRe: Updated version?
alexdresko
5:56 14 Sep '06  
Have you updated it yet? I have an immediate need to use the code.. :/

I'm not a player, I just code a lot!
Alex Dresko

GeneralRe: Updated version?
dan neely
5:57 18 Sep '06  
The updates are all apparently fairly minor tweak/bugfixes. Unless there's something I've overlooked, the updated version should be dropin compatable with the current one. Alternately if you need one of the pending updates, you could read the last years forum messages and make it yourself.
QuestionRe: Updated version?
Jonas Nordlund
0:49 3 Sep '07  
Hmm, I can't seem to find any posts in the message boards on this. I tried searching for both "messageboxex" and the author's user name, but came up with nothing. Has those posts been lost now?Frown


Last Updated 27 Apr 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010