using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using Yaulw.Win32; using System.Drawing; using System.ComponentModel; using WPFWin = System.Windows; using WPFWinInterop = System.Windows.Interop; using Yaulw.Tools; namespace Yaulw.WinForms { /// /// MsgBox is a WindowsForms MessageBox that can be centered to the Parent /// public static class MsgBox { #region Public Properties /// /// Message Box Icon to use /// public static Icon DefaultTitleBarIcon { get; set; } /// /// Set the max number of characters to show on each line /// public static uint MaxNumberOfCharactersPerLine { get; set; } /// /// the default max number of characters on each line /// public const uint DefaultNumberOfCharactersPerLine = 62; #endregion #region Public Header Properties /// /// Get / Set to show a header in the Message Box /// public static bool ShowHeader { get; set; } /// /// Get / Set the Error Header /// public static string MsgBox_ErrorHeader { get; set; } /// /// Get / Set the Fatal Error Header /// public static string MsgBox_FatalErrorHeader { get; set; } /// /// Get / Set the Warning Header /// public static string MsgBox_WarningHeader { get; set; } /// /// Get / Set the Information Header /// public static string MsgBox_InfoHeader { get; set; } #endregion #region Public Footer Properties /// /// Get / Set to show a footer in the Message Box /// public static bool ShowFooter { get; set; } /// /// Get / Set the Error Footer /// public static string MsgBox_ErrorFooter { get; set; } /// /// Get / Set the Fatal Error Footer /// public static string MsgBox_FatalErrorFooter { get; set; } /// /// Get / Set the Warning Footer /// public static string MsgBox_WarningFooter { get; set; } /// /// Get / Set the Information Footer /// public static string MsgBox_InfoFooter { get; set; } #endregion #region Public Title Header Properties /// /// Get / Set to show a header in the Message Box Title /// public static bool ShowTitleHeader { get; set; } /// /// Get / Set the Error Title Header /// public static string MsgBox_ErrorTitleHeader { get; set; } /// /// Get / Set the Fatal Error Title Header /// public static string MsgBox_FatalErrorTitleHeader { get; set; } /// /// Get / Set the Warning Title Header /// public static string MsgBox_WarningTitleHeader { get; set; } /// /// Get / Set the Information Title Header /// public static string MsgBox_InfoTitleHeader { get; set; } #endregion #region Construction /// /// MsgBox Construction, ShowHeader, ShowFooter, ShowTitleHeader defaulted to true /// static MsgBox() { DefaultTitleBarIcon = null; MaxNumberOfCharactersPerLine = DefaultNumberOfCharactersPerLine; // Header Init ShowHeader = true; ShowFooter = true; ShowTitleHeader = true; } #endregion #region Public Static Methods /// /// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box 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(Yaulw.Win32.Convert.ConverthWndToIWin32Window(interop.Handle), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon); } return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon); } /// /// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult Show(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon) { return Show(parent, Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon); } /// /// Shows a custom Message Box (centered to Desktop), with the DefaultTitleBarIcon /// /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult Show(String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon) { return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon); } #endregion #region Public Static Methods Extended /// /// Shows Warning MessageBox (WPF) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowWarning(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation); } /// /// Shows Warning MessageBox (WinForms) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowWarning(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation); } /// /// Shows Warning MessageBox (Desktop) /// /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowWarning(String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation); } /// /// Shows Fatal Error MessageBox (WPF) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowFatalError(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { _ShowFatal = true; DialogResult dr = Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error); _ShowFatal = false; return dr; } /// /// Shows Fatal Error MessageBox (WinForms) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowFatalError(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { _ShowFatal = true; DialogResult dr = Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error); _ShowFatal = false; return dr; } /// /// Shows Fatal Error MessageBox (Desktop) /// /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowFatalError(String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { _ShowFatal = true; DialogResult dr = Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error); _ShowFatal = false; return dr; } /// /// Shows Error MessageBox (WPF) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowError(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error); } /// /// Shows Error MessageBox (WinForms) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowError(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error); } /// /// Shows Error MessageBox (Desktop) /// /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowError(String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error); } /// /// Shows Information MessageBox (WPF) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowInfo(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Information); } /// /// Shows Information MessageBox (WinForms) /// /// Window To center Message Box Against /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowInfo(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Information); } /// /// Shows Information MessageBox (Desktop) /// /// Title to show /// Text to show /// buttons to show /// icon to show /// the result of the Message Box public static DialogResult ShowInfo(String Title, String Text, MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK) { return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Information); } #endregion #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; #endregion #region Private Methods /// /// Delegate to make All Message Boxes Thread-Safe /// private delegate DialogResult ShowMsgBoxDelegate(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon, Icon TitleBarIcon); /// /// *Main MessageBox Show Function* allows you to center the Message Box to the Parent * Dispatcher Safe * /// /// Result of Dialog private 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); } } /// /// Internal Message Box Showing Function, responsible for showing the message box, setting the hook, etc /// /// any IWin32Window /// message to show /// title to show /// buttons to show /// messageboxicon /// Title bar Icon /// 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); // Perform header/footer/title actions HeaderFooterTitleAction(ref msg, ref title, icon); // Properly Format and Pad the Message MsgTextPaddingAndFormatting(ref msg); // 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(); else _hIcon = IntPtr.Zero; // 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; } /// /// Responsible for adding Header / Footer / Title Information /// /// text to add header/footer for, if set /// text to add title header for, if set /// Message Icon used in MessageBox private static void HeaderFooterTitleAction(ref string msg, ref string title, MessageBoxIcon icon) { #region Header Action if (ShowHeader) { if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorHeader) && _ShowFatal) msg = MsgBox_FatalErrorHeader + "\n\n" + msg; else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorHeader) && !_ShowFatal) msg = MsgBox_ErrorHeader + "\n\n" + msg; else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningHeader)) msg = MsgBox_WarningHeader + "\n\n" + msg; else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoHeader)) msg = MsgBox_InfoHeader + "\n\n" + msg; } #endregion #region Footer Action if (ShowFooter) { if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorFooter) && _ShowFatal) msg = msg + "\n\n" + MsgBox_FatalErrorFooter; else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorFooter) && !_ShowFatal) msg = msg + "\n\n" + MsgBox_ErrorFooter; else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningFooter)) msg = msg + "\n\n" + MsgBox_WarningFooter; else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoFooter)) msg = msg + "\n\n" + 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 } /// /// Perform Message Text padding and Text Wrapping /// /// the Padded and Text Wrapped Message private static void MsgTextPaddingAndFormatting(ref string msg) { // 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) { sb.Append(lines[i]); sb.Append("\n"); } else if (lines[i].Length > MaxNumberOfCharactersPerLine) { // Split up all the SubLines into a List List nSubLinesList = new List(); for (int j = 0; j < lines[i].Length; j = j + (int)MaxNumberOfCharactersPerLine) { string line = lines[i].Substring(j, ((lines[i].Length - j) > (int)MaxNumberOfCharactersPerLine) ? (int)MaxNumberOfCharactersPerLine : (lines[i].Length - j)); nSubLinesList.Add(line); } // Perform proper Text Wrapping on all Sub Lines for (int j = 0; j < nSubLinesList.Count; ++j) { string line1 = nSubLinesList[j]; string line2 = (j + 1 < nSubLinesList.Count) ? nSubLinesList[j + 1] : String.Empty; if (!String.IsNullOrEmpty(line2)) { if (StringTool.StringEndsWithLetter(line1) && StringTool.StringStartsWithLetter(line2)) { string word1 = StringTool.StringFetchLastWord(line1); string word2 = StringTool.StringFetchFirstWord(line2); string word = word1 + word2; // Use Text Wrapping to make sure word is wrapped correctly if (word.Length < (int)MaxNumberOfCharactersPerLine) { StringTool.StringStripeLastWord(ref line1); StringTool.StringStripeFirstWord(ref line2); // Now perform the proper corrections to the actual list nSubLinesList[j] = line1.PadRight((int)MaxNumberOfCharactersPerLine); nSubLinesList[j + 1] = word + line2; // Adjust lines string toMoveDown = ""; for (int z = j + 1; z < nSubLinesList.Count; ++z) { // First Append the Move down if (!String.IsNullOrEmpty(toMoveDown)) { nSubLinesList[z] = toMoveDown + nSubLinesList[z]; toMoveDown = ""; } // Check Char Limit * make adjustment as needed * if (nSubLinesList[z].Length > MaxNumberOfCharactersPerLine) { toMoveDown = nSubLinesList[z].Substring((int)MaxNumberOfCharactersPerLine); nSubLinesList[z] = nSubLinesList[z].Substring(0, (int)MaxNumberOfCharactersPerLine); } } // Add the dangling Move Down as a new Line(s) if (!String.IsNullOrEmpty(toMoveDown)) { for (int z = 0; z < toMoveDown.Length; z = z + (int)MaxNumberOfCharactersPerLine) { string line = toMoveDown.Substring(z, ((toMoveDown.Length - z) > (int)MaxNumberOfCharactersPerLine) ? (int)MaxNumberOfCharactersPerLine : (toMoveDown.Length - z)); nSubLinesList.Add(line); } } } } } } // Iterate all subLines and add them to the main list * Padded * foreach (string line in nSubLinesList) { if (line.Length == (int)MaxNumberOfCharactersPerLine) { sb.Append(line); sb.Append("\n"); } else { sb.Append(line.PadRight((int)MaxNumberOfCharactersPerLine)); sb.Append("\n"); } } } } // Write nicely formatted Message out msg = sb.ToString(); } else { // do nothing, string is miracioulsy exactly correct } } /// /// Unhook the User Window Hook /// private static void Unhook() { User32.UnhookWindowsHookEx(_hHook); _hHook = 0; _hookProcDelegate = null; _msg = null; _title = null; } /// /// Callback for the User Window Hook /// /// /// wParam Passed in /// lParam Passed in /// the result of the next hook in the chain 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. /// /// handle of child window to center 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 } }