From 9d0f5aeb3bb7af8dc7bb31b2b458f0c00d96248e Mon Sep 17 00:00:00 2001 From: DarknessFX Date: Thu, 7 Nov 2024 19:44:30 +0000 Subject: [PATCH] . --- .../.vscode/ToSystray.code-workspace | 194 +++++ programs/ToSystray/.vscode/launch.json | 36 + programs/ToSystray/.vscode/settings.json | 3 + programs/ToSystray/.vscode/tasks.json | 101 +++ programs/ToSystray/README.md | 4 + programs/ToSystray/ToSystray.ico | Bin 0 -> 99678 bytes programs/ToSystray/ToSystray.png | Bin 0 -> 13390 bytes programs/ToSystray/ToSystray.rc | 32 + programs/ToSystray/build.zig | 49 ++ programs/ToSystray/main.zig | 148 ++++ programs/ToSystray/winapi.zig | 818 ++++++++++++++++++ 11 files changed, 1385 insertions(+) create mode 100644 programs/ToSystray/.vscode/ToSystray.code-workspace create mode 100644 programs/ToSystray/.vscode/launch.json create mode 100644 programs/ToSystray/.vscode/settings.json create mode 100644 programs/ToSystray/.vscode/tasks.json create mode 100644 programs/ToSystray/README.md create mode 100644 programs/ToSystray/ToSystray.ico create mode 100644 programs/ToSystray/ToSystray.png create mode 100644 programs/ToSystray/ToSystray.rc create mode 100644 programs/ToSystray/build.zig create mode 100644 programs/ToSystray/main.zig create mode 100644 programs/ToSystray/winapi.zig diff --git a/programs/ToSystray/.vscode/ToSystray.code-workspace b/programs/ToSystray/.vscode/ToSystray.code-workspace new file mode 100644 index 0000000..3dd0051 --- /dev/null +++ b/programs/ToSystray/.vscode/ToSystray.code-workspace @@ -0,0 +1,194 @@ +{ + "folders": [{ "path": ".." }], + "settings": { + // Zig Workspace + "files.exclude": { + "*.lnk": true, + "**/.git": true, + ".gitignore": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + // VSCODE FOLDERS -------- + "**/.vscode": true, + "**/.code-workspace": true, + // ZIG FOLDERS -------- + "**/zig-cache": true + }, + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/*.code-search": true, + // ZIG FOLDERS -------- + "**/zig-out": true + }, + "files.watcherExclude": { + // ZIG FOLDERS -------- + "**/zig-cache": true + }, + + // DarknessFX settings + "telemetry.telemetryLevel": "off", + "workbench.colorTheme": "Default Dark+", + "workbench.startupEditor": "none", + "workbench.colorCustomizations": { + "statusBar.background" : "#1A1A1A", + "statusBar.noFolderBackground" : "#212121", + "statusBar.debuggingBackground": "#263238", + "editorBracketHighlight.foreground1": "#888888", + "editorBracketHighlight.foreground2": "#686888", + "editorBracketHighlight.foreground3": "#688868", + "editorBracketHighlight.foreground4": "#886868", + "editorBracketHighlight.foreground5": "#686868", + }, + "editor.tokenColorCustomizations": { + "comments": "#546E7A", + "functions": "#DFAB4B", + "keywords": "#367CB6", + "numbers": "#CE9178", + "strings": "#CE9178", + "types": "#2EA990", + "variables": "#7CBCDE", + + "[Default Dark+]": { + "textMateRules": [ + { + "scope": [ + "other", + "source", + "keyword.operator", + "keyword.operator.noexcept", + "punctuation", + "punctuation.dot", + "punctuation.comma", + "punctuation.definitions", + "punctuation.definition.comment", + "punctuation.definition.tag", + "punctuation.definition.tag.html", + "punctuation.definition.tag.begin.html", + "punctuation.definition.tag.end.html", + "punctuation.section.embedded", + "punctuation.separator", + "punctuation.separator.inheritance.php", + ], + "settings": { + "foreground": "#758E68", + "fontStyle": "", + } + }, + { + "scope": [ + "comment", + ], + "settings": { + "fontStyle": "italic", + } + }, + { + "scope": [ + "keyword", + "keyword.control", + "keyword.other", + "keyword.other.template", + "keyword.other.substitution", + "keyword.other.unit", + "storage", + "storage.type", + "storage.modifier", + "keywordLiteral", + "keyword.literal", + "keyword.constant.default", + ], + "settings": { + "fontStyle": "italic", + "foreground": "#367CB6" + } + }, + { + "scope": [ + "support.class", + "support.type", + "entity.name.type", + "entity.name.namespace", + "entity.other.attribute", + "entity.name.scope-resolution", + "entity.name.class", + ], + "settings": { + "foreground": "#2EA990" + } + }, + ], + }, + }, + "editor.tabSize": 2, + "editor.fontSize": 16, + "editor.unicodeHighlight.invisibleCharacters": false, + "editor.autoClosingBrackets": "never", + "editor.autoSurround": "never", + "editor.autoClosingQuotes": "never", + "editor.detectIndentation": false, + "editor.lightbulb.enabled": "off", + "workbench.editor.focusRecentEditorAfterClose": false, + "workbench.panel.defaultLocation": "left", + "workbench.panel.opensMaximized": "never", + "workbench.editor.tabSizing": "fixed", + "workbench.editor.tabSizingFixedMaxWidth": 140, + "workbench.sideBar.location": "right", + "debug.allowBreakpointsEverywhere": true, + "debug.onTaskErrors": "abort", + "explorer.confirmDragAndDrop": false, + "explorer.compactFolders": false, + "explorer.confirmDelete": false, + "terminal.integrated.profiles.windows": { + "Windows Terminal": { + "path": "wt", + "args": [ + "-p", "cmd", "cmd" + ], + "icon": "terminal-bash", + }, + "Command Prompt": { + "path": [ + "${env:windir}\\Sysnative\\cmd.exe", + "${env:windir}\\System32\\cmd.exe" + ], + "args": [], + "icon": "terminal-cmd" + }, + "PowerShell": { + "source": "PowerShell", + "icon": "terminal-powershell" + }, + "Git Bash": { + "source": "Git Bash" + }, + }, + "terminal.integrated.tabs.location": "left", + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "C_Cpp.vcFormat.space.groupSquareBrackets": false, + "C_Cpp.loggingLevel": "Debug", + "C_Cpp.codeAnalysis.clangTidy.codeAction.formatFixes": false, + "git.openRepositoryInParentFolders": "never", + "html.autoCreateQuotes": false, + "zig.buildFilePath": "${workspaceFolder}", + "zig.formattingProvider": "off", + "zig.checkForUpdate": false, + "zig.zls.enabled": true, + "zig.zls.highlightGlobalVarDeclarations": true, + "zig.zls.semanticTokens": "full", + "zig.zls.enableArgumentPlaceholders": false, + "zig.zls.inlayHintsExcludeSingleArgument": false, + "zig.zls.enableAutofix": false, + "zig.zls.checkForUpdate": false, + "zig.zls.enableInlayHints": false, + "zig.zls.preferAstCheckAsChildProcess": false, + }, + "extensions": { + "recommendations": [ + "pkief.material-icon-theme" + ] + } +} diff --git a/programs/ToSystray/.vscode/launch.json b/programs/ToSystray/.vscode/launch.json new file mode 100644 index 0000000..94aeebe --- /dev/null +++ b/programs/ToSystray/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "cppvsdbg", + "request": "launch", + "presentation": { + "hidden": false, + "group": "", + "order": 1 + }, + "program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}.exe", + "args": [ "C:\\Windows\\System32\\notepad.exe", "Notepad" ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "preLaunchTask": "${defaultBuildTask}", + "console": "integratedTerminal", + "symbolSearchPath": "${workspaceFolder}/bin/Debug/", + }, + { + "name": "Debug Attach", + "type": "cppvsdbg", + "request": "attach", + "presentation": { + "hidden": true, + "group": "", + "order": 2 + }, + "preLaunchTask": "Zig: Run main", + "internalConsoleOptions": "openOnFirstSessionStart", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/programs/ToSystray/.vscode/settings.json b/programs/ToSystray/.vscode/settings.json new file mode 100644 index 0000000..eb7750c --- /dev/null +++ b/programs/ToSystray/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.configureOnOpen": false +} \ No newline at end of file diff --git a/programs/ToSystray/.vscode/tasks.json b/programs/ToSystray/.vscode/tasks.json new file mode 100644 index 0000000..61a302e --- /dev/null +++ b/programs/ToSystray/.vscode/tasks.json @@ -0,0 +1,101 @@ +{ + "tasks": [{ + "label": "Zig: Build", + "args": [ "build", "--summary", "all" ], + "detail": "zig build --summary all", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "build", "isDefault": true }, + "presentation": { "group": "build", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Build Release Safe.", + "args": [ "build", "-Doptimize=ReleaseSafe", "--summary", "all" ], + "detail": "zig build -Doptimize=ReleaseSafe --summary all", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "build", "isDefault": false }, + "presentation": { "group": "build", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Build Release Fast.", + "args": [ "build", "-Doptimize=ReleaseFast", "--summary", "all" ], + "detail": "zig build -Doptimize=ReleaseFast --summary all", + "command": "zig","type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "build", "isDefault": false }, + "presentation": { "group": "build", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Build Release Small.", + "args": [ "build", "-Doptimize=ReleaseSmall", "--summary", "all" ], + "detail": "zig build -Doptimize=ReleaseSmall --summary all", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "build", "isDefault": false }, + "presentation": { "group": "build", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Build Release Strip.", + "args": [ ], + "detail": "zig build-exe -O ReleaseSmall -fstrip -fsingle-threaded (+ lots of options) main.zig", + "command": "buildReleaseStrip.bat", "type": "shell", "options": { "cwd": "${workspaceRoot}\\tools" }, "group": { "kind": "build", "isDefault": false }, + "presentation": { "group": "build", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Test", + "args": [ "test", "${file}" ], + "detail": "'zig test' in the current workspace.", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "test", "isDefault": true }, + "presentation": { "group": "test", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run main", + "args": [ "run", "main.zig" ], + "detail": "zig run main.zig", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": true }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run main (With Args)", + "args": [ "run", "main.zig", "--", "D:\\Windows\\System32\\notepad.exe", "Notepad" ], + "detail": "zig run main.zig -- ArgsForYourProgram", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run main (Fast)", + "args": [ "run", "main.zig", "-O", "ReleaseFast" ], + "detail": "zig run main.zig -O ReleaseFast", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run main (Safe)", + "args": [ "run", "main.zig", "-O", "ReleaseSafe" ], + "detail": "zig run main.zig -O ReleaseSafe", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run main (Small)", + "args": [ "run", "main.zig", "-O", "ReleaseSmall" ], + "detail": "zig run main.zig -O ReleaseSmall", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Run current file", + "args": [ "run", "${file}" ], + "detail": "'zig run' active file in the current workspace.", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "launch", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "zTime Zig: Run current file", + "args": [ "zig", "run", "${file}" ], + "detail": "'zTime zig run' active file in the current workspace.", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "zTime", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }, + { + "label": "Zig: Docs", + "args": [ "run", "-femit-docs", "main.zig" ], + "detail": "Generate docs from source comments.", + "command": "zig", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "group": { "kind": "none", "isDefault": false }, + "presentation": { "group": "docs", "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true, "close": false }, "problemMatcher": [] + }], + "version": "2.0.0" +} \ No newline at end of file diff --git a/programs/ToSystray/README.md b/programs/ToSystray/README.md new file mode 100644 index 0000000..52b6944 --- /dev/null +++ b/programs/ToSystray/README.md @@ -0,0 +1,4 @@ +##Credits + +Application Icon uses https://icons8.com/icon/yEiCI6F0rUO8/tray from https://icons8.com +.PNG image converted to .ICO by https://redketchup.io/ \ No newline at end of file diff --git a/programs/ToSystray/ToSystray.ico b/programs/ToSystray/ToSystray.ico new file mode 100644 index 0000000000000000000000000000000000000000..73c306b834a2e04c1d864eecaf10565961b2f053 GIT binary patch literal 99678 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 literal 0 HcmV?d00001 diff --git a/programs/ToSystray/ToSystray.png b/programs/ToSystray/ToSystray.png new file mode 100644 index 0000000000000000000000000000000000000000..04a345483c6bd77b201a321e0f5a8b8cc26e4889 GIT binary patch literal 13390 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 F{}1d$5_A9n literal 0 HcmV?d00001 diff --git a/programs/ToSystray/ToSystray.rc b/programs/ToSystray/ToSystray.rc new file mode 100644 index 0000000..b1f0835 --- /dev/null +++ b/programs/ToSystray/ToSystray.rc @@ -0,0 +1,32 @@ +#include "windows.h" + +IDI_ICON1 ICON "ToSysTray.ico" + +1 VERSIONINFO + FILEVERSION 0,9,0,0 + PRODUCTVERSION 0,9,0,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x1L + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "ToSysTray" + VALUE "FileDescription", "ToSysTray" + VALUE "FileVersion", "0.9.0.0" + VALUE "InternalName", "ToSysTray.exe" + VALUE "LegalCopyright", "Copyleft(c)" + VALUE "OriginalFilename", "ToSysTray.exe" + VALUE "ProductName", "ToSysTray" + VALUE "ProductVersion", "0.9.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/programs/ToSystray/build.zig b/programs/ToSystray/build.zig new file mode 100644 index 0000000..6969b59 --- /dev/null +++ b/programs/ToSystray/build.zig @@ -0,0 +1,49 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + //Build + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const projectname = "ToSystray"; + const rootfile = "main.zig"; + + const exe = b.addExecutable(.{ + .name = projectname, + .root_source_file = b.path( rootfile ), + .target = target, + .optimize = optimize + }); + exe.addWin32ResourceFile(.{ + .file = b.path(projectname ++ ".rc"), + .flags = &.{"/c65001"}, + }); + + switch (optimize) { + .Debug => b.exe_dir = "bin/Debug", + .ReleaseSafe => b.exe_dir = "bin/ReleaseSafe", + .ReleaseFast => b.exe_dir = "bin/ReleaseFast", + .ReleaseSmall => b.exe_dir = "bin/ReleaseSmall" + //else => b.exe_dir = "bin/Else", + } + b.installArtifact(exe); + + //Run + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + //Tests + const unit_tests = b.addTest(.{ + .root_source_file = b.path( rootfile ), + .target = target, + .optimize = optimize, + }); + const run_unit_tests = b.addRunArtifact(unit_tests); + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_unit_tests.step); +} diff --git a/programs/ToSystray/main.zig b/programs/ToSystray/main.zig new file mode 100644 index 0000000..72c37bf --- /dev/null +++ b/programs/ToSystray/main.zig @@ -0,0 +1,148 @@ +//!zig-autodoc-section: ToSystray +//! ToSystray.exe : +//! Utility tool that run other application and hide app window into systray. +//! Helpful to keep applications in the Windows System Tray instead of +//! occupying space in the Taskbar. + +// Build using Zig 0.12.0-dev.3160+aa7d16aba +// ============================================================================ +// Globals. +// +const std = @import("std"); +const win = @import("winapi.zig"); +const assert = std.debug.assert; + +const ToolName: []const u8 = "ToSystray"; +const TApp = struct { + Path: []const u8 = "", + Title: []const u8 = "", + Process: win.HANDLE = undefined, + Thread: win.HANDLE = undefined, + Window: win.HANDLE = undefined, + isMinimized: bool = false, + isClosed: bool = false, + dwProcess: win.DWORD = undefined, + dwThread: win.DWORD = undefined, + SelfPath: []const u8 = "", +}; +var App: TApp = .{}; +const wnd = win.wnd; + +// ============================================================================ +// Main core and app flow. +// + +pub export fn wWinMain(hInstance: win.HINSTANCE, hPrevInstance: ?win.HINSTANCE, + pCmdLine: ?win.LPWSTR, nCmdShow: win.INT) callconv(win.WINAPI) win.INT { + _ = &hInstance; _ = &hPrevInstance; _ = &pCmdLine; _ = &nCmdShow; + + App.Title = ToolName; + win.HideConsoleWindow(); + + LoadArgs() + orelse return PopupUsage(); + + wnd.hInstance = hInstance; + + LaunchApp() + orelse return LaunchAppFailed(); + defer CloseAppHandles(); + + win.Create() + orelse return 1; + defer win.Destroy(); + + while (!wnd.exit) { + win.ProcessMsg(); + } + + return 0; +} + +fn LaunchApp() ?void { + wnd.path = toStringA(App.Path); + wnd.title = toStringA(App.Title); + if (win.ExtractIconA(wnd.hInstance, toStringA(App.SelfPath), 0)) |icontmp| + wnd.icon = icontmp; + + const result = win.CreateProcess(App.Path) + orelse return null; + + App.Process = result.hProcess; + App.Thread = result.hThread; + App.dwProcess = result.dwProcessId; + App.dwThread = result.dwThreadId; +} + +fn LaunchAppFailed() win.INT { + return 1; +} + +fn CloseAppHandles() void { + win.CloseAppHandles(App.Process, App.Thread); +} + +fn LoadArgs() ?void { + const buf_alloc = std.heap.page_allocator; + const buffer = buf_alloc.create([4096]u16) catch unreachable; + defer std.heap.page_allocator.destroy(buffer); + var args = std.process.ArgIterator.initWithAllocator(buf_alloc) catch unreachable; + defer args.deinit(); + + if (args.next()) |arg0| + App.SelfPath = toRetCopy(arg0); +// if (!args.skip()) return null; + if (args.next()) |arg1| + App.Path = toRetCopy(arg1); + if (args.next()) |arg2| + App.Title = toRetCopy(arg2); + + if (std.mem.eql(u8, App.Path, "")) return null; +} + +// ============================================================================ +// Helpers +// +inline fn isNull(any: anytype) bool { return any == null; } +inline fn toRetCopy(any: anytype) @TypeOf(any) { + const any_cpy = std.heap.page_allocator.dupe( + @typeInfo(@TypeOf(any)).Pointer.child, + any) catch unreachable; + return @as(@TypeOf(any), @ptrCast(any_cpy)); +} +inline fn toPtr(handle: win.HANDLE) usize { return @as(usize, @intFromPtr(handle)); } +inline fn toStringA(string: []const u8) [*:0]const u8 { return @as([*:0]const u8, @ptrCast(string)); } +fn PopupUsage() win.INT { + return win.MessageBoxA(null, + "Usage:\n" ++ + " ToSystray.exe \"path_to_exe\" (optional)\"WindowTitle\" \n" ++ + "Sample:\n" ++ + " ToSystray.exe \"C:\\Windows\\System32\\Notepad.exe\" \"Notepad\" ", + "Error: No arguments", + win.MB_OK | win.MB_ICONERROR + ); +} + +// ============================================================================ +// Tests +// +const expect = std.testing.expect; +const expectError = std.testing.expectError; + +test "LoadArgs" { + try expect(LoadArgs() == null); + std.debug.print("\nEmpty args => display PopupUsage().\n", .{ }); +} + +test "LaunchApp" { + App.Path = "Notepad.exe"; + App.Title = "Notepad"; + std.debug.print( + "\nLoadArgs() filled with:\nApp.Title: {s}\nApp.Path: {s}\nTest LaunchApp();\n", + .{ App.Title, App.Path }); + + try expect(LaunchApp() != null); + + std.debug.print("App\nProcess: {d}\nThread: {d}\ndwProcess: {d}\ndwThread: {d}\n", .{ + toPtr(App.Process), toPtr(App.Thread), App.dwProcess, App.dwThread }); +} \ No newline at end of file diff --git a/programs/ToSystray/winapi.zig b/programs/ToSystray/winapi.zig new file mode 100644 index 0000000..cb37825 --- /dev/null +++ b/programs/ToSystray/winapi.zig @@ -0,0 +1,818 @@ +//!zig-autodoc-section: Windows API +//! Windows API +const std = @import("std"); +usingnamespace std.os.windows; +usingnamespace std.os.windows.kernel32; + +pub const wnd = struct { + pub var handle: HWND = undefined; + pub var hInstance: HINSTANCE = undefined; + pub var path: [*:0]const u8 = ""; + pub var title: [*:0]const u8= ""; + pub var title_buf: [255:0]u8 = std.mem.zeroes([255:0]u8); + pub var size: RECT= .{ + .left=0, + .top=0, + .right=1280, + .bottom=720 + }; + pub var width: INT = 1280; + pub var height: INT = 720; + pub var hdc: HDC = undefined; + pub var dpi: UINT = 0; + pub var hRC: HGLRC = undefined; + pub var msg: MSG = std.mem.zeroes(MSG); + pub var class: WNDCLASSEXA = std.mem.zeroes(WNDCLASSEXA); + pub var icon: HICON = undefined; + pub var iconsmall: HICON = undefined; + pub var guid: GUID = .{ + .Data1 = 0xFF6E5556, + .Data2 = 0xB53F, + .Data3 = 0x4B8A, + .Data4 = .{0x81, 0x63, 0x32, 0x4C, 0x8C, 0x9E, 0x93, 0x98} + }; + pub var appProcess: DWORD = undefined; + pub var appHwnd: HWND = undefined; + pub var consolehwnd: HWND = undefined; + pub var visible: bool = false; + pub var exit: bool = false; +}; + +pub fn Create() ?void { + CreateWindow(wnd.hInstance) + orelse return null; + + _ = UpdateWindow(wnd.handle); +} + +fn CreateWindow(hInstance: HINSTANCE) ?void { + const wndpath = toRemoveQuotes(wnd.path); + if ( @as(usize, @intFromPtr(ExtractIconA(hInstance, wndpath, 0))) > 0) { + wnd.icon = ExtractIconA(hInstance, wndpath, 0).?; + } + wnd.class = .{ + .cbSize = @sizeOf(WNDCLASSEXA), + .style = CS_DBLCLKS | CS_OWNDC, + .lpfnWndProc = WindowProc, + .cbClsExtra = 0, + .cbWndExtra = 0, + .hInstance = hInstance, + .hIcon = wnd.icon, + .hCursor = LoadCursorA(null, IDC_ARROW), + .hbrBackground = null, + .lpszMenuName = null, + .lpszClassName = wnd.title, + .hIconSm = null, + }; + _ = RegisterClassExA(&wnd.class); + _ = AdjustWindowRectEx(&wnd.size, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); + // wnd.title, WS_OVERLAPPEDWINDOW | WS_VISIBLE + if (CreateWindowExA( + WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, wnd.title, wnd.title, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, + null, null, hInstance, null) + ) |hwnd| { + wnd.handle = hwnd; + } else { + return null; + } + wnd.hdc = GetDC(wnd.handle).?; +} + +pub fn CreateProcess(CmdLine: []const u8) ?*PROCESS_INFORMATION { + wnd.title_buf = toStringBuffer(wnd.title); + wnd.guid.Data4[7] = GetRandom(); + + _ = SetCurrentDirectoryA(toPathString(wnd.path)); + + var CmdLine_: ?[*:0]u8 = undefined; + var cmdlinebuf = std.mem.zeroes([255]u8); _ = &cmdlinebuf; + const cmdlineUpper = std.ascii.upperString(&cmdlinebuf, CmdLine); + if (std.mem.indexOf(u8, cmdlineUpper, "BAT") != null) { + _ = ShowWindow(wnd.consolehwnd, SW_SHOW); + } + cmdlinebuf = std.mem.zeroes([255]u8); + const cmdline_ins = "CMD.EXE /C \""; + var idx: u8 = 0; + while (idx < 255) : (idx += 1) { + if (idx < cmdline_ins.len) { + cmdlinebuf[idx] = cmdline_ins[idx]; + } else { + if (idx - cmdline_ins.len >= CmdLine.len) break; + cmdlinebuf[idx] = CmdLine[idx - cmdline_ins.len]; + } + } + cmdlinebuf[idx] = '\"'; + CmdLine_ = @as(?[*:0]u8, @ptrCast(@constCast(&cmdlinebuf))); + + var startInfo: STARTUPINFOA = std.mem.zeroes(STARTUPINFOA); + var lpProcessInformation: PROCESS_INFORMATION = std.mem.zeroes(PROCESS_INFORMATION); + startInfo.cb = @sizeOf(STARTUPINFOA); + + const result: BOOL = CreateProcessA(null, + CmdLine_, null, null, FALSE, 0, null, null, + &startInfo, &lpProcessInformation + ); + if (result == FALSE) return null; + + _ = WaitForInputIdle( lpProcessInformation.hProcess, INFINITE ); + std.time.sleep(std.time.ns_per_s * 0.5); + var retries: u8 = 0; + while (wnd.appHwnd == undefined) { + ProcessMsg(); + EnumWindows(EnumWindowProc, 0); + std.time.sleep(std.time.ns_per_s * 1); + retries += 1; + if (retries > 15) return null; + } + + const wndstyle: LONG = GetWindowLongA(wnd.appHwnd, GWL_EXSTYLE); + _ = SetWindowLongA(wnd.appHwnd, GWL_EXSTYLE, wndstyle | WS_VISIBLE); + wnd.appProcess = lpProcessInformation.dwProcessId; + wnd.visible = true; + return &lpProcessInformation; +} + +pub fn ProcessMsg() void { + while (PeekMessageA(&wnd.msg, null, 0, 0, PM_REMOVE) != 0) { + _ = TranslateMessage(&wnd.msg); + _ = DispatchMessageA(&wnd.msg); + if (wnd.msg.message == WM_QUIT) { wnd.exit = true; } + } +} + +pub export fn EnumWindowProc(hwnd: HWND, lParam: LPARAM) + callconv(WINAPI) INT { _ = &lParam; + + if (IsWindowVisible(hwnd) == FALSE) return TRUE; + + const wndtext_len: usize = + @as(usize, @intCast(GetWindowTextLengthA(hwnd))); _ = &wndtext_len; + if (wndtext_len == 0) return TRUE; + + var wndtext: [255:0]u8 = std.mem.zeroes([255:0]u8); _ = &wndtext; + _ = GetWindowTextA(hwnd, &wndtext, 255); + + var wndtextbuf = std.mem.zeroes([255]u8); _ = &wndtextbuf; + const wndtextUpper = std.ascii.upperString(&wndtextbuf, &wndtext); + var wndtitlebuf = std.mem.zeroes([255]u8); _ = &wndtitlebuf; + const wndtitletmp = std.mem.sliceTo(wnd.title, 0); + var count: usize = 0; + for (wndtitletmp, 0..wndtitletmp.len) |char, idx| { + wndtitlebuf[idx] = std.ascii.toUpper(char); + count = idx; + } + const wndtmp: []const u8 = wndtitlebuf[0..count]; + if (std.mem.indexOf(u8, wndtextUpper, wndtmp) != null) { + wnd.appHwnd = hwnd; + return FALSE; + } + + return TRUE; +} + +fn AddNotificationIcon(hWnd: HWND) void { + var tooltip: [128]CHAR = std.mem.zeroes([128]CHAR); + const tooltip_msg = "Click to toogle Show/Hide program.\nRight-click to remove systray icon."; + @memcpy(tooltip[0..tooltip_msg.len], tooltip_msg); + + var nid: NOTIFYICONDATAA = std.mem.zeroes(NOTIFYICONDATAA); + nid.cbSize = @sizeOf(NOTIFYICONDATAA); + nid.hWnd = hWnd; + nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP | NIF_GUID; + nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK; + nid.guidItem = wnd.guid; + nid.hIcon = wnd.icon; + nid.szTip = tooltip; + _ = Shell_NotifyIconA(NIM_ADD, &nid); + nid.DUMMYUNIONNAME.uVersion = NOTIFYICON_VERSION_4; + _ = Shell_NotifyIconA(NIM_SETVERSION, &nid); +} + +fn DeleteNotificationIcon() void { + var nid: NOTIFYICONDATAA = std.mem.zeroes(NOTIFYICONDATAA); + nid.cbSize = @sizeOf(NOTIFYICONDATAA); + nid.uFlags = NIF_GUID; + nid.guidItem = wnd.guid; + _ = Shell_NotifyIconA(NIM_DELETE, &nid); +} + + +fn WindowProc( hWnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM ) callconv(WINAPI) LRESULT { + switch (uMsg) { + WM_CREATE => { + AddNotificationIcon(hWnd); + }, + WM_DESTROY => { + PostQuitMessage(0); + return 0; + }, + WM_PAINT => { + var ps: PAINTSTRUCT = undefined; + const hdc: HDC = BeginPaint(hWnd, &ps) orelse undefined; + _ = FillRect(hdc, &ps.rcPaint, @ptrFromInt( COLOR_WINDOW+1)); + _ = EndPaint(hWnd, &ps); + }, + WM_SIZE => { + wnd.width = @as(INT, @intCast(LOWORD(lParam))); + wnd.height = @as(INT, @intCast(HIWORD(lParam))); + }, + WM_KEYDOWN, + WM_SYSKEYDOWN => { + switch (wParam) { + VK_ESCAPE => { //SHIFT+ESC = EXIT + if (GetAsyncKeyState(VK_LSHIFT) & 0x01 == 1) { + PostQuitMessage(0); + return 0; + } + }, + else => {} + } + }, + WMAPP_NOTIFYCALLBACK => { + switch (LOWORD(lParam)) { + WM_LBUTTONDOWN => { + TogleWindow(); + }, + WM_RBUTTONDOWN => { + if (!wnd.visible) TogleWindow(); + wnd.exit = true; + return 0; + }, + WM_CONTEXTMENU => { + // POINT const pt = { LOWORD(wParam), HIWORD(wParam) }; + // ShowContextMenu(hwnd, pt); + }, + else => {}, + } + }, + else => _=.{}, + } + + return DefWindowProcA(hWnd, uMsg, wParam, lParam); +} + +pub fn Destroy() void { + _ = ReleaseDC(wnd.handle, wnd.hdc); + _ = UnregisterClassA(wnd.title, wnd.hInstance); + _ = DestroyWindow(wnd.handle); +} + +pub fn CloseAppHandles(hProcess: HANDLE, hThread: HANDLE) void { + std.os.windows.CloseHandle(hThread); + std.os.windows.CloseHandle(hProcess); + _ = DestroyIcon(wnd.icon); + DeleteNotificationIcon(); +} + +fn TogleWindow() void { + wnd.visible = !wnd.visible; + ShowWindow(wnd.appHwnd, if (wnd.visible) SW_SHOW else SW_HIDE); +} + +inline fn toStringA(string: []const u8) [*:0]const u8 { return @as([*:0]const u8, @ptrCast(string)); } + +fn toStringBuffer(string: [*:0]const u8) [255:0]u8 { + var ret: [255:0]u8 = std.mem.zeroes([255:0]u8); + for (std.mem.span(string), 0..) |char, idx| { + ret[idx] = char; + } + return ret; +} + +fn toPathString(string: [*:0]const u8) [*:0]const u8 { + var ret: [255]u8 = std.mem.zeroes([255]u8); + var count: usize = 0; + var offset: usize = 0; + for (std.mem.span(string), 0..) |char, idx| { + if (char == '\"') { + offset += 1; + continue; + } + ret[idx - offset] = char; + count = idx - offset; + } + const rettmp: []const u8 = ret[0..(count+1)]; + const dirname = std.heap.page_allocator.dupe(u8, std.fs.path.dirname(rettmp).?) catch unreachable; + const dirappend = '\\'; + ret = std.mem.zeroes([255]u8); count = 0; offset = 0; + for (dirname, 0..dirname.len) |char, idx| { + ret[idx] = char; + count = idx; + } + ret[count + 1] = dirappend; + const ret_cpy = std.heap.page_allocator.dupe(u8, &ret) catch unreachable; + const ret2: [*:0]const u8 = @as([*:0]const u8, @ptrCast(ret_cpy)); + return ret2; +} + +inline fn toRetCopy(any: anytype) @TypeOf(any) { + const any_cpy = std.heap.page_allocator.dupe( + @typeInfo(@TypeOf(any)).Pointer.child, any) catch unreachable; + return @as(@TypeOf(any), @ptrCast(any_cpy)); +} + +fn GetRandom() u8 { + var prng = std.rand.DefaultPrng.init(blk: { + var seed: u64 = undefined; + std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable; + break :blk seed; + }); + const rand = prng.random(); + return rand.int(u8); +} + +fn toRemoveQuotes(string: [*:0]const u8) [*:0]const u8 { + const str2 = std.mem.sliceTo(string, 0); + var strbuf: [255]u8 = std.mem.zeroes([255]u8); + var offset: u8 = 0; + for (str2, 0..str2.len) |char, idx| { + if (char == '\"') { + offset += 1; + continue; + } + strbuf[idx - offset] = char; + } + const strtmp: []const u8 = &strbuf; + const strtmp2 = toRetCopy(strtmp); + return toStringA(strtmp2); +} + +pub fn HideConsoleWindow() void { + const BUF_TITLE = 1024; + var pszWindowTitle: [BUF_TITLE:0]CHAR = std.mem.zeroes([BUF_TITLE:0]CHAR); + + _ = GetConsoleTitleA(&pszWindowTitle, BUF_TITLE); + wnd.consolehwnd = FindWindowA(null, &pszWindowTitle); + _ = ShowWindow(wnd.consolehwnd, SW_HIDE); +} + +const TRUE = std.os.windows.TRUE; +const FALSE = std.os.windows.FALSE; + +pub const WINAPI = std.os.windows.WINAPI; +pub const HWND = std.os.windows.HWND; +pub const HINSTANCE = std.os.windows.HINSTANCE; +pub const LPWSTR = std.os.windows.LPWSTR; +pub const LPSTR = std.os.windows.LPSTR; +pub const LPCSTR = std.os.windows.LPCSTR; +pub const INT = std.os.windows.INT; +pub const HANDLE = std.os.windows.HANDLE; +const UINT = std.os.windows.UINT; +const LONG = std.os.windows.LONG; +const BOOL = std.os.windows.BOOL; +pub const DWORD = std.os.windows.DWORD; +const WORD = std.os.windows.WORD; +const RECT = std.os.windows.RECT; +const LRESULT = std.os.windows.LRESULT; +const LONG_PTR = std.os.windows.LONG_PTR; +const WPARAM = std.os.windows.WPARAM; +const LPARAM = std.os.windows.LPARAM; +const POINT = std.os.windows.POINT; +const HDC = *opaque{}; +const HBRUSH = *opaque{}; +const HGLRC = std.os.windows.HGLRC; +const HICON = std.os.windows.HICON; +const HCURSOR = std.os.windows.HCURSOR; +const ATOM = std.os.windows.ATOM; +const HMENU = std.os.windows.HMENU; +const LPVOID = std.os.windows.LPVOID; +const BYTE = std.os.windows.BYTE; +const CHAR = std.os.windows.CHAR; +const GUID = std.os.windows.GUID; +const PNOTIFYICONDATAA = NOTIFYICONDATAA; +const HRESULT = std.os.windows.HRESULT; +const INFINITE = std.os.windows.INFINITE; + +const IDC_ARROW: LONG = 32512; +const CW_USEDEFAULT: i32 = @bitCast(@as(u32, 0x80000000)); +const CS_DBLCLKS = 0x0008; +const CS_OWNDC = 0x0020; +pub const MB_OK = 0x00000000; +pub const MB_ICONERROR = 0x00000010; +const COLOR_WINDOW = 5; +const VK_ESCAPE = 27; +const VK_LSHIFT = 160; + +const GWL_STYLE: INT = -16; +const GWL_EXSTYLE: INT = -20; + +const SW_HIDE: INT = 0; +const SW_SHOW: INT = 5; + +const WS_OVERLAPPED = 0x00000000; +const WS_POPUP = 0x80000000; +const WS_CHILD = 0x40000000; +const WS_MINIMIZE = 0x20000000; +const WS_VISIBLE = 0x10000000; +const WS_DISABLED = 0x08000000; +const WS_CLIPSIBLINGS = 0x04000000; +const WS_CLIPCHILDREN = 0x02000000; +const WS_MAXIMIZE = 0x01000000; +const WS_CAPTION = WS_BORDER | WS_DLGFRAME; +const WS_BORDER = 0x00800000; +const WS_DLGFRAME = 0x00400000; +const WS_VSCROLL = 0x00200000; +const WS_HSCROLL = 0x00100000; +const WS_SYSMENU = 0x00080000; +const WS_THICKFRAME = 0x00040000; +const WS_GROUP = 0x00020000; +const WS_TABSTOP = 0x00010000; +const WS_MINIMIZEBOX = 0x00020000; +const WS_MAXIMIZEBOX = 0x00010000; +const WS_TILED = WS_OVERLAPPED; +const WS_ICONIC = WS_MINIMIZE; +const WS_SIZEBOX = WS_THICKFRAME; +const WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW; +const WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; +const WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU; +const WS_CHILDWINDOW = WS_CHILD; + +const WS_EX_DLGMODALFRAME = 0x00000001; +const WS_EX_NOPARENTNOTIFY = 0x00000004; +const WS_EX_TOPMOST = 0x00000008; +const WS_EX_ACCEPTFILES = 0x00000010; +const WS_EX_TRANSPARENT = 0x00000020; +const WS_EX_MDICHILD = 0x00000040; +const WS_EX_TOOLWINDOW = 0x00000080; +const WS_EX_WINDOWEDGE = 0x00000100; +const WS_EX_CLIENTEDGE = 0x00000200; +const WS_EX_CONTEXTHELP = 0x00000400; +const WS_EX_RIGHT = 0x00001000; +const WS_EX_LEFT = 0x00000000; +const WS_EX_RTLREADING = 0x00002000; +const WS_EX_LTRREADING = 0x00000000; +const WS_EX_LEFTSCROLLBAR = 0x00004000; +const WS_EX_RIGHTSCROLLBAR = 0x00000000; +const WS_EX_CONTROLPARENT = 0x00010000; +const WS_EX_STATICEDGE = 0x00020000; +const WS_EX_APPWINDOW = 0x00040000; +const WS_EX_LAYERED = 0x00080000; +const WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE; +const WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; + +const WM_NULL = 0x0000; +const WM_CREATE = 0x0001; +const WM_DESTROY = 0x0002; +const WM_MOVE = 0x0003; +const WM_SIZE = 0x0005; +const WM_ACTIVATE = 0x0006; +const WM_SETFOCUS = 0x0007; +const WM_KILLFOCUS = 0x0008; +const WM_ENABLE = 0x000A; +const WM_SETREDRAW = 0x000B; +const WM_SETTEXT = 0x000C; +const WM_GETTEXT = 0x000D; +const WM_GETTEXTLENGTH = 0x000E; +const WM_PAINT = 0x000F; +const WM_CLOSE = 0x0010; +const WM_QUERYENDSESSION = 0x0011; +const WM_QUIT = 0x0012; +const WM_KEYDOWN = 0x0100; +const WM_KEYUP = 0x0101; +const WM_CHAR = 0x0102; +const WM_DEADCHAR = 0x0103; +const WM_SYSKEYDOWN = 0x0104; +const WM_SYSKEYUP = 0x0105; +const WM_SYSCHAR = 0x0106; +const WM_SYSDEADCHAR = 0x0107; +const WM_CONTEXTMENU = 0x007B; +const WM_APP = 0x8000; +const WMAPP_NOTIFYCALLBACK = WM_APP + 1; +const WM_LBUTTONDOWN = 0x0201; +const WM_RBUTTONDOWN = 0x0204; + +const PM_NOREMOVE = 0x0000; +const PM_REMOVE = 0x0001; +const PM_NOYIELD = 0x0002; + +const NIM_ADD = 0x00000000; +const NIM_MODIFY = 0x00000001; +const NIM_DELETE = 0x00000002; +const NIM_SETFOCUS = 0x00000003; +const NIM_SETVERSION = 0x00000004; + +const NIF_MESSAGE = 0x00000001; +const NIF_ICON = 0x00000002; +const NIF_TIP = 0x00000004; +const NIF_STATE = 0x00000008; +const NIF_INFO = 0x00000010; +const NIF_GUID = 0x00000020; +const NIF_REALTIME = 0x00000040; +const NIF_SHOWTIP = 0x00000080; + +const NOTIFYICON_VERSION_4 = 4; +const LIM_SMALL = 0; + +const WNDCLASSEXA = extern struct { + cbSize: UINT = @sizeOf(WNDCLASSEXA), + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: i32 = 0, + cbWndExtra: i32 = 0, + hInstance: HINSTANCE, + hIcon: ?HICON, + hCursor: ?HCURSOR, + hbrBackground: ?HBRUSH, + lpszMenuName: ?[*:0]const u8, + lpszClassName: [*:0]const u8, + hIconSm: ?HICON, +}; + +const WNDPROC = *const fn ( + hwnd: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM +) callconv(WINAPI) LRESULT; + +const MSG = extern struct { + hWnd: ?HWND, + message: UINT, + wParam: WPARAM, + lParam: LPARAM, + time: DWORD, + pt: POINT, + lPrivate: DWORD, +}; + +const PAINTSTRUCT = extern struct { + hdc: HDC, + fErase: BOOL, + rcPaint: RECT, + fRestore: BOOL, + fIncUpdate: BOOL, + rgbReserved: [32]BYTE +}; + +pub const PROCESS_INFORMATION = extern struct { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD, +}; + +const SECURITY_ATTRIBUTES = extern struct { + nLength: DWORD, + lpSecurityDescriptor: ?*anyopaque, + bInheritHandle: BOOL, +}; + +const STARTUPINFOA = extern struct { + cb: DWORD, + lpReserved: ?LPSTR, + lpDesktop: ?LPSTR, + lpTitle: ?LPSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountChars: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: ?*BYTE, + hStdInput: ?HANDLE, + hStdOutput: ?HANDLE, + hStdError: ?HANDLE, +}; + +const NOTIFYICONDATAA = extern struct { + cbSize: DWORD, + hWnd: HWND, + uID: UINT, + uFlags: UINT, + uCallbackMessage: UINT, + hIcon: HICON, + szTip: [128]CHAR, + dwState: DWORD, + dwStateMask: DWORD, + szInfo: [256]CHAR, + DUMMYUNIONNAME: extern union { + uTimeout: UINT, + uVersion: UINT + }, + szInfoTitle: [64]CHAR, + dwInfoFlags: DWORD, + guidItem: GUID, + hBalloonIcon: HICON +}; + + +fn LOWORD(l: LONG_PTR) UINT { return @as(u32, @intCast(l)) & 0xFFFF; } +fn HIWORD(l: LONG_PTR) UINT { return (@as(u32, @intCast(l)) >> 16) & 0xFFFF; } + +pub fn toUtf8(any: LPWSTR) []u8 { + const bufU16 = std.unicode.fmtUtf16Le(std.mem.span( any )).data; + var bufU8: [4096]u8 = undefined; + for (bufU16, 0..) |char, i| { + bufU8[i] = @as(u8, @truncate(char)); + } + return bufU8[0..bufU16.len]; +} + +pub extern "kernel32" fn GetCommandLineA( +) callconv(WINAPI) ?LPSTR; + +pub extern "user32" fn MessageBoxA( + hWnd: ?HWND, + lpText: [*:0]const u8, + lpCaption: [*:0]const u8, + uType: UINT +) callconv(WINAPI) INT; + +extern "user32" fn UpdateWindow( + hWnd: HWND +) callconv(WINAPI) BOOL; + +extern "user32" fn LoadCursorA( + hInstance: ?HINSTANCE, + lpCursorName: LONG, +) callconv(WINAPI) HCURSOR; + +extern "user32" fn RegisterClassExA( + *const WNDCLASSEXA +) callconv(WINAPI) ATOM; + +extern "user32" fn UnregisterClassA( + lpClassName: [*:0]const u8, + hInstance: HINSTANCE +) callconv(WINAPI) BOOL; + +extern "user32" fn AdjustWindowRectEx( + lpRect: *RECT, + dwStyle: DWORD, + bMenu: BOOL, + dwExStyle: DWORD +) callconv(WINAPI) BOOL; + +extern "user32" fn CreateWindowExA( + dwExStyle: DWORD, + lpClassName: [*:0]const u8, + lpWindowName: [*:0]const u8, + dwStyle: DWORD, + X: i32, + Y: i32, + nWidth: i32, + nHeight: i32, + hWindParent: ?HWND, + hMenu: ?HMENU, + hInstance: HINSTANCE, + lpParam: ?LPVOID +) callconv(WINAPI) ?HWND; + +extern "user32" fn DestroyWindow( + hWnd: HWND +) callconv(WINAPI) BOOL; + +extern "user32" fn GetDC( + hWnd: ?HWND +) callconv(WINAPI) ?HDC; + +extern "user32" fn ReleaseDC( + hWnd: ?HWND, + hDC: HDC +) callconv(WINAPI) i32; + +extern "user32" fn PostQuitMessage( + nExitCode: i32 +) callconv(WINAPI) void; + +extern "user32" fn PeekMessageA( + lpMsg: *MSG, + hWnd: ?HWND, + wMsgFilterMin: UINT, + wMsgFilterMax: UINT, + wRemoveMsg: UINT +) callconv(WINAPI) BOOL; + +extern "user32" fn TranslateMessage( + lpMsg: *const MSG +) callconv(WINAPI) BOOL; + +extern "user32" fn DispatchMessageA( + lpMsg: *const MSG +) callconv(WINAPI) LRESULT; + +extern "user32" fn DefWindowProcA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM +) callconv(WINAPI) LRESULT; + +extern "user32" fn BeginPaint( + hWnd: ?HWND, + lpPaint: ?*PAINTSTRUCT, +) callconv(WINAPI) ?HDC; + +extern "user32" fn FillRect( + hDC: ?HDC, + lprc: ?*const RECT, + hbr: ?HBRUSH +) callconv(WINAPI) INT; + +extern "user32" fn EndPaint( + hWnd: HWND, + lpPaint: *const PAINTSTRUCT +) callconv(WINAPI) BOOL; + +extern "user32" fn GetAsyncKeyState( + nKey: c_int +) callconv(WINAPI) INT; + +extern "kernel32" fn CreateProcessA( + lpApplicationName: ?LPCSTR, + lpCommandLine: ?LPSTR, + lpProcessAttributes: ?*SECURITY_ATTRIBUTES, + lpThreadAttributes: ?*SECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: ?*anyopaque, + lpCurrentDirectory: ?LPCSTR, + lpStartupInfo: *STARTUPINFOA, + lpProcessInformation: *PROCESS_INFORMATION, +) callconv(WINAPI) BOOL; + +pub extern "shell32" fn ExtractIconA( + hInst: HINSTANCE, + pszExeFileName: LPCSTR, + nIconIndex: UINT +) callconv(WINAPI) ?HICON; + +extern "shell32" fn Shell_NotifyIconA( + dwMessage: DWORD, + lpData: *NOTIFYICONDATAA +) callconv(WINAPI) BOOL; + +extern "user32" fn DestroyIcon( + hIcon: HICON, +) callconv(WINAPI) BOOL; + +extern "comctl32" fn LoadIconMetric( + hInst: ?HINSTANCE, + pszName: LPCSTR, + lims: INT, + phico: *HICON +) callconv(WINAPI) HRESULT; + +extern "user32" fn SetWindowLongA( + hWnd: HWND, + nIndex: INT, + dwNewLong: LONG +) callconv(WINAPI) HRESULT; + +extern "user32" fn GetWindowLongA( + hWnd: HWND, + nIndex: INT +) callconv(WINAPI) LONG ; + +extern "user32" fn ShowWindow( + hWnd: HWND, + nCmdShow: INT +) callconv(WINAPI) void; + +extern "user32" fn EnumWindows( + lpEnumFunc: WNDENUMPROC, + lParam: LPARAM +) callconv(WINAPI) void; + +const WNDENUMPROC = *const fn ( + hwnd: HWND, + lParam: LPARAM +) callconv(WINAPI) INT; + +extern "user32" fn IsWindowVisible( + hwnd: HWND +) callconv(WINAPI) BOOL; + +extern "user32" fn GetWindowTextA( + hwnd: HWND, + lpString: LPSTR, + nMaxCount: INT +) callconv(WINAPI) INT; + +extern "user32" fn GetWindowTextLengthA( + hWnd: ?HWND +) callconv(WINAPI) INT; + +extern "kernel32" fn SetCurrentDirectoryA( + lpPathName: LPCSTR +) callconv(WINAPI) BOOL; + +extern "user32" fn WaitForInputIdle( + hProcess: HANDLE, + dwMilliseconds: DWORD +) callconv(WINAPI) DWORD; + +extern "kernel32" fn GetConsoleTitleA( + lpConsoleTitle: LPSTR, + nSize: DWORD, +) callconv(WINAPI) DWORD; + +extern "kernel32" fn FindWindowA( + lpClassName: ?LPSTR, + lpWindowName: ?LPSTR, +) callconv(WINAPI) HWND; \ No newline at end of file