From 6c4a37655b991ace765162a5e855ee90e805b3f0 Mon Sep 17 00:00:00 2001 From: dahall Date: Mon, 8 Feb 2021 15:30:54 -0700 Subject: [PATCH] Added `WindowClass` to ensupsulate information about a window class. --- PInvoke/User32/WindowClass.cs | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 PInvoke/User32/WindowClass.cs diff --git a/PInvoke/User32/WindowClass.cs b/PInvoke/User32/WindowClass.cs new file mode 100644 index 00000000..53d043ca --- /dev/null +++ b/PInvoke/User32/WindowClass.cs @@ -0,0 +1,143 @@ +using System; +using System.Runtime.InteropServices; +using static Vanara.PInvoke.User32; + +namespace Vanara.PInvoke +{ + /// Encapsulates a window class. + public class WindowClass + { + /// The instance of the populated for the window class. + public readonly WNDCLASSEX wc; + + /// Initializes a new instance of the class and registers the class name. + /// + /// + /// A string that specifies the window class name. The class name can be any name registered with RegisterClass or RegisterClassEx, + /// or any of the predefined control-class names. + /// + /// + /// The maximum length for lpszClassName is 256. If lpszClassName is greater than the maximum length, the + /// RegisterClassEx function will fail. + /// + /// + /// A handle to the instance that contains the window procedure for the class. + /// + /// A pointer to the window procedure. You must use the CallWindowProc function to call the window procedure. For more information, + /// see WindowProc. + /// + /// The class style(s). This member can be any combination of the Class Styles. + /// + /// A handle to the class icon. This member must be a handle to an icon resource. If this member is NULL, the system provides + /// a default icon. + /// + /// + /// A handle to a small icon that is associated with the window class. If this member is NULL, the system searches the icon + /// resource specified by the hIcon member for an icon of the appropriate size to use as the small icon. + /// + /// + /// A handle to the class cursor. This member must be a handle to a cursor resource. If this member is NULL, an application + /// must explicitly set the cursor shape whenever the mouse moves into the application's window. + /// + /// + /// A handle to the class background brush. This member can be a handle to the brush to be used for painting the background, or it + /// can be a color value. A color value must be one of the following standard system colors (the value 1 must be added to the chosen color). + /// + /// The system automatically deletes class background brushes when the class is unregistered by using . + /// An application should not delete these brushes. + /// + /// + /// When this member is NULL, an application must paint its own background whenever it is requested to paint in its client + /// area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test + /// the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function. + /// + /// + /// + /// A string that specifies the resource name of the class menu, as the name appears in the resource file. If you use an integer to + /// identify the menu, use the MAKEINTRESOURCE macro. If this member is NULL, windows belonging to this class have no default menu. + /// + /// + /// The number of extra bytes to allocate following the window-class structure. The system initializes the bytes to zero. + /// + /// + /// The number of extra bytes to allocate following the window instance. The system initializes the bytes to zero. If an application + /// uses WNDCLASSEX to register a dialog box created by using the CLASS directive in the resource file, it must set + /// this member to DLGWINDOWEXTRA. + /// + public WindowClass(string className, HINSTANCE hInst, WindowProc wndProc, WindowClassStyles styles = 0, HICON hIcon = default, HICON hSmIcon = default, + HCURSOR hCursor = default, HBRUSH hbrBkgd = default, string menuName = null, int extraBytes = 0, int extraWinBytes = 0) + { + // TODO: Find way to hold on to wndProc ref + wc = new WNDCLASSEX + { + cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)), + lpfnWndProc = wndProc, + hInstance = hInst, + lpszClassName = className, + style = styles, + hIcon = hIcon, + hIconSm = hSmIcon, + hCursor = hCursor, + hbrBackground = hbrBkgd, + lpszMenuName = menuName, + cbClsExtra = extraBytes, + cbWndExtra = extraWinBytes, + }; + Atom = Win32Error.ThrowLastErrorIfNull(Macros.MAKEINTATOM(RegisterClassEx(wc))); + } + + private WindowClass(in WNDCLASSEX wcx) => wc = wcx; + + /// Gets the class atom that uniquely identifies the registered class. + public IntPtr Atom { get; private set; } + + /// Gets the windows class name. + public string ClassName => wc.lpszClassName; + + /// Gets the class style(s). + public WindowClassStyles Styles => wc.style; + + /// Gets a instance associated with a window handle. + /// The window handle to examine. + /// + /// If the function finds a matching window and successfully copies the data, the return value is a + /// instance. If not, is returned. + /// + public static WindowClass GetInstanceFromWindow(HWND hWnd) + { + var atom = GetClassWord(hWnd, -32 /*GCW_ATOM*/); + var hInst = GetClassLong(hWnd, -16 /*GCL_HMODULE*/); + var wcx = new WNDCLASSEX { cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)) }; + return GetClassInfoEx(hInst, Macros.MAKEINTATOM(atom), ref wcx) ? new WindowClass(wcx) : null; + } + + /// Gets a instance by looking up the name. + /// + /// The class name. The name must be that of a preregistered class or a class registered by a previous call to the RegisterClass or + /// RegisterClassEx function. + /// + /// + /// A handle to the instance of the application that created the class. To retrieve information about classes defined by the system + /// (such as buttons or list boxes), set this parameter to NULL. + /// + /// + /// If the function finds a matching class and successfully copies the data, the return value is a + /// instance. If not, is returned. + /// + public static WindowClass GetNamedInstance(string className, HINSTANCE hInst = default) + { + var wcx = new WNDCLASSEX { cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)) }; + return GetClassInfoEx(hInst, className, ref wcx) ? new WindowClass(wcx) : null; + } + + /// Unregisters this window class. + /// + /// If the function succeeds, the return value is . + /// + /// If the class could not be found or if a window still exists that was created with the class, the return value is . To get extended error information, call GetLastError. + /// + /// + public bool Unregister() => UnregisterClass(wc.lpszClassName, wc.hInstance); + } +} \ No newline at end of file