using System; using System.Windows.Forms; using static Vanara.PInvoke.User32; namespace Vanara.Extensions { /// Control extension methods. public static partial class ControlExtension { /// /// Performs an action on a control after its handle has been created. If the control's handle has already been created, the action is executed immediately. /// /// This control. /// The action to execute. public static void CallWhenHandleValid(this Control ctrl, Action action) { if (ctrl.IsHandleCreated) { action(ctrl); } else if (!ctrl.IsDesignMode()) { void handler(object sender, EventArgs e) { if (!ctrl.IsHandleCreated) return; ctrl.HandleCreated -= handler; action(ctrl); } ctrl.HandleCreated += handler; } } /// Enables all children of a control. /// This control. /// If set to true enable all children, otherwise disable all children. public static void EnableChildren(this Control ctl, bool enabled) { foreach (Control sub in ctl.Controls) { if (sub is ButtonBase || sub is ListControl || sub is TextBoxBase) sub.Enabled = enabled; sub.EnableChildren(enabled); } } /// Gets the control in the list of parents of type T. /// The based of the parent control to retrieve. /// This control. /// The parent control matching T or null if not found. public static T GetParent(this Control ctrl) where T : class { var p = ctrl.Parent; while (p != null & !(p is T)) p = p.Parent; return p as T; } /// Gets the top-most control in the list of parents of type T. /// The based of the parent control to retrieve. /// This control. /// The top-most parent control matching T or null if not found. public static T GetTopMostParent(this Control ctrl) where T : class { var stack = new System.Collections.Generic.Stack(); var p = ctrl.Parent; while (p != null) { stack.Push(p); p = p.Parent; } while (stack.Count > 0) if ((p = stack.Pop()) is T) return p as T; return null; } /// Gets the right to left property. /// This control. /// Culture defined direction of text for this control. public static RightToLeft GetRightToLeftProperty(this Control ctrl) { while (ctrl != null) { if (ctrl.RightToLeft != RightToLeft.Inherit) return ctrl.RightToLeft; ctrl = ctrl.Parent; } return RightToLeft.No; } /// Determines whether this control is in design mode. /// This control. /// true if in design mode; otherwise, false. public static bool IsDesignMode(this Control ctrl) { var p = ctrl; while (p != null) { var site = p.Site; if (site != null && site.DesignMode) return true; p = p.Parent; } return false; } /// /// Gets a string using a message pattern that asks for the string length by sending a GetXXXLen message and then a GetXXXText message. /// /// The control. /// The window message identifier for retrieving the string length. /// The window message identifier for retrieving the string. /// The string result from the message call. public static string GetMessageString(this Control ctrl, uint getLenMsg, uint getTextMsg) { if (!ctrl.IsHandleCreated) return null; var cp = ctrl.SendMessage(getLenMsg).ToInt32() + 1; var sb = new System.Text.StringBuilder(cp); Vanara.PInvoke.User32.SendMessage(ctrl.Handle, getTextMsg, ref cp, sb); return sb.ToString(); } /// Retrieves the window styles. /// The control. /// The window styles public static int GetStyle(this Control ctrl) => GetWindowLongAuto(ctrl.Handle, WindowLongFlags.GWL_STYLE).ToInt32(); /// Removes the mnemonic, if one exists, from the string. /// The string. /// A mnemonic free string. public static string RemoveMnemonic(this string str) { if (str == null) return null; var idx = str?.IndexOf('&'); if (idx >= 0) { var sb = new System.Text.StringBuilder(str); sb.Remove(idx.Value, 1); return sb.ToString(); } return str; } /// /// /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not /// return until the window procedure has processed the message. /// /// /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's /// message queue and return immediately, use the PostMessage or PostThreadMessage function. /// /// /// /// /// A window whose window procedure will receive the message. /// /// /// Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal /// integrity level. /// /// /// The message to be sent. /// Additional message-specific information. /// Additional message-specific information. /// The return value specifies the result of the message processing; it depends on the message sent. public static IntPtr SendMessage(this IWin32Window wnd, uint msg, IntPtr wParam = default, IntPtr lParam = default) => wnd.Handle != IntPtr.Zero && wnd.Handle.ToInt32() != -1 ? Vanara.PInvoke.User32.SendMessage(wnd.Handle, msg, wParam, lParam) : IntPtr.Zero; /// Sets the windows styles. /// The control. /// The style flags. /// if set to true add the style, otherwise remove it. public static void SetStyle(this Control ctrl, int style, bool on = true) { var href = ctrl.Handle; int oldstyle = GetWindowLongAuto(href, WindowLongFlags.GWL_STYLE).ToInt32(); if ((oldstyle & style) != style && on) SetWindowLong(href, WindowLongFlags.GWL_STYLE, new IntPtr(oldstyle | style)); else if ((oldstyle & style) == style && !on) SetWindowLong(href, WindowLongFlags.GWL_STYLE, new IntPtr(oldstyle & ~style)); ctrl.Refresh(); } /// Converts a structure to a structure. /// The MSG instance. /// An equivalent structure. public static Message ToMessage(this PInvoke.MSG msg) => Message.Create((IntPtr)msg.hwnd, (int)msg.message, msg.wParam, msg.lParam); /// Converts a structure to a structure. /// The Message instance. /// An equivalent structure. public static PInvoke.MSG ToMSG(this Message msg) => new PInvoke.MSG { message = (uint)msg.Msg, hwnd = msg.HWnd, wParam = msg.WParam, lParam = msg.LParam }; } }