483 lines
21 KiB
C#
483 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Watchdog.WatchdogLib.Win32;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using System.ComponentModel;
|
|
using WPFWin = System.Windows;
|
|
using WPFWinInterop = System.Windows.Interop;
|
|
|
|
namespace Watchdog.WatchdogLib.WinForms
|
|
{
|
|
/// <summary>
|
|
/// MsgBox is a WindowsForms MessageBox that can be centered to the Parent
|
|
/// </summary>
|
|
public static class MsgBox
|
|
{
|
|
#region Private Static Members
|
|
|
|
private static User32.WindowsHookProc _hookProcDelegate = null;
|
|
private static int _hHook = 0;
|
|
private static string _title = null;
|
|
private static string _msg = null;
|
|
private static IntPtr _hIcon = IntPtr.Zero;
|
|
private static bool _IsDesktopOwner = false;
|
|
private static bool _ShowFatal = false;
|
|
|
|
// Delegate to make All Message Boxes Thread-Safe
|
|
private delegate DialogResult ShowMsgBoxDelegate(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon, Icon TitleBarIcon);
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
public static Icon DefaultTitleBarIcon { get; set; }
|
|
public static uint MaxNumberOfCharactersPerLine { get; set; }
|
|
public const uint DefaultNumberOfCharactersPerLine = 62;
|
|
|
|
#endregion
|
|
|
|
#region Public Header Properties
|
|
|
|
public static bool ShowHeader { get; set; }
|
|
public static string MsgBox_ErrorHeader { get; set; }
|
|
public static string MsgBox_FatalErrorHeader { get; set; }
|
|
public static string MsgBox_WarningHeader { get; set; }
|
|
public static string MsgBox_InfoHeader { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Public Footer Properties
|
|
|
|
public static bool ShowFooter { get; set; }
|
|
public static string MsgBox_ErrorFooter { get; set; }
|
|
public static string MsgBox_FatalErrorFooter { get; set; }
|
|
public static string MsgBox_WarningFooter { get; set; }
|
|
public static string MsgBox_InfoFooter { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Public Title Header Properties
|
|
|
|
public static bool ShowTitleHeader { get; set; }
|
|
public static string MsgBox_ErrorTitleHeader { get; set; }
|
|
public static string MsgBox_FatalErrorTitleHeader { get; set; }
|
|
public static string MsgBox_WarningTitleHeader { get; set; }
|
|
public static string MsgBox_InfoTitleHeader { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
static MsgBox()
|
|
{
|
|
DefaultTitleBarIcon = null;
|
|
MaxNumberOfCharactersPerLine = DefaultNumberOfCharactersPerLine;
|
|
|
|
// Header Init
|
|
MsgBox_FatalErrorHeader = String.Empty;
|
|
MsgBox_ErrorHeader = String.Empty;
|
|
MsgBox_WarningHeader = String.Empty;
|
|
MsgBox_InfoHeader = String.Empty;
|
|
ShowHeader = true;
|
|
|
|
// Footer Init
|
|
MsgBox_FatalErrorFooter = String.Empty;
|
|
MsgBox_ErrorFooter = String.Empty;
|
|
MsgBox_WarningFooter = String.Empty;
|
|
MsgBox_InfoFooter = String.Empty;
|
|
ShowFooter = true;
|
|
|
|
// Title Header Init
|
|
MsgBox_FatalErrorTitleHeader = String.Empty;
|
|
MsgBox_ErrorTitleHeader = String.Empty;
|
|
MsgBox_WarningTitleHeader = String.Empty;
|
|
MsgBox_InfoTitleHeader = String.Empty;
|
|
ShowTitleHeader = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Static Methods
|
|
|
|
/// <summary>
|
|
/// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon
|
|
/// </summary>
|
|
public static DialogResult Show(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
|
|
{
|
|
if (parent != null)
|
|
{
|
|
WPFWinInterop.WindowInteropHelper interop = new WPFWinInterop.WindowInteropHelper(parent);
|
|
if(interop.Handle != IntPtr.Zero)
|
|
return Show(Watchdog.WatchdogLib.Win32.Convert.ConverthWndToIWin32Window(interop.Handle), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
|
|
}
|
|
return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon
|
|
/// </summary>
|
|
public static DialogResult Show(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
|
|
{
|
|
return Show(parent, Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows a custom Message Box (centered to Desktop), with the DefaultTitleBarIcon
|
|
/// </summary>
|
|
public static DialogResult Show(String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
|
|
{
|
|
return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
|
|
}
|
|
|
|
/// <summary>
|
|
/// *Main MessageBox Show Function* allows you to center the Message Box to the Parent
|
|
/// </summary>
|
|
/// <returns>Result of Dialog </returns>
|
|
public static DialogResult Show(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon, Icon TitleBarIcon)
|
|
{
|
|
ISynchronizeInvoke InvokeObject = null;
|
|
if (parent != null && parent is ISynchronizeInvoke)
|
|
InvokeObject = (ISynchronizeInvoke)parent;
|
|
|
|
// Invoke if we need to * Make MessageBoxes generally Thread-safe *
|
|
if ((InvokeObject != null) && InvokeObject.InvokeRequired)
|
|
{
|
|
DialogResult result = (DialogResult)InvokeObject.Invoke(new ShowMsgBoxDelegate(MsgBox.Show), new object[] { parent, Title, Text, MsgBoxButtons, MsgBoxIcon, TitleBarIcon });
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return MsgBox.ShowInternal(parent, Text, Title, MsgBoxButtons, MsgBoxIcon, TitleBarIcon);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Static Methods Extended
|
|
|
|
/// <summary>
|
|
/// Shows Warning MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowWarning(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowWarning(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Warning MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowWarning(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowWarning(String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Fatal Error MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowFatalError(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowFatalError(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
_ShowFatal = true;
|
|
DialogResult dr = Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
|
|
_ShowFatal = false;
|
|
return dr;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Fatal Error MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowFatalError(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowFatalError(String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
_ShowFatal = true;
|
|
DialogResult dr = Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
|
|
_ShowFatal = false;
|
|
return dr;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Error MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowError(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowError(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Error MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowError(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowError(String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Information MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowInfo(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowInfo(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Information);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Information MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowInfo(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowInfo(String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Information);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Default MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowDefault(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowDefault(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.None);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows Default MessageBox
|
|
/// </summary>
|
|
//public static DialogResult ShowDefault(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
|
|
public static DialogResult ShowDefault(String Text, String Title, MessageBoxButtons MsgBoxButtons)
|
|
{
|
|
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.None);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="owner"></param>
|
|
/// <param name="msg"></param>
|
|
/// <param name="title"></param>
|
|
/// <param name="btns"></param>
|
|
/// <param name="icon"></param>
|
|
/// <param name="TitleBarIcon"></param>
|
|
/// <returns></returns>
|
|
private static DialogResult ShowInternal(IWin32Window owner, string msg, string title, MessageBoxButtons btns, MessageBoxIcon icon, Icon TitleBarIcon)
|
|
{
|
|
// Create a callback delegate
|
|
_hookProcDelegate = new User32.WindowsHookProc(HookCallback);
|
|
|
|
#region Header Action
|
|
if (ShowHeader)
|
|
{
|
|
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorHeader) && _ShowFatal)
|
|
msg = MsgBox_FatalErrorHeader + msg;
|
|
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorHeader) && !_ShowFatal)
|
|
msg = MsgBox_ErrorHeader + msg;
|
|
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningHeader))
|
|
msg = MsgBox_WarningHeader + msg;
|
|
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoHeader))
|
|
msg = MsgBox_InfoHeader + msg;
|
|
}
|
|
#endregion
|
|
|
|
#region Footer Action
|
|
if (ShowFooter)
|
|
{
|
|
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorFooter) && _ShowFatal)
|
|
msg = msg + MsgBox_FatalErrorFooter;
|
|
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorFooter) && !_ShowFatal)
|
|
msg = msg + MsgBox_ErrorFooter;
|
|
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningFooter))
|
|
msg = msg + MsgBox_WarningFooter;
|
|
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoFooter))
|
|
msg = msg + MsgBox_InfoFooter;
|
|
}
|
|
#endregion
|
|
|
|
#region Title Header
|
|
if (ShowTitleHeader)
|
|
{
|
|
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorTitleHeader) && _ShowFatal)
|
|
title = MsgBox_FatalErrorTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
|
|
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorTitleHeader) && !_ShowFatal)
|
|
title = MsgBox_ErrorTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
|
|
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningTitleHeader))
|
|
title = MsgBox_WarningTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
|
|
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoTitleHeader))
|
|
title = MsgBox_InfoTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
|
|
}
|
|
#endregion
|
|
|
|
#region Text Padding
|
|
|
|
// Stripe last \n, if exists
|
|
if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg[msg.Length - 1] == '\n'))
|
|
msg = msg.Remove(msg.Length - 1);
|
|
|
|
// Make sure the text looks good, by using padding
|
|
if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg.Length < MaxNumberOfCharactersPerLine))
|
|
{
|
|
string[] lines = msg.Split('\n');
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (string line in lines)
|
|
{
|
|
sb.Append(line.PadRight((int)MaxNumberOfCharactersPerLine));
|
|
sb.Append("\n");
|
|
}
|
|
msg = sb.ToString();
|
|
}
|
|
else if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg.Length > MaxNumberOfCharactersPerLine))
|
|
{
|
|
// Incredible and amazing Padding code
|
|
string[] lines = msg.Split('\n');
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i = 0; i < lines.Length; ++i)
|
|
{
|
|
if (lines[i].Length < MaxNumberOfCharactersPerLine)
|
|
{
|
|
sb.Append(lines[i].PadRight((int)MaxNumberOfCharactersPerLine));
|
|
sb.Append("\n");
|
|
}
|
|
else if (lines[i].Length > MaxNumberOfCharactersPerLine)
|
|
{
|
|
// truncate
|
|
for (int j = 0; j < lines[i].Length; j = j + (int)MaxNumberOfCharactersPerLine)
|
|
{
|
|
string strSub = lines[i].Substring(j, ((lines[i].Length - j) > (int)MaxNumberOfCharactersPerLine) ? (int)MaxNumberOfCharactersPerLine : (lines[i].Length - j));
|
|
if (strSub.Length == (int)MaxNumberOfCharactersPerLine)
|
|
{
|
|
sb.Append(strSub);
|
|
sb.Append("\n");
|
|
}
|
|
else
|
|
{
|
|
sb.Append(strSub.PadRight((int)MaxNumberOfCharactersPerLine));
|
|
sb.Append("\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sb.Append(lines[i]);
|
|
sb.Append("\n");
|
|
}
|
|
}
|
|
|
|
// Write nicely formatted Message out
|
|
msg = sb.ToString();
|
|
}
|
|
else
|
|
{
|
|
// do nothing, string is miracioulsy exactly correct
|
|
}
|
|
#endregion
|
|
|
|
// Remember the title & message that we'll look for.
|
|
// The hook sees *all* windows, so we need to make sure we operate on the right one.
|
|
_msg = msg;
|
|
_title = title;
|
|
|
|
// if Owner is the Desktop Window
|
|
_IsDesktopOwner = (owner.Handle == Functions.GetDestopWindow().Handle);
|
|
|
|
// Icon could not be present
|
|
if (TitleBarIcon != null)
|
|
_hIcon = TitleBarIcon.ToBitmap().GetHicon();
|
|
|
|
// Set the hook.
|
|
// Suppress "GetCurrentThreadId() is deprecated" warning.
|
|
// It's documented that Thread.ManagedThreadId doesn't work with SetWindowsHookEx()
|
|
#pragma warning disable 0618
|
|
_hHook = User32.SetWindowsHookEx(Definitions.WH_CBT, _hookProcDelegate, IntPtr.Zero, AppDomain.GetCurrentThreadId());
|
|
#pragma warning restore 0618
|
|
|
|
// Pop a standard MessageBox. The hook will center it.
|
|
DialogResult rslt = DialogResult.None;
|
|
if (_IsDesktopOwner)
|
|
rslt = MessageBox.Show(_msg, _title, btns, icon);
|
|
else
|
|
rslt = MessageBox.Show(owner, _msg, _title, btns, icon);
|
|
|
|
// Release hook, clean up (may have already occurred)
|
|
Unhook();
|
|
|
|
return rslt;
|
|
}
|
|
|
|
private static void Unhook()
|
|
{
|
|
User32.UnhookWindowsHookEx(_hHook);
|
|
_hHook = 0;
|
|
_hookProcDelegate = null;
|
|
_msg = null;
|
|
_title = null;
|
|
}
|
|
|
|
private static int HookCallback(int code, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
int hHook = _hHook; // Local copy for CallNextHookEx() JIC we release _hHook
|
|
|
|
// Look for HCBT_ACTIVATE, *not* HCBT_CREATEWND:
|
|
// child controls haven't yet been created upon HCBT_CREATEWND.
|
|
if (code == Definitions.HCBT_ACTIVATE)
|
|
{
|
|
string cls = Functions.GetWindowClassName(wParam);
|
|
if (cls == "#32770") // MessageBoxes are Dialog boxes
|
|
{
|
|
string title = Functions.GetWindowText(wParam);
|
|
string msg = Functions.GetDlgItemText(wParam, 0xFFFF); // -1 aka IDC_STATIC
|
|
if ((title == _title) && (msg == _msg))
|
|
{
|
|
// Only Center the Window, if the Owner is NOT the Desktop
|
|
if (!_IsDesktopOwner)
|
|
CenterWindowOnParent(wParam);
|
|
|
|
Unhook(); // Release hook - we've done what we needed
|
|
|
|
// Now we also want to set the Icon on the Dialog
|
|
if (_hIcon != IntPtr.Zero)
|
|
{
|
|
User32.SendMessage(wParam, (int)Definitions.WM.WM_SETICON, (IntPtr)1, _hIcon);
|
|
User32.SendMessage(wParam, (int)Definitions.WM.WM_SETICON, (IntPtr)0, _hIcon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return User32.CallNextHookEx(hHook, code, wParam, lParam);
|
|
}
|
|
|
|
// Boilerplate window-centering code.
|
|
// Split out of HookCallback() for clarity.
|
|
private static void CenterWindowOnParent(IntPtr hChildWnd)
|
|
{
|
|
// Get child (MessageBox) size
|
|
Structures.RECT rcChild = new Structures.RECT();
|
|
User32.GetWindowRect(hChildWnd, out rcChild);
|
|
int cxChild = rcChild.right - rcChild.left;
|
|
int cyChild = rcChild.bottom - rcChild.top;
|
|
|
|
// Get parent (Form) size & location
|
|
IntPtr hParent = User32.GetParent(hChildWnd);
|
|
Structures.RECT rcParent = new Structures.RECT();
|
|
User32.GetWindowRect(hParent, out rcParent);
|
|
int cxParent = rcParent.right - rcParent.left;
|
|
int cyParent = rcParent.bottom - rcParent.top;
|
|
|
|
// Center the MessageBox on the Form
|
|
int x = rcParent.left + (cxParent - cxChild) / 2;
|
|
int y = rcParent.top + (cyParent - cyChild) / 2;
|
|
uint uFlags = 0x15; // SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
User32.SetWindowPos(hChildWnd, IntPtr.Zero, x, y, 0, 0, uFlags);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|