diff --git a/PInvoke/User32/BasicMessageWindow.cs b/PInvoke/User32/BasicMessageWindow.cs
index 2dff4a59..1f643ef7 100644
--- a/PInvoke/User32/BasicMessageWindow.cs
+++ b/PInvoke/User32/BasicMessageWindow.cs
@@ -19,30 +19,15 @@ namespace Vanara.PInvoke;
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate bool BasicMessageWindowFilter(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam, out IntPtr lReturn);
-/// An interface that represents a Win32 window with created and destroyed events.
-public interface IWindowCore
-{
- /// Gets the window handle.
- /// The window handle.
- HWND Handle { get; }
-
- /// Occurs when the window is created and has a valid handle.
- event Action Created;
-
- /// Occurs when the window has been destroyed.
- event Action Destroyed;
-}
-
/// Simple window to process messages.
///
///
///
-public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle, IWindowCore
+public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle
{
private readonly WeakReference weakSelfRef;
private SafeHWND hwnd;
private bool isDisposed;
- private ParamIndexer paramIndexer;
private WindowClass wCls;
/// Initializes a new instance of the class.
@@ -54,168 +39,20 @@ public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle, IWin
hwnd = CreateWindow();
}
- private BasicMessageWindow() { }
-
/// Finalizes an instance of the class.
~BasicMessageWindow() => Dispose(false);
- /// Occurs when the window is created and has a valid handle.
- public event Action Created;
-
- /// Occurs when the window has been destroyed.
- public event Action Destroyed;
-
- ///
- /// Gets or sets the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that
- /// are relative to the upper-left corner of the screen.
- ///
- /// A RECT structure with the screen coordinates of the upper-left and lower-right corners of the window.
- public RECT Bounds
- {
- get { Win32Error.ThrowLastErrorIfFalse(GetWindowRect(Handle, out RECT r)); return r; }
- set => SetPosition(value.Location, value.Size);
- }
-
- /// Gets the name of the windows class.
- /// The name of the windows class.
- public string ClassName => wCls?.ClassName;
-
- ///
- /// Gets the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client
- /// area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left
- /// corner are (0,0).
- ///
- ///
- /// A RECT structure with the client coordinates. The left and top members are zero. The right and bottom members contain the width and
- /// height of the window.
- ///
- public RECT ClientRect
- {
- get { Win32Error.ThrowLastErrorIfFalse(GetClientRect(Handle, out RECT r)); return r; }
- }
-
- /// Gets a value indicating whether this is enabled.
- /// if enabled; otherwise, .
- public bool Enabled => IsWindowEnabled(Handle);
-
- /// Gets a value indicating whether the window has input focus.
- /// if focused; otherwise, .
- public bool Focused => GetFocus().Equals(Handle);
-
- /// Gets the window handle.
- /// The window handle.
+ /// Gets the handle.
+ /// The handle.
public HWND Handle => hwnd ?? HWND.NULL;
/// Gets or sets the callback method used to filter window messages.
/// The callback method.
public BasicMessageWindowFilter MessageFilter { get; set; }
- /// Gets or sets information about the window.
- /// The information indexer.
- public ISupportIndexer Param => paramIndexer ??= new ParamIndexer(this);
-
- ///
- /// Gets or sets the position of the window. The dimensions are given in screen coordinates that are relative to the upper-left corner of
- /// the screen.
- ///
- /// The position of window.
- public POINT Position
- {
- get
- {
- Win32Error.ThrowLastErrorIfFalse(GetWindowRect(Handle, out RECT r));
- return r.Location;
- }
- set => Win32Error.ThrowLastErrorIfFalse(SetWindowPos(Handle, default, value.X, value.Y, -1, -1, SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOZORDER));
- }
-
- /// Gets or sets the window's show state.
- /// The show state.
- public ShowWindowCommand ShowState
- {
- get
- {
- if (!Visible)
- return ShowWindowCommand.SW_HIDE;
- if (IsIconic(Handle))
- return ShowWindowCommand.SW_MINIMIZE;
- if (IsZoomed(Handle))
- return ShowWindowCommand.SW_MAXIMIZE;
- return ShowWindowCommand.SW_NORMAL;
- }
- set => Win32Error.ThrowLastErrorIfFalse(ShowWindow(Handle, value));
- }
-
- /// Gets or sets the size of the window.
- /// The size of window.
- public SIZE Size
- {
- get
- {
- Win32Error.ThrowLastErrorIfFalse(GetWindowRect(Handle, out RECT r));
- return r.Size;
- }
- set => Win32Error.ThrowLastErrorIfFalse(SetWindowPos(Handle, default, -1, -1, value.cx, value.cy, SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOZORDER));
- }
-
- /// Gets or sets the value of the style bit for the window.
- /// The styles value.
- public WindowStyles Styles
- {
- get => (WindowStyles)Param[WindowLongFlags.GWL_STYLE].ToInt32();
- set => Param[WindowLongFlags.GWL_STYLE] = (IntPtr)(int)value;
- }
-
- /// Gets or sets the value of the extended style bit for the window.
- /// The extended styles value.
- public WindowStylesEx StylesEx
- {
- get => (WindowStylesEx)Param[WindowLongFlags.GWL_EXSTYLE].ToInt32();
- set => Param[WindowLongFlags.GWL_EXSTYLE] = (IntPtr)(int)value;
- }
-
- /// Gets or sets the text of the window's title bar (if it has one).
- /// The text of the title bar.
- public string Text
- {
- get
- {
- if (!Handle.IsNull)
- {
- int len = GetWindowTextLength(Handle);
- if (len > 0)
- {
- StringBuilder sb = new(len);
- if (GetWindowText(Handle, sb, sb.Capacity) > 0)
- {
- return sb.ToString();
- }
- }
- }
- return string.Empty;
- }
- set => Win32Error.ThrowLastErrorIfFalse(SetWindowText(Handle, value));
- }
-
- /// Gets or sets a value indicating whether this window is visible.
- /// if visible; otherwise, .
- public bool Visible
- {
- get => IsWindowVisible(Handle);
- set => ShowState = value ? ShowWindowCommand.SW_SHOW : ShowWindowCommand.SW_HIDE;
- }
-
- /// Converts a rectangle from this window's client coordinates to screen coordinates.
- /// A in client coordinates.
- /// The resulting in screen coordinates.
- public virtual RECT ClientToScreen(in RECT clientRect)
- {
- RECT screenRect = clientRect;
- SetLastError(0);
- Win32Error.ThrowLastErrorIf(MapWindowPoints(Handle, IntPtr.Zero, ref screenRect), i => i == 0);
- Win32Error.ThrowLastErrorIfFalse(AdjustWindowRectEx(ref screenRect, Styles, GetMenu(Handle) != IntPtr.Zero, StylesEx));
- return screenRect;
- }
+ /// Gets the name of the class.
+ /// The name of the class.
+ public string ClassName => wCls?.ClassName;
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
@@ -224,157 +61,21 @@ public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle, IWin
System.GC.SuppressFinalize(this);
}
- /// Sets input focus to the window.
- public void Focus() => Win32Error.ThrowLastErrorIf(SetFocus(Handle), h => h.IsNull);
-
- ///
- /// Invalidates the specified region of the windows (adds it to the window's update region, which is the area that will be repainted at
- /// the next paint operation), and causes a paint message to be sent to the window. Optionally, invalidates the child windows assigned to
- /// the window.
- ///
- /// to invalidate the window's child windows; otherwise, .
- ///
- /// A that represents the region to invalidate. This value can be , in which case the entire
- /// client region is invalidated.
- ///
- public void Invalidate(bool erase = false, PRECT pRect = null) => Win32Error.ThrowLastErrorIfFalse(InvalidateRect(Handle, pRect, erase));
-
- /// Converts a rectangle from screen coordinates to this window's client coordinates.
- /// A in screen coordinates.
- /// The resulting in client coordinates.
- public virtual RECT ScreenToClient(in RECT screenRect)
- {
- RECT clientRect = screenRect;
- SetLastError(0);
- Win32Error.ThrowLastErrorIf(MapWindowPoints(IntPtr.Zero, Handle, ref clientRect), i => i == 0);
- RECT invRect = default;
- Win32Error.ThrowLastErrorIfFalse(AdjustWindowRectEx(ref invRect, Styles, GetMenu(Handle) != IntPtr.Zero, StylesEx));
- SubtractRect(out clientRect, clientRect, invRect);
- return clientRect;
- }
-
- ///
- /// Changes the size, position, and Z order of a child, pop-up, or top-level window. These windows are ordered according to their
- /// appearance on the screen. The topmost window receives the highest rank and is the first window in the Z order.
- ///
- ///
- /// Type: HWND
- ///
- /// A handle to the window to precede the positioned window in the Z order. This parameter must be a window handle or one of the
- /// following values.
- ///
- ///
- ///
- /// Value
- /// Meaning
- ///
- /// -
- /// HWND_BOTTOM (HWND)1
- ///
- /// Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost
- /// status and is placed at the bottom of all other windows.
- ///
- ///
- /// -
- /// HWND_NOTOPMOST (HWND)-2
- ///
- /// Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is
- /// already a non-topmost window.
- ///
- ///
- /// -
- /// HWND_TOP (HWND)0
- /// Places the window at the top of the Z order.
- ///
- /// -
- /// HWND_TOPMOST (HWND)-1
- /// Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
- ///
- ///
- /// For more information about how this parameter is used, see the following Remarks section.
- ///
- /// The new position of the window, in client coordinates.
- /// The new width of the window, in pixels.
- /// The window sizing and positioning flags. This parameter can be one of more values from .
- ///
- /// Type: Type: BOOL
- /// If the function succeeds, the return value is nonzero.
- /// If the function fails, the return value is zero. To get extended error information, call GetLastError.
- ///
- ///
- ///
- /// As part of the Vista re-architecture, all services were moved off the interactive desktop into Session 0. hwnd and window manager
- /// operations are only effective inside a session and cross-session attempts to manipulate the hwnd will fail. For more information, see
- /// The Windows Vista Developer Story: Application Compatibility Cookbook.
- ///
- ///
- /// If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to take effect. Use
- /// the following combination for uFlags: .
- ///
- ///
- /// A window can be made a topmost window either by setting the hWndInsertAfter parameter to HWND_TOPMOST and ensuring that the
- /// SWP_NOZORDER flag is not set, or by setting a window's position in the Z order so that it is above any existing topmost
- /// windows. When a non-topmost window is made topmost, its owned windows are also made topmost. Its owners, however, are not changed.
- ///
- ///
- /// If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that a window
- /// be simultaneously activated and its position in the Z order changed), the value specified in hWndInsertAfter is used only in the
- /// following circumstances.
- ///
- ///
- /// -
- /// Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hWndInsertAfter.
- ///
- /// -
- /// The window identified by hWnd is not the active window.
- ///
- ///
- ///
- /// An application cannot activate an inactive window without also bringing it to the top of the Z order. Applications can change an
- /// activated window's position in the Z order without restrictions, or it can activate a window and then move it to the top of the
- /// topmost or non-topmost windows.
- ///
- ///
- /// If a topmost window is repositioned to the bottom ( HWND_BOTTOM) of the Z order or after any non-topmost window, it is no
- /// longer topmost. When a topmost window is made non-topmost, its owners and its owned windows are also made non-topmost windows.
- ///
- ///
- /// A non-topmost window can own a topmost window, but the reverse cannot occur. Any window (for example, a dialog box) owned by a
- /// topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner.
- ///
- /// If an application is not in the foreground, and should be in the foreground, it must call the SetForegroundWindow function.
- /// To use SetWindowPos to bring a window to the top, the process that owns the window must have SetForegroundWindow permission.
- ///
- public void SetPosition(POINT position, SIZE size, HWND hWndInsertAfter = default, SetWindowPosFlags flags = SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOZORDER) =>
- Win32Error.ThrowLastErrorIfFalse(SetWindowPos(Handle, hWndInsertAfter, position.X, position.Y, size.cx, size.cy, flags));
-
- ///
- /// The Validate function validates the client area within a rectangle by removing the rectangle from the update region of the
- /// this window.
- ///
- ///
- /// A structure that contains the client coordinates of the rectangle to be removed from the update region. If this
- /// parameter is , the entire client area is removed.
- ///
- public void Validate(PRECT pRect = null) => Win32Error.ThrowLastErrorIfFalse(ValidateRect(Handle, pRect));
-
/// Returns the value of the handle field.
/// An IntPtr representing the value of the handle field.
IntPtr IHandle.DangerousGetHandle() => (IntPtr)Handle;
- /// Method used to create the window. When overriding, the hWnd field must be set to the handle of the created window.
+ ///
+ /// Method used to create the window. When overriding, the hWnd field must be set to the handle of the created window.
+ ///
protected virtual SafeHWND CreateWindow()
{
lock (this)
{
if (!Handle.IsNull)
- {
throw new InvalidOperationException("Window handle already exists.");
- }
-
- HINSTANCE hInst = GetModuleHandle();
- wCls = new WindowClass($"{GetType().Name}+{Guid.NewGuid()}", hInst, WndProc);
- return Win32Error.ThrowLastErrorIfInvalid(CreateWindowEx(0, wCls.Atom, hWndParent: HWND.HWND_MESSAGE, hInstance: hInst));
+ wCls = new WindowClass($"{GetType().Name}+{Guid.NewGuid()}", default, WndProc, hbrBkgd: WindowClass.NullBrush);
+ return Win32Error.ThrowLastErrorIfInvalid(CreateWindowEx(0, wCls.ClassName, hWndParent: HWND.HWND_MESSAGE, hInstance: wCls.wc.hInstance));
}
}
@@ -386,7 +87,6 @@ public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle, IWin
{
if (isDisposed)
return;
-
isDisposed = true;
hwnd?.Dispose(); // Calls DestroyWindow
@@ -398,40 +98,8 @@ public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle, IWin
{
if (msg == (uint)WindowMessage.WM_NCCREATE)
return (IntPtr)1;
-
- try
- {
- return !weakSelfRef.IsAlive || weakSelfRef.Target is null || MessageFilter is null || !MessageFilter.Invoke(hwnd, msg, wParam, lParam, out IntPtr lRet)
- ? DefWindowProc(hwnd, msg, wParam, lParam) : lRet;
- }
- finally
- {
- switch ((WindowMessage)msg)
- {
- case WindowMessage.WM_CREATE:
- Created?.Invoke();
- break;
- case WindowMessage.WM_NCDESTROY:
- Destroyed?.Invoke();
- break;
- }
- }
+ return !weakSelfRef.IsAlive || weakSelfRef.Target is null || MessageFilter is null || !MessageFilter.Invoke(hwnd, msg, wParam, lParam, out IntPtr lRet)
+ ? DefWindowProc(hwnd, msg, wParam, lParam)
+ : lRet;
}
-
- private class ParamIndexer : ISupportIndexer
- {
- private readonly BasicMessageWindow win;
-
- public ParamIndexer(BasicMessageWindow win) => this.win = win;
-
- public IntPtr this[WindowLongFlags flag]
- {
- get => GetWindowLongAuto(win.Handle, flag);
- set
- {
- SetLastError(0);
- Win32Error.ThrowLastErrorIf(SetWindowLong(win.Handle, flag, (int)value), i => i == 0);
- }
- }
- }
-}
\ No newline at end of file
+}