From b72469b046e1e9dca26bfe438991dbba71b2a5b0 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Wed, 17 Nov 2021 13:21:06 -0800 Subject: [PATCH] msgbox in a proper windows message loop --- src/main-windows.zig | 343 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 340 insertions(+), 3 deletions(-) diff --git a/src/main-windows.zig b/src/main-windows.zig index 2ec9385..d8e1b19 100644 --- a/src/main-windows.zig +++ b/src/main-windows.zig @@ -3,12 +3,349 @@ const w = std.os.windows; extern "user32" fn MessageBoxA(hWnd: ?w.HANDLE, lpText: ?w.LPCSTR, lpCaption: ?w.LPCSTR, uType: w.UINT) callconv(w.WINAPI) c_int; +const WINDOW_EX_STYLE = enum(u32) { + DLGMODALFRAME = 1, + NOPARENTNOTIFY = 4, + TOPMOST = 8, + ACCEPTFILES = 16, + TRANSPARENT = 32, + MDICHILD = 64, + TOOLWINDOW = 128, + WINDOWEDGE = 256, + CLIENTEDGE = 512, + CONTEXTHELP = 1024, + RIGHT = 4096, + LEFT = 0, + RTLREADING = 8192, + // LTRREADING = 0, this enum value conflicts with LEFT + LEFTSCROLLBAR = 16384, + // RIGHTSCROLLBAR = 0, this enum value conflicts with LEFT + CONTROLPARENT = 65536, + STATICEDGE = 131072, + APPWINDOW = 262144, + OVERLAPPEDWINDOW = 768, + PALETTEWINDOW = 392, + LAYERED = 524288, + NOINHERITLAYOUT = 1048576, + NOREDIRECTIONBITMAP = 2097152, + LAYOUTRTL = 4194304, + COMPOSITED = 33554432, + NOACTIVATE = 134217728, + _, + pub fn initFlags(o: struct { + DLGMODALFRAME: u1 = 0, + NOPARENTNOTIFY: u1 = 0, + TOPMOST: u1 = 0, + ACCEPTFILES: u1 = 0, + TRANSPARENT: u1 = 0, + MDICHILD: u1 = 0, + TOOLWINDOW: u1 = 0, + WINDOWEDGE: u1 = 0, + CLIENTEDGE: u1 = 0, + CONTEXTHELP: u1 = 0, + RIGHT: u1 = 0, + LEFT: u1 = 0, + RTLREADING: u1 = 0, + LEFTSCROLLBAR: u1 = 0, + CONTROLPARENT: u1 = 0, + STATICEDGE: u1 = 0, + APPWINDOW: u1 = 0, + OVERLAPPEDWINDOW: u1 = 0, + PALETTEWINDOW: u1 = 0, + LAYERED: u1 = 0, + NOINHERITLAYOUT: u1 = 0, + NOREDIRECTIONBITMAP: u1 = 0, + LAYOUTRTL: u1 = 0, + COMPOSITED: u1 = 0, + NOACTIVATE: u1 = 0, + }) WINDOW_EX_STYLE { + return @intToEnum(WINDOW_EX_STYLE, (if (o.DLGMODALFRAME == 1) @enumToInt(WINDOW_EX_STYLE.DLGMODALFRAME) else 0) | (if (o.NOPARENTNOTIFY == 1) @enumToInt(WINDOW_EX_STYLE.NOPARENTNOTIFY) else 0) | (if (o.TOPMOST == 1) @enumToInt(WINDOW_EX_STYLE.TOPMOST) else 0) | (if (o.ACCEPTFILES == 1) @enumToInt(WINDOW_EX_STYLE.ACCEPTFILES) else 0) | (if (o.TRANSPARENT == 1) @enumToInt(WINDOW_EX_STYLE.TRANSPARENT) else 0) | (if (o.MDICHILD == 1) @enumToInt(WINDOW_EX_STYLE.MDICHILD) else 0) | (if (o.TOOLWINDOW == 1) @enumToInt(WINDOW_EX_STYLE.TOOLWINDOW) else 0) | (if (o.WINDOWEDGE == 1) @enumToInt(WINDOW_EX_STYLE.WINDOWEDGE) else 0) | (if (o.CLIENTEDGE == 1) @enumToInt(WINDOW_EX_STYLE.CLIENTEDGE) else 0) | (if (o.CONTEXTHELP == 1) @enumToInt(WINDOW_EX_STYLE.CONTEXTHELP) else 0) | (if (o.RIGHT == 1) @enumToInt(WINDOW_EX_STYLE.RIGHT) else 0) | (if (o.LEFT == 1) @enumToInt(WINDOW_EX_STYLE.LEFT) else 0) | (if (o.RTLREADING == 1) @enumToInt(WINDOW_EX_STYLE.RTLREADING) else 0) | (if (o.LEFTSCROLLBAR == 1) @enumToInt(WINDOW_EX_STYLE.LEFTSCROLLBAR) else 0) | (if (o.CONTROLPARENT == 1) @enumToInt(WINDOW_EX_STYLE.CONTROLPARENT) else 0) | (if (o.STATICEDGE == 1) @enumToInt(WINDOW_EX_STYLE.STATICEDGE) else 0) | (if (o.APPWINDOW == 1) @enumToInt(WINDOW_EX_STYLE.APPWINDOW) else 0) | (if (o.OVERLAPPEDWINDOW == 1) @enumToInt(WINDOW_EX_STYLE.OVERLAPPEDWINDOW) else 0) | (if (o.PALETTEWINDOW == 1) @enumToInt(WINDOW_EX_STYLE.PALETTEWINDOW) else 0) | (if (o.LAYERED == 1) @enumToInt(WINDOW_EX_STYLE.LAYERED) else 0) | (if (o.NOINHERITLAYOUT == 1) @enumToInt(WINDOW_EX_STYLE.NOINHERITLAYOUT) else 0) | (if (o.NOREDIRECTIONBITMAP == 1) @enumToInt(WINDOW_EX_STYLE.NOREDIRECTIONBITMAP) else 0) | (if (o.LAYOUTRTL == 1) @enumToInt(WINDOW_EX_STYLE.LAYOUTRTL) else 0) | (if (o.COMPOSITED == 1) @enumToInt(WINDOW_EX_STYLE.COMPOSITED) else 0) | (if (o.NOACTIVATE == 1) @enumToInt(WINDOW_EX_STYLE.NOACTIVATE) else 0)); + } +}; + +extern "USER32" fn CreateWindowExA( + dwExStyle: WINDOW_EX_STYLE, + lpClassName: ?[*:0]const u8, + lpWindowName: ?[*:0]const u8, + dwStyle: WINDOW_STYLE, + X: i32, + Y: i32, + nWidth: i32, + nHeight: i32, + hWndParent: ?w.HWND, + hMenu: ?w.HMENU, + hInstance: ?w.HINSTANCE, + lpParam: ?*c_void, +) callconv(w.WINAPI) ?w.HWND; + +const WNDPROC = fn ( + param0: w.HWND, + param1: u32, + param2: w.WPARAM, + param3: w.LPARAM, +) callconv(w.WINAPI) w.LRESULT; + +const WNDCLASS_STYLES = enum(u32) { + VREDRAW = 1, + HREDRAW = 2, + DBLCLKS = 8, + OWNDC = 32, + CLASSDC = 64, + PARENTDC = 128, + NOCLOSE = 512, + SAVEBITS = 2048, + BYTEALIGNCLIENT = 4096, + BYTEALIGNWINDOW = 8192, + GLOBALCLASS = 16384, + IME = 65536, + DROPSHADOW = 131072, + _, + pub fn initFlags(o: struct { + VREDRAW: u1 = 0, + HREDRAW: u1 = 0, + DBLCLKS: u1 = 0, + OWNDC: u1 = 0, + CLASSDC: u1 = 0, + PARENTDC: u1 = 0, + NOCLOSE: u1 = 0, + SAVEBITS: u1 = 0, + BYTEALIGNCLIENT: u1 = 0, + BYTEALIGNWINDOW: u1 = 0, + GLOBALCLASS: u1 = 0, + IME: u1 = 0, + DROPSHADOW: u1 = 0, + }) WNDCLASS_STYLES { + return @intToEnum(WNDCLASS_STYLES, (if (o.VREDRAW == 1) @enumToInt(WNDCLASS_STYLES.VREDRAW) else 0) | (if (o.HREDRAW == 1) @enumToInt(WNDCLASS_STYLES.HREDRAW) else 0) | (if (o.DBLCLKS == 1) @enumToInt(WNDCLASS_STYLES.DBLCLKS) else 0) | (if (o.OWNDC == 1) @enumToInt(WNDCLASS_STYLES.OWNDC) else 0) | (if (o.CLASSDC == 1) @enumToInt(WNDCLASS_STYLES.CLASSDC) else 0) | (if (o.PARENTDC == 1) @enumToInt(WNDCLASS_STYLES.PARENTDC) else 0) | (if (o.NOCLOSE == 1) @enumToInt(WNDCLASS_STYLES.NOCLOSE) else 0) | (if (o.SAVEBITS == 1) @enumToInt(WNDCLASS_STYLES.SAVEBITS) else 0) | (if (o.BYTEALIGNCLIENT == 1) @enumToInt(WNDCLASS_STYLES.BYTEALIGNCLIENT) else 0) | (if (o.BYTEALIGNWINDOW == 1) @enumToInt(WNDCLASS_STYLES.BYTEALIGNWINDOW) else 0) | (if (o.GLOBALCLASS == 1) @enumToInt(WNDCLASS_STYLES.GLOBALCLASS) else 0) | (if (o.IME == 1) @enumToInt(WNDCLASS_STYLES.IME) else 0) | (if (o.DROPSHADOW == 1) @enumToInt(WNDCLASS_STYLES.DROPSHADOW) else 0)); + } +}; +const WINDOW_STYLE = enum(u32) { + OVERLAPPED = 0, + POPUP = 2147483648, + CHILD = 1073741824, + MINIMIZE = 536870912, + VISIBLE = 268435456, + DISABLED = 134217728, + CLIPSIBLINGS = 67108864, + CLIPCHILDREN = 33554432, + MAXIMIZE = 16777216, + CAPTION = 12582912, + BORDER = 8388608, + DLGFRAME = 4194304, + VSCROLL = 2097152, + HSCROLL = 1048576, + SYSMENU = 524288, + THICKFRAME = 262144, + GROUP = 131072, + TABSTOP = 65536, + // MINIMIZEBOX = 131072, this enum value conflicts with GROUP + // MAXIMIZEBOX = 65536, this enum value conflicts with TABSTOP + // TILED = 0, this enum value conflicts with OVERLAPPED + // ICONIC = 536870912, this enum value conflicts with MINIMIZE + // SIZEBOX = 262144, this enum value conflicts with THICKFRAME + TILEDWINDOW = 13565952, + // OVERLAPPEDWINDOW = 13565952, this enum value conflicts with TILEDWINDOW + POPUPWINDOW = 2156396544, + // CHILDWINDOW = 1073741824, this enum value conflicts with CHILD + ACTIVECAPTION = 1, + _, + pub fn initFlags(o: struct { + OVERLAPPED: u1 = 0, + POPUP: u1 = 0, + CHILD: u1 = 0, + MINIMIZE: u1 = 0, + VISIBLE: u1 = 0, + DISABLED: u1 = 0, + CLIPSIBLINGS: u1 = 0, + CLIPCHILDREN: u1 = 0, + MAXIMIZE: u1 = 0, + CAPTION: u1 = 0, + BORDER: u1 = 0, + DLGFRAME: u1 = 0, + VSCROLL: u1 = 0, + HSCROLL: u1 = 0, + SYSMENU: u1 = 0, + THICKFRAME: u1 = 0, + GROUP: u1 = 0, + TABSTOP: u1 = 0, + TILEDWINDOW: u1 = 0, + POPUPWINDOW: u1 = 0, + ACTIVECAPTION: u1 = 0, + }) WINDOW_STYLE { + return @intToEnum(WINDOW_STYLE, (if (o.OVERLAPPED == 1) @enumToInt(WINDOW_STYLE.OVERLAPPED) else 0) | (if (o.POPUP == 1) @enumToInt(WINDOW_STYLE.POPUP) else 0) | (if (o.CHILD == 1) @enumToInt(WINDOW_STYLE.CHILD) else 0) | (if (o.MINIMIZE == 1) @enumToInt(WINDOW_STYLE.MINIMIZE) else 0) | (if (o.VISIBLE == 1) @enumToInt(WINDOW_STYLE.VISIBLE) else 0) | (if (o.DISABLED == 1) @enumToInt(WINDOW_STYLE.DISABLED) else 0) | (if (o.CLIPSIBLINGS == 1) @enumToInt(WINDOW_STYLE.CLIPSIBLINGS) else 0) | (if (o.CLIPCHILDREN == 1) @enumToInt(WINDOW_STYLE.CLIPCHILDREN) else 0) | (if (o.MAXIMIZE == 1) @enumToInt(WINDOW_STYLE.MAXIMIZE) else 0) | (if (o.CAPTION == 1) @enumToInt(WINDOW_STYLE.CAPTION) else 0) | (if (o.BORDER == 1) @enumToInt(WINDOW_STYLE.BORDER) else 0) | (if (o.DLGFRAME == 1) @enumToInt(WINDOW_STYLE.DLGFRAME) else 0) | (if (o.VSCROLL == 1) @enumToInt(WINDOW_STYLE.VSCROLL) else 0) | (if (o.HSCROLL == 1) @enumToInt(WINDOW_STYLE.HSCROLL) else 0) | (if (o.SYSMENU == 1) @enumToInt(WINDOW_STYLE.SYSMENU) else 0) | (if (o.THICKFRAME == 1) @enumToInt(WINDOW_STYLE.THICKFRAME) else 0) | (if (o.GROUP == 1) @enumToInt(WINDOW_STYLE.GROUP) else 0) | (if (o.TABSTOP == 1) @enumToInt(WINDOW_STYLE.TABSTOP) else 0) | (if (o.TILEDWINDOW == 1) @enumToInt(WINDOW_STYLE.TILEDWINDOW) else 0) | (if (o.POPUPWINDOW == 1) @enumToInt(WINDOW_STYLE.POPUPWINDOW) else 0) | (if (o.ACTIVECAPTION == 1) @enumToInt(WINDOW_STYLE.ACTIVECAPTION) else 0)); + } +}; + +const WNDCLASSA = extern struct { + style: WNDCLASS_STYLES, + lpfnWndProc: ?WNDPROC, + cbClsExtra: i32, + cbWndExtra: i32, + hInstance: ?w.HINSTANCE, + hIcon: ?w.HICON, + hCursor: ?w.HCURSOR, + hbrBackground: ?w.HBRUSH, + lpszMenuName: ?[*:0]const u8, + lpszClassName: ?[*:0]const u8, +}; + +extern "USER32" fn RegisterClassA( + lpWndClass: ?*const WNDCLASSA, +) callconv(w.WINAPI) u16; + +const WS_OVERLAPPEDWINDOW = WINDOW_STYLE.TILEDWINDOW; +const CW_USEDEFAULT = @as(i32, -2147483648); +const BOOL = i32; + +const MSG = extern struct { + hwnd: ?w.HWND, + message: u32, + wParam: w.WPARAM, + lParam: w.LPARAM, + time: u32, + pt: w.POINT, +}; +const SHOW_WINDOW_CMD = enum(u32) { + FORCEMINIMIZE = 11, + HIDE = 0, + MAXIMIZE = 3, + MINIMIZE = 6, + RESTORE = 9, + SHOW = 5, + SHOWDEFAULT = 10, + // SHOWMAXIMIZED = 3, this enum value conflicts with MAXIMIZE + SHOWMINIMIZED = 2, + SHOWMINNOACTIVE = 7, + SHOWNA = 8, + SHOWNOACTIVATE = 4, + SHOWNORMAL = 1, + // NORMAL = 1, this enum value conflicts with SHOWNORMAL + // MAX = 11, this enum value conflicts with FORCEMINIMIZE + // PARENTCLOSING = 1, this enum value conflicts with SHOWNORMAL + // OTHERZOOM = 2, this enum value conflicts with SHOWMINIMIZED + // PARENTOPENING = 3, this enum value conflicts with MAXIMIZE + // OTHERUNZOOM = 4, this enum value conflicts with SHOWNOACTIVATE + // SCROLLCHILDREN = 1, this enum value conflicts with SHOWNORMAL + // INVALIDATE = 2, this enum value conflicts with SHOWMINIMIZED + // ERASE = 4, this enum value conflicts with SHOWNOACTIVATE + SMOOTHSCROLL = 16, + _, + pub fn initFlags(o: struct { + FORCEMINIMIZE: u1 = 0, + HIDE: u1 = 0, + MAXIMIZE: u1 = 0, + MINIMIZE: u1 = 0, + RESTORE: u1 = 0, + SHOW: u1 = 0, + SHOWDEFAULT: u1 = 0, + SHOWMINIMIZED: u1 = 0, + SHOWMINNOACTIVE: u1 = 0, + SHOWNA: u1 = 0, + SHOWNOACTIVATE: u1 = 0, + SHOWNORMAL: u1 = 0, + SMOOTHSCROLL: u1 = 0, + }) SHOW_WINDOW_CMD { + return @intToEnum(SHOW_WINDOW_CMD, (if (o.FORCEMINIMIZE == 1) @enumToInt(SHOW_WINDOW_CMD.FORCEMINIMIZE) else 0) | (if (o.HIDE == 1) @enumToInt(SHOW_WINDOW_CMD.HIDE) else 0) | (if (o.MAXIMIZE == 1) @enumToInt(SHOW_WINDOW_CMD.MAXIMIZE) else 0) | (if (o.MINIMIZE == 1) @enumToInt(SHOW_WINDOW_CMD.MINIMIZE) else 0) | (if (o.RESTORE == 1) @enumToInt(SHOW_WINDOW_CMD.RESTORE) else 0) | (if (o.SHOW == 1) @enumToInt(SHOW_WINDOW_CMD.SHOW) else 0) | (if (o.SHOWDEFAULT == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWDEFAULT) else 0) | (if (o.SHOWMINIMIZED == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWMINIMIZED) else 0) | (if (o.SHOWMINNOACTIVE == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWMINNOACTIVE) else 0) | (if (o.SHOWNA == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWNA) else 0) | (if (o.SHOWNOACTIVATE == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWNOACTIVATE) else 0) | (if (o.SHOWNORMAL == 1) @enumToInt(SHOW_WINDOW_CMD.SHOWNORMAL) else 0) | (if (o.SMOOTHSCROLL == 1) @enumToInt(SHOW_WINDOW_CMD.SMOOTHSCROLL) else 0)); + } +}; + +extern "USER32" fn ShowWindow( + hWnd: ?w.HWND, + nCmdShow: SHOW_WINDOW_CMD, +) callconv(w.WINAPI) BOOL; + +extern "USER32" fn GetMessageA( + lpMsg: ?*MSG, + hWnd: ?w.HWND, + wMsgFilterMin: u32, + wMsgFilterMax: u32, +) callconv(w.WINAPI) BOOL; + +extern "USER32" fn TranslateMessage( + lpMsg: ?*const MSG, +) callconv(w.WINAPI) BOOL; + +const LRESULT = isize; + +extern "USER32" fn DispatchMessageA( + lpMsg: ?*const MSG, +) callconv(w.WINAPI) LRESULT; + pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCmdLine: w.PWSTR, nCmdShow: w.INT) w.INT { - _ = hInstance; _ = hPrevInstance; _ = lpCmdLine; - _ = nCmdShow; - _ = MessageBoxA(null, "all your codebase are belong to us", "title", 0); + // Register the window class. + var wc: WNDCLASSA = .{ + .lpszClassName = "Clipboard watcher", + .hInstance = hInstance, + .lpfnWndProc = MainWndProc, + // default vals + .style = WNDCLASS_STYLES.initFlags(.{}), + .cbClsExtra = 0, + .cbWndExtra = 0, + .hIcon = null, + .hCursor = null, + .hbrBackground = null, + .lpszMenuName = null, + }; + + _ = RegisterClassA(&wc); + + // Create the window. + + var hwnd = CreateWindowExA( + WINDOW_EX_STYLE.initFlags(.{}), // Optional window styles. + wc.lpszClassName.?, // Window class + "Windows program - in zig", // Window text + WS_OVERLAPPEDWINDOW, // Window style + + // Size and position + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + + null, // Parent window + null, // Menu + hInstance, // Instance handle + null, // Additional application data + ); + + if (hwnd == null) + return 0; + + _ = ShowWindow(hwnd, @intToEnum(SHOW_WINDOW_CMD, nCmdShow)); + + // Run the message loop. + + var msg: MSG = .{ + .hwnd = null, + .message = 0, + .wParam = 0, + .lParam = 0, + .time = 0, + .pt = .{ + .x = 0, + .y = 0, + }, + }; + + while (GetMessageA(&msg, null, 0, 0) > 0) { + _ = TranslateMessage(&msg); + _ = DispatchMessageA(&msg); + } + + return 0; +} + +fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT { //APIENTRY { + _ = hwnd; + _ = uMsg; // uMsg is actually a pointer to the message + _ = wParam; + _ = lParam; + + _ = MessageBoxA(null, "all your codebase are belong to us", "title", 0); + std.time.sleep(2 * std.time.ns_per_s); + return 0; }