lex452, понятно. Указание родительской формы блокирует форму, но не ориентирует стандартный message box относительно неё.
Если хорошо подумать, то это логично. Бывают и достаточно маленькие формы, расположенные так, что центрированный относительно них message box не влезет в экран.
Поэтому остаётся два пути:
1) Создать собственный модальный dialog box (форму), настроить его, как хочется, и использовать вместо стандартного message box. Тут следует учитывать, что message box бывают оконными, задачными и общесистемными. Первые блокируют родительское окно, но сохраняют работоспособность других окон приложения, работающих в других потоках. Вторые блокируют всю задачу (все её потоки). Третьи блокируют все окна на экране у всех задач. Ещё следует учитывать, что стандартный message box обрабатывает комбинации клавиш "скопировать в буфер обмена" и копирует в буфер обмена выведенный текст, заголовок окна и кнопки (в текстовом виде). Т.е. полная собственная реализация message box не так проста.
2) Параллельно с вызовом message box запустит демона, который найдёт окно открытого message box и пошлёт ему системные сообщения, изменяющие его положение на экране. Этот вариант будет работать только для оконных message box, при котором другие потоки задачи не блокируются. И этот вариант обладает рядом рисков, связанных с нахождением нужного окна. Во-первых, если искать окно по заголовку, таких окон с одинаковым заголовком может оказаться несколько. Во-вторых, пользователь может нажать Enter или Esc достаточно быстро, чтобы message box закрылся сразу же после открытия, и демон, чтобы не зависнуть, должен этот случай предусматривать.
Первый вариант трудоёмкий, но не сложный.
Второй вариант интереснее. На скорую руку собранное решение выглядит примерно так:
class MessageBox
{
struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int GetWindowRect(IntPtr hWnd, ref Rect lpRect);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
private class DaemonParameters
{
public IntPtr ParentWindow;
public string MessageBoxTitle;
}
private static void MoveMessageBox(IntPtr messageBox, DaemonParameters parameters)
{
Rect messageBoxArea = new Rect();
int foundMessageBox = GetWindowRect(messageBox, ref messageBoxArea);
if (foundMessageBox != 0)
{
Rect parentWindowArea = new Rect();
int foundParentWindow = GetWindowRect(parameters.ParentWindow, ref parentWindowArea);
if (foundParentWindow != 0)
{
int widthDifference = (parentWindowArea.Right - parentWindowArea.Left) - (messageBoxArea.Right - messageBoxArea.Left);
int heightDifference = (parentWindowArea.Bottom - parentWindowArea.Top) - (messageBoxArea.Bottom - messageBoxArea.Top);
int x = parentWindowArea.Left + widthDifference / 2;
int y = parentWindowArea.Top + heightDifference / 2;
SetWindowPos(messageBox, IntPtr.Zero, x, y, 0, 0, 0x0001);
}
}
}
private static IntPtr FindMessageBox(DaemonParameters parameters)
{
return FindWindow(null, parameters.MessageBoxTitle);
}
private static void RunDaemon(object param)
{
try
{
DaemonParameters parameters = param as DaemonParameters;
bool isDone = false;
while(!isDone)
{
System.Threading.Thread.Sleep(1);
IntPtr handle = FindMessageBox(parameters);
if (handle != IntPtr.Zero)
{
MoveMessageBox(handle, parameters);
isDone = true;
}
}
}
catch(System.Threading.ThreadAbortException)
{
}
}
private static System.Threading.Thread BeginDaemon(DaemonParameters parameters)
{
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(RunDaemon));
thread.Start(parameters);
return thread;
}
private static void EndDaemon(System.Threading.Thread thread)
{
if (thread.IsAlive)
{
thread.Abort();
}
}
public static System.Windows.Forms.DialogResult Show(System.Windows.Forms.Form parentWindow, string text, string caption)
{
DaemonParameters parameters = new DaemonParameters();
parameters.ParentWindow = parentWindow.Handle;
parameters.MessageBoxTitle = caption;
System.Threading.Thread daemonThread = BeginDaemon(parameters);
System.Windows.Forms.DialogResult result = System.Windows.Forms.MessageBox.Show(parentWindow, text, caption);
EndDaemon(daemonThread);
return result;
}
}
При этом стандартный класс MessageBox перекрывается собственным. Всякие параметры, связанные с украшательствами, можно добавить самостоятельно. Обязательно нужно указывать заголовок message box, при этом у разных message box должны быть разные заголовки, иначе не будет работать. Но если заменить алгоритм поиска окна, используя вместо FindWindow что-нибудь другое - например через GetWindow или т.п. функции перебирать все окна и потом разными запросами идентифицировать нужное, то и это ограничение можно обойти.