MessageBox and subtleties

Gloops

Well-known member
Joined
Jun 30, 2022
Messages
137
Programming Experience
10+
Hello everybody,

My MessageBox displayed the message, but behind other windows, and with the mouse cursor in the middle of the message window instead of the middle of the button.
Furthermore, after I positioned the mouse cursor, the previous position was still visible, so I saw two mouse cursors on the screen.

So, I corrected that, it works good, but I wonder whether a much more simple solution does not exist.

And also, to evaluate the correct position of the cursor, on WinForms you have Control.PointToScreen, but I am not sure that can be used on a MessageBox. I put values hardcoded, that is not sure to adapt if I change the sizes of the fonts in Windows.
Manage a MessageBox:
       private void Button_Click(Object sender, EventArgs e)
       {
                if (fic.FullName.Equals(strPath))
                {
                    bFicPresent = true;
                    Form messageForm = new Form();
                    messageForm.TopMost = true;
                    strWindowToPosition = "File already present";
                    timer2.Enabled = true;
                    MessageBox.Show(messageForm, String.Format("{1} :\n{0}", fic.FullName, strWindowToPosition), strWindowToPosition);
                    messageForm.Close();
                    break;
                }
       }

        string strWindowToPosition;

        private void timer2_Tick(object sender, EventArgs e)
        {
            timer2.Enabled = false;
            //System.Threading.Thread.Sleep(1000);
            RECT rect = new RECT();
            IntPtr hWnd = FindWindow(null, strWindowToPosition);
            SetForegroundWindow(hWnd);
            SetActiveWindow(hWnd);
            GetWindowRect(hWnd, out rect);
            int x = rect.Right - (btnShortcut.Width + 60);
            int y = rect.Bottom - 70;
            //lblInfo.Text = x.ToString();
            SetCursorPos(x, y);
            #region mask old position of cursor
            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread.Sleep(100);
                SetCursorPos(x--, y--);
            }
            #endregion
        }

The timer is also used at another place, where I do not use messageForm to manage the TopMost attribute. It some of works, but the MessageBox appears behind the calling form. I found a solution by hiding the calling form until the user has validated the message.

I repeat the title of the MessageBox at the top of the message, as during several months my Windows did not show the titles of the messages, either in C# or in Javascript. Having it repeated looks strange but works, if it is not displayed at all you miss some information.
 
Since you don't want to post a minimal program showing the problem that you are running into, here's a minimal program that shows that there is no problem:
1) "Snap To" works correctly for a custom form with a default button. (see line 30)
2) "Snap To" works correctly for message boxes that have two buttons. (see lines 19, 26)

C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;

namespace WinForms
{
    class MainForm : Form
    {
        MainForm()
        {
            var left = new Button()
            {
                Text = "Left",
                Dock = DockStyle.Left
            };
            left.Click += (o, e) => MessageBox.Show("You clicked on left.", "Left", MessageBoxButtons.OKCancel);

            var right = new Button()
            {
                Text = "Right",
                Dock = DockStyle.Right
            };
            right.Click += (o, e) => MessageBox.Show("You clicked on right.", "Right", MessageBoxButtons.YesNo);

            Controls.AddRange(new[] { left, right });

            AcceptButton = right;
            Text = "Main";
            Size = new Size(800, 600);
            CenterToScreen();
        }

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}
 
After that, it is up to the applications to do the job.
No it is not. It's up to the OS to put the mouse on the default button.
 
Yes, with a dedicated form, it is OK.
The problem is only with the MessageBox instruction, as per code in message 22.
We can get the job done, either with a dedicated form or by using APIs in a timer.
The objective could be to let the programmer concentrate on the main topic of his program, rather than on the subtleties to position the mouse cursor on a button.
In this perspective, a one-line instruction seems more appropriate, and already existed in the eighties. But it no more reacts as documented.
 
OK, going to open a ticket by the Visual Studio team, for the MessageBox default button.
You better be able to give them a minimal repro case that shows that the mouse is not being moved to the default button.

For me the following works correctly:
C#:
class Main
{
    [STAThread]
    static void Main()
    {
        System.Windows.Forms.MessageBox.Show("It works", "Test", MessageBoxButtons.YesNo);
    }
}
 
You better be able to give them a minimal repro case that shows that the mouse is not being moved to the default button.

For me the following works correctly:
C#:
class Main
{
    [STAThread]
    static void Main()
    {
        System.Windows.Forms.MessageBox.Show("It works", "Test", MessageBoxButtons.YesNo);
    }
}
Yes and you can provide a default button with some more parameters, as appears in message 22.
But this does not work in my case. It shows the button, but the mouse cursor stays in the middle of the screen.
 
This is not a Visual Studio bug. It's an issue with the Win32 API for MessageBox().

For message box with just on OK button, the flag that need to be passed are MB_OK. Now, if you want the OK button to be selected as the default button with the mouse moved to it, then you need to OR in the MB_DEFBUTTON1 flag. This is essentially what you are trying to do in your post #22. But now if you look closely at the Win32 MessageBox() documentation:
C#:
MB_OK == 0x00000000
MB_DEFBUTTON1 == 0x00000000

So effectively it's a call to MessageBox() passing in 0 as the flags like line 32 in my post #14.

(See:

)

If are going to file a bug, file it with the Windows team, not the Visual Studio team.
 
You better be able to give them a minimal repro case that shows that the mouse is not being moved to the default button.

For me the following works correctly:
C#:
class Main
{
    [STAThread]
    static void Main()
    {
        System.Windows.Forms.MessageBox.Show("It works", "Test", MessageBoxButtons.YesNo);
    }
}
Right, if I type the instruction in the program.cs module, the mouse cursor comes on the first button.
But if you type it on a form, it does not.
My first try was in the Form_Load, and the cursor stayed in the middle.
I was more clear when I called it from the click of a button, as then the mouse cursor was on the button, and then it stayed there when calling the MessageBox.
As if the form or the button repositioned the mouse cursor after the MessageBox, which, I think, is counter-intuitive.
 
My first try was in the Form_Load, and the cursor stayed in the middle.
That's because at Form_Load time, the window is not yet visible. There is no where to move the cursor to.
 
This is not a Visual Studio bug. It's an issue with the Win32 API for MessageBox().

For message box with just on OK button, the flag that need to be passed are MB_OK. Now, if you want the OK button to be selected as the default button with the mouse moved to it, then you need to OR in the MB_DEFBUTTON1 flag. This is essentially what you are trying to do in your post #22. But now if you look closely at the Win32 MessageBox() documentation:
C#:
MB_OK == 0x00000000
MB_DEFBUTTON1 == 0x00000000

So effectively it's a call to MessageBox() passing in 0 as the flags like line 32 in my post #14.

(See:

)

If are going to file a bug, file it with the Windows team, not the Visual Studio team.
I have to admit that you are much more precise in a certain number of aspects, when calling different layers calling each other, and knowing which one is in default when the final result is not correct.
 
That's because at Form_Load time, the window is not yet visible. There is no where to move the cursor to.
You mean the message window ?
Oh, no, the form window. It positions the cursor in the middle after the message box has been created, you mean ?
Perhaps I should try with another event.
Do you think the same is true with the click of a button of the form?
The mouse cursor stays on the caller button.
 
Instead of just talking about your code, post the minimal repro code.
 
So, here is my second try :
Calling a MessageBox from a button on a form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WFATestMessageBox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            string strMessage = "I write a message and have fun with it.";
            string strTitle = "A title for my message";
            MessageBox.Show(this,
                strMessage,
                strTitle,
                MessageBoxButtons.OK,
                MessageBoxIcon.Information,
                MessageBoxDefaultButton.Button1);
        }
    }
}

The mouse cursor stays on button1, with the text "Test MessageBox".

My previous try was with the MessageBox in the Form_Load : the mouse cursor stayed in the middle of the screen, depending probably on the options to position the form.
 
See posts #27 and #28 which verified that the system message box does not snap the mouse to the OK button on when it has only one button. Post #37 shows why this is happening.
 
See posts #27 and #28 which verified that the system message box does not snap the mouse to the OK button on when it has only one button. Post #37 shows why this is happening.
I have to try again with two buttons, I do not remember the cursor was positioned.
When I saw the 0 value for the first button, I thought that is was positioned by default.
And then I realized there was a nuance between giving a value of 0 and no value at all.
I remember in Access you had everything in the same parameter, the displayed buttons and the default button. So they had to be sure of values not mismatching.
Now there are two separate parameters. If they want to receive a 0 in the last one to focus on the first button, that can be OK, but you are right that it supposes to well think to different possible effects.
Particularly supposing that they mix both parameters after receiving them.
 

Latest posts

Back
Top Bottom