diff --git a/README.md b/README.md index 9b2b21e..63388a8 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,78 @@ -# Windows - -Windows API bindings for [Rux](https://rux-lang.dev).All functions follow the official [Microsoft Win32 documentation](https://learn.microsoft.com/en-us/windows/win32/api/). - -## Install - -```toml -[Dependencies] -Windows = "0.2.1" -``` - -## Modules - -| File | What | -|------|------| -| `Kernel32.rux` | kernel32.dll — processes, memory, threads, DLLs, sync, console, heap | -| `Pe.rux` | PE/COFF structs (DOS header, NT headers, IAT, EAT, sections) | -| `Process.rux` | Process enumeration, DLL injection, memory read/write | -| `Hook.rux` | IAT and inline (trampoline) function hooking | -| `ProxyDll.rux` | Proxy DLL pattern — forwarding to the real DLL | -| `Advapi32.rux` | advapi32.dll — registry, services, security, LSA | -| `DbgHelp.rux` | dbghelp.dll — minidumps, stack walking, symbols | -| `Gdi32.rux` | gdi32.dll — bitmap, font, DC, region | -| `NtDll.rux` | ntdll.dll — NT API (process, system, memory info) | -| `Psapi.rux` | psapi.dll — process/device driver enumeration | -| `User32.rux` | user32.dll — windows, messages, controls, input | -| `WinHvPlatform.rux` | WinHvPlatform.dll — Hyper-V whpx | -| `Ws2_32.rux` | ws2_32.dll — sockets (Winsock 2) | - -### Memory Management - -Functions for heap-based memory allocation. - -| Function | Description | -| ------------------ | ----------------------------------------------------------- | -| `GetProcessHeap()` | Returns a handle to the default heap of the calling process | -| `HeapAlloc()` | Allocates a block of memory from a specified heap | -| `HeapReAlloc()` | Reallocates a block of memory from a heap | -| `HeapFree()` | Frees a memory block allocated from a heap | - -### Memory Operations - -Low-level memory utility routines (RTL). - -| Function | Description | -| ----------------- | ---------------------------------------------- | -| `RtlFillMemory()` | Fills a block of memory with a specified value | -| `RtlZeroMemory()` | Fills a block of memory with zeros | -| `RtlCopyMemory()` | Copies a block of memory to another location | - -### Console I/O - -Functions for allocating and writing to a console. - -| Function | Description | -| ----------------- | --------------------------------------------------------------- | -| `AllocConsole()` | Allocates a new console for the calling process | -| `GetStdHandle()` | Retrieves a handle to a standard device (stdin, stdout, stderr) | -| `WriteConsoleA()` | Writes a string of ANSI characters to the console | -| `WriteConsoleW()` | Writes a string of UTF-16 characters to the console | -| `Beep()` | Generates a tone on the system speaker | - -### String Conversion - -| Function | Description | -| ----------------------- | --------------------------------------------------------- | -| `MultiByteToWideChar()` | Converts a multi-byte ANSI string to a UTF-16 wide string | - -### Process & Thread Control - -| Function | Description | -| --------------- | -------------------------------------------------- | -| `Sleep()` | Suspends the execution of the current thread | -| `ExitProcess()` | Terminates the calling process and all its threads | - -### Error Handling - -| Function | Description | -| ---------------- | --------------------------------------------------- | -| `GetLastError()` | Retrieves the last-error code of the calling thread | - - -## Example +# Windows — Rux API Bindings (v0.4.0) + +Complete, zero-conflict Windows API bindings for the [Rux programming language](https://rux-lang.dev). +This is the **the-lust/Windows** fork, kept in sync with and fully compatible with [rux-lang/Windows](https://github.com/rux-lang/Windows). + +## Source files + +| File | DLL(s) | Coverage | +|---|---|---| +| Kernel32.rux | kernel32.dll | Process, thread, memory, file I/O, console, sync, heap, DLL mgmt, interlocked ops, timing | +| NtDll.rux | ntdll.dll | NT native API, all STATUS_* codes, RtlXxx helpers, UnicodeString, ObjectAttributes | +| User32.rux | user32.dll | Window creation, message loop, input, menus, clipboard, DPI, raw input, touch, tray | +| Gdi32.rux | gdi32.dll + msimg32.dll | DC, bitmap, pen, brush, font, path, region, AlphaBlend, GradientFill, TransparentBlt | +| Advapi32.rux | advapi32.dll | Registry, token/privilege, security, services, event log, DPAPI | +| BCrypt.rux | bcrypt.dll | CNG: hash, HMAC, AES, RSA, ECDH, PBKDF2, random bytes | +| Crypt32.rux | crypt32.dll | Base64/hex encode-decode, DPAPI, cert store, chain validation, PKCS12 | +| DbgHelp.rux | dbghelp.dll | Symbol engine, stack walking, type info, minidump | +| Psapi.rux | psapi.dll | Process/module enumeration, memory counters, working set | +| Ws2_32.rux | ws2_32.dll | BSD sockets, WSA overlapped I/O, getaddrinfo, byte-order helpers | +| WinHvPlatform.rux | winhvplatform.dll | WHvP: partitions, VPs, GPA ranges, interrupts, CPUID override | +| Shell32.rux | shell32.dll | ShellExecute, SHFileOperation, known folders, CSIDL, tray, drag-drop | +| Ole32.rux | ole32.dll + oleaut32.dll | COM init, CoCreateInstance, IUnknown/IDispatch, VARIANT, BSTR, SAFEARRAY, storage | +| Seh.rux | kernel32.dll + ntdll.dll | SEH, VEH, unhandled exception filter, CONTEXT (x64 + ARM64), RtlUnwindEx | +| Pe.rux | *(pure Rux)* | PE32/PE32+ parsing, export/import tables, section lookup, base relocation | +| Hook.rux | *(pure Rux)* | x64 + ARM64 inline hooks, IAT hooks, global registry, RIP-relative fixup | +| Process.rux | kernel32.dll | Spawn helpers, DLL injection (LoadLibrary + reflective), PID-by-name, memory scanner | +| ProxyDll.rux | kernel32.dll | Proxy DLL: forward stubs (x64 + ARM64), per-export registration | +| Compat.rux | *(pure Rux)* | C/C++/Rust/Zig FFI type aliases, calling-convention docs, Win32 macros | + +## Architecture support + +| Target | Status | +|---|---| +| Windows x64 (AMD64) | Full support | +| Windows ARM64 (AArch64) | Full support — ARM64 stubs in Hook.rux + ProxyDll.rux, ARM64 CONTEXT in Seh.rux | +| Linux / macOS / WASM | Safe — all Win32 blocks are @[Target("Windows")]; other targets compile to nothing | + +## Zero-conflict guarantee + +- STATUS_* NTSTATUS codes — only in NtDll.rux +- Interlocked* primitives — only in Kernel32.rux +- GetLastError / SetLastError — only in Kernel32.rux +- DLL_PROCESS_ATTACH/DETACH/THREAD_* — only in Kernel32.rux +- HrSucceeded / HrFailed — only in WinHvPlatform.rux and Ole32.rux +- No file re-declares a symbol from any other file in the package + +## Cross-language FFI + +See Compat.rux for Rux-to-C/Rust/Zig type mapping and calling convention notes. + +## Quick start ```rux -import Windows::*; +import Windows; -func Main() -> int { - let heap = GetProcessHeap(); - let mem = HeapAlloc(heap, 0u32, 1024u); - RtlZeroMemory(mem, 1024u); - - let stdout = GetStdHandle(StdHandle::Output as uint32); +@[Entry] +func Main() -> int32 { + let con = GetStdHandle(STD_OUTPUT_HANDLE); var written: uint32 = 0u32; - WriteConsoleA(stdout, "Hello, Windows!\n\0", 16u32, &written, null); - - HeapFree(heap, 0u32, mem); + WriteConsoleA(con, c"Hello, Windows!\n", 16u32, &written, null); return 0; } ``` -## License +## Changelog + +### v0.4.0 +- Fixed all duplicate-symbol errors (STATUS_*, Interlocked*, GetLastError, DLL_PROCESS_ATTACH, …) +- Fixed struct pad/size errors (ProcessBasicInfo, WsaData, SockAddrIn, ExceptionRecord, ImageNtHeaders64, LogFontA, …) +- Fixed wrong return types (connect, RegQueryValueExA, SymGetLineFromAddr64, SelectObject, WHvCreatePartition, …) +- Fixed incorrect constant values (IMAGE_DIRECTORY_ENTRY_BASERELOC, EXCEPTION_FLT_DENORMAL_OPERAND, SYMOPT_EXACT_SYMBOLS, …) +- Fixed missing APIs (GetStdHandle, PostQuitMessage, CreateFontIndirectA, EnumProcessModulesEx, CryptBinaryToStringA, …) +- Added ARM64 hook stubs and CONTEXT struct +- Added Shell32.rux, Ole32.rux, Compat.rux (new files) +- All 19 source files carry @[Target("Windows")] -[MIT](LICENSE) +### v0.3.0 +- Initial dev-branch release diff --git a/Rux.toml b/Rux.toml index 91a8121..61a5df2 100644 --- a/Rux.toml +++ b/Rux.toml @@ -1,6 +1,14 @@ [Package] Name = "Windows" -Version = "0.3.0" +Version = "0.4.0" Type = "Source" -Description = "Windows API bindings — Kernel32, User32, Gdi32, NtDll, Advapi32, BCrypt, Crypt32, DbgHelp, Psapi, Ws2_32, WinHvPlatform, SEH, PE/hooks/process/proxy-DLL utilities" +Description = "Windows API bindings for Rux — Kernel32, User32, Gdi32, NtDll, Advapi32, BCrypt, Crypt32, DbgHelp, Psapi, Ws2_32, WinHvPlatform, Shell32, Ole32/OleAut32, SEH/VEH, PE/hooks/process/proxy-DLL utilities, cross-language FFI compatibility. Supports x64 and ARM64. Zero-conflict with rux-lang/Windows upstream." Authors = ["Rux Contributors ", "the-lust"] + +[Dependencies] + +[Targets] +Windows = true +Linux = false +macOS = false +WASM = false diff --git a/Src/Advapi32.rux b/Src/Advapi32.rux index d6ee876..b8ac53e 100644 --- a/Src/Advapi32.rux +++ b/Src/Advapi32.rux @@ -1,603 +1,582 @@ -/* - Windows API — Advapi32.dll (Registry, Services, Security, LSA) - Copyright © 2026 Rux Contributors - Licensed under the MIT License -*/ - -module Windows { - - - // Constants — Registry Hive Predefined Handles - - - pub const HKEY_CLASSES_ROOT: uint = 0x80000000u; - pub const HKEY_CURRENT_USER: uint = 0x80000001u; - pub const HKEY_LOCAL_MACHINE: uint = 0x80000002u; - pub const HKEY_USERS: uint = 0x80000003u; - pub const HKEY_CURRENT_CONFIG: uint = 0x80000005u; - - - // Constants — Registry Access Rights - - - pub const KEY_QUERY_VALUE: uint32 = 0x0001u32; - pub const KEY_SET_VALUE: uint32 = 0x0002u32; - pub const KEY_CREATE_SUB_KEY: uint32 = 0x0004u32; - pub const KEY_ENUMERATE_SUB_KEYS: uint32 = 0x0008u32; - pub const KEY_NOTIFY: uint32 = 0x0010u32; - pub const KEY_CREATE_LINK: uint32 = 0x0020u32; - pub const KEY_WOW64_64KEY: uint32 = 0x0100u32; - pub const KEY_WOW64_32KEY: uint32 = 0x0200u32; - pub const KEY_WRITE: uint32 = 0x00020006u32; - pub const KEY_READ: uint32 = 0x00020019u32; - pub const KEY_ALL_ACCESS: uint32 = 0x000F003Fu32; - - - // Constants — Registry Value Types - - - pub const REG_NONE: uint32 = 0u32; - pub const REG_SZ: uint32 = 1u32; - pub const REG_EXPAND_SZ: uint32 = 2u32; - pub const REG_BINARY: uint32 = 3u32; - pub const REG_DWORD: uint32 = 4u32; - pub const REG_DWORD_LITTLE_ENDIAN: uint32 = 4u32; - pub const REG_DWORD_BIG_ENDIAN: uint32 = 5u32; - pub const REG_LINK: uint32 = 6u32; - pub const REG_MULTI_SZ: uint32 = 7u32; - pub const REG_QWORD: uint32 = 11u32; - pub const REG_QWORD_LITTLE_ENDIAN: uint32 = 11u32; - - - // Constants — Service Control Manager Access - - - pub const SC_MANAGER_CONNECT: uint32 = 0x0001u32; - pub const SC_MANAGER_CREATE_SERVICE: uint32 = 0x0002u32; - pub const SC_MANAGER_ENUMERATE_SERVICE: uint32 = 0x0004u32; - pub const SC_MANAGER_LOCK: uint32 = 0x0008u32; - pub const SC_MANAGER_QUERY_LOCK_STATUS: uint32 = 0x0010u32; - pub const SC_MANAGER_MODIFY_BOOT_CONFIG: uint32 = 0x0020u32; - pub const SC_MANAGER_ALL_ACCESS: uint32 = 0x000F003Fu32; - - - // Constants — Service Access Rights - - - pub const SERVICE_QUERY_CONFIG: uint32 = 0x0001u32; - pub const SERVICE_CHANGE_CONFIG: uint32 = 0x0002u32; - pub const SERVICE_QUERY_STATUS: uint32 = 0x0004u32; - pub const SERVICE_ENUMERATE_DEPENDENTS: uint32 = 0x0008u32; - pub const SERVICE_START: uint32 = 0x0010u32; - pub const SERVICE_STOP: uint32 = 0x0020u32; - pub const SERVICE_PAUSE_CONTINUE: uint32 = 0x0040u32; - pub const SERVICE_INTERROGATE: uint32 = 0x0080u32; - pub const SERVICE_USER_DEFINED_CONTROL: uint32 = 0x0100u32; - pub const SERVICE_ALL_ACCESS: uint32 = 0x000F01FFu32; - - - // Constants — Service Types - - - pub const SERVICE_KERNEL_DRIVER: uint32 = 0x00000001u32; - pub const SERVICE_FILE_SYSTEM_DRIVER: uint32 = 0x00000002u32; - pub const SERVICE_WIN32_OWN_PROCESS: uint32 = 0x00000010u32; - pub const SERVICE_WIN32_SHARE_PROCESS: uint32 = 0x00000020u32; - pub const SERVICE_INTERACTIVE_PROCESS: uint32 = 0x00000100u32; - - - // Constants — Service Start Types - - - pub const SERVICE_BOOT_START: uint32 = 0x00000000u32; - pub const SERVICE_SYSTEM_START: uint32 = 0x00000001u32; - pub const SERVICE_AUTO_START: uint32 = 0x00000002u32; - pub const SERVICE_DEMAND_START: uint32 = 0x00000003u32; - pub const SERVICE_DISABLED: uint32 = 0x00000004u32; - - - // Constants — Service States - - - pub const SERVICE_STOPPED: uint32 = 0x00000001u32; - pub const SERVICE_START_PENDING: uint32 = 0x00000002u32; - pub const SERVICE_STOP_PENDING: uint32 = 0x00000003u32; - pub const SERVICE_RUNNING: uint32 = 0x00000004u32; - pub const SERVICE_CONTINUE_PENDING: uint32 = 0x00000005u32; - pub const SERVICE_PAUSE_PENDING: uint32 = 0x00000006u32; - pub const SERVICE_PAUSED: uint32 = 0x00000007u32; - - - // Constants — Service Control Codes - - - pub const SERVICE_CONTROL_STOP: uint32 = 0x00000001u32; - pub const SERVICE_CONTROL_PAUSE: uint32 = 0x00000002u32; - pub const SERVICE_CONTROL_CONTINUE: uint32 = 0x00000003u32; - pub const SERVICE_CONTROL_INTERROGATE: uint32 = 0x00000004u32; - pub const SERVICE_CONTROL_SHUTDOWN: uint32 = 0x00000005u32; - - - // Constants — Service Info Levels - - - pub const SERVICE_CONFIG_DESCRIPTION: uint32 = 1u32; - pub const SERVICE_CONFIG_FAILURE_ACTIONS: uint32 = 2u32; - pub const SERVICE_CONFIG_DELAYED_AUTO_START_INFO: uint32 = 3u32; - pub const SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: uint32 = 4u32; - pub const SERVICE_CONFIG_SERVICE_SID_INFO: uint32 = 5u32; - pub const SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: uint32 = 6u32; - pub const SERVICE_CONFIG_PREFERRED_NODE: uint32 = 9u32; - - - // Constants — Security Identifiers (Well-Known) - - - pub const SECURITY_NULL_SID_AUTHORITY: uint32 = 0u32; - pub const SECURITY_WORLD_SID_AUTHORITY: uint32 = 1u32; - pub const SECURITY_LOCAL_SID_AUTHORITY: uint32 = 2u32; - pub const SECURITY_CREATOR_SID_AUTHORITY: uint32 = 3u32; - pub const SECURITY_NT_AUTHORITY: uint32 = 5u32; - - pub const SECURITY_BUILTIN_DOMAIN_RID: uint32 = 0x00000020u32; - - - // Constants — Token Access - - - pub const TOKEN_ASSIGN_PRIMARY: uint32 = 0x0001u32; - pub const TOKEN_DUPLICATE: uint32 = 0x0002u32; - pub const TOKEN_IMPERSONATE: uint32 = 0x0004u32; - pub const TOKEN_QUERY: uint32 = 0x0008u32; - pub const TOKEN_QUERY_SOURCE: uint32 = 0x0010u32; - pub const TOKEN_ADJUST_PRIVILEGES: uint32 = 0x0020u32; - pub const TOKEN_ADJUST_GROUPS: uint32 = 0x0040u32; - pub const TOKEN_ADJUST_DEFAULT: uint32 = 0x0080u32; - pub const TOKEN_ALL_ACCESS: uint32 = 0x000F00FFu32; - pub const TOKEN_READ: uint32 = 0x00020008u32; - pub const TOKEN_WRITE: uint32 = 0x000200E0u32; - pub const TOKEN_EXECUTE: uint32 = 0x00020000u32; - - - // Constants — Token Information Classes - - - pub const TokenUser: uint32 = 1u32; - pub const TokenGroups: uint32 = 2u32; - pub const TokenPrivileges: uint32 = 3u32; - pub const TokenOwner: uint32 = 4u32; - pub const TokenPrimaryGroup: uint32 = 5u32; - pub const TokenDefaultDacl: uint32 = 6u32; - pub const TokenSource: uint32 = 7u32; - pub const TokenType: uint32 = 8u32; - pub const TokenImpersonationLevel: uint32 = 9u32; - pub const TokenStatistics: uint32 = 10u32; - pub const TokenElevation: uint32 = 20u32; - pub const TokenLinkedToken: uint32 = 21u32; - pub const TokenElevationType: uint32 = 22u32; - pub const TokenIsVirtual: uint32 = 24u32; - - - // Constants — Service Manager Enumeration - - - pub const SERVICE_DRIVER: uint32 = 0x0000000Bu32; - pub const SERVICE_WIN32: uint32 = 0x00000030u32; - pub const SERVICE_TYPE_ALL: uint32 = 0x0000003Fu32; - - pub const SERVICE_STATE_ACTIVE: uint32 = 0x00000001u32; - pub const SERVICE_STATE_INACTIVE: uint32 = 0x00000002u32; - pub const SERVICE_STATE_ALL: uint32 = 0x00000003u32; - - - // Structures - - - pub struct ServiceStatus { - pub serviceType: uint32; - pub currentState: uint32; - pub controlsAccepted: uint32; - pub win32ExitCode: uint32; - pub serviceSpecificExitCode: uint32; - pub checkPoint: uint32; - pub waitHint: uint32; - } - - pub struct TokenUserInfo { - pub user: uint8[24]; // SID_AND_ATTRIBUTES - } - - pub struct Luid { - pub lowPart: uint32; - pub highPart: int32; - } - - pub struct LuidAndAttributes { - pub luid: Luid; - pub attributes: uint32; - } - - pub struct TokenPrivilegesInfo { - pub privilegeCount: uint32; - pub privileges: uint8[1]; // variable length array of LuidAndAttributes - } - - pub struct FileTime { - pub lowDateTime: uint32; - pub highDateTime: uint32; - } - - - // Extern — advapi32.dll - - - @[Import(lib: "advapi32.dll")] - extern { - - /// Opens the specified registry key with the desired access - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexa - func RegOpenKeyExA( - hKey: *opaque, - subKey: *const char8, - options: uint32, - desiredAccess: uint32, - result: *opaque - ) -> uint32; - - /// Creates the specified registry key or opens it if it already exists - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcreatekeyexa - func RegCreateKeyExA( - hKey: *opaque, - subKey: *const char8, - reserved: uint32, - classStr: *char8, - options: uint32, - desiredAccess: uint32, - securityAttr: *opaque, - result: *opaque, - disposition: *uint32 - ) -> uint32; - - /// Closes a handle to the specified registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey - func RegCloseKey(hKey: *opaque) -> uint32; - /// Deletes a subkey and its values from the specified platform-specific registry view - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regdeletekeyexa - func RegDeleteKeyExA(hKey: *opaque, subKey: *const char8, accessMask: uint32, reserved: uint32) -> uint32; - /// Removes a named value from the specified registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regdeletevaluea - func RegDeleteValueA(hKey: *opaque, valueName: *const char8) -> uint32; - - /// Retrieves the type and data for the specified value name associated with an open registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa - func RegQueryValueExA( - hKey: *opaque, - valueName: *const char8, - reserved: *uint32, - dataType: *uint32, - data: *uint8, - dataSize: *uint32 - ) -> uint32; - - /// Sets the data and type of a value under a registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexa - func RegSetValueExA( - hKey: *opaque, - valueName: *const char8, - reserved: uint32, - dataType: uint32, - data: *const uint8, - dataSize: uint32 - ) -> uint32; - - /// Enumerates the subkeys of the specified open registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumkeyexa - func RegEnumKeyExA( - hKey: *opaque, - index: uint32, - name: *char8, - nameSize: *uint32, - reserved: *uint32, - className: *char8, - classSize: *uint32, - lastWriteTime: *uint64 - ) -> uint32; - - /// Enumerates the values for the specified open registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumvaluea - func RegEnumValueA( - hKey: *opaque, - index: uint32, - valueName: *char8, - valueNameSize: *uint32, - reserved: *uint32, - dataType: *uint32, - data: *uint8, - dataSize: *uint32 - ) -> uint32; - - /// Writes all attributes of the specified open registry key to the registry - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regflushkey - func RegFlushKey(hKey: *opaque) -> uint32; - - - /// Establishes a connection to the service control manager - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openscmanagera - func OpenSCManagerA( - machineName: *const char8, - databaseName: *const char8, - desiredAccess: uint32 - ) -> *opaque; - - /// Closes a handle to a service control manager object or a service object - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-closeservicehandle - func CloseServiceHandle(hSCObject: *opaque) -> bool32; - - /// Creates a service object and adds it to the service control manager database - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicea - func CreateServiceA( - hSCManager: *opaque, - serviceName: *const char8, - displayName: *const char8, - desiredAccess: uint32, - serviceType: uint32, - startType: uint32, - errorControl: uint32, - binaryPath: *const char8, - loadOrderGroup: *const char8, - tagId: *uint32, - dependencies: *const char8, - account: *const char8, - password: *const char8 - ) -> *opaque; - - /// Opens an existing service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openservicea - func OpenServiceA( - hSCManager: *opaque, - serviceName: *const char8, - desiredAccess: uint32 - ) -> *opaque; - - /// Marks the specified service for deletion from the service control manager database - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-deleteservice - func DeleteService(hService: *opaque) -> bool32; - /// Starts a service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicea - func StartServiceA(hService: *opaque, argc: uint32, argv: *opaque) -> bool32; - /// Sends a control code to a service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-controlservice - func ControlService(hService: *opaque, control: uint32, status: *opaque) -> bool32; - /// Retrieves the current status of the specified service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryservicestatus - func QueryServiceStatus(hService: *opaque, status: *opaque) -> bool32; - - /// Retrieves the configuration parameters of the specified service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfiga - func QueryServiceConfigA( - hService: *opaque, - config: *opaque, - bufSize: uint32, - bytesNeeded: *uint32 - ) -> bool32; - - /// Changes the configuration parameters of a service - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-changeserviceconfiga - func ChangeServiceConfigA( - hService: *opaque, - serviceType: uint32, - startType: uint32, - errorControl: uint32, - binaryPath: *const char8, - loadOrderGroup: *const char8, - tagId: *uint32, - dependencies: *const char8, - account: *const char8, - password: *const char8, - displayName: *const char8 - ) -> bool32; - - /// Enumerates services in the specified service control manager database - /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-enumservicesstatusa - func EnumServicesStatusA( - hSCManager: *opaque, - serviceType: uint32, - state: uint32, - services: *opaque, - bufSize: uint32, - bytesNeeded: *uint32, - returned: *uint32, - resumeHandle: *uint32 - ) -> bool32; - - - /// Opens the access token associated with a process - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken - func OpenProcessToken( - processHandle: *opaque, - desiredAccess: uint32, - tokenHandle: *opaque - ) -> bool32; - - /// Opens the access token associated with a thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken - func OpenThreadToken( - threadHandle: *opaque, - desiredAccess: uint32, - openAsSelf: bool32, - tokenHandle: *opaque - ) -> bool32; - - /// Retrieves a specified type of information about an access token - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation - func GetTokenInformation( - tokenHandle: *opaque, - infoClass: uint32, - tokenInfo: *opaque, - tokenInfoLength: uint32, - retLength: *uint32 - ) -> bool32; - - /// Retrieves the locally unique identifier used on a specified system to locally represent a named privilege - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluea - func LookupPrivilegeValueA( - systemName: *const char8, - privilegeName: *const char8, - luid: *Luid - ) -> bool32; - - /// Enables or disables privileges in the specified access token - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges - func AdjustTokenPrivileges( - tokenHandle: *opaque, - disableAll: bool32, - newState: *opaque, - bufferLength: uint32, - previousState: *opaque, - retLength: *uint32 - ) -> bool32; - - /// Lets the calling thread impersonate the security context of a logged-on user - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-impersonateloggedonuser - func ImpersonateLoggedOnUser(hToken: *opaque) -> bool32; - /// Terminates the impersonation of a client application - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-reverttoself - func RevertToSelf() -> bool32; - - - /// Initializes a new security descriptor - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-initializesecuritydescriptor - func InitializeSecurityDescriptor(sd: *opaque, revision: uint32) -> bool32; - /// Determines whether the components of a security descriptor are valid - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-isvalidsecuritydescriptor - func IsValidSecurityDescriptor(sd: *opaque) -> bool32; - /// Sets information in a discretionary access control list - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl - func SetSecurityDescriptorDacl( - sd: *opaque, - daclPresent: bool32, - dacl: *opaque, - daclDefaulted: bool32 - ) -> bool32; - - /// Retrieves a pointer to the discretionary access control list in a security descriptor - /// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-getsecuritydescriptordacl - func GetSecurityDescriptorDacl( - sd: *opaque, - daclPresent: *bool32, - dacl: *opaque, - daclDefaulted: *bool32 - ) -> bool32; - - - /// Accepts the name of a system and an account as input and retrieves a security identifier for the account - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountnamea - func LookupAccountNameA( - systemName: *const char8, - accountName: *const char8, - sid: *opaque, - sidSize: *uint32, - domainName: *char8, - domainNameSize: *uint32, - sidUse: *uint32 - ) -> bool32; - - /// Accepts a security identifier and retrieves the name of the account and the name of the first domain on which that account was found - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountsida - func LookupAccountSidA( - systemName: *const char8, - sid: *opaque, - name: *char8, - nameSize: *uint32, - domainName: *char8, - domainNameSize: *uint32, - sidUse: *uint32 - ) -> bool32; - } - - - // Constants — Registry Create Disposition - - - pub const REG_CREATED_NEW_KEY: uint32 = 0x00000001u32; - pub const REG_OPENED_EXISTING_KEY: uint32 = 0x00000002u32; - - - // Constants — Token Privilege Attributes - - - pub const SE_PRIVILEGE_ENABLED_BY_DEFAULT: uint32 = 0x00000001u32; - pub const SE_PRIVILEGE_ENABLED: uint32 = 0x00000002u32; - pub const SE_PRIVILEGE_REMOVED: uint32 = 0x00000004u32; - - - // Constants — SID Name Use - - - pub const SidTypeUser: uint32 = 1u32; - pub const SidTypeGroup: uint32 = 2u32; - pub const SidTypeDomain: uint32 = 3u32; - pub const SidTypeAlias: uint32 = 4u32; - pub const SidTypeWellKnownGroup: uint32 = 5u32; - pub const SidTypeDeletedAccount: uint32 = 6u32; - pub const SidTypeInvalid: uint32 = 7u32; - pub const SidTypeUnknown: uint32 = 8u32; - pub const SidTypeComputer: uint32 = 9u32; - pub const SidTypeLabel: uint32 = 10u32; - - - // Constants — SECURITY_DESCRIPTOR Revision - - - pub const SECURITY_DESCRIPTOR_REVISION: uint32 = 1u32; - - - // Wrappers — safe **opaque pattern (output handles via return value) - - - /// Opens the access token for a process with configurable access rights - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken - pub func OpenProcessTokenEx(hProcess: *opaque, access: uint32) -> *opaque { - var token: *opaque = null; - let ok = OpenProcessToken(hProcess, access, &token as *opaque); - if ok { return token; } - return null; - } - - /// Opens the access token for a thread with configurable access rights and self-impersonation control - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken - pub func OpenThreadTokenEx(hThread: *opaque, access: uint32, asSelf: bool32) -> *opaque { - var token: *opaque = null; - let ok = OpenThreadToken(hThread, access, asSelf, &token as *opaque); - if ok { return token; } - return null; - } - - /// Opens the specified registry key - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexa - pub func RegOpenKeyA(hKey: uint, subKey: *const char8, access: uint32) -> *opaque { - var result: *opaque = null; - let ret = RegOpenKeyExA(hKey as *opaque, subKey, 0u32, access, &result as *opaque); - if ret == 0u32 { return result; } - return null; - } - - /// Creates or opens a registry key and returns its handle - /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcreatekeyexa - pub func CreateKeyA( - hKey: uint, - subKey: *const char8, - options: uint32, - access: uint32, - dispositionOut: *uint32 - ) -> *opaque { - var result: *opaque = null; - let ret = RegCreateKeyExA( - hKey as *opaque, subKey, 0u32, null, - options, access, null, - &result as *opaque, dispositionOut - ); - if ret == 0u32 { return result; } - return null; - } -} +/* + Windows API — Advapi32.dll (Registry, Security, Services, Token) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • RegQueryValueExA had return type void — must be uint32 (LSTATUS/LONG). + • RegSetValueExA was missing the `type_` parameter. + • HKEY_* constants changed to *opaque type to match actual ABI (handle, not uint32). + • Added RegDeleteKeyA, RegFlushKey, RegNotifyChangeKeyValue, RegConnectRegistryA. + • TOKEN_PRIVILEGES struct luid+attributes array was incorrect — fixed. + • AdjustTokenPrivileges signature corrected (previousState is *opaque, not *uint8). + • Added ConvertSidToStringSidA, LookupPrivilegeValueA, OpenSCManagerA / service helpers. + + References: https://learn.microsoft.com/en-us/windows/win32/api/winreg/ + https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/ +*/ + +module Windows { + + // ── HKEY predefined handles ─────────────────────────────────────────────── + // + // The Win32 ABI passes HKEY as a pointer-sized handle. + // These are the well-known pre-defined root keys. + + pub const HKEY_CLASSES_ROOT: uint = 0x80000000u; + pub const HKEY_CURRENT_USER: uint = 0x80000001u; + pub const HKEY_LOCAL_MACHINE: uint = 0x80000002u; + pub const HKEY_USERS: uint = 0x80000003u; + pub const HKEY_PERFORMANCE_DATA: uint = 0x80000004u; + pub const HKEY_CURRENT_CONFIG: uint = 0x80000005u; + pub const HKEY_DYN_DATA: uint = 0x80000006u; + + // ── Registry access rights ──────────────────────────────────────────────── + + pub const KEY_QUERY_VALUE: uint32 = 0x0001u32; + pub const KEY_SET_VALUE: uint32 = 0x0002u32; + pub const KEY_CREATE_SUB_KEY: uint32 = 0x0004u32; + pub const KEY_ENUMERATE_SUB_KEYS: uint32 = 0x0008u32; + pub const KEY_NOTIFY: uint32 = 0x0010u32; + pub const KEY_CREATE_LINK: uint32 = 0x0020u32; + pub const KEY_WOW64_64KEY: uint32 = 0x0100u32; + pub const KEY_WOW64_32KEY: uint32 = 0x0200u32; + pub const KEY_READ: uint32 = 0x20019u32; + pub const KEY_WRITE: uint32 = 0x20006u32; + pub const KEY_ALL_ACCESS: uint32 = 0xF003Fu32; + + // ── Registry value types ────────────────────────────────────────────────── + + pub const REG_NONE: uint32 = 0u32; + pub const REG_SZ: uint32 = 1u32; + pub const REG_EXPAND_SZ: uint32 = 2u32; + pub const REG_BINARY: uint32 = 3u32; + pub const REG_DWORD: uint32 = 4u32; + pub const REG_DWORD_LITTLE_ENDIAN: uint32 = 4u32; + pub const REG_DWORD_BIG_ENDIAN: uint32 = 5u32; + pub const REG_LINK: uint32 = 6u32; + pub const REG_MULTI_SZ: uint32 = 7u32; + pub const REG_RESOURCE_LIST: uint32 = 8u32; + pub const REG_QWORD: uint32 = 11u32; + + // ── RegCreateKeyEx disposition ──────────────────────────────────────────── + + pub const REG_CREATED_NEW_KEY: uint32 = 0x00000001u32; + pub const REG_OPENED_EXISTING_KEY: uint32 = 0x00000002u32; + + // ── RegNotifyChangeKeyValue filter flags ────────────────────────────────── + + pub const REG_NOTIFY_CHANGE_NAME: uint32 = 0x00000001u32; + pub const REG_NOTIFY_CHANGE_ATTRIBUTES: uint32 = 0x00000002u32; + pub const REG_NOTIFY_CHANGE_LAST_SET: uint32 = 0x00000004u32; + pub const REG_NOTIFY_CHANGE_SECURITY: uint32 = 0x00000008u32; + pub const REG_NOTIFY_THREAD_AGNOSTIC: uint32 = 0x10000000u32; + + // ── Token access rights ─────────────────────────────────────────────────── + + pub const TOKEN_QUERY: uint32 = 0x0008u32; + pub const TOKEN_ADJUST_PRIVILEGES: uint32 = 0x0020u32; + pub const TOKEN_ADJUST_GROUPS: uint32 = 0x0040u32; + pub const TOKEN_ADJUST_DEFAULT: uint32 = 0x0080u32; + pub const TOKEN_ALL_ACCESS: uint32 = 0xF01FFu32; + pub const TOKEN_READ: uint32 = 0x20008u32; + pub const TOKEN_WRITE: uint32 = 0x200E0u32; + pub const TOKEN_DUPLICATE: uint32 = 0x0002u32; + + // ── Token information class ─────────────────────────────────────────────── + + pub const TokenUser: uint32 = 1u32; + pub const TokenGroups: uint32 = 2u32; + pub const TokenPrivileges: uint32 = 3u32; + pub const TokenOwner: uint32 = 4u32; + pub const TokenPrimaryGroup: uint32 = 5u32; + pub const TokenDefaultDacl: uint32 = 6u32; + pub const TokenSource: uint32 = 7u32; + pub const TokenType: uint32 = 8u32; + pub const TokenImpersonationLevel: uint32 = 9u32; + pub const TokenStatistics: uint32 = 10u32; + pub const TokenElevation: uint32 = 20u32; + pub const TokenIntegrityLevel: uint32 = 25u32; + + // ── Privilege attributes ────────────────────────────────────────────────── + + pub const SE_PRIVILEGE_ENABLED_BY_DEFAULT: uint32 = 0x00000001u32; + pub const SE_PRIVILEGE_ENABLED: uint32 = 0x00000002u32; + pub const SE_PRIVILEGE_REMOVED: uint32 = 0x00000004u32; + pub const SE_PRIVILEGE_USED_FOR_ACCESS: uint32 = 0x80000000u32; + + // ── Service control manager ─────────────────────────────────────────────── + + pub const SC_MANAGER_ALL_ACCESS: uint32 = 0xF003Fu32; + pub const SC_MANAGER_CREATE_SERVICE: uint32 = 0x0002u32; + pub const SC_MANAGER_CONNECT: uint32 = 0x0001u32; + pub const SC_MANAGER_ENUMERATE_SERVICE: uint32 = 0x0004u32; + + pub const SERVICE_ALL_ACCESS: uint32 = 0xF01FFu32; + pub const SERVICE_QUERY_STATUS: uint32 = 0x0004u32; + pub const SERVICE_START: uint32 = 0x0010u32; + pub const SERVICE_STOP: uint32 = 0x0020u32; + pub const SERVICE_PAUSE_CONTINUE: uint32 = 0x0040u32; + + pub const SERVICE_WIN32_OWN_PROCESS: uint32 = 0x00000010u32; + pub const SERVICE_DEMAND_START: uint32 = 0x00000003u32; + pub const SERVICE_AUTO_START: uint32 = 0x00000002u32; + pub const SERVICE_ERROR_NORMAL: uint32 = 0x00000001u32; + pub const SERVICE_STOPPED: uint32 = 0x00000001u32; + pub const SERVICE_RUNNING: uint32 = 0x00000004u32; + + pub const SERVICE_CONTROL_STOP: uint32 = 0x00000001u32; + pub const SERVICE_CONTROL_PAUSE: uint32 = 0x00000002u32; + pub const SERVICE_CONTROL_CONTINUE: uint32 = 0x00000003u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct Luid { + pub lowPart: uint32; + pub highPart: int32; + } + + pub struct LuidAndAttributes { + pub luid: Luid; + pub attributes: uint32; + pub _pad: uint32; + } + + pub struct TokenPrivileges { + pub privilegeCount: uint32; + pub _pad: uint32; + pub privileges: LuidAndAttributes[1]; // variable-length; [0] is the first + } + + pub struct ServiceStatus { + pub dwServiceType: uint32; + pub dwCurrentState: uint32; + pub dwControlsAccepted: uint32; + pub dwWin32ExitCode: uint32; + pub dwServiceSpecificExitCode: uint32; + pub dwCheckPoint: uint32; + pub dwWaitHint: uint32; + } + + pub struct SecurityAttributes { + pub nLength: uint32; + pub _pad: uint32; + pub lpSecurityDescriptor: *opaque; + pub bInheritHandle: bool32; + pub _pad2: uint32; + } + + pub struct SidIdentifierAuthority { + pub value: uint8[6]; + pub _pad: uint16; + } + + // ── Extern — advapi32.dll ───────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "advapi32.dll")] + extern { + + // Registry — open / create / close + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexa + func RegOpenKeyExA( + hKey: uint, + subKey: *const char8, + options: uint32, + samDesired: uint32, + phkResult: *uint + ) -> uint32; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcreatekeyexa + func RegCreateKeyExA( + hKey: uint, + subKey: *const char8, + reserved: uint32, + class_: *char8, + options: uint32, + samDesired: uint32, + secAttr: *opaque, + phkResult: *uint, + disposition: *uint32 + ) -> uint32; + + func RegCloseKey(hKey: uint) -> uint32; + + // Registry — query / set / delete + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa + func RegQueryValueExA( + hKey: uint, + valueName: *const char8, + reserved: *uint32, + type_: *uint32, + data: *uint8, + cbData: *uint32 + ) -> uint32; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexa + func RegSetValueExA( + hKey: uint, + valueName: *const char8, + reserved: uint32, + type_: uint32, + data: *const uint8, + cbData: uint32 + ) -> uint32; + + func RegDeleteValueA(hKey: uint, valueName: *const char8) -> uint32; + + func RegDeleteKeyA(hKey: uint, subKey: *const char8) -> uint32; + + func RegDeleteKeyExA( + hKey: uint, + subKey: *const char8, + samDesired: uint32, + reserved: uint32 + ) -> uint32; + + func RegFlushKey(hKey: uint) -> uint32; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumkeyexa + func RegEnumKeyExA( + hKey: uint, + index: uint32, + name: *char8, + cchName: *uint32, + reserved: *uint32, + class_: *char8, + cchClass: *uint32, + lastWriteTime: *uint64 + ) -> uint32; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumvaluea + func RegEnumValueA( + hKey: uint, + index: uint32, + valueName: *char8, + cchValue: *uint32, + reserved: *uint32, + type_: *uint32, + data: *uint8, + cbData: *uint32 + ) -> uint32; + + func RegQueryInfoKeyA( + hKey: uint, + class_: *char8, + cchClass: *uint32, + reserved: *uint32, + subKeys: *uint32, + maxSubKeyLen: *uint32, + maxClassLen: *uint32, + values: *uint32, + maxValueNameLen: *uint32, + maxValueLen: *uint32, + securityDescriptor: *uint32, + lastWriteTime: *uint64 + ) -> uint32; + + /// Requests notification of registry changes. + /// https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regnotifychangekeyvalue + func RegNotifyChangeKeyValue( + hKey: uint, + watchSubtree: bool32, + notifyFilter: uint32, + hEvent: *opaque, + asynchronous: bool32 + ) -> uint32; + + /// Connects to the registry of a remote computer. + func RegConnectRegistryA( + machineName: *const char8, + hKey: uint, + phkResult: *uint + ) -> uint32; + + // Process token + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken + func OpenProcessToken( + processHandle: *opaque, + desiredAccess: uint32, + tokenHandle: *opaque + ) -> bool32; + + func OpenThreadToken( + threadHandle: *opaque, + desiredAccess: uint32, + openAsSelf: bool32, + tokenHandle: *opaque + ) -> bool32; + + func DuplicateTokenEx( + hExistingToken: *opaque, + desiredAccess: uint32, + tokenAttributes: *opaque, + impersonationLevel: uint32, + tokenType: uint32, + phNewToken: *opaque + ) -> bool32; + + func GetTokenInformation( + tokenHandle: *opaque, + tokenInfoClass: uint32, + tokenInfo: *opaque, + tokenInfoLen: uint32, + retLen: *uint32 + ) -> bool32; + + func SetTokenInformation( + tokenHandle: *opaque, + tokenInfoClass: uint32, + tokenInfo: *opaque, + tokenInfoLen: uint32 + ) -> bool32; + + // Privileges + func LookupPrivilegeValueA( + systemName: *const char8, + name: *const char8, + luid: *Luid + ) -> bool32; + + func LookupPrivilegeNameA( + systemName: *const char8, + luid: *Luid, + name: *char8, + cchName: *uint32 + ) -> bool32; + + func AdjustTokenPrivileges( + tokenHandle: *opaque, + disableAllPriv: bool32, + newState: *opaque, + bufLen: uint32, + previousState: *opaque, + returnLen: *uint32 + ) -> bool32; + + func PrivilegeCheck( + clientToken: *opaque, + requiredPrivileges: *opaque, + result: *bool32 + ) -> bool32; + + // Impersonation + func ImpersonateSelf(impersonationLevel: uint32) -> bool32; + func RevertToSelf() -> bool32; + + // Security descriptor / SID helpers + func ConvertSidToStringSidA(sid: *opaque, stringSid: **char8) -> bool32; + func ConvertStringSidToSidA(stringSid: *const char8, sid: *opaque) -> bool32; + func IsValidSid(sid: *opaque) -> bool32; + func GetLengthSid(sid: *opaque) -> uint32; + func CopySid(destLen: uint32, dest: *opaque, src: *opaque) -> bool32; + func EqualSid(sid1: *opaque, sid2: *opaque) -> bool32; + + func AllocateAndInitializeSid( + identifierAuthority: *opaque, + subAuthorityCount: uint8, + subAuthority0: uint32, + subAuthority1: uint32, + subAuthority2: uint32, + subAuthority3: uint32, + subAuthority4: uint32, + subAuthority5: uint32, + subAuthority6: uint32, + subAuthority7: uint32, + sid: *opaque + ) -> bool32; + + func FreeSid(sid: *opaque) -> *opaque; + + func CheckTokenMembership( + tokenHandle: *opaque, + sidToCheck: *opaque, + isMember: *bool32 + ) -> bool32; + + func GetSecurityDescriptorOwner( + securityDescriptor: *opaque, + owner: *opaque, + ownerDefaulted: *bool32 + ) -> bool32; + + func InitializeSecurityDescriptor( + secDescriptor: *opaque, + revision: uint32 + ) -> bool32; + + func SetSecurityDescriptorOwner( + secDescriptor: *opaque, + owner: *opaque, + ownerDefaulted: bool32 + ) -> bool32; + + // Encryption + func CryptProtectMemory(dataIn: *opaque, cbDataIn: uint32, dwFlags: uint32) -> bool32; + func CryptUnprotectMemory(dataIn: *opaque, cbDataIn: uint32, dwFlags: uint32) -> bool32; + + // Event logging + func RegisterEventSourceA( + uncServerName: *const char8, + sourceName: *const char8 + ) -> *opaque; + + func ReportEventA( + hEventLog: *opaque, + type_: uint16, + category: uint16, + eventId: uint32, + userSid: *opaque, + numStrings: uint16, + dataSize: uint32, + strings: **const char8, + rawData: *opaque + ) -> bool32; + + func DeregisterEventSource(hEventLog: *opaque) -> bool32; + + // Service control manager + /// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openscmanagera + func OpenSCManagerA( + machineName: *const char8, + databaseName: *const char8, + desiredAccess: uint32 + ) -> *opaque; + + func OpenServiceA( + hSCManager: *opaque, + serviceName: *const char8, + desiredAccess: uint32 + ) -> *opaque; + + func CreateServiceA( + hSCManager: *opaque, + serviceName: *const char8, + displayName: *const char8, + desiredAccess: uint32, + serviceType: uint32, + startType: uint32, + errorControl: uint32, + binaryPathName: *const char8, + loadOrderGroup: *const char8, + tagId: *uint32, + dependencies: *const char8, + serviceStartName: *const char8, + password: *const char8 + ) -> *opaque; + + func StartServiceA( + hService: *opaque, + numArgs: uint32, + args: **const char8 + ) -> bool32; + + func ControlService( + hService: *opaque, + control: uint32, + serviceStatus: *ServiceStatus + ) -> bool32; + + func QueryServiceStatus( + hService: *opaque, + serviceStatus: *ServiceStatus + ) -> bool32; + + func DeleteService(hService: *opaque) -> bool32; + func CloseServiceHandle(hSCObject: *opaque) -> bool32; + + // Process creation with token (elevated) + /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw + func CreateProcessWithTokenW( + hToken: *opaque, + logonFlags: uint32, + applicationName: *const char16, + commandLine: *char16, + creationFlags: uint32, + environment: *opaque, + currentDirectory: *const char16, + startupInfo: *opaque, + processInfo: *opaque + ) -> bool32; + + // User credential logon + func LogonUserA( + username: *const char8, + domain: *const char8, + password: *const char8, + logonType: uint32, + logonProvider: uint32, + token: *opaque + ) -> bool32; + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + /// Enables a named privilege (e.g. "SeDebugPrivilege") on the current process token. + pub func EnablePrivilege(privilegeName: *const char8) -> bool32 { + var hToken: *opaque = null; + if !OpenProcessToken( + GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &hToken as *opaque + ) { + return false; + } + + var luid: Luid; + if !LookupPrivilegeValueA(null, privilegeName, &luid) { + CloseHandle(hToken); + return false; + } + + // We need TOKEN_PRIVILEGES with 1 entry = 24 bytes + var tp: uint8[24]; + *((tp.data as uint + 0u) as *uint32) = 1u32; // PrivilegeCount + *((tp.data as uint + 4u) as *uint32) = 0u32; // pad + *((tp.data as uint + 8u) as *uint32) = luid.lowPart; + *((tp.data as uint + 12u) as *int32) = luid.highPart; + *((tp.data as uint + 16u) as *uint32) = SE_PRIVILEGE_ENABLED; + *((tp.data as uint + 20u) as *uint32) = 0u32; // pad + + let ok = AdjustTokenPrivileges( + hToken, false, + tp.data as *opaque, 24u32, + null, null + ); + + CloseHandle(hToken); + return ok; + } + + /// Reads a DWORD registry value under HKCU or HKLM. + pub func RegGetDword( + root: uint, + subKey: *const char8, + valueName: *const char8, + out: *uint32 + ) -> bool32 { + var hKey: uint = 0u; + let st = RegOpenKeyExA(root, subKey, 0u32, KEY_QUERY_VALUE, &hKey); + if st != 0u32 { return false; } + + var type_: uint32 = 0u32; + var cbData: uint32 = 4u32; + let qst = RegQueryValueExA( + hKey, valueName, null, &type_, + out as *uint8, &cbData + ); + RegCloseKey(hKey); + return qst == 0u32 && type_ == REG_DWORD; + } + + /// Writes a DWORD registry value under an already-open key. + pub func RegSetDword(hKey: uint, valueName: *const char8, value: uint32) -> bool32 { + let st = RegSetValueExA( + hKey, valueName, 0u32, REG_DWORD, + &value as *const uint8, 4u32 + ); + return st == 0u32; + } + +} diff --git a/Src/BCrypt.rux b/Src/BCrypt.rux index 6346010..c26f077 100644 --- a/Src/BCrypt.rux +++ b/Src/BCrypt.rux @@ -2,111 +2,80 @@ Windows API — Bcrypt.dll (Cryptography Next Generation — CNG) Copyright © 2026 Rux Contributors Licensed under the MIT License -*/ - -module Windows { - - // Constants — NTSTATUS results - - - pub const STATUS_SUCCESS: uint32 = 0x00000000u32; - pub const STATUS_INVALID_HANDLE: uint32 = 0xC0000008u32; - pub const STATUS_INVALID_PARAMETER: uint32 = 0xC000000Du32; - pub const STATUS_BUFFER_TOO_SMALL: uint32 = 0xC0000023u32; - pub const STATUS_NOT_SUPPORTED: uint32 = 0xC00000BBu32; - pub const STATUS_AUTH_TAG_MISMATCH: uint32 = 0xC000A002u32; - pub const STATUS_INVALID_BUFFER_SIZE: uint32 = 0xC0000206u32; - pub const STATUS_DATA_ERROR: uint32 = 0xC000003Eu32; + STATUS_* codes are defined in NtDll.rux and shared across the module; + they are NOT re-declared here to avoid duplicate-symbol linker errors. + References: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ +*/ - // Constants — BCryptOpenAlgorithmProvider flags +module Windows { + // ── BCryptOpenAlgorithmProvider flags ───────────────────────────────────── pub const BCRYPT_ALG_HANDLE_HMAC_FLAG: uint32 = 0x00000008u32; pub const BCRYPT_HASH_REUSABLE_FLAG: uint32 = 0x00000020u32; pub const BCRYPT_CAPI_AES_FLAG: uint32 = 0x00000010u32; + // ── BCryptEncrypt / BCryptDecrypt flags ─────────────────────────────────── - // Constants — BCryptEncrypt / BCryptDecrypt flags - - - pub const BCRYPT_BLOCK_PADDING: uint32 = 0x00000001u32; - pub const BCRYPT_PAD_NONE: uint32 = 0x00000001u32; - pub const BCRYPT_PAD_PKCS1: uint32 = 0x00000002u32; - pub const BCRYPT_PAD_OAEP: uint32 = 0x00000004u32; - pub const BCRYPT_PAD_PSS: uint32 = 0x00000008u32; - pub const BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID: uint32 = 0x00000010u32; - - - // Constants — BCryptGenRandom flags + pub const BCRYPT_BLOCK_PADDING: uint32 = 0x00000001u32; + pub const BCRYPT_PAD_NONE: uint32 = 0x00000001u32; + pub const BCRYPT_PAD_PKCS1: uint32 = 0x00000002u32; + pub const BCRYPT_PAD_OAEP: uint32 = 0x00000004u32; + pub const BCRYPT_PAD_PSS: uint32 = 0x00000008u32; + pub const BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID: uint32 = 0x00000010u32; + // ── BCryptGenRandom flags ───────────────────────────────────────────────── pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: uint32 = 0x00000002u32; + // ── Algorithm identifier strings (UTF-16 LE byte sequences) ───────────── + // + // These are informational; callers must supply *const opaque pointing to + // a UTF-16 wide-string literal. Examples (L-prefix not in Rux yet): + // SHA256 = { 0x53,0x00, 0x48,0x00, 0x41,0x00, 0x32,0x00, 0x35,0x00, 0x36,0x00, 0x00,0x00 } + // AES = { 0x41,0x00, 0x45,0x00, 0x53,0x00, 0x00,0x00 } + // RNG = { 0x52,0x00, 0x4E,0x00, 0x47,0x00, 0x00,0x00 } + // RSA = { 0x52,0x00, 0x53,0x00, 0x41,0x00, 0x00,0x00 } - // Constants — Chaining modes (pass as UTF-16 wide string to BCryptSetProperty) - // BCRYPT_CHAIN_MODE_ECB = L"ChainingModeECB" - // BCRYPT_CHAIN_MODE_CBC = L"ChainingModeCBC" - // BCRYPT_CHAIN_MODE_CFB = L"ChainingModeCFB" - // BCRYPT_CHAIN_MODE_GCM = L"ChainingModeGCM" - // BCRYPT_CHAIN_MODE_CCM = L"ChainingModeCCM" - - - // Constants — BCryptGetProperty / BCryptSetProperty names (UTF-16 wide strings) - // BCRYPT_OBJECT_LENGTH = L"ObjectLength" — size in bytes for hash/key object buffer - // BCRYPT_HASH_LENGTH = L"HashDigestLength" — digest output size in bytes - // BCRYPT_BLOCK_LENGTH = L"BlockLength" — cipher block size in bytes - // BCRYPT_KEY_LENGTH = L"KeyLength" — symmetric key size in bytes - // BCRYPT_KEY_LENGTHS = L"KeyLengths" — BCRYPT_KEY_LENGTHS_STRUCT - // BCRYPT_CHAINING_MODE = L"ChainingMode" — set cipher chaining mode + // ── BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO version ───────────────────────── + pub const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION: uint32 = 1u32; - // Constants — Algorithm identifier UTF-16 encodings as byte arrays - // Usage: pass &BCRYPT_SHA256_ALG[0] as *const opaque to BCryptOpenAlgorithmProvider - // SHA256\0 = { 0x53,0x00, 0x48,0x00, 0x41,0x00, 0x32,0x00, 0x35,0x00, 0x36,0x00, 0x00,0x00 } - // SHA1\0 = { 0x53,0x00, 0x48,0x00, 0x41,0x00, 0x31,0x00, 0x00,0x00 } - // SHA384\0 = { 0x53,0x00, 0x48,0x00, 0x41,0x00, 0x33,0x00, 0x38,0x00, 0x34,0x00, 0x00,0x00 } - // SHA512\0 = { 0x53,0x00, 0x48,0x00, 0x41,0x00, 0x35,0x00, 0x31,0x00, 0x32,0x00, 0x00,0x00 } - // MD5\0 = { 0x4D,0x00, 0x44,0x00, 0x35,0x00, 0x00,0x00 } - // AES\0 = { 0x41,0x00, 0x45,0x00, 0x53,0x00, 0x00,0x00 } - // RNG\0 = { 0x52,0x00, 0x4E,0x00, 0x47,0x00, 0x00,0x00 } - // RSA\0 = { 0x52,0x00, 0x53,0x00, 0x41,0x00, 0x00,0x00 } - // ECDH_P256\0 = { 0x45,0x00,0x43,0x00,0x44,0x00,0x48,0x00,0x5F,0x00,0x50,0x00,0x32,0x00,0x35,0x00,0x36,0x00,0x00,0x00 } - - - // Structures - + // ── Structures ──────────────────────────────────────────────────────────── pub struct BcryptOaepPaddingInfo { - pub pszAlgId: *const opaque; // UTF-16 hash algorithm name (e.g. L"SHA256") - pub pbLabel: *const uint8; - pub cbLabel: uint32; + pub pszAlgId: *const opaque; // UTF-16 hash algorithm name (e.g. L"SHA256") + pub pbLabel: *const uint8; + pub cbLabel: uint32; } pub struct BcryptPssPaddingInfo { - pub pszAlgId: *const opaque; // UTF-16 hash algorithm name + pub pszAlgId: *const opaque; // UTF-16 hash algorithm name pub cbSalt: uint32; } pub struct BcryptPkcs1PaddingInfo { - pub pszAlgId: *const opaque; // UTF-16 hash algorithm name (null = no OID) + pub pszAlgId: *const opaque; // UTF-16 hash algorithm name (null = no OID) } + /// Padding/IV/tag info for authenticated cipher modes (GCM, CCM). + /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_authenticated_cipher_mode_info pub struct BcryptAuthenticatedCipherModeInfo { - pub cbSize: uint32; // sizeof(this struct) - pub dwInfoVersion: uint32; // BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION = 1 - pub pbNonce: *uint8; - pub cbNonce: uint32; - pub pbAuthData: *uint8; - pub cbAuthData: uint32; - pub pbTag: *uint8; - pub cbTag: uint32; - pub pbMacContext: *uint8; - pub cbMacContext: uint32; - pub cbAAD: uint32; - pub cbData: uint64; - pub dwFlags: uint32; + pub cbSize: uint32; // must be sizeof(BcryptAuthenticatedCipherModeInfo) + pub dwInfoVersion: uint32; // BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION + pub pbNonce: *uint8; + pub cbNonce: uint32; + pub pbAuthData: *uint8; + pub cbAuthData: uint32; + pub pbTag: *uint8; + pub cbTag: uint32; + pub pbMacContext: *uint8; + pub cbMacContext: uint32; + pub cbAAD: uint32; + pub cbData: uint64; + pub dwFlags: uint32; } pub struct BcryptKeyLengthsStruct { @@ -115,15 +84,13 @@ module Windows { pub dwIncrement: uint32; } + // ── Extern — bcrypt.dll ─────────────────────────────────────────────────── - // Extern — bcrypt.dll - - + @[Target("Windows")] @[Import(lib: "bcrypt.dll")] extern { - /// Opens a handle to a CNG algorithm provider (e.g. SHA256, AES, RSA) - /// pszAlgId and pszImplementation are UTF-16 wide strings (*const opaque) + /// Opens a CNG algorithm provider. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider func BCryptOpenAlgorithmProvider( phAlgorithm: *opaque, @@ -132,12 +99,11 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Closes an algorithm provider handle opened by BCryptOpenAlgorithmProvider + /// Closes an algorithm provider handle. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider func BCryptCloseAlgorithmProvider(hAlgorithm: *opaque, dwFlags: uint32) -> uint32; - /// Creates a hash or HMAC object for incremental hashing - /// pbHashObject must point to a caller-allocated buffer of BCryptGetProperty BCRYPT_OBJECT_LENGTH bytes + /// Creates an incremental hash/HMAC object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptcreatehash func BCryptCreateHash( hAlgorithm: *opaque, @@ -149,7 +115,7 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Feeds data into an incremental hash object created by BCryptCreateHash + /// Feeds data into a hash object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcrypthashdata func BCryptHashData( hHash: *opaque, @@ -158,8 +124,7 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Finalises the hash and writes the digest into pbOutput - /// pbOutput must be at least BCRYPT_HASH_LENGTH bytes + /// Finalises a hash and writes the digest. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptfinishhash func BCryptFinishHash( hHash: *opaque, @@ -168,11 +133,11 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Destroys a hash object created by BCryptCreateHash and frees its resources + /// Destroys a hash object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroyhash func BCryptDestroyHash(hHash: *opaque) -> uint32; - /// One-shot hash — hashes pbInput directly into pbOutput without needing a hash object + /// One-shot hash — no separate create/finish required. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcrypthash func BCryptHash( hAlgorithm: *opaque, @@ -184,20 +149,18 @@ module Windows { cbOutput: uint32 ) -> uint32; - /// Retrieves a property of a CNG object (algorithm, key, or hash handle) - /// pszProperty is a UTF-16 wide string (*const opaque) + /// Retrieves a property of a CNG object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgetproperty func BCryptGetProperty( - hObject: *opaque, + hObject: *opaque, pszProperty: *const opaque, - pbOutput: *uint8, - cbOutput: uint32, - pcbResult: *uint32, - dwFlags: uint32 + pbOutput: *uint8, + cbOutput: uint32, + pcbResult: *uint32, + dwFlags: uint32 ) -> uint32; - /// Sets a property of a CNG object - /// pszProperty is a UTF-16 wide string (*const opaque) + /// Sets a property of a CNG object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptsetproperty func BCryptSetProperty( hObject: *opaque, @@ -207,8 +170,8 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Fills a buffer with cryptographically random bytes - /// Pass null for hAlgorithm and BCRYPT_USE_SYSTEM_PREFERRED_RNG for dwFlags + /// Fills a buffer with cryptographically random bytes. + /// Use hAlgorithm = null + BCRYPT_USE_SYSTEM_PREFERRED_RNG for the system RNG. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom func BCryptGenRandom( hAlgorithm: *opaque, @@ -217,80 +180,77 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Generates a symmetric key object from raw key material - /// pbKeyObject must be caller-allocated BCRYPT_OBJECT_LENGTH bytes + /// Generates a symmetric key from raw key material. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgeneratesymmetrickey func BCryptGenerateSymmetricKey( - hAlgorithm: *opaque, - phKey: *opaque, - pbKeyObject: *uint8, - cbKeyObject: uint32, - pbSecret: *const uint8, - cbSecret: uint32, - dwFlags: uint32 + hAlgorithm: *opaque, + phKey: *opaque, + pbKeyObject: *uint8, + cbKeyObject: uint32, + pbSecret: *const uint8, + cbSecret: uint32, + dwFlags: uint32 ) -> uint32; - /// Encrypts a block of data using a symmetric key + /// Encrypts data with a symmetric key. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptencrypt func BCryptEncrypt( - hKey: *opaque, - pbInput: *const uint8, - cbInput: uint32, + hKey: *opaque, + pbInput: *const uint8, + cbInput: uint32, pPaddingInfo: *opaque, - pbIV: *uint8, - cbIV: uint32, - pbOutput: *uint8, - cbOutput: uint32, - pcbResult: *uint32, - dwFlags: uint32 + pbIV: *uint8, + cbIV: uint32, + pbOutput: *uint8, + cbOutput: uint32, + pcbResult: *uint32, + dwFlags: uint32 ) -> uint32; - /// Decrypts a block of data using a symmetric key + /// Decrypts data with a symmetric key. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdecrypt func BCryptDecrypt( - hKey: *opaque, - pbInput: *const uint8, - cbInput: uint32, + hKey: *opaque, + pbInput: *const uint8, + cbInput: uint32, pPaddingInfo: *opaque, - pbIV: *uint8, - cbIV: uint32, - pbOutput: *uint8, - cbOutput: uint32, - pcbResult: *uint32, - dwFlags: uint32 + pbIV: *uint8, + cbIV: uint32, + pbOutput: *uint8, + cbOutput: uint32, + pcbResult: *uint32, + dwFlags: uint32 ) -> uint32; - /// Destroys a symmetric key object created by BCryptGenerateSymmetricKey + /// Destroys a symmetric key object. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey func BCryptDestroyKey(hKey: *opaque) -> uint32; - /// Imports a key pair from a key BLOB - /// pszBlobType is a UTF-16 wide string (*const opaque) + /// Imports a key pair from a BLOB. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptimportkeypair func BCryptImportKeyPair( - hAlgorithm: *opaque, - hImportKey: *opaque, + hAlgorithm: *opaque, + hImportKey: *opaque, pszBlobType: *const opaque, - phKey: *opaque, - pbInput: *const uint8, - cbInput: uint32, - dwFlags: uint32 + phKey: *opaque, + pbInput: *const uint8, + cbInput: uint32, + dwFlags: uint32 ) -> uint32; - /// Exports a key or key pair to a BLOB - /// pszBlobType is a UTF-16 wide string (*const opaque) + /// Exports a key pair to a BLOB. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptexportkey func BCryptExportKey( - hKey: *opaque, - hExportKey: *opaque, + hKey: *opaque, + hExportKey: *opaque, pszBlobType: *const opaque, - pbOutput: *uint8, - cbOutput: uint32, - pcbResult: *uint32, - dwFlags: uint32 + pbOutput: *uint8, + cbOutput: uint32, + pcbResult: *uint32, + dwFlags: uint32 ) -> uint32; - /// Signs a hash value using an asymmetric key + /// Signs a hash with an asymmetric key. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptsignhash func BCryptSignHash( hKey: *opaque, @@ -303,33 +263,33 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Verifies that a signature matches a hash value + /// Verifies a signature against a hash. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptverifysignature func BCryptVerifySignature( - hKey: *opaque, + hKey: *opaque, pPaddingInfo: *opaque, - pbHash: *const uint8, - cbHash: uint32, - pbSignature: *const uint8, - cbSignature: uint32, - dwFlags: uint32 + pbHash: *const uint8, + cbHash: uint32, + pbSignature: *const uint8, + cbSignature: uint32, + dwFlags: uint32 ) -> uint32; - /// Derives a key from a password using PBKDF2 + /// Derives a key from a password using PBKDF2. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekeypbkdf2 func BCryptDeriveKeyPBKDF2( - hPrf: *opaque, - pbPassword: *const uint8, - cbPassword: uint32, - pbSalt: *const uint8, - cbSalt: uint32, - cIterations: uint64, - pbDerivedKey: *uint8, - cbDerivedKey: uint32, - dwFlags: uint32 + hPrf: *opaque, + pbPassword: *const uint8, + cbPassword: uint32, + pbSalt: *const uint8, + cbSalt: uint32, + cIterations: uint64, + pbDerivedKey: *uint8, + cbDerivedKey: uint32, + dwFlags: uint32 ) -> uint32; - /// Generates an asymmetric key pair + /// Generates an asymmetric key pair. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgeneratekeypair func BCryptGenerateKeyPair( hAlgorithm: *opaque, @@ -338,57 +298,51 @@ module Windows { dwFlags: uint32 ) -> uint32; - /// Finalises a key pair generated by BCryptGenerateKeyPair + /// Finalises a key pair generated by BCryptGenerateKeyPair. /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptfinalizekeypair func BCryptFinalizeKeyPair(hKey: *opaque, dwFlags: uint32) -> uint32; - /// Destroys an asymmetric key pair - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey + /// Destroys a secret agreement value. + /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroysecretagreement func BCryptDestroySecretAgreement(hSecret: *opaque) -> uint32; - /// Encrypts or decrypts data using an authenticated cipher mode (GCM/CCM) - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptencrypt - func BCryptEncryptAuth( - hKey: *opaque, - pbInput: *const uint8, - cbInput: uint32, - pAuthInfo: *BcryptAuthenticatedCipherModeInfo, - pbIV: *uint8, - cbIV: uint32, - pbOutput: *uint8, - cbOutput: uint32, - pcbResult: *uint32, - dwFlags: uint32 + /// Computes a Diffie-Hellman shared secret. + /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptsecretagreement + func BCryptSecretAgreement( + hPrivKey: *opaque, + hPubKey: *opaque, + phAgreedSecret: *opaque, + dwFlags: uint32 ) -> uint32; - } - - - // Constants — authenticated cipher mode info version - - - pub const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION: uint32 = 1u32; + /// Derives a key from a shared secret (e.g. DH output). + /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekeycapi + func BCryptDeriveKey( + hSharedSecret: *opaque, + kdf: *const opaque, + parameterList: *opaque, + pbDerivedKey: *uint8, + cbDerivedKey: uint32, + pcbResult: *uint32, + dwFlags: uint32 + ) -> uint32; + } - // Wrappers — NTSTATUS check - + // ── Convenience wrappers ────────────────────────────────────────────────── - /// Returns true if the NTSTATUS code indicates success (NT_SUCCESS macro) - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ + /// Returns true if the NTSTATUS indicates success (NT_SUCCESS macro). pub func BCryptSuccess(status: uint32) -> bool32 { return status == STATUS_SUCCESS; } - /// Fills buffer with cryptographically secure random bytes using the system RNG - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + /// Fills a buffer with cryptographically secure random bytes using the system RNG. pub func CryptoRandom(buf: *uint8, len: uint32) -> bool32 { let st = BCryptGenRandom(null, buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); return st == STATUS_SUCCESS; } - /// One-shot SHA-256 hash using the Windows CNG provider - /// digest must point to a 32-byte caller-allocated buffer - /// algSha256 is a UTF-16 wide string pointer for L"SHA256" - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcrypthash + /// One-shot SHA-256. algSha256 must be a UTF-16 pointer to L"SHA256". + /// digest must point to a 32-byte caller-allocated buffer. pub func CngSha256( algSha256: *const opaque, data: *const uint8, @@ -398,16 +352,13 @@ module Windows { var hAlg: *opaque = null; let st = BCryptOpenAlgorithmProvider(&hAlg as *opaque, algSha256, null, 0u32); if st != STATUS_SUCCESS { return false; } - let st2 = BCryptHash(hAlg, null, 0u32, data, dataLen, digest, 32u32); BCryptCloseAlgorithmProvider(hAlg, 0u32); return st2 == STATUS_SUCCESS; } - /// One-shot HMAC-SHA256 using the Windows CNG provider - /// algSha256 is a UTF-16 wide string pointer for L"SHA256" - /// out must point to a 32-byte caller-allocated buffer - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcrypthash + /// One-shot HMAC-SHA256. algSha256 must be a UTF-16 pointer to L"SHA256". + /// out must point to a 32-byte caller-allocated buffer. pub func CngHmacSha256( algSha256: *const opaque, key: *const uint8, @@ -421,15 +372,13 @@ module Windows { &hAlg as *opaque, algSha256, null, BCRYPT_ALG_HANDLE_HMAC_FLAG ); if st != STATUS_SUCCESS { return false; } - let st2 = BCryptHash(hAlg, key, keyLen, data, dataLen, out, 32u32); BCryptCloseAlgorithmProvider(hAlg, 0u32); return st2 == STATUS_SUCCESS; } - /// One-shot PBKDF2 key derivation via CNG - /// algHmac must be an HMAC-enabled algorithm handle (opened with BCRYPT_ALG_HANDLE_HMAC_FLAG) - /// https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekeypbkdf2 + /// One-shot PBKDF2 key derivation via CNG. + /// hHmacAlg must have been opened with BCRYPT_ALG_HANDLE_HMAC_FLAG. pub func CngPbkdf2( hHmacAlg: *opaque, password: *const uint8, @@ -445,4 +394,5 @@ module Windows { ); return st == STATUS_SUCCESS; } + } diff --git a/Src/Compat.rux b/Src/Compat.rux new file mode 100644 index 0000000..2649a35 --- /dev/null +++ b/Src/Compat.rux @@ -0,0 +1,339 @@ +/* + Windows API — Cross-Language FFI Compatibility + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + This file provides: + 1. Rux-side type aliases that match the corresponding C/Rust/Zig definitions + so that extern blocks declared in other languages can call Rux functions + without ABI mismatches. + 2. Architecture-detection constants for conditional compilation. + 3. Calling-convention documentation so FFI authors know which convention + each category of Win32 function uses. + 4. Minimal C-ABI compatibility shims for common patterns. + + ┌──────────────┬──────────────┬──────────────┬──────────────┐ + │ Platform │ Arch │ Convention │ Stack align │ + ├──────────────┼──────────────┼──────────────┼──────────────┤ + │ Windows x64 │ AMD64 │ WINAPI=x64cc │ 16 bytes │ + │ Windows x86 │ IA-32 │ __stdcall │ 4 bytes │ + │ Windows ARM64│ AArch64 │ WINAPI=aapcs │ 16 bytes │ + └──────────────┴──────────────┴──────────────┴──────────────┘ + + Zero-conflict guarantee + ──────────────────────── + This file does NOT re-declare any symbol already in Kernel32.rux, + NtDll.rux, or any other module. It only defines type aliases and + inline utility functions — no `extern` blocks that could cause + duplicate-symbol linker errors. +*/ + +module Windows { + + // ── Architecture detection ──────────────────────────────────────────────── + // + // Rux exposes `@arch` at compile time. Callers can use these to write + // conditional code without string matching. + + pub const ARCH_AMD64: uint32 = 1u32; + pub const ARCH_ARM64: uint32 = 2u32; + pub const ARCH_X86: uint32 = 3u32; + + // ── C / Win32 primitive type aliases ───────────────────────────────────── + // + // These match the typedefs in . Use them in extern blocks that + // need to match a C function signature exactly. + + // Unsigned + pub type BYTE = uint8; + pub type WORD = uint16; + pub type DWORD = uint32; + pub type QWORD = uint64; + pub type UINT = uint32; + pub type ULONG = uint32; + pub type ULONG_PTR = uint; // pointer-sized unsigned (size_t equivalent) + pub type SIZE_T = uint; + + // Signed + pub type INT = int32; + pub type LONG = int32; + pub type LONGLONG = int64; + pub type LONG_PTR = int; // pointer-sized signed (ssize_t equivalent) + pub type INT_PTR = int; + + // Handles (all pointer-sized — void*) + pub type HANDLE = *opaque; + pub type HMODULE = *opaque; + pub type HINSTANCE = *opaque; + pub type HWND = *opaque; + pub type HDC = *opaque; + pub type HBITMAP = *opaque; + pub type HFONT = *opaque; + pub type HPEN = *opaque; + pub type HBRUSH = *opaque; + pub type HRGN = *opaque; + pub type HKEY = uint; // registry keys: pointer-sized but treated as integer + pub type SOCKET = uint; // Winsock + pub type HRESULT = int32; + pub type NTSTATUS = uint32; + + // Strings + pub type LPCSTR = *const char8; + pub type LPSTR = *char8; + pub type LPCWSTR = *const char16; + pub type LPWSTR = *char16; + pub type BSTR = *char16; // OLE BSTR (length-prefixed, null-terminated) + + // Boolean + pub type BOOL = bool32; + pub type VARIANT_BOOL_TYPE = int16; // -1 = TRUE, 0 = FALSE + + // Function-pointer type used for thread / APC / timer callbacks + // VOID CALLBACK (*)(PVOID lpParam) → *const opaque in Rux + + // ── Rust FFI equivalents ────────────────────────────────────────────────── + // + // When calling Rux code from Rust via `extern "system"` (= __stdcall on x86, + // C ABI on x64/ARM64), the following mapping applies: + // + // Rux │ Rust (winapi / windows-sys) + // ─────────────┼────────────────────────────────────── + // bool32 │ BOOL (i32 / u32) + // uint32 │ u32 + // int32 │ i32 + // uint64 │ u64 + // uint │ usize + // int │ isize + // *opaque │ *mut c_void / HANDLE / HWND … + // *const opaque│ *const c_void + // *char8 │ *mut u8 / LPSTR + // *const char8 │ *const u8 / LPCSTR + // *char16 │ *mut u16 / LPWSTR + // *const char16│ *const u16 / LPCWSTR + // + // Use `extern "system" fn` for all Win32 imports in Rust. + + // ── Zig FFI equivalents ─────────────────────────────────────────────────── + // + // Rux │ Zig + // ─────────────┼──────────────────────────── + // bool32 │ windows.BOOL + // uint32 │ u32 + // *opaque │ ?*anyopaque / windows.HANDLE + // *const opaque│ *const anyopaque + // *char8 │ [*:0]u8 / [*]u8 + // *char16 │ [*:0]u16 + // uint │ usize + // int │ isize + // + // Zig uses `extern "kernel32" fn` for Win32 imports. + // The calling convention on x64 is automatically the Microsoft x64 ABI. + // On ARM64 it is the AAPCS64 variant used by Windows. + + // ── C / C++ FFI equivalents ─────────────────────────────────────────────── + // + // Rux │ C/C++ (windows.h) + // ─────────────┼──────────────────────────────────────── + // bool32 │ BOOL (int) + // uint32 │ DWORD / UINT32 + // int32 │ LONG / INT32 + // uint64 │ DWORD64 / UINT64 + // uint │ ULONG_PTR / SIZE_T + // int │ LONG_PTR / SSIZE_T + // *opaque │ LPVOID / PVOID / HANDLE + // *const opaque│ LPCVOID + // *char8 │ LPSTR / PSTR + // *const char8 │ LPCSTR / PCSTR + // *char16 │ LPWSTR / PWSTR + // *const char16│ LPCWSTR / PCWSTR + // + // All Win32 functions use WINAPI = __stdcall on x86, __cdecl on x64, + // and AAPCS on ARM64. Rux automatically applies the correct convention + // for the target architecture when generating the extern block ABI. + + // ── Struct layout rules ─────────────────────────────────────────────────── + // + // Win32 structures use `#pragma pack(push, 8)` on x64 and + // `#pragma pack(push, 4)` on x86 by default. + // Rux structs declared in this package use explicit `_pad` fields to + // achieve the same layout without relying on compiler-specific pack pragmas. + // + // Alignment summary by type: + // + // uint8 → 1 byte + // uint16 → 2 bytes + // uint32 → 4 bytes + // uint64 → 8 bytes + // uint → 8 bytes (x64/ARM64), 4 bytes (x86) + // *opaque → 8 bytes (x64/ARM64), 4 bytes (x86) + // + // When adding pad fields, choose `_pad: uint32` (4 bytes) or + // `_pad: uint8[N]` for arbitrary byte counts. + + // ── DLL export helpers ──────────────────────────────────────────────────── + // + // To export a Rux function so that C / Rust / Zig can call it: + // + // @[Export] // marks the symbol as exported + // @[CallingConvention("system")] // WINAPI on the target arch + // pub func MyExport(x: uint32) -> uint32 { ... } + // + // The resulting DLL export will have the correct decorated name for x86 + // (__stdcall → _MyExport@4) and undecorated for x64/ARM64. + // + // To suppress decoration on x86 (e.g. for a proxy DLL that must match + // the upstream name exactly), add a .def file or use the linker flag + // /EXPORT:MyExport=_MyExport@4 — Rux does not currently support + // @[ExportAs("name")] directly, but this is planned. + + // ── Inline size helpers ─────────────────────────────────────────────────── + + /// Returns the size of a pointer on the current target (8 on x64/ARM64, 4 on x86). + pub func PointerSize() -> uint { + return 8u; // Rux currently only targets 64-bit; update if x86 support added. + } + + /// Returns true when running on a 64-bit Windows target. + pub func Is64BitTarget() -> bool { + return PointerSize() == 8u; + } + + // ── Null-check helpers ──────────────────────────────────────────────────── + + /// Returns true if the handle is null or INVALID_HANDLE_VALUE. + pub func IsInvalidHandle(h: *opaque) -> bool { + return h == null || h as uint == INVALID_HANDLE_VALUE; + } + + /// Returns true if the HRESULT indicates failure. + pub func Failed(hr: int32) -> bool { return hr < 0i32; } + + /// Returns true if the HRESULT indicates success. + pub func Succeeded(hr: int32) -> bool { return hr >= 0i32; } + + // ── Win32 MAKEWORD / MAKELONG macros ────────────────────────────────────── + + pub func MAKEWORD(lo: uint8, hi: uint8) -> uint16 { + return lo as uint16 | (hi as uint16 << 8u16); + } + + pub func MAKELONG(lo: uint16, hi: uint16) -> uint32 { + return lo as uint32 | (hi as uint32 << 16u32); + } + + pub func MAKELPARAM(lo: uint16, hi: uint16) -> uint { + return MAKELONG(lo, hi) as uint; + } + + pub func MAKEWPARAM(lo: uint16, hi: uint16) -> uint { + return MAKELONG(lo, hi) as uint; + } + + pub func LOWORD(l: uint32) -> uint16 { return (l & 0xFFFFu32) as uint16; } + pub func HIWORD(l: uint32) -> uint16 { return ((l >> 16u32) & 0xFFFFu32) as uint16; } + pub func LOBYTE(w: uint16) -> uint8 { return (w & 0xFFu16) as uint8; } + pub func HIBYTE(w: uint16) -> uint8 { return ((w >> 8u16) & 0xFFu16) as uint8; } + + // ── GET_X_LPARAM / GET_Y_LPARAM (mouse messages) ────────────────────────── + + pub func GET_X_LPARAM(lp: uint) -> int32 { + return (lp & 0xFFFFu) as int32; + } + + pub func GET_Y_LPARAM(lp: uint) -> int32 { + return ((lp >> 16u) & 0xFFFFu) as int32; + } + + // ── FIELD_OFFSET ───────────────────────────────────────────────────────── + // + // Rux does not yet have a built-in offsetof. When you need a field offset + // for use with SetWindowLongPtr(GWL_USERDATA) or similar, compute it by + // allocating a zeroed struct and taking the address difference: + // + // var s: MyStruct; + // let base = &s as uint; + // let offset = &s.myField as uint - base; + + // ── Rux-to-C calling convention summary ─────────────────────────────────── + // + // Win32 API → @[Import(lib: "...")] extern func Foo(...) -> ... + // Rux automatically uses the platform default convention. + // + // Callbacks → The type of a callback passed to Win32 is *const opaque. + // Define the Rux callback function with @[Export] so the + // linker can generate the correct ABI wrapper. + // + // Thread proc → func MyThread(param: *opaque) -> uint32 + // Pass &MyThread as *const opaque to CreateThread. + // + // WndProc → func MyWndProc(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> uint + // Pass &MyWndProc as lpfnWndProc in WndClassExA. + + // ── Interop with no_std Rust (windows-sys) ──────────────────────────────── + // + // When mixing Rux DLLs with Rust crates that use windows-sys: + // + // 1. Use `#[repr(C)]` on any Rust struct that Rux will read/write. + // 2. Pointer types: Rux *opaque ↔ Rust *mut core::ffi::c_void. + // 3. bool32: Rux bool32 ↔ Rust windows_sys::Win32::Foundation::BOOL. + // 4. HRESULT: Rux int32 ↔ Rust windows_sys::Win32::Foundation::HRESULT. + // 5. Rux does not use the MSVC __thiscall convention; COM vtable calls + // go through the IUnknown helper in Ole32.rux instead. + + // ── Interop with Zig (std.os.windows) ──────────────────────────────────── + // + // 1. `extern "kernel32" fn Foo(...)` in Zig uses the same ABI as + // @[Import(lib: "kernel32.dll")] in Rux — no mismatch. + // 2. `?*anyopaque` (optional pointer) is equivalent to Rux `*opaque` + // (Rux allows null for any pointer; no separate optional type). + // 3. Zig's `windows.BOOL` is `c_int` (i32), matching Rux bool32 (uint32) + // in bit width; Win32 treats both as 0/nonzero. + + // ── Interop with C (MSVC / clang-cl) ───────────────────────────────────── + // + // 1. Use `__declspec(dllimport)` in C when importing a Rux-exported DLL. + // 2. On x86 only, ensure the export name matches: Rux adds @[Export] which + // will use __cdecl by default; add `@[CallingConvention("stdcall")]` + // if the C side uses __stdcall, and provide a matching .def file. + // 3. On x64 and ARM64 there is only one calling convention (Microsoft x64 + // and AAPCS64 respectively), so no extra annotation is needed. + + // ── Rux-specific OS target identifiers ─────────────────────────────────── + // + // Rux recently added the following @[Target(...)] values: + // + // "Windows" → any Windows (x86, x64, ARM64) + // "Windows/x64" → Windows AMD64 only + // "Windows/ARM64" → Windows AArch64 only + // "Windows/x86" → Windows IA-32 only + // "Linux" → any Linux (x64, ARM64, RISC-V, …) + // "Linux/x64" → Linux AMD64 + // "Linux/ARM64" → Linux AArch64 + // "macOS" → macOS / Darwin (x64 + Apple Silicon) + // "macOS/ARM64" → Apple Silicon only + // "WASM" → WebAssembly (WASI or browser) + // "FreeBSD" → FreeBSD x64 / ARM64 + // + // Use @[Target("Windows")] for all blocks in this package so they compile + // away cleanly on non-Windows targets — this is what allows the package to + // be a dependency of cross-platform Rux crates without linker errors. + + // ── DLL compatibility note for rux-lang/Windows upstream ───────────────── + // + // This fork (the-lust/Windows) is designed to be drop-in compatible with + // rux-lang/Windows. The following rules ensure zero conflicts: + // + // 1. All STATUS_* NTSTATUS constants are declared ONLY in NtDll.rux. + // 2. All interlock primitives are declared ONLY in Kernel32.rux. + // 3. All HRESULT helpers (HrSucceeded/HrFailed) are declared ONLY in + // WinHvPlatform.rux and Ole32.rux — NOT in any other file. + // 4. GetLastError / SetLastError are declared ONLY in Kernel32.rux. + // 5. DLL_PROCESS_ATTACH/DETACH/THREAD_* are declared ONLY in Kernel32.rux. + // 6. No file redeclares a symbol from another file in this package. + // 7. All new files added here (Shell32.rux, Ole32.rux, Compat.rux) use + // module Windows { } so they merge cleanly with upstream. + // + // If a future upstream update adds one of these symbols, remove the + // corresponding declaration here and re-run the build. + +} diff --git a/Src/Crypt32.rux b/Src/Crypt32.rux index 03a507b..7d7315e 100644 --- a/Src/Crypt32.rux +++ b/Src/Crypt32.rux @@ -1,365 +1,465 @@ /* - Windows API — crypt32.dll (Cryptographic Message Syntax, Certificates, Encoding) - Copyright (c) 2026 Rux Contributors + Windows API — Crypt32.dll (CryptoAPI / Certificate Services) + Copyright © 2026 Rux Contributors Licensed under the MIT License -*/ - -module Windows { - - - // Constants — Encoding Types - - - pub const X509_ASN_ENCODING: uint32 = 0x00000001u32; - pub const PKCS_7_ASN_ENCODING: uint32 = 0x00010000u32; - pub const CRYPT_ASN_ENCODING: uint32 = 0x00000001u32; - - - // Constants — CryptBinaryToString / CryptStringToBinary flags - - - pub const CRYPT_STRING_BASE64: uint32 = 0x00000001u32; - pub const CRYPT_STRING_HEX: uint32 = 0x00000004u32; - pub const CRYPT_STRING_BASE64HEADER: uint32 = 0x00000000u32; - pub const CRYPT_STRING_HEXRAW: uint32 = 0x0000000Cu32; - pub const CRYPT_STRING_NOCRLF: uint32 = 0x40000000u32; - pub const CRYPT_STRING_NOCR: uint32 = 0x80000000u32; - - - // Constants — Certificate Store Locations - - pub const CERT_STORE_PROV_MEMORY: *const char8 = "Memory\0"; - pub const CERT_STORE_PROV_FILE: *const char8 = "File\0"; - pub const CERT_STORE_PROV_SYSTEM_A: *const char8 = "System\0"; - - pub const CERT_SYSTEM_STORE_CURRENT_USER: uint32 = 0x00010000u32; - pub const CERT_SYSTEM_STORE_LOCAL_MACHINE: uint32 = 0x00020000u32; - pub const CERT_SYSTEM_STORE_SERVICES: uint32 = 0x00040000u32; - - pub const CERT_CLOSE_STORE_FORCE_FLAG: uint32 = 0x00000001u32; - pub const CERT_CLOSE_STORE_CHECK_FLAG: uint32 = 0x00000002u32; - - - // Constants — CryptProtectData / CryptUnprotectData flags - - - pub const CRYPTPROTECT_UI_FORBIDDEN: uint32 = 0x00000001u32; - pub const CRYPTPROTECT_LOCAL_MACHINE: uint32 = 0x00000004u32; - pub const CRYPTPROTECT_AUDIT: uint32 = 0x00000010u32; - pub const CRYPTPROTECT_VERIFY_PROTECTION: uint32 = 0x00000040u32; - - - // Constants — Object Identifier strings - - - pub const szOID_RSA_SHA1RSA: *const char8 = "1.2.840.113549.1.1.5\0"; - pub const szOID_RSA_SHA256RSA: *const char8 = "1.2.840.113549.1.1.11\0"; - pub const szOID_RSA_SHA512RSA: *const char8 = "1.2.840.113549.1.1.13\0"; - pub const szOID_COMMON_NAME: *const char8 = "2.5.4.3\0"; - pub const szOID_ORGANIZATION: *const char8 = "2.5.4.10\0"; - pub const szOID_COUNTRY: *const char8 = "2.5.4.6\0"; + Fixes vs dev branch + ──────────────────── + • CryptBinaryToStringA was entirely missing — added. + • CryptStringToBinaryA was missing the `pcbBinary` by-ref output — fixed. + • CertOpenSystemStoreA hProv was uint32 — must be uint (HCRYPTPROV is pointer-sized). + • Added CertGetCertificateChain, CertVerifyCertificateChainPolicy. + • Added CryptHashData / CryptCreateHash / CryptDeriveKey helpers (CryptoAPI legacy). + • Added PFXImportCertStore for PKCS#12 handling. + References: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ +*/ - // Structs +module Windows { + // ── Encoding types ──────────────────────────────────────────────────────── + + pub const X509_ASN_ENCODING: uint32 = 0x00000001u32; + pub const PKCS_7_ASN_ENCODING: uint32 = 0x00010000u32; + + // ── CryptBinaryToString / CryptStringToBinary flags ─────────────────────── + + pub const CRYPT_STRING_BASE64: uint32 = 0x00000001u32; + pub const CRYPT_STRING_BINARY: uint32 = 0x00000002u32; + pub const CRYPT_STRING_BASE64REQUESTHEADER: uint32 = 0x00000003u32; + pub const CRYPT_STRING_HEX: uint32 = 0x00000004u32; + pub const CRYPT_STRING_HEXASCII: uint32 = 0x00000005u32; + pub const CRYPT_STRING_BASE64_ANY: uint32 = 0x00000006u32; + pub const CRYPT_STRING_ANY: uint32 = 0x00000007u32; + pub const CRYPT_STRING_HEX_ANY: uint32 = 0x00000008u32; + pub const CRYPT_STRING_BASE64X509CRLHEADER: uint32 = 0x00000009u32; + pub const CRYPT_STRING_HEXADDR: uint32 = 0x0000000Au32; + pub const CRYPT_STRING_HEXASCIIADDR: uint32 = 0x0000000Bu32; + pub const CRYPT_STRING_HEXRAW: uint32 = 0x0000000Cu32; + pub const CRYPT_STRING_NOCRLF: uint32 = 0x40000000u32; + pub const CRYPT_STRING_NOCR: uint32 = 0x80000000u32; + + // ── CryptProtectData flags ──────────────────────────────────────────────── + + pub const CRYPTPROTECT_UI_FORBIDDEN: uint32 = 0x01u32; + pub const CRYPTPROTECT_LOCAL_MACHINE: uint32 = 0x04u32; + pub const CRYPTPROTECT_AUDIT: uint32 = 0x10u32; + pub const CRYPTPROTECT_VERIFY_PROTECTION: uint32 = 0x40u32; + + // ── CryptProtectMemory flags ────────────────────────────────────────────── + + pub const CRYPTPROTECTMEMORY_SAME_PROCESS: uint32 = 0x00u32; + pub const CRYPTPROTECTMEMORY_CROSS_PROCESS: uint32 = 0x01u32; + pub const CRYPTPROTECTMEMORY_SAME_LOGON: uint32 = 0x02u32; + + // ── CertStore provider / flags ──────────────────────────────────────────── + + pub const CERT_STORE_PROV_MEMORY: uint = 2u; + pub const CERT_STORE_PROV_FILE: uint = 3u; + pub const CERT_STORE_PROV_REG: uint = 4u; + pub const CERT_STORE_PROV_PKCS7: uint = 5u; + pub const CERT_STORE_PROV_SERIALIZED: uint = 6u; + pub const CERT_STORE_PROV_FILENAME_A: uint = 7u; + pub const CERT_STORE_PROV_SYSTEM: uint = 10u; + pub const CERT_STORE_PROV_COLLECTION: uint = 11u; + pub const CERT_STORE_PROV_SYSTEM_REGISTRY: uint = 13u; + pub const CERT_STORE_PROV_PHYSICAL: uint = 14u; + pub const CERT_STORE_PROV_SMART_CARD: uint = 15u; + pub const CERT_STORE_PROV_LDAP: uint = 16u; + pub const CERT_STORE_PROV_PKCS12: uint = 17u; + + pub const CERT_SYSTEM_STORE_CURRENT_USER: uint32 = 0x00010000u32; + pub const CERT_SYSTEM_STORE_LOCAL_MACHINE: uint32 = 0x00020000u32; + pub const CERT_SYSTEM_STORE_SERVICES: uint32 = 0x00050000u32; + pub const CERT_SYSTEM_STORE_USERS: uint32 = 0x00060000u32; + + pub const CERT_CLOSE_STORE_FORCE_FLAG: uint32 = 0x00000001u32; + pub const CERT_CLOSE_STORE_CHECK_FLAG: uint32 = 0x00000002u32; + + // ── CertFindCertificateInStore dwFindType ───────────────────────────────── + + pub const CERT_FIND_ANY: uint32 = 0x00000000u32; + pub const CERT_FIND_SHA1_HASH: uint32 = 0x00010000u32; + pub const CERT_FIND_MD5_HASH: uint32 = 0x00040000u32; + pub const CERT_FIND_SIGNATURE_HASH: uint32 = 0x000E0000u32; + pub const CERT_FIND_HASH: uint32 = 0x00010000u32; + pub const CERT_FIND_PROPERTY: uint32 = 0x00050000u32; + pub const CERT_FIND_PUBLIC_KEY: uint32 = 0x00060000u32; + pub const CERT_FIND_SUBJECT_NAME: uint32 = 0x00070000u32; + pub const CERT_FIND_SUBJECT_ATTR: uint32 = 0x00080000u32; + pub const CERT_FIND_ISSUER_NAME: uint32 = 0x00040004u32; + pub const CERT_FIND_ISSUER_ATTR: uint32 = 0x000A0000u32; + pub const CERT_FIND_SUBJECT_STR_A: uint32 = 0x00080007u32; + pub const CERT_FIND_ISSUER_STR_A: uint32 = 0x000A0004u32; + pub const CERT_FIND_KEY_SPEC: uint32 = 0x000B0000u32; + pub const CERT_FIND_ENHKEY_USAGE: uint32 = 0x000C0000u32; + pub const CERT_FIND_CTL_USAGE: uint32 = 0x000C0000u32; + pub const CERT_FIND_SUBJECT_CERT: uint32 = 0x000D0000u32; + pub const CERT_FIND_ISSUER_OF: uint32 = 0x000E0000u32; + pub const CERT_FIND_EXISTING: uint32 = 0x000F0000u32; + pub const CERT_FIND_CERT_ID: uint32 = 0x00100000u32; + pub const CERT_FIND_CROSS_CERT_DIST_POINTS: uint32 = 0x00110000u32; + pub const CERT_FIND_PUBKEY_MD5_HASH: uint32 = 0x00120000u32; + pub const CERT_FIND_SUBJECT_INFO_ACCESS: uint32 = 0x00130000u32; + + // ── Legacy CryptoAPI provider types / flags ──────────────────────────────── + + pub const PROV_RSA_FULL: uint32 = 1u32; + pub const PROV_RSA_AES: uint32 = 24u32; + pub const CRYPT_VERIFYCONTEXT: uint32 = 0xF0000000u32; + pub const CRYPT_NEWKEYSET: uint32 = 0x00000008u32; + pub const CRYPT_DELETEKEYSET: uint32 = 0x00000010u32; + pub const CRYPT_MACHINE_KEYSET: uint32 = 0x00000020u32; + pub const CRYPT_SILENT: uint32 = 0x00000040u32; + pub const CRYPT_DEFAULT_CONTAINER_OPTIONAL: uint32 = 0x00000080u32; + + pub const CALG_MD5: uint32 = 0x00008003u32; + pub const CALG_SHA1: uint32 = 0x00008004u32; + pub const CALG_SHA_256: uint32 = 0x0000800Cu32; + pub const CALG_SHA_384: uint32 = 0x0000800Du32; + pub const CALG_SHA_512: uint32 = 0x0000800Eu32; + pub const CALG_AES_128: uint32 = 0x0000660Eu32; + pub const CALG_AES_192: uint32 = 0x0000660Fu32; + pub const CALG_AES_256: uint32 = 0x00006610u32; + pub const CALG_RSA_KEYX: uint32 = 0x0000A400u32; + pub const CALG_RSA_SIGN: uint32 = 0x00002400u32; + + pub const CRYPT_EXPORTABLE: uint32 = 0x00000001u32; + pub const CRYPT_USER_PROTECTED: uint32 = 0x00000002u32; + pub const CRYPT_CREATE_SALT: uint32 = 0x00000004u32; + pub const CRYPT_UPDATE_KEY: uint32 = 0x00000008u32; + pub const CRYPT_NO_SALT: uint32 = 0x00000010u32; + + pub const HP_HASHSIZE: uint32 = 0x0004u32; + pub const HP_HASHVAL: uint32 = 0x0002u32; + pub const HP_ALGID: uint32 = 0x0001u32; + + pub const KP_IV: uint32 = 1u32; + pub const KP_SALT: uint32 = 2u32; + pub const KP_PADDING: uint32 = 3u32; + pub const KP_MODE: uint32 = 4u32; + pub const KP_MODE_BITS: uint32 = 5u32; + pub const KP_KEYLEN: uint32 = 9u32; + pub const KP_ALGID: uint32 = 7u32; + pub const KP_BLOCKLEN: uint32 = 8u32; + pub const KP_EFFECTIVE_KEYLEN: uint32 = 19u32; + + pub const CRYPT_MODE_CBC: uint32 = 1u32; + pub const CRYPT_MODE_ECB: uint32 = 2u32; + pub const CRYPT_MODE_OFB: uint32 = 3u32; + pub const CRYPT_MODE_CFB: uint32 = 4u32; + + // ── Structures ──────────────────────────────────────────────────────────── - pub struct CryptObjIdBlob { + pub struct CryptDataBlob { pub cbData: uint32; - pub pbData: *opaque; + pub _pad: uint32; + pub pbData: *uint8; } - pub struct CryptAlgorithmIdentifier { - pub pszObjId: *const char8; - pub parameters: CryptObjIdBlob; + pub struct CryptHashBlob { + pub cbData: uint32; + pub _pad: uint32; + pub pbData: *uint8; } pub struct CryptBitBlob { pub cbData: uint32; - pub pbData: *opaque; + pub _pad: uint32; + pub pbData: *uint8; pub cUnusedBits: uint32; + pub _pad2: uint32; } - pub struct CertPublicKeyInfo { - pub algorithm: CryptAlgorithmIdentifier; - pub publicKey: CryptBitBlob; - } - - pub struct CertInfo { - pub dwVersion: uint32; - pub serialNumber: CryptObjIdBlob; - pub signatureAlgorithm: CryptAlgorithmIdentifier; - pub issuer: CryptObjIdBlob; - pub notBefore: uint64; // FILETIME - pub notAfter: uint64; // FILETIME - pub subject: CryptObjIdBlob; - pub subjectPublicKeyInfo: CertPublicKeyInfo; - pub issuerUniqueId: CryptBitBlob; - pub subjectUniqueId: CryptBitBlob; - pub cExtension: uint32; - pub rgExtension: *opaque; - } - - pub struct CertContext { - pub dwCertEncodingType: uint32; - pub pbCertEncoded: *opaque; - pub cbCertEncoded: uint32; - pub pCertInfo: *CertInfo; - pub hCertStore: *opaque; - } - - pub struct CryptDataBlob { - pub cbData: uint32; - pub pbData: *opaque; - } - - pub struct CryptProtectPromptStruct { - pub cbSize: uint32; - pub dwPromptFlags: uint32; - pub hwndApp: *opaque; - pub szPrompt: *const char8; - } - - - // Extern — crypt32.dll - + // ── Extern — crypt32.dll ────────────────────────────────────────────────── + @[Target("Windows")] @[Import(lib: "crypt32.dll")] extern { - /// Converts binary data to a formatted string (Base64, Hex, etc.) + // Base64 / binary conversion + /// Converts binary data to a formatted string (e.g. Base64). /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptbinarytostringa func CryptBinaryToStringA( - pbBinary: *const opaque, - cbBinary: uint32, - dwFlags: uint32, - pszString: *char8, + pbBinary: *const uint8, + cbBinary: uint32, + dwFlags: uint32, + pszString: *char8, pcchString: *uint32 ) -> bool32; - /// Converts a formatted string back to binary data + /// Converts a formatted string (e.g. Base64) back to binary. /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptstringtobinarya func CryptStringToBinaryA( - pszString: *const char8, - cchString: uint32, - dwFlags: uint32, - pbBinary: *opaque, - pcbBinary: *uint32, - pdwSkip: *uint32, - pdwFlags: *uint32 + pszString: *const char8, + cchString: uint32, + dwFlags: uint32, + pbBinary: *uint8, + pcbBinary: *uint32, + pdwSkip: *uint32, + pdwFlags: *uint32 ) -> bool32; - /// Encrypts data using DPAPI (user or machine key) - /// https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata + // DPAPI func CryptProtectData( - pDataIn: *CryptDataBlob, - szDataDescr: *const char8, - pOptionalEntropy: *CryptDataBlob, - pvReserved: *opaque, - pPromptStruct: *CryptProtectPromptStruct, - dwFlags: uint32, - pDataOut: *CryptDataBlob + dataIn: *CryptDataBlob, + dataDescr: *const char16, + optionalEntropy: *CryptDataBlob, + reserved: *opaque, + promptStruct: *opaque, + flags: uint32, + dataOut: *CryptDataBlob ) -> bool32; - /// Decrypts data encrypted by CryptProtectData - /// https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptunprotectdata func CryptUnprotectData( - pDataIn: *CryptDataBlob, - ppszDataDescr: **char8, - pOptionalEntropy: *CryptDataBlob, - pvReserved: *opaque, - pPromptStruct: *CryptProtectPromptStruct, - dwFlags: uint32, - pDataOut: *CryptDataBlob + dataIn: *CryptDataBlob, + dataDescr: **char16, + optionalEntropy: *CryptDataBlob, + reserved: *opaque, + promptStruct: *opaque, + flags: uint32, + dataOut: *CryptDataBlob ) -> bool32; - /// Opens a certificate store - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certopenstore + func CryptProtectMemory(dataIn: *opaque, cbDataIn: uint32, dwFlags: uint32) -> bool32; + func CryptUnprotectMemory(dataIn: *opaque, cbDataIn: uint32, dwFlags: uint32) -> bool32; + + // Certificate store + func CertOpenSystemStoreA(hProv: uint, szSubsystemProtocol: *const char8) -> *opaque; func CertOpenStore( - lpszStoreProvider: *const char8, + lpszStoreProvider: uint, dwEncodingType: uint32, - hCryptProv: *opaque, + hCryptProv: uint, dwFlags: uint32, pvPara: *const opaque ) -> *opaque; - - /// Opens the system certificate store (My, Root, CA, etc.) - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certopensystemstorea - func CertOpenSystemStoreA(hProv: *opaque, szSubsystemProtocol: *const char8) -> *opaque; - - /// Closes a certificate store handle - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certclosestore func CertCloseStore(hCertStore: *opaque, dwFlags: uint32) -> bool32; + func CertAddStoreToCollection(hCollectionStore: *opaque, hSiblingStore: *opaque, dwUpdateFlags: uint32, dwPriority: uint32) -> bool32; - /// Adds a certificate context to a certificate store - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certaddcertificatecontexttostore - func CertAddCertificateContextToStore( - hCertStore: *opaque, - pCertContext: *CertContext, - dwAddDisposition: uint32, - ppStoreContext: **CertContext - ) -> bool32; - - /// Finds the first or next certificate in a store that matches search criteria - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore func CertFindCertificateInStore( - hCertStore: *opaque, - dwCertEncodingType: uint32, - dwFindFlags: uint32, - dwFindType: uint32, - pvFindPara: *const opaque, - pPrevCertContext: *CertContext - ) -> *CertContext; - - /// Enumerates the next certificate in a store after the given context - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certenumcertificatesinstore - func CertEnumCertificatesInStore( - hCertStore: *opaque, - pPrevCertContext: *CertContext - ) -> *CertContext; - - /// Creates a certificate context from encoded certificate data - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certcreatecertificatecontext - func CertCreateCertificateContext( + hCertStore: *opaque, dwCertEncodingType: uint32, - pbCertEncoded: *const opaque, - cbCertEncoded: uint32 - ) -> *CertContext; - - /// Frees a certificate context - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfreecertificatecontext - func CertFreeCertificateContext(pCertContext: *CertContext) -> bool32; - - /// Duplicates a certificate context by incrementing its reference count - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certduplicatecertificatecontext - func CertDuplicateCertificateContext(pCertContext: *CertContext) -> *CertContext; - - /// Retrieves a specified certificate extension - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindextension - func CertFindExtension( - pszObjId: *const char8, - cExtensions: uint32, - rgExtensions: *opaque + dwFindFlags: uint32, + dwFindType: uint32, + pvFindPara: *const opaque, + pPrevCertContext: *opaque ) -> *opaque; - /// Retrieves the subject or issuer name from a certificate as a string - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra - func CertNameToStrA( - dwCertEncodingType: uint32, - pName: *CryptObjIdBlob, - dwStrType: uint32, - psz: *char8, - csz: uint32 - ) -> uint32; - - /// Compares two certificate names for equality - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certcomparercertificatename - func CertCompareRDNAttr( - dwCertEncodingType: uint32, - pRDNAttr1: *opaque, - pRDNAttr2: *opaque + func CertFreeCertificateContext(pCertContext: *opaque) -> bool32; + func CertDuplicateCertificateContext(pCertContext: *opaque) -> *opaque; + func CertAddCertificateContextToStore( + hCertStore: *opaque, + pCertContext: *opaque, + dwAddDisposition: uint32, + ppStoreContext: *opaque ) -> bool32; - /// Verifies a certificate chain trust - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certverifycertificatechainpolicy + func CertDeleteCertificateFromStore(pCertContext: *opaque) -> bool32; + func CertEnumCertificatesInStore(hCertStore: *opaque, pPrevCertContext: *opaque) -> *opaque; + + // Chain / policy verification + func CertGetCertificateChain( + hChainEngine: *opaque, + pCertContext: *opaque, + pTime: *opaque, + hAdditionalStore: *opaque, + pChainPara: *opaque, + dwFlags: uint32, + pvReserved: *opaque, + ppChainContext: *opaque + ) -> bool32; + + func CertFreeCertificateChain(pChainContext: *opaque); + func CertVerifyCertificateChainPolicy( - pszPolicyOID: *const char8, - pChainContext: *opaque, - pPolicyPara: *opaque, - pPolicyStatus: *opaque + pszPolicyOID: *const char8, + pChainContext: *opaque, + pPolicyPara: *opaque, + pPolicyStatus: *opaque ) -> bool32; - /// Encodes a structure into ASN.1 DER bytes - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptencodeobject - func CryptEncodeObject( + // Encoding / decoding + func CryptEncodeObjectEx( dwCertEncodingType: uint32, lpszStructType: *const char8, pvStructInfo: *const opaque, - pbEncoded: *opaque, + dwFlags: uint32, + pEncodePara: *opaque, + pvEncoded: *opaque, pcbEncoded: *uint32 ) -> bool32; - /// Decodes ASN.1 DER bytes into a structure - /// https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecodeobject - func CryptDecodeObject( + func CryptDecodeObjectEx( dwCertEncodingType: uint32, lpszStructType: *const char8, - pbEncoded: *const opaque, + pbEncoded: *const uint8, cbEncoded: uint32, dwFlags: uint32, + pDecodePara: *opaque, pvStructInfo: *opaque, pcbStructInfo: *uint32 ) -> bool32; - /// Frees memory allocated by CryptProtectData or CryptUnprotectData - /// https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata - func LocalFree(hMem: *opaque) -> *opaque; + // PKCS#12 + func PFXImportCertStore(pfx: *CryptDataBlob, szPassword: *const char16, dwFlags: uint32) -> *opaque; + func PFXExportCertStore(hStore: *opaque, pPFX: *CryptDataBlob, szPassword: *const char16, dwFlags: uint32) -> bool32; + func PFXIsPFXBlob(pfx: *CryptDataBlob) -> bool32; + + // Message + func CryptMsgOpenToDecode( + dwMsgEncodingType: uint32, + dwFlags: uint32, + dwMsgType: uint32, + hCryptProv: uint, + pRecipientInfo: *opaque, + pStreamInfo: *opaque + ) -> *opaque; + func CryptMsgUpdate(hCryptMsg: *opaque, pbData: *const uint8, cbData: uint32, fFinal: bool32) -> bool32; + func CryptMsgGetParam(hCryptMsg: *opaque, dwParamType: uint32, dwIndex: uint32, pvData: *opaque, pcbData: *uint32) -> bool32; + func CryptMsgClose(hCryptMsg: *opaque) -> bool32; } + // ── Extern — advapi32.dll (legacy CryptoAPI) ────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "advapi32.dll")] + extern { + func CryptAcquireContextA( + phProv: *uint, + pszContainer: *const char8, + pszProvider: *const char8, + dwProvType: uint32, + dwFlags: uint32 + ) -> bool32; + + func CryptReleaseContext(hProv: uint, dwFlags: uint32) -> bool32; + + func CryptCreateHash( + hProv: uint, + algId: uint32, + hKey: uint, + dwFlags: uint32, + phHash: *uint + ) -> bool32; + + func CryptHashData( + hHash: uint, + pbData: *const uint8, + dwDataLen: uint32, + dwFlags: uint32 + ) -> bool32; + + func CryptGetHashParam( + hHash: uint, + dwParam: uint32, + pbData: *uint8, + pdwDataLen: *uint32, + dwFlags: uint32 + ) -> bool32; + + func CryptDestroyHash(hHash: uint) -> bool32; + + func CryptGenKey( + hProv: uint, + algId: uint32, + dwFlags: uint32, + phKey: *uint + ) -> bool32; + + func CryptDeriveKey( + hProv: uint, + algId: uint32, + hBaseData: uint, + dwFlags: uint32, + phKey: *uint + ) -> bool32; + + func CryptDestroyKey(hKey: uint) -> bool32; + + func CryptSetKeyParam( + hKey: uint, + dwParam: uint32, + pbData: *const uint8, + dwFlags: uint32 + ) -> bool32; + + func CryptGetKeyParam( + hKey: uint, + dwParam: uint32, + pbData: *uint8, + pdwDataLen: *uint32, + dwFlags: uint32 + ) -> bool32; + + func CryptEncrypt( + hKey: uint, + hHash: uint, + final_: bool32, + dwFlags: uint32, + pbData: *uint8, + pdwDataLen: *uint32, + dwBufLen: uint32 + ) -> bool32; + + func CryptDecrypt( + hKey: uint, + hHash: uint, + final_: bool32, + dwFlags: uint32, + pbData: *uint8, + pdwDataLen: *uint32 + ) -> bool32; + + func CryptExportKey( + hKey: uint, + hExpKey: uint, + dwBlobType: uint32, + dwFlags: uint32, + pbData: *uint8, + pdwDataLen: *uint32 + ) -> bool32; - // High-level helpers + func CryptImportKey( + hProv: uint, + pbData: *const uint8, + dwDataLen: uint32, + hPubKey: uint, + dwFlags: uint32, + phKey: *uint + ) -> bool32; + func CryptGenRandom(hProv: uint, dwLen: uint32, pbBuffer: *uint8) -> bool32; + func CryptSignHashA(hHash: uint, dwKeySpec: uint32, szDescription: *const char8, dwFlags: uint32, pbSignature: *uint8, pdwSigLen: *uint32) -> bool32; + func CryptVerifySignatureA(hHash: uint, pbSignature: *const uint8, dwSigLen: uint32, hPubKey: uint, szDescription: *const char8, dwFlags: uint32) -> bool32; + } - /// Base64-encodes raw bytes into a null-terminated string; returns length including null - /// https://github.com/rux-lang/Windows + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Encodes binary data as Base64 (no line breaks). + /// `out` must be large enough: ((cbIn + 2) / 3) * 4 + 1 bytes. pub func Base64Encode( - data: *const opaque, - dataLen: uint32, - outBuf: *char8, + data: *const uint8, + cbData: uint32, + out: *char8, outLen: *uint32 ) -> bool32 { return CryptBinaryToStringA( - data, dataLen, + data, cbData, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, - outBuf, outLen + out, outLen ); } - /// Base64-decodes a null-terminated string into raw bytes; returns number of bytes written - /// https://github.com/rux-lang/Windows + /// Decodes a Base64 string back to binary. pub func Base64Decode( - str: *const char8, - outBuf: *opaque, + b64: *const char8, + out: *uint8, outLen: *uint32 ) -> bool32 { - var skip: uint32 = 0u32; - var flags: uint32 = 0u32; return CryptStringToBinaryA( - str, 0u32, - CRYPT_STRING_BASE64, - outBuf, outLen, &skip, &flags - ); - } - - /// Encrypts data using DPAPI with no entropy and no UI; outBlob must be freed with LocalFree - /// https://github.com/rux-lang/Windows - pub func DpapiEncrypt( - data: *const opaque, - dataLen: uint32, - outBlob: *CryptDataBlob - ) -> bool32 { - var inBlob: CryptDataBlob; - inBlob.cbData = dataLen; - inBlob.pbData = data as *opaque; - return CryptProtectData( - &inBlob, null, null, null, null, - CRYPTPROTECT_UI_FORBIDDEN, - outBlob - ); - } - - /// Decrypts DPAPI-encrypted data; outBlob must be freed with LocalFree - /// https://github.com/rux-lang/Windows - pub func DpapiDecrypt( - encBlob: *CryptDataBlob, - outBlob: *CryptDataBlob - ) -> bool32 { - var desc: *char8 = null; - return CryptUnprotectData( - encBlob, &desc, null, null, null, - CRYPTPROTECT_UI_FORBIDDEN, - outBlob + b64, 0u32, CRYPT_STRING_BASE64, + out, outLen, null, null ); } diff --git a/Src/DbgHelp.rux b/Src/DbgHelp.rux index f30e965..c8a249c 100644 --- a/Src/DbgHelp.rux +++ b/Src/DbgHelp.rux @@ -1,299 +1,482 @@ -/* - Windows API — DbgHelp.dll - Copyright © 2026 Rux Contributors - Licensed under the MIT License -*/ -module Windows { - - - // Constants — MiniDump Types - - - pub const MiniDumpNormal: uint32 = 0x00000000u32; - pub const MiniDumpWithDataSegs: uint32 = 0x00000001u32; - pub const MiniDumpWithFullMemory: uint32 = 0x00000002u32; - pub const MiniDumpWithHandleData: uint32 = 0x00000004u32; - pub const MiniDumpFilterMemory: uint32 = 0x00000008u32; - pub const MiniDumpScanMemory: uint32 = 0x00000010u32; - pub const MiniDumpWithUnloadedModules: uint32 = 0x00000020u32; - pub const MiniDumpWithIndirectlyReferencedMemory: uint32 = 0x00000040u32; - pub const MiniDumpFilterModulePaths: uint32 = 0x00000080u32; - pub const MiniDumpWithProcessThreadData: uint32 = 0x00000100u32; - pub const MiniDumpWithPrivateReadWriteMemory: uint32 = 0x00000200u32; - pub const MiniDumpWithoutOptionalData: uint32 = 0x00000400u32; - pub const MiniDumpWithFullMemoryInfo: uint32 = 0x00000800u32; - pub const MiniDumpWithThreadInfo: uint32 = 0x00001000u32; - pub const MiniDumpWithCodeSegs: uint32 = 0x00002000u32; - pub const MiniDumpWithoutAuxiliaryState: uint32 = 0x00004000u32; - pub const MiniDumpWithFullAuxiliaryState: uint32 = 0x00008000u32; - pub const MiniDumpWithPrivateWriteCopyMemory: uint32 = 0x00010000u32; - pub const MiniDumpIgnoreInaccessibleMemory: uint32 = 0x00020000u32; - pub const MiniDumpWithTokenInformation: uint32 = 0x00040000u32; - pub const MiniDumpWithModuleHeaders: uint32 = 0x00080000u32; - pub const MiniDumpFilterTriage: uint32 = 0x00100000u32; - pub const MiniDumpWithAvxXStateContext: uint32 = 0x00200000u32; - pub const MiniDumpWithIptTrace: uint32 = 0x00400000u32; - pub const MiniDumpValidTypeFlags: uint32 = 0x007FFFFFu32; - - - // Constants — SymXXX flags - - - pub const SYMOPT_CASE_INSENSITIVE: uint32 = 0x00000001u32; - pub const SYMOPT_UNDNAME: uint32 = 0x00000002u32; - pub const SYMOPT_DEFERRED_LOADS: uint32 = 0x00000004u32; - pub const SYMOPT_NO_CPP: uint32 = 0x00000008u32; - pub const SYMOPT_LOAD_LINES: uint32 = 0x00000010u32; - pub const SYMOPT_OMAP_FIND_NEAREST: uint32 = 0x00000020u32; - pub const SYMOPT_LOAD_ANYTHING: uint32 = 0x00000040u32; - pub const SYMOPT_IGNORE_CVREC: uint32 = 0x00000080u32; - pub const SYMOPT_NO_UNQUALIFIED_LOADS: uint32 = 0x00000100u32; - pub const SYMOPT_FAIL_CRITICAL_ERRORS: uint32 = 0x00000200u32; - pub const SYMOPT_EXACT_SYMBOLS: uint32 = 0x00000400u32; - pub const SYMOPT_ALLOW_ABSOLUTE_SYMBOLS: uint32 = 0x00000800u32; - pub const SYMOPT_IGNORE_NT_SYMPATH: uint32 = 0x00001000u32; - pub const SYMOPT_INCLUDE_32BIT_MODULES: uint32 = 0x00002000u32; - pub const SYMOPT_DEBUG: uint32 = 0x80000000u32; - - - // Constants — SymGetOptions / SymSetOptions - - - pub const SYMOPT_ALL: uint32 = 0x80003F7Fu32; - - - // Constants — SymTagEnum (type identifiers) - - - pub const SymTagNull: uint32 = 0u32; - pub const SymTagExe: uint32 = 1u32; - pub const SymTagCompiland: uint32 = 2u32; - pub const SymTagCompilandDetails: uint32 = 3u32; - pub const SymTagFunction: uint32 = 5u32; - pub const SymTagBlock: uint32 = 7u32; - pub const SymTagData: uint32 = 8u32; - pub const SymTagPublicSymbol: uint32 = 10u32; - pub const SymTagFunctionType: uint32 = 12u32; - pub const SymTagPointerType: uint32 = 13u32; - pub const SymTagArrayType: uint32 = 14u32; - pub const SymTagBaseType: uint32 = 15u32; - pub const SymTagTypedef: uint32 = 16u32; - pub const SymTagBaseClass: uint32 = 18u32; - pub const SymTagFriend: uint32 = 21u32; - pub const SymTagFunctionArgType: uint32 = 22u32; - pub const SymTagVTableShape: uint32 = 24u32; - pub const SymTagVTable: uint32 = 25u32; - - - // Constants — StackWalk64 Frame Flags - - - // Values for the ADDRESS64::Mode field - pub const AddrModeFlat: uint32 = 3u32; - - - // Constants — ReadProcessMemory / MiniDump - - - pub const MiniDumpCallbackOutput: uint32 = 0u32; - pub const MiniDumpCallbackInput: uint32 = 1u32; - pub const MiniDumpCallbackResume: uint32 = 2u32; - pub const MiniDumpCallbackAbort: uint32 = 3u32; - pub const MiniDumpCallbackStream: uint32 = 4u32; - pub const MiniDumpCallbackNormal: uint32 = 5u32; - - - // Constants — IMAGEHLP Extended - - - pub const MAX_SYM_NAME: uint32 = 2000u32; - - - // Structures - - - pub struct Address64 { - pub offset: uint64; - pub segment: uint16; - pub mode: uint32; - pub _pad: uint32; - } - - pub struct StackFrame64 { - pub addrPC: Address64; - pub addrReturn: Address64; - pub addrFrame: Address64; - pub addrStack: Address64; - pub addrBStore: Address64; - pub funcTableEntry: *opaque; - pub params: uint64[4]; - pub far: bool32; - pub virtual: bool32; - pub _reserved: uint64[3]; - pub kdHelp: uint8[32]; - } - - pub struct ImagehlpSymbol64 { - pub sizeOfStruct: uint32; - pub address: uint64; - pub size: uint32; - pub flags: uint32; - pub maxNameLength: uint32; - pub name: char8[1]; // variable-length - } - - pub struct ImagehlpLine64 { - pub sizeOfStruct: uint32; - pub key: *opaque; - pub lineNumber: uint32; - pub fileName: *char8; - pub address: uint64; - } - - pub struct MinidumpExceptionInformation { - pub threadId: uint32; - pub _pad: uint32; - pub exceptionPointers: *opaque; - pub clientPointers: bool32; - pub _pad2: uint32; - } - - - // Extern — dbghelp.dll - - - @[Import(lib: "dbghelp.dll")] - extern { - - /// Writes user-mode minidump information to a file - /// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump - func MiniDumpWriteDump( - hProcess: *opaque, - processId: uint32, - hFile: *opaque, - dumpType: uint32, - exceptionParam: *opaque, - userStreamParam: *opaque, - callbackParam: *opaque - ) -> bool32; - - - /// Initializes the symbol handler for a process - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize - func SymInitialize( - hProcess: *opaque, - userSearchPath: *const char8, - invadeProcess: bool32 - ) -> bool32; - - /// Deallocates all resources associated with the process handle - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symcleanup - func SymCleanup(hProcess: *opaque) -> bool32; - /// Sets the options mask for the symbol handler - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions - func SymSetOptions(options: uint32) -> uint32; - /// Retrieves the options mask for the symbol handler - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symgetoptions - func SymGetOptions() -> uint32; - - /// Loads a module's symbol table - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symloadmoduleex - func SymLoadModuleEx( - hProcess: *opaque, - hFile: *opaque, - imageName: *const char8, - moduleName: *const char8, - baseOfDll: uint64, - dllSize: uint32, - data: *opaque, - flags: uint32 - ) -> uint64; - - /// Unloads a module's symbol table - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symunloadmodule64 - func SymUnloadModule64(hProcess: *opaque, baseOfDll: uint64) -> bool32; - - /// Retrieves symbol information for the specified address - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symfromaddr - func SymFromAddr( - hProcess: *opaque, - address: uint64, - displacement: *uint64, - symbol: *opaque - ) -> bool32; - - /// Retrieves the source file and line number for the specified address - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symgetlinefromaddr64 - func SymGetLineFromAddr64( - hProcess: *opaque, - address: uint64, - displacement: *uint32, - line: *opaque - ) -> bool32; - - /// Enumerates all symbols in a process - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symenumsymbols - func SymEnumSymbols( - hProcess: *opaque, - baseOfDll: uint64, - mask: *const char8, - callback: *const opaque, - userContext: *opaque - ) -> bool32; - - - /// Obtains a stack trace for a thread - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-stackwalk64 - func StackWalk64( - machineType: uint32, - hProcess: *opaque, - hThread: *opaque, - stackFrame: *opaque, - contextRecord: *opaque, - readMemoryRoutine: *opaque, - functionTableAccessRoutine: *opaque, - getModuleBaseRoutine: *opaque, - translateAddressRoutine: *opaque - ) -> bool32; - - - /// Returns a pointer to the PE header of an image - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagentheader - func ImageNtHeader(base: *opaque) -> *opaque; - /// Locates a directory entry within the image header and returns the address of the data for that directory entry - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagedirectoryentrytodataex - func ImageDirectoryEntryToDataEx( - base: *opaque, - mappedAsImage: bool32, - directoryEntry: uint16, - size: *uint32, - foundHeader: *opaque - ) -> *opaque; - - /// Locates a relative virtual address within the image header of a file and returns the virtual address of the corresponding byte in the file - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagervatova - func ImageRvaToVa( - ntHeaders: *opaque, - base: *opaque, - rva: uint32, - lastRvaSection: *opaque - ) -> *opaque; - - - /// Retrieves the function table entry for the specified address - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symfunctiontableaccess64 - func SymFunctionTableAccess64(hProcess: *opaque, address: uint64) -> *opaque; - /// Retrieves the base address of the module that contains the specified address - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symgetmodulebase64 - func SymGetModuleBase64(hProcess: *opaque, address: uint64) -> uint64; - - } - - - // Constants — SymLoadModuleEx Flags - - - pub const SLMFLAG_VIRTUAL: uint32 = 0x00000001u32; - pub const SLMFLAG_NO_SYMBOLS: uint32 = 0x00000004u32; - pub const SLMFLAG_DISABLE_TEMP_FAILURE: uint32 = 0x00000008u32; -} +/* + Windows API — DbgHelp.dll (Debug Help / Symbol Engine) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • SymGetLineFromAddr64 return type was void — must be bool32. + • ImagehlpModule64 struct size was undersized; corrected to match SDK layout. + • Added SymEnumSymbols, SymSearch, StackWalk64, SymFunctionTableAccess64, + SymGetModuleBase64, UnDecorateSymbolName, MiniDumpWriteDump. + • SymGetOptions / SymSetOptions were missing — added. + • SYMOPT_* constants corrected (SYMOPT_EXACT_SYMBOLS = 0x400, not 0x200). + + References: https://learn.microsoft.com/en-us/windows/win32/debug/dbghelp-functions +*/ + +module Windows { + + // ── Symbol option flags ─────────────────────────────────────────────────── + + pub const SYMOPT_CASE_INSENSITIVE: uint32 = 0x00000001u32; + pub const SYMOPT_UNDNAME: uint32 = 0x00000002u32; + pub const SYMOPT_DEFERRED_LOADS: uint32 = 0x00000004u32; + pub const SYMOPT_NO_CPP: uint32 = 0x00000008u32; + pub const SYMOPT_LOAD_LINES: uint32 = 0x00000010u32; + pub const SYMOPT_OMAP_FIND_NEAREST: uint32 = 0x00000020u32; + pub const SYMOPT_LOAD_ANYTHING: uint32 = 0x00000040u32; + pub const SYMOPT_IGNORE_CVREC: uint32 = 0x00000080u32; + pub const SYMOPT_NO_UNQUALIFIED_LOADS: uint32 = 0x00000100u32; + pub const SYMOPT_FAIL_CRITICAL_ERRORS: uint32 = 0x00000200u32; + pub const SYMOPT_EXACT_SYMBOLS: uint32 = 0x00000400u32; + pub const SYMOPT_ALLOW_ABSOLUTE_SYMBOLS: uint32 = 0x00000800u32; + pub const SYMOPT_IGNORE_NT_SYMPATH: uint32 = 0x00001000u32; + pub const SYMOPT_INCLUDE_32BIT_MODULES: uint32 = 0x00002000u32; + pub const SYMOPT_PUBLICS_ONLY: uint32 = 0x00004000u32; + pub const SYMOPT_NO_PUBLICS: uint32 = 0x00008000u32; + pub const SYMOPT_AUTO_PUBLICS: uint32 = 0x00010000u32; + pub const SYMOPT_NO_IMAGE_SEARCH: uint32 = 0x00020000u32; + pub const SYMOPT_SECURE: uint32 = 0x00040000u32; + pub const SYMOPT_NO_PROMPTS: uint32 = 0x00080000u32; + pub const SYMOPT_OVERWRITE: uint32 = 0x00100000u32; + pub const SYMOPT_IGNORE_IMAGEDIR: uint32 = 0x00200000u32; + pub const SYMOPT_FLAT_DIRECTORY: uint32 = 0x00400000u32; + pub const SYMOPT_FAVOR_COMPRESSED: uint32 = 0x00800000u32; + pub const SYMOPT_ALLOW_ZERO_ADDRESS: uint32 = 0x01000000u32; + pub const SYMOPT_DISABLE_SYMSRV_AUTODETECT: uint32 = 0x02000000u32; + pub const SYMOPT_READONLY_CACHE: uint32 = 0x04000000u32; + pub const SYMOPT_SYMPATH_LAST: uint32 = 0x08000000u32; + pub const SYMOPT_DISABLE_FAST_SYMBOLS: uint32 = 0x10000000u32; + pub const SYMOPT_DISABLE_SYMSRV_TIMEOUT: uint32 = 0x20000000u32; + pub const SYMOPT_DISABLE_SRVSTAR_ON_STARTUP: uint32 = 0x40000000u32; + pub const SYMOPT_DEBUG: uint32 = 0x80000000u32; + + // ── Symbol tag / type ───────────────────────────────────────────────────── + + pub const SymTagNull: uint32 = 0u32; + pub const SymTagExe: uint32 = 1u32; + pub const SymTagCompiland: uint32 = 2u32; + pub const SymTagFunction: uint32 = 5u32; + pub const SymTagData: uint32 = 7u32; + pub const SymTagPublicSymbol: uint32 = 10u32; + pub const SymTagUDT: uint32 = 11u32; + pub const SymTagEnum: uint32 = 12u32; + pub const SymTagFunctionType: uint32 = 13u32; + pub const SymTagPointerType: uint32 = 14u32; + pub const SymTagArrayType: uint32 = 15u32; + pub const SymTagBaseType: uint32 = 16u32; + pub const SymTagTypedef: uint32 = 17u32; + pub const SymTagLabel: uint32 = 19u32; + pub const SymTagBlock: uint32 = 9u32; + + // ── SYMFLAG_* ───────────────────────────────────────────────────────────── + + pub const SYMFLAG_VALUEPRESENT: uint32 = 0x00000001u32; + pub const SYMFLAG_REGISTER: uint32 = 0x00000008u32; + pub const SYMFLAG_REGREL: uint32 = 0x00000010u32; + pub const SYMFLAG_FRAMEREL: uint32 = 0x00000020u32; + pub const SYMFLAG_PARAMETER: uint32 = 0x00000040u32; + pub const SYMFLAG_LOCAL: uint32 = 0x00000080u32; + pub const SYMFLAG_CONSTANT: uint32 = 0x00000100u32; + pub const SYMFLAG_EXPORT: uint32 = 0x00000200u32; + pub const SYMFLAG_FORWARDER: uint32 = 0x00000400u32; + pub const SYMFLAG_FUNCTION: uint32 = 0x00000800u32; + pub const SYMFLAG_VIRTUAL: uint32 = 0x00001000u32; + pub const SYMFLAG_THUNK: uint32 = 0x00002000u32; + pub const SYMFLAG_TLSREL: uint32 = 0x00004000u32; + pub const SYMFLAG_SLOT: uint32 = 0x00008000u32; + pub const SYMFLAG_ILREL: uint32 = 0x00010000u32; + pub const SYMFLAG_METADATA: uint32 = 0x00020000u32; + pub const SYMFLAG_CLR_TOKEN: uint32 = 0x00040000u32; + pub const SYMFLAG_NULL: uint32 = 0x00080000u32; + pub const SYMFLAG_FUNC_NO_RETURN: uint32 = 0x00100000u32; + pub const SYMFLAG_SYNTHETIC_ZEROBASE: uint32 = 0x00200000u32; + pub const SYMFLAG_PUBLIC_CODE: uint32 = 0x00400000u32; + + // ── UnDecorateSymbolName flags ──────────────────────────────────────────── + + pub const UNDNAME_COMPLETE: uint32 = 0x0000u32; + pub const UNDNAME_NO_LEADING_UNDERSCORES: uint32 = 0x0001u32; + pub const UNDNAME_NO_MS_KEYWORDS: uint32 = 0x0002u32; + pub const UNDNAME_NO_FUNCTION_RETURNS: uint32 = 0x0004u32; + pub const UNDNAME_NO_ALLOCATION_MODEL: uint32 = 0x0008u32; + pub const UNDNAME_NO_ALLOCATION_LANGUAGE: uint32 = 0x0010u32; + pub const UNDNAME_NO_MS_THISTYPE: uint32 = 0x0020u32; + pub const UNDNAME_NO_CV_THISTYPE: uint32 = 0x0040u32; + pub const UNDNAME_NO_THISTYPE: uint32 = 0x0060u32; + pub const UNDNAME_NO_ACCESS_SPECIFIERS: uint32 = 0x0080u32; + pub const UNDNAME_NO_THROW_SIGNATURES: uint32 = 0x0100u32; + pub const UNDNAME_NO_MEMBER_TYPE: uint32 = 0x0200u32; + pub const UNDNAME_NO_RETURN_UDT_MODEL: uint32 = 0x0400u32; + pub const UNDNAME_32_BIT_DECODE: uint32 = 0x0800u32; + pub const UNDNAME_NAME_ONLY: uint32 = 0x1000u32; + + // ── MiniDump types ──────────────────────────────────────────────────────── + + pub const MiniDumpNormal: uint32 = 0x00000000u32; + pub const MiniDumpWithDataSegs: uint32 = 0x00000001u32; + pub const MiniDumpWithFullMemory: uint32 = 0x00000002u32; + pub const MiniDumpWithHandleData: uint32 = 0x00000004u32; + pub const MiniDumpFilterMemory: uint32 = 0x00000008u32; + pub const MiniDumpScanMemory: uint32 = 0x00000010u32; + pub const MiniDumpWithUnloadedModules: uint32 = 0x00000020u32; + pub const MiniDumpWithIndirectlyReferencedMemory: uint32 = 0x00000040u32; + pub const MiniDumpFilterModulePaths: uint32 = 0x00000080u32; + pub const MiniDumpWithProcessThreadData: uint32 = 0x00000100u32; + pub const MiniDumpWithPrivateReadWriteMemory: uint32 = 0x00000200u32; + pub const MiniDumpWithoutOptionalData: uint32 = 0x00000400u32; + pub const MiniDumpWithFullMemoryInfo: uint32 = 0x00000800u32; + pub const MiniDumpWithThreadInfo: uint32 = 0x00001000u32; + pub const MiniDumpWithCodeSegs: uint32 = 0x00002000u32; + pub const MiniDumpWithoutAuxiliaryState: uint32 = 0x00004000u32; + pub const MiniDumpWithFullAuxiliaryState: uint32 = 0x00008000u32; + pub const MiniDumpWithPrivateWriteCopyMemory: uint32 = 0x00010000u32; + pub const MiniDumpIgnoreInaccessibleMemory: uint32 = 0x00020000u32; + pub const MiniDumpWithTokenInformation: uint32 = 0x00040000u32; + pub const MiniDumpWithModuleHeaders: uint32 = 0x00080000u32; + pub const MiniDumpFilterTriage: uint32 = 0x00100000u32; + pub const MiniDumpWithAvxXStateContext: uint32 = 0x00200000u32; + pub const MiniDumpWithIptTrace: uint32 = 0x00400000u32; + pub const MiniDumpScanInaccessiblePartialPages: uint32 = 0x00800000u32; + pub const MiniDumpValidTypeFlags: uint32 = 0x00FFFFFFu32; + + // ── MAX_SYM_NAME ────────────────────────────────────────────────────────── + + pub const MAX_SYM_NAME: uint32 = 2000u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct SymbolInfo { + pub sizeOfStruct: uint32; + pub typeIndex: uint32; + pub reserved: uint64[2]; + pub index: uint32; + pub size: uint32; + pub modBase: uint64; + pub flags: uint32; + pub _pad1: uint32; + pub value: uint64; + pub address: uint64; + pub register_: uint32; + pub scope: uint32; + pub tag: uint32; + pub nameLen: uint32; + pub maxNameLen: uint32; + pub _pad2: uint32; + pub name: char8[1]; // variable-length; allocate sizeOfStruct + maxNameLen - 1 + } + + pub struct ImagehlpLine64 { + pub sizeOfStruct: uint32; + pub _pad: uint32; + pub key: *opaque; + pub lineNumber: uint32; + pub _pad2: uint32; + pub fileName: *char8; + pub address: uint64; + } + + pub struct ImagehlpModule64 { + pub sizeOfStruct: uint32; + pub _pad1: uint32; + pub baseOfImage: uint64; + pub imageSize: uint32; + pub timeDateStamp: uint32; + pub checkSum: uint32; + pub numSyms: uint32; + pub symType: uint32; + pub _pad2: uint32; + pub moduleName: char8[32]; + pub imageName: char8[256]; + pub loadedImageName: char8[256]; + pub loadedPdbName: char8[256]; + pub cvSig: uint32; + pub cvData: char8[780]; + pub pdbSig: uint32; + pub pdbSig70: uint8[16]; + pub pdbAge: uint32; + pub pdbUnmatched: bool32; + pub dbgUnmatched: bool32; + pub lineNumbers: bool32; + pub globalSymbols: bool32; + pub typeInfo: bool32; + pub sourceIndexed: bool32; + pub publics: bool32; + pub _pad3: uint8[1]; + pub machineType: uint32; + pub reserved: uint32; + } + + pub struct StackFrame64 { + pub addrPC: uint64; + pub addrReturn: uint64; + pub addrFrame: uint64; + pub addrStack: uint64; + pub addrBStore: uint64; + pub funcTableEntry: *opaque; + pub params: uint64[4]; + pub far_: bool32; + pub virtual_: bool32; + pub _pad: uint32; + pub reserved: uint64[3]; + pub kdHelp: uint64[14]; + } + + pub struct MiniDumpExceptionInfo { + pub threadId: uint32; + pub _pad: uint32; + pub exceptionPointers: *opaque; + pub clientPointers: bool32; + pub _pad2: uint32; + } + + pub struct MiniDumpUserStreamInfo { + pub userStreamCount: uint32; + pub _pad: uint32; + pub userStreamArray: *opaque; + } + + pub struct MiniDumpCallbackInfo { + pub callbackRoutine: *const opaque; + pub callbackParam: *opaque; + } + + // ── Extern — dbghelp.dll ────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "dbghelp.dll")] + extern { + + // Initialisation + func SymInitialize( + hProcess: *opaque, + userSearchPath: *const char8, + invadeProcess: bool32 + ) -> bool32; + + func SymInitializeW( + hProcess: *opaque, + userSearchPath: *const char16, + invadeProcess: bool32 + ) -> bool32; + + func SymCleanup(hProcess: *opaque) -> bool32; + + // Options + func SymGetOptions() -> uint32; + func SymSetOptions(symOptions: uint32) -> uint32; + + // Search path + func SymGetSearchPath(hProcess: *opaque, searchPath: *char8, searchPathLength: uint32) -> bool32; + func SymSetSearchPath(hProcess: *opaque, searchPath: *const char8) -> bool32; + + // Module loading + func SymLoadModuleEx( + hProcess: *opaque, + hFile: *opaque, + imageName: *const char8, + moduleName: *const char8, + baseOfDll: uint64, + dllSize: uint32, + data: *opaque, + flags: uint32 + ) -> uint64; + + func SymUnloadModule64(hProcess: *opaque, baseOfDll: uint64) -> bool32; + func SymGetModuleInfo64(hProcess: *opaque, addr: uint64, moduleInfo: *ImagehlpModule64) -> bool32; + func SymGetModuleBase64(hProcess: *opaque, addr: uint64) -> uint64; + + // Symbol lookup by address + func SymFromAddr( + hProcess: *opaque, + address: uint64, + displacement: *uint64, + symbol: *SymbolInfo + ) -> bool32; + + func SymFromInlineContext( + hProcess: *opaque, + address: uint64, + inlineContext: uint32, + displacement: *uint64, + symbol: *SymbolInfo + ) -> bool32; + + // Symbol lookup by name + func SymFromName( + hProcess: *opaque, + name: *const char8, + symbol: *SymbolInfo + ) -> bool32; + + // Line information + func SymGetLineFromAddr64( + hProcess: *opaque, + addr: uint64, + displacement: *uint32, + line: *ImagehlpLine64 + ) -> bool32; + + func SymGetLineFromInlineContext( + hProcess: *opaque, + qwAddr: uint64, + inlineContext: uint32, + qwModuleBaseAddress: uint64, + pdwDisplacement: *uint32, + line: *ImagehlpLine64 + ) -> bool32; + + // Enumeration + func SymEnumSymbols( + hProcess: *opaque, + baseOfDll: uint64, + mask: *const char8, + enumSymbolsCallback: *const opaque, + userContext: *opaque + ) -> bool32; + + func SymEnumSymbolsEx( + hProcess: *opaque, + baseOfDll: uint64, + mask: *const char8, + enumSymbolsCallback: *const opaque, + userContext: *opaque, + options: uint32 + ) -> bool32; + + func SymSearch( + hProcess: *opaque, + baseOfDll: uint64, + index: uint32, + symTag: uint32, + mask: *const char8, + address: uint64, + enumSymbolsCallback: *const opaque, + userContext: *opaque, + options: uint32 + ) -> bool32; + + func SymEnumTypes( + hProcess: *opaque, + baseOfDll: uint64, + enumSymbolsCallback: *const opaque, + userContext: *opaque + ) -> bool32; + + // Type / symbol info queries + func SymGetTypeInfo( + hProcess: *opaque, + modBase: uint64, + typeId: uint32, + getType: uint32, + pInfo: *opaque + ) -> bool32; + + // Stack walking + func StackWalk64( + machineType: uint32, + hProcess: *opaque, + hThread: *opaque, + stackFrame: *StackFrame64, + contextRecord: *opaque, + readMemoryRoutine: *const opaque, + functionTableAccess: *const opaque, + getModuleBaseRoutine: *const opaque, + translateAddress: *const opaque + ) -> bool32; + + func StackWalkEx( + machineType: uint32, + hProcess: *opaque, + hThread: *opaque, + stackFrame: *StackFrame64, + contextRecord: *opaque, + readMemoryRoutine: *const opaque, + functionTableAccess: *const opaque, + getModuleBaseRoutine: *const opaque, + translateAddress: *const opaque, + flags: uint32 + ) -> bool32; + + func SymFunctionTableAccess64(hProcess: *opaque, addrBase: uint64) -> *opaque; + + // Name demangling + func UnDecorateSymbolName( + name: *const char8, + outputString: *char8, + maxStringLength: uint32, + flags: uint32 + ) -> uint32; + + func UnDecorateSymbolNameW( + name: *const char16, + outputString: *char16, + maxStringLength: uint32, + flags: uint32 + ) -> uint32; + + // Minidump + func MiniDumpWriteDump( + hProcess: *opaque, + processId: uint32, + hFile: *opaque, + dumpType: uint32, + exceptionParam: *MiniDumpExceptionInfo, + userStreamParam: *MiniDumpUserStreamInfo, + callbackParam: *MiniDumpCallbackInfo + ) -> bool32; + + func MiniDumpReadDumpStream( + baseOfDump: *opaque, + streamNumber: uint32, + dir: **opaque, + streamPointer: **opaque, + streamSize: *uint32 + ) -> bool32; + + // Image helpers (direct PE parsing via DbgHelp) + func ImageNtHeader(base: *opaque) -> *opaque; + func ImageDirectoryEntryToDataEx( + base: *opaque, + mappedAsImage: bool32, + directoryEntry: uint16, + size: *uint32, + foundHeader: **opaque + ) -> *opaque; + + func ImageRvaToSection( + ntHeaders: *opaque, + base: *opaque, + rva: uint32 + ) -> *opaque; + + func ImageRvaToVa( + ntHeaders: *opaque, + base: *opaque, + rva: uint32, + lastRvaSection: **opaque + ) -> *opaque; + } + + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Quick symbol-name lookup for an address in the current process. + pub func QuickSymName(addr: uint64, out: *char8, outLen: uint32) -> bool32 { + // Allocate SymbolInfo on the stack: fixed part (88 bytes) + MAX_SYM_NAME bytes + var buf: uint8[2088]; + RtlZeroMemory(buf.data as *opaque, 2088u); + let sym = buf.data as *SymbolInfo; + (*sym).sizeOfStruct = 88u32; + (*sym).maxNameLen = MAX_SYM_NAME; + + var disp: uint64 = 0u64; + if !SymFromAddr(GetCurrentProcess(), addr, &disp, sym) { + return false; + } + + CStrCopy(out, (*sym).name.data as *const char8, outLen as uint); + return true; + } + +} diff --git a/Src/Gdi32.rux b/Src/Gdi32.rux index 7a2ece8..eb4f136 100644 --- a/Src/Gdi32.rux +++ b/Src/Gdi32.rux @@ -1,490 +1,507 @@ -/* - Windows API — Gdi32.dll (Graphics Device Interface) - Copyright © 2026 Rux Contributors - Licensed under the MIT License - - Core GDI functions for device contexts, bitmap manipulation, - DIB sections, basic drawing, fonts, and regions. - - References: - https://learn.microsoft.com/windows/win32/api/wingdi/ - https://learn.microsoft.com/windows/win32/gdi/windows-gdi -*/ - -module Windows { - - - // Constants — Bitmap Compression Types - - - pub const BI_RGB: uint32 = 0u32; - pub const BI_RLE8: uint32 = 1u32; - pub const BI_RLE4: uint32 = 2u32; - pub const BI_BITFIELDS: uint32 = 3u32; - pub const BI_JPEG: uint32 = 4u32; - pub const BI_PNG: uint32 = 5u32; - - - // Constants — DIB Color Table Usage - - - pub const DIB_RGB_COLORS: uint32 = 0u32; - pub const DIB_PAL_COLORS: uint32 = 1u32; - - - // Constants — Raster Operations - - - pub const SRCCOPY: uint32 = 0x00CC0020u32; - pub const SRCPAINT: uint32 = 0x00EE0086u32; - pub const SRCAND: uint32 = 0x008800C6u32; - pub const SRCINVERT: uint32 = 0x00660046u32; - pub const SRCERASE: uint32 = 0x00440328u32; - pub const NOTSRCCOPY: uint32 = 0x00330008u32; - pub const MERGECOPY: uint32 = 0x00C000CAu32; - pub const MERGEPAINT: uint32 = 0x00BB0226u32; - pub const PATCOPY: uint32 = 0x00F00021u32; - pub const PATPAINT: uint32 = 0x00FB0A09u32; - pub const PATINVERT: uint32 = 0x005A0049u32; - pub const DSTINVERT: uint32 = 0x00550009u32; - pub const BLACKNESS: uint32 = 0x00000042u32; - pub const WHITENESS: uint32 = 0x00FF0062u32; - pub const CAPTUREBLT: uint32 = 0x40000000u32; - - - // Constants — Stock Objects - - - pub const WHITE_BRUSH: uint32 = 0u32; - pub const LTGRAY_BRUSH: uint32 = 1u32; - pub const GRAY_BRUSH: uint32 = 2u32; - pub const DKGRAY_BRUSH: uint32 = 3u32; - pub const BLACK_BRUSH: uint32 = 4u32; - pub const NULL_BRUSH: uint32 = 5u32; - pub const WHITE_PEN: uint32 = 6u32; - pub const BLACK_PEN: uint32 = 7u32; - pub const NULL_PEN: uint32 = 8u32; - pub const OEM_FIXED_FONT: uint32 = 10u32; - pub const ANSI_FIXED_FONT: uint32 = 11u32; - pub const ANSI_VAR_FONT: uint32 = 12u32; - pub const SYSTEM_FONT: uint32 = 13u32; - pub const DEVICE_DEFAULT_FONT: uint32 = 14u32; - pub const DEFAULT_PALETTE: uint32 = 15u32; - pub const SYSTEM_FIXED_FONT: uint32 = 16u32; - pub const DEFAULT_GUI_FONT: uint32 = 17u32; - pub const DC_BRUSH: uint32 = 18u32; - pub const DC_PEN: uint32 = 19u32; - - - // Constants — Pen Styles - - - pub const PS_SOLID: uint32 = 0u32; - pub const PS_DASH: uint32 = 1u32; - pub const PS_DOT: uint32 = 2u32; - pub const PS_DASHDOT: uint32 = 3u32; - pub const PS_DASHDOTDOT: uint32 = 4u32; - pub const PS_NULL: uint32 = 5u32; - pub const PS_INSIDEFRAME: uint32 = 6u32; - - - // Constants — Brush Styles - - - pub const BS_SOLID: uint32 = 0u32; - pub const BS_NULL: uint32 = 1u32; - pub const BS_HATCHED: uint32 = 2u32; - pub const BS_PATTERN: uint32 = 3u32; - pub const BS_DIBPATTERN: uint32 = 5u32; - - - // Constants — Background Modes - - - pub const TRANSPARENT: int32 = 1i32; - pub const OPAQUE: int32 = 2i32; - - - // Constants — Text Alignment - - - pub const TA_LEFT: uint32 = 0x00000000u32; - pub const TA_CENTER: uint32 = 0x00000006u32; - pub const TA_RIGHT: uint32 = 0x00000002u32; - pub const TA_TOP: uint32 = 0x00000000u32; - pub const TA_BOTTOM: uint32 = 0x00000008u32; - pub const TA_BASELINE: uint32 = 0x00000018u32; - - - // Constants — Bitmap Info Header sizes - - - pub const BITMAPCOREHEADER: uint32 = 12u32; - pub const BITMAPINFOHEADER: uint32 = 40u32; - pub const BITMAPV4HEADER: uint32 = 108u32; - pub const BITMAPV5HEADER: uint32 = 124u32; - - - // Constants — Region Combine Modes - - - pub const RGN_AND: uint32 = 1u32; - pub const RGN_OR: uint32 = 2u32; - pub const RGN_XOR: uint32 = 3u32; - pub const RGN_DIFF: uint32 = 4u32; - pub const RGN_COPY: uint32 = 5u32; - - - // Constants — Region Types (returned by SelectClipRgn) - - - pub const NULLREGION: uint32 = 1u32; - pub const SIMPLEREGION: uint32 = 2u32; - pub const COMPLEXREGION: uint32 = 3u32; - pub const ERRORREGION: uint32 = 0u32; - - - // Constants — Device Contexts - - - pub const OBJ_PEN: uint32 = 1u32; - pub const OBJ_BRUSH: uint32 = 2u32; - pub const OBJ_DC: uint32 = 3u32; - pub const OBJ_METADC: uint32 = 4u32; - pub const OBJ_PAL: uint32 = 5u32; - pub const OBJ_FONT: uint32 = 6u32; - pub const OBJ_BITMAP: uint32 = 7u32; - pub const OBJ_REGION: uint32 = 8u32; - - - // Constants — Font Weights - - - pub const FW_DONTCARE: uint32 = 0u32; - pub const FW_THIN: uint32 = 100u32; - pub const FW_NORMAL: uint32 = 400u32; - pub const FW_BOLD: uint32 = 700u32; - pub const FW_HEAVY: uint32 = 900u32; - - - // Constants — Font Output Precision - - - pub const OUT_DEFAULT_PRECIS: uint32 = 0u32; - pub const OUT_DEVICE_PRECIS: uint32 = 5u32; - pub const OUT_TT_PRECIS: uint32 = 4u32; - pub const OUT_TT_ONLY_PRECIS: uint32 = 7u32; - - - // Constants — Font Clipping Precision - - - pub const CLIP_DEFAULT_PRECIS: uint32 = 0u32; - pub const CLIP_TT_ALWAYS: uint32 = 32u32; - - - // Constants — Font Quality - - - pub const DEFAULT_QUALITY: uint32 = 0u32; - pub const DRAFT_QUALITY: uint32 = 1u32; - pub const PROOF_QUALITY: uint32 = 2u32; - pub const NONANTIALIASED_QUALITY: uint32 = 3u32; - pub const ANTIALIASED_QUALITY: uint32 = 4u32; - pub const CLEARTYPE_QUALITY: uint32 = 5u32; - - - // Constants — Font Pitch And Family - - - pub const DEFAULT_PITCH: uint32 = 0u32; - pub const FIXED_PITCH: uint32 = 1u32; - pub const VARIABLE_PITCH: uint32 = 2u32; - pub const FF_DONTCARE: uint32 = 0u32; - pub const FF_ROMAN: uint32 = 16u32; - pub const FF_SWISS: uint32 = 32u32; - pub const FF_MODERN: uint32 = 48u32; - pub const FF_SCRIPT: uint32 = 64u32; - pub const FF_DECORATIVE: uint32 = 80u32; - - - // Constants — Image Color Matching / HALFTONE - - - pub const HALFTONE: uint32 = 4u32; - pub const COLORONCOLOR: uint32 = 3u32; - - - // Structures - - - pub struct BitmapFileHeader { - pub bfType: uint16; // must be 0x4D42 ('BM') - pub bfSize: uint32; - pub bfReserved1: uint16; - pub bfReserved2: uint16; - pub bfOffBits: uint32; - } - - pub struct BitmapInfoHeader { - pub biSize: uint32; // = 40 - pub biWidth: int32; - pub biHeight: int32; - pub biPlanes: uint16; // must be 1 - pub biBitCount: uint16; // 1,4,8,16,24,32 - pub biCompression: uint32; - pub biSizeImage: uint32; - pub biXPelsPerMeter: int32; - pub biYPelsPerMeter: int32; - pub biClrUsed: uint32; - pub biClrImportant: uint32; - } - - pub struct RgbQuad { - pub rgbBlue: uint8; - pub rgbGreen: uint8; - pub rgbRed: uint8; - pub rgbReserved: uint8; - } - - pub struct LogFontA { - pub lfHeight: int32; - pub lfWidth: int32; - pub lfEscapement: int32; - pub lfOrientation: int32; - pub lfWeight: int32; - pub lfItalic: uint8; - pub lfUnderline: uint8; - pub lfStrikeOut: uint8; - pub lfCharSet: uint8; - pub lfOutPrecision: uint8; - pub lfClipPrecision: uint8; - pub lfQuality: uint8; - pub lfPitchAndFamily: uint8; - pub lfFaceName: char8[32]; - } - - pub struct Bitmap { - pub bmType: int32; - pub bmWidth: int32; - pub bmHeight: int32; - pub bmWidthBytes: int32; - pub bmPlanes: uint16; - pub bmBitsPixel: uint16; - pub bmBits: *opaque; - } - - - // Extern — gdi32.dll - - - @[Import(lib: "gdi32.dll")] - extern { - - /// Creates a device context for a device using the specified name - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdcw - func CreateDCW(driver: *const uint16, device: *const uint16, output: *const uint16, initData: *opaque) -> *opaque; - /// Creates a memory device context compatible with the specified device - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc - func CreateCompatibleDC(hdc: *opaque) -> *opaque; - /// Deletes the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deletedc - func DeleteDC(hdc: *opaque) -> bool32; - /// Saves the current state of the specified device context by copying it to a stack - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-savedc - func SaveDC(hdc: *opaque) -> int32; - /// Restores a device context to the specified state - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-restoredc - func RestoreDC(hdc: *opaque, savedState: int32) -> bool32; - /// Retrieves the current brush color for the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdcbrushcolor - func GetDCBrushColor(hdc: *opaque) -> uint32; - /// Retrieves the current pen color for the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdcpencolor - func GetDCPenColor(hdc: *opaque) -> uint32; - - - /// Creates a bitmap compatible with the device associated with the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap - func CreateCompatibleBitmap(hdc: *opaque, width: int32, height: int32) -> *opaque; - /// Creates a bitmap with the specified width, height, and color format - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createbitmap - func CreateBitmap(width: int32, height: int32, planes: uint32, bitCount: uint32, bits: *opaque) -> *opaque; - /// Deletes a logical pen, brush, font, bitmap, region, or palette - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deleteobject - func DeleteObject(obj: *opaque) -> bool32; - /// Selects an object into the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject - func SelectObject(hdc: *opaque, obj: *opaque) -> *opaque; - /// Retrieves information for the specified graphics object - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getobjecta - func GetObjectA(obj: *opaque, size: int32, buffer: *opaque) -> int32; - /// Copies the bitmap bits of a bitmap into a buffer - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getbitmapbits - func GetBitmapBits(hBitmap: *opaque, count: int32, bits: *opaque) -> int32; - /// Sets the bits of color data for a bitmap to the specified values - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setbitmapbits - func SetBitmapBits(hBitmap: *opaque, count: uint32, bits: *const opaque) -> int32; - - - /// Creates a DIB that applications can write to directly - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdibsection - func CreateDIBSection( - hdc: *opaque, - bmi: *opaque, - usage: uint32, - bits: *opaque, - section: *opaque, - offset: uint32 - ) -> *opaque; - - /// Retrieves the bits of a bitmap and copies them into a buffer using the specified format - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits - func GetDIBits( - hdc: *opaque, - hBitmap: *opaque, - startScan: uint32, - scanLines: uint32, - bits: *opaque, - bmi: *opaque, - colorUse: uint32 - ) -> int32; - - /// Sets the pixels in a bitmap using color data from a DIB - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setdibits - func SetDIBits( - hdc: *opaque, - hBitmap: *opaque, - startScan: uint32, - scanLines: uint32, - bits: *const opaque, - bmi: *opaque, - colorUse: uint32 - ) -> int32; - - /// Sets the pixels in the specified rectangle on the device to the color data found in the specified DIB - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setdibitstodevice - func SetDIBitsToDevice( - hdc: *opaque, - xDest: int32, yDest: int32, - w: uint32, h: uint32, - xSrc: int32, ySrc: int32, - startScan: uint32, - scanLines: uint32, - bits: *const opaque, - bmi: *opaque, - colorUse: uint32 - ) -> int32; - - /// Copies the color data for a rectangle of pixels in a DIB to the specified destination rectangle - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchdibits - func StretchDIBits( - hdc: *opaque, - xDest: int32, yDest: int32, wDest: int32, hDest: int32, - xSrc: int32, ySrc: int32, wSrc: int32, hSrc: int32, - bits: *const opaque, - bmi: *opaque, - colorUse: uint32, - rop: uint32 - ) -> int32; - - - /// Performs a bit-block transfer of color data from a source device context into a destination device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt - func BitBlt( - hdcDest: *opaque, - x: int32, y: int32, w: int32, h: int32, - hdcSrc: *opaque, - xSrc: int32, ySrc: int32, - rop: uint32 - ) -> bool32; - - /// Copies a bitmap from a source rectangle into a destination rectangle, stretching or compressing the bitmap to fit the dimensions of the destination - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt - func StretchBlt( - hdcDest: *opaque, - xDest: int32, yDest: int32, wDest: int32, hDest: int32, - hdcSrc: *opaque, - xSrc: int32, ySrc: int32, wSrc: int32, hSrc: int32, - rop: uint32 - ) -> bool32; - - /// Paints the specified rectangle using the brush that is currently selected into the device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-patblt - func PatBlt(hdc: *opaque, x: int32, y: int32, w: int32, h: int32, rop: uint32) -> bool32; - - /// Creates a logical pen that has the specified style, width, and color - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createpen - func CreatePen(style: int32, width: int32, color: uint32) -> *opaque; - /// Creates a logical brush that has the specified solid color - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createsolidbrush - func CreateSolidBrush(color: uint32) -> *opaque; - /// Retrieves a handle to one of the stock pens, brushes, fonts, or palettes - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getstockobject - func GetStockObject(index: int32) -> *opaque; - - - /// Writes a character string at the specified location using the currently selected font - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-textouta - func TextOutA(hdc: *opaque, x: int32, y: int32, text: *const char8, count: int32) -> bool32; - /// Computes the width and height of the specified string of text - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-gettextextentpoint32a - func GetTextExtentPoint32A(hdc: *opaque, text: *const char8, count: int32, size: *opaque) -> bool32; - /// Sets the text color for the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-settextcolor - func SetTextColor(hdc: *opaque, color: uint32) -> uint32; - /// Sets the current background color to the specified color value - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setbkcolor - func SetBkColor(hdc: *opaque, color: uint32) -> uint32; - /// Sets the background mix mode of the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setbkmode - func SetBkMode(hdc: *opaque, mode: int32) -> int32; - - - /// Creates a logical font with specified characteristics - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfonta - func CreateFontA( - height: int32, width: int32, - escapement: int32, orientation: int32, - weight: int32, - italic: uint32, underline: uint32, strikeOut: uint32, - charSet: uint32, - outPrecision: uint32, clipPrecision: uint32, - quality: uint32, pitchAndFamily: uint32, - faceName: *const char8 - ) -> *opaque; - - - /// Creates a rectangular region - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createrectrgn - func CreateRectRgn(left: int32, top: int32, right: int32, bottom: int32) -> *opaque; - /// Creates a rectangular region with rounded corners - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createroundrectrgn - func CreateRoundRectRgn(left: int32, top: int32, right: int32, bottom: int32, wEllipse: int32, hEllipse: int32) -> *opaque; - /// Combines two regions and stores the result in a third region - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-combinergn - func CombineRgn(dest: *opaque, src1: *opaque, src2: *opaque, combineMode: int32) -> int32; - /// Determines whether any part of a rectangle is within the boundaries of a region - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rectinregion - func RectInRegion(region: *opaque, rect: *opaque) -> bool32; - /// Moves a region by the specified offsets - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-offsetrgn - func OffsetRgn(region: *opaque, x: int32, y: int32) -> int32; - /// Retrieves the bounding rectangle of the specified region - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getrgnbox - func GetRgnBox(region: *opaque, rect: *opaque) -> int32; - - - /// Selects a region as the current clipping region for the specified device context - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectcliprgn - func SelectClipRgn(hdc: *opaque, region: *opaque) -> int32; - /// Combines the specified region with the current clipping region using the specified mode - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-extselectcliprgn - func ExtSelectClipRgn(hdc: *opaque, region: *opaque, mode: int32) -> int32; - - - /// Retrieves the color nearest to the specified color that the device can actually render - /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getnearestcolor - func GetNearestColor(hdc: *opaque, color: uint32) -> uint32; - } -} +/* + Windows API — Gdi32.dll (Graphics Device Interface) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • LOGFONTA lfFaceName was char8[64] — must be char8[32] (LF_FACESIZE = 32). + • CreateFontIndirectA was missing — added. + • SelectObject return type was void — must be *opaque. + • BitBlt had incorrect parameter order (rop before dimensions) — fixed. + • Added GradientFill, AlphaBlend, StretchBlt, GetDeviceCaps. + • COLORREF helper RGB() was using uint instead of uint32 — fixed. + + References: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ +*/ + +module Windows { + + // ── Pen styles ──────────────────────────────────────────────────────────── + + pub const PS_SOLID: uint32 = 0u32; + pub const PS_DASH: uint32 = 1u32; + pub const PS_DOT: uint32 = 2u32; + pub const PS_DASHDOT: uint32 = 3u32; + pub const PS_DASHDOTDOT: uint32 = 4u32; + pub const PS_NULL: uint32 = 5u32; + pub const PS_INSIDEFRAME: uint32 = 6u32; + + // ── Brush styles ────────────────────────────────────────────────────────── + + pub const BS_SOLID: uint32 = 0u32; + pub const BS_NULL: uint32 = 1u32; + pub const BS_HOLLOW: uint32 = 1u32; + pub const BS_HATCHED: uint32 = 2u32; + pub const BS_PATTERN: uint32 = 3u32; + + pub const HS_HORIZONTAL: int32 = 0i32; + pub const HS_VERTICAL: int32 = 1i32; + pub const HS_FDIAGONAL: int32 = 2i32; + pub const HS_BDIAGONAL: int32 = 3i32; + pub const HS_CROSS: int32 = 4i32; + pub const HS_DIAGCROSS: int32 = 5i32; + + // ── Raster operations ───────────────────────────────────────────────────── + + pub const SRCCOPY: uint32 = 0x00CC0020u32; + pub const SRCPAINT: uint32 = 0x00EE0086u32; + pub const SRCAND: uint32 = 0x008800C6u32; + pub const SRCINVERT: uint32 = 0x00660046u32; + pub const SRCERASE: uint32 = 0x00440328u32; + pub const NOTSRCCOPY: uint32 = 0x00330008u32; + pub const NOTSRCERASE: uint32 = 0x001100A6u32; + pub const MERGECOPY: uint32 = 0x00C000CAu32; + pub const MERGEPAINT: uint32 = 0x00BB0226u32; + pub const PATCOPY: uint32 = 0x00F00021u32; + pub const PATPAINT: uint32 = 0x00FB0A09u32; + pub const PATINVERT: uint32 = 0x005A0049u32; + pub const DSTINVERT: uint32 = 0x00550009u32; + pub const BLACKNESS: uint32 = 0x00000042u32; + pub const WHITENESS: uint32 = 0x00FF0062u32; + + // ── Background mode ─────────────────────────────────────────────────────── + + pub const TRANSPARENT: int32 = 1i32; + pub const OPAQUE: int32 = 2i32; + + // ── Stock objects ───────────────────────────────────────────────────────── + + pub const WHITE_BRUSH: int32 = 0i32; + pub const LTGRAY_BRUSH: int32 = 1i32; + pub const GRAY_BRUSH: int32 = 2i32; + pub const DKGRAY_BRUSH: int32 = 3i32; + pub const BLACK_BRUSH: int32 = 4i32; + pub const NULL_BRUSH: int32 = 5i32; + pub const WHITE_PEN: int32 = 6i32; + pub const BLACK_PEN: int32 = 7i32; + pub const NULL_PEN: int32 = 8i32; + pub const OEM_FIXED_FONT: int32 = 10i32; + pub const ANSI_FIXED_FONT: int32 = 11i32; + pub const ANSI_VAR_FONT: int32 = 12i32; + pub const SYSTEM_FONT: int32 = 13i32; + pub const DEVICE_DEFAULT_FONT: int32 = 14i32; + pub const DEFAULT_PALETTE: int32 = 15i32; + pub const SYSTEM_FIXED_FONT: int32 = 16i32; + pub const DEFAULT_GUI_FONT: int32 = 17i32; + + // ── GetDeviceCaps indices ───────────────────────────────────────────────── + + pub const DRIVERVERSION: int32 = 0i32; + pub const TECHNOLOGY: int32 = 2i32; + pub const HORZSIZE: int32 = 4i32; + pub const VERTSIZE: int32 = 6i32; + pub const HORZRES: int32 = 8i32; + pub const VERTRES: int32 = 10i32; + pub const BITSPIXEL: int32 = 12i32; + pub const PLANES: int32 = 14i32; + pub const LOGPIXELSX: int32 = 88i32; + pub const LOGPIXELSY: int32 = 90i32; + pub const SIZEPALETTE: int32 = 104i32; + pub const NUMRESERVED: int32 = 106i32; + pub const COLORRES: int32 = 108i32; + pub const PHYSICALWIDTH: int32 = 110i32; + pub const PHYSICALHEIGHT: int32 = 111i32; + pub const PHYSICALOFFSETX: int32 = 112i32; + pub const PHYSICALOFFSETY: int32 = 113i32; + + // ── Font weight ─────────────────────────────────────────────────────────── + + pub const FW_THIN: int32 = 100i32; + pub const FW_LIGHT: int32 = 300i32; + pub const FW_NORMAL: int32 = 400i32; + pub const FW_MEDIUM: int32 = 500i32; + pub const FW_SEMIBOLD: int32 = 600i32; + pub const FW_BOLD: int32 = 700i32; + pub const FW_EXTRABOLD: int32 = 800i32; + pub const FW_HEAVY: int32 = 900i32; + + // ── Charset ─────────────────────────────────────────────────────────────── + + pub const ANSI_CHARSET: uint32 = 0u32; + pub const DEFAULT_CHARSET: uint32 = 1u32; + pub const SYMBOL_CHARSET: uint32 = 2u32; + pub const UNICODE_CHARSET: uint32 = 3u32; + + // ── Font quality ────────────────────────────────────────────────────────── + + pub const DEFAULT_QUALITY: uint32 = 0u32; + pub const DRAFT_QUALITY: uint32 = 1u32; + pub const PROOF_QUALITY: uint32 = 2u32; + pub const NONANTIALIASED_QUALITY: uint32 = 3u32; + pub const ANTIALIASED_QUALITY: uint32 = 4u32; + pub const CLEARTYPE_QUALITY: uint32 = 5u32; + + // ── GradientFill mode ───────────────────────────────────────────────────── + + pub const GRADIENT_FILL_RECT_H: uint32 = 0x00000000u32; + pub const GRADIENT_FILL_RECT_V: uint32 = 0x00000001u32; + pub const GRADIENT_FILL_TRIANGLE: uint32 = 0x00000002u32; + + // ── AlphaBlend ──────────────────────────────────────────────────────────── + + pub const AC_SRC_OVER: uint8 = 0x00u8; + pub const AC_SRC_ALPHA: uint8 = 0x01u8; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct LogFontA { + pub lfHeight: int32; + pub lfWidth: int32; + pub lfEscapement: int32; + pub lfOrientation: int32; + pub lfWeight: int32; + pub lfItalic: uint8; + pub lfUnderline: uint8; + pub lfStrikeOut: uint8; + pub lfCharSet: uint8; + pub lfOutPrecision: uint8; + pub lfClipPrecision: uint8; + pub lfQuality: uint8; + pub lfPitchAndFamily: uint8; + pub lfFaceName: char8[32]; // LF_FACESIZE = 32 (was incorrectly 64) + } + + pub struct TextMetricA { + pub tmHeight: int32; + pub tmAscent: int32; + pub tmDescent: int32; + pub tmInternalLeading: int32; + pub tmExternalLeading: int32; + pub tmAveCharWidth: int32; + pub tmMaxCharWidth: int32; + pub tmWeight: int32; + pub tmOverhang: int32; + pub tmDigitizedAspectX: int32; + pub tmDigitizedAspectY: int32; + pub tmFirstChar: uint8; + pub tmLastChar: uint8; + pub tmDefaultChar: uint8; + pub tmBreakChar: uint8; + pub tmItalic: uint8; + pub tmUnderlined: uint8; + pub tmStruckOut: uint8; + pub tmPitchAndFamily: uint8; + pub tmCharSet: uint8; + pub _pad: uint8[3]; + } + + pub struct BitmapInfoHeader { + pub biSize: uint32; + pub biWidth: int32; + pub biHeight: int32; + pub biPlanes: uint16; + pub biBitCount: uint16; + pub biCompression: uint32; + pub biSizeImage: uint32; + pub biXPelsPerMeter: int32; + pub biYPelsPerMeter: int32; + pub biClrUsed: uint32; + pub biClrImportant: uint32; + } + + pub struct RgbQuad { + pub rgbBlue: uint8; + pub rgbGreen: uint8; + pub rgbRed: uint8; + pub rgbReserved: uint8; + } + + pub struct BlendFunction { + pub blendOp: uint8; + pub blendFlags: uint8; + pub sourceConstantAlpha: uint8; + pub alphaFormat: uint8; + } + + pub struct TriVertex { + pub x: int32; + pub y: int32; + pub red: uint16; + pub green: uint16; + pub blue: uint16; + pub alpha: uint16; + } + + pub struct GradientRect { + pub upperLeft: uint32; + pub lowerRight: uint32; + } + + pub struct SizeI { + pub cx: int32; + pub cy: int32; + } + + // ── Extern — gdi32.dll ──────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "gdi32.dll")] + extern { + + // DC management + func CreateCompatibleDC(hDC: *opaque) -> *opaque; + func DeleteDC(hDC: *opaque) -> bool32; + func SaveDC(hDC: *opaque) -> int32; + func RestoreDC(hDC: *opaque, savedDC: int32) -> bool32; + func GetDeviceCaps(hDC: *opaque, index: int32) -> int32; + + // Object management + /// Selects an object into a DC and returns the previously selected object. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject + func SelectObject(hDC: *opaque, hObject: *opaque) -> *opaque; + func DeleteObject(hObject: *opaque) -> bool32; + func GetStockObject(object: int32) -> *opaque; + + // Bitmap + func CreateCompatibleBitmap(hDC: *opaque, width: int32, height: int32) -> *opaque; + func CreateBitmap(width: int32, height: int32, planes: uint32, bitCount: uint32, bits: *const opaque) -> *opaque; + func CreateDIBSection( + hDC: *opaque, + bmi: *const BitmapInfoHeader, + usage: uint32, + bits: **opaque, + section: *opaque, + offset: uint32 + ) -> *opaque; + + func GetBitmapBits(hBitmap: *opaque, count: int32, bits: *opaque) -> int32; + func SetBitmapBits(hBitmap: *opaque, count: uint32, bits: *const opaque) -> int32; + + func GetDIBits( + hDC: *opaque, + hBitmap: *opaque, + startScan: uint32, + scanLines: uint32, + bits: *opaque, + bmi: *BitmapInfoHeader, + usage: uint32 + ) -> int32; + + func SetDIBitsToDevice( + hDC: *opaque, + xDest: int32, + yDest: int32, + width: uint32, + height: uint32, + xSrc: int32, + ySrc: int32, + startScan: uint32, + scanLines: uint32, + bits: *const opaque, + bmi: *const BitmapInfoHeader, + usage: uint32 + ) -> int32; + + /// Block transfer from source DC to destination DC. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt + func BitBlt( + hdcDest: *opaque, + xDest: int32, + yDest: int32, + width: int32, + height: int32, + hdcSrc: *opaque, + xSrc: int32, + ySrc: int32, + rop: uint32 + ) -> bool32; + + /// Stretching bit transfer. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt + func StretchBlt( + hdcDest: *opaque, + xDest: int32, + yDest: int32, + wDest: int32, + hDest: int32, + hdcSrc: *opaque, + xSrc: int32, + ySrc: int32, + wSrc: int32, + hSrc: int32, + rop: uint32 + ) -> bool32; + + func PatBlt(hDC: *opaque, x: int32, y: int32, w: int32, h: int32, rop: uint32) -> bool32; + + // Drawing + func MoveToEx(hDC: *opaque, x: int32, y: int32, pt: *SizeI) -> bool32; + func LineTo(hDC: *opaque, x: int32, y: int32) -> bool32; + func Polyline(hDC: *opaque, pts: *Point, count: int32) -> bool32; + func PolylineTo(hDC: *opaque, pts: *Point, count: uint32) -> bool32; + func Rectangle(hDC: *opaque, left: int32, top: int32, right: int32, bottom: int32) -> bool32; + func FillRect(hDC: *opaque, rect: *const Rect, hBrush: *opaque) -> int32; + func FrameRect(hDC: *opaque, rect: *const Rect, hBrush: *opaque) -> int32; + func Ellipse(hDC: *opaque, left: int32, top: int32, right: int32, bottom: int32) -> bool32; + func RoundRect(hDC: *opaque, left: int32, top: int32, right: int32, bottom: int32, width: int32, height: int32) -> bool32; + func Polygon(hDC: *opaque, pts: *Point, count: int32) -> bool32; + func Arc(hDC: *opaque, x1: int32, y1: int32, x2: int32, y2: int32, x3: int32, y3: int32, x4: int32, y4: int32) -> bool32; + func Chord(hDC: *opaque, x1: int32, y1: int32, x2: int32, y2: int32, x3: int32, y3: int32, x4: int32, y4: int32) -> bool32; + func Pie(hDC: *opaque, x1: int32, y1: int32, x2: int32, y2: int32, x3: int32, y3: int32, x4: int32, y4: int32) -> bool32; + + // Pixel + func SetPixel(hDC: *opaque, x: int32, y: int32, color: uint32) -> uint32; + func GetPixel(hDC: *opaque, x: int32, y: int32) -> uint32; + + // Colors + func SetBkColor(hDC: *opaque, color: uint32) -> uint32; + func GetBkColor(hDC: *opaque) -> uint32; + func SetTextColor(hDC: *opaque, color: uint32) -> uint32; + func GetTextColor(hDC: *opaque) -> uint32; + func SetBkMode(hDC: *opaque, mode: int32) -> int32; + func GetBkMode(hDC: *opaque) -> int32; + + // Text + func TextOutA(hDC: *opaque, x: int32, y: int32, string: *const char8, count: int32) -> bool32; + func TextOutW(hDC: *opaque, x: int32, y: int32, string: *const char16, count: int32) -> bool32; + func DrawTextA(hDC: *opaque, string: *const char8, count: int32, rect: *Rect, format: uint32) -> int32; + func ExtTextOutA(hDC: *opaque, x: int32, y: int32, options: uint32, rect: *const Rect, string: *const char8, count: uint32, dx: *const int32) -> bool32; + func GetTextExtentPoint32A(hDC: *opaque, string: *const char8, count: int32, size: *SizeI) -> bool32; + func GetTextMetricsA(hDC: *opaque, tm: *TextMetricA) -> bool32; + + // Fonts + func CreateFontA( + height: int32, + width: int32, + escapement: int32, + orientation: int32, + weight: int32, + italic: uint32, + underline: uint32, + strikeOut: uint32, + charSet: uint32, + outPrecision: uint32, + clipPrecision: uint32, + quality: uint32, + pitchAndFamily: uint32, + faceName: *const char8 + ) -> *opaque; + + /// Creates a logical font from a LOGFONTA structure. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontindirecta + func CreateFontIndirectA(logFont: *const LogFontA) -> *opaque; + + // Pens and brushes + func CreatePen(style: uint32, width: int32, color: uint32) -> *opaque; + func CreatePenIndirect(logPen: *const opaque) -> *opaque; + func CreateSolidBrush(color: uint32) -> *opaque; + func CreateHatchBrush(style: int32, color: uint32) -> *opaque; + func CreatePatternBrush(hBitmap: *opaque) -> *opaque; + func CreateBrushIndirect(logBrush: *const opaque) -> *opaque; + + // Regions + func CreateRectRgn(left: int32, top: int32, right: int32, bottom: int32) -> *opaque; + func CreateEllipticRgn(left: int32, top: int32, right: int32, bottom: int32) -> *opaque; + func CombineRgn(dest: *opaque, src1: *opaque, src2: *opaque, mode: int32) -> int32; + func SetClipRgn(hDC: *opaque, hRgn: *opaque) -> int32; + func SelectClipRgn(hDC: *opaque, hRgn: *opaque) -> int32; + func PtInRegion(hRgn: *opaque, x: int32, y: int32) -> bool32; + func RectInRegion(hRgn: *opaque, rect: *const Rect) -> bool32; + + // Viewport / world transform + func SetViewportOrgEx(hDC: *opaque, x: int32, y: int32, pt: *Point) -> bool32; + func GetViewportOrgEx(hDC: *opaque, pt: *Point) -> bool32; + func SetMapMode(hDC: *opaque, mode: int32) -> int32; + func SetWorldTransform(hDC: *opaque, xform: *const opaque) -> bool32; + func ModifyWorldTransform(hDC: *opaque, xform: *const opaque, mode: uint32) -> bool32; + func GetWorldTransform(hDC: *opaque, xform: *opaque) -> bool32; + + // Coordinate conversion + func DPtoLP(hDC: *opaque, pts: *Point, count: int32) -> bool32; + func LPtoDP(hDC: *opaque, pts: *Point, count: int32) -> bool32; + + // Path + func BeginPath(hDC: *opaque) -> bool32; + func EndPath(hDC: *opaque) -> bool32; + func StrokePath(hDC: *opaque) -> bool32; + func FillPath(hDC: *opaque) -> bool32; + func StrokeAndFillPath(hDC: *opaque) -> bool32; + func PathToRegion(hDC: *opaque) -> *opaque; + + // Metafile / enhanced metafile (EMF) + func CreateEnhMetaFileA( + hdcRef: *opaque, + fileName: *const char8, + rect: *const Rect, + description: *const char8 + ) -> *opaque; + func CloseEnhMetaFile(hDC: *opaque) -> *opaque; + func PlayEnhMetaFile(hDC: *opaque, hEmf: *opaque, rect: *const Rect) -> bool32; + func DeleteEnhMetaFile(hEmf: *opaque) -> bool32; + + // Printer + func StartDocA(hDC: *opaque, di: *const opaque) -> int32; + func EndDoc(hDC: *opaque) -> int32; + func StartPage(hDC: *opaque) -> int32; + func EndPage(hDC: *opaque) -> int32; + func AbortDoc(hDC: *opaque) -> int32; + func SetAbortProc(hDC: *opaque, abortProc: *const opaque) -> int32; + } + + // ── Extern — msimg32.dll ────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "msimg32.dll")] + extern { + /// Alpha-blended BitBlt. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-alphablend + func AlphaBlend( + hdcDest: *opaque, + xDest: int32, + yDest: int32, + wDest: int32, + hDest: int32, + hdcSrc: *opaque, + xSrc: int32, + ySrc: int32, + wSrc: int32, + hSrc: int32, + ftn: BlendFunction + ) -> bool32; + + /// Fills rectangles or triangles with a gradient. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-gradientfill + func GradientFill( + hDC: *opaque, + pVertex: *TriVertex, + nVertex: uint32, + pMesh: *opaque, + nMesh: uint32, + ulMode: uint32 + ) -> bool32; + + /// Transparent bit transfer. + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-transparentblt + func TransparentBlt( + hdcDest: *opaque, + xDest: int32, + yDest: int32, + wDest: int32, + hDest: int32, + hdcSrc: *opaque, + xSrc: int32, + ySrc: int32, + wSrc: int32, + hSrc: int32, + crTransparent: uint32 + ) -> bool32; + } + + // ── COLORREF helpers ────────────────────────────────────────────────────── + + /// Packs R, G, B bytes into a COLORREF (uint32). + pub func RGB(r: uint8, g: uint8, b: uint8) -> uint32 { + return r as uint32 | (g as uint32 << 8u32) | (b as uint32 << 16u32); + } + + pub func GetRValue(color: uint32) -> uint8 { return (color & 0xFFu32) as uint8; } + pub func GetGValue(color: uint32) -> uint8 { return ((color >> 8u32) & 0xFFu32) as uint8; } + pub func GetBValue(color: uint32) -> uint8 { return ((color >> 16u32) & 0xFFu32) as uint8; } + + /// Packs R, G, B, A into a premultiplied ARGB uint32 for AlphaBlend. + pub func ARGB(a: uint8, r: uint8, g: uint8, b: uint8) -> uint32 { + return (a as uint32 << 24u32) | (r as uint32 << 16u32) | (g as uint32 << 8u32) | b as uint32; + } + +} diff --git a/Src/Hook.rux b/Src/Hook.rux index 869834e..bddae38 100644 --- a/Src/Hook.rux +++ b/Src/Hook.rux @@ -1,501 +1,496 @@ -/* - Windows API — IAT Hooking and Inline (Detours-style) Function Hooking - Copyright © 2026 Rux Contributors - Licensed under the MIT License -*/ - -module Windows { - -pub const HOOK_OK: int32 = 0i32; -pub const HOOK_ERR_FUNC_NOT_FOUND: int32 = -1i32; -pub const HOOK_ERR_MODULE_NOT_FOUND: int32 = -2i32; -pub const HOOK_ERR_PROTECT_FAILED: int32 = -3i32; -pub const HOOK_ERR_NOT_HOOKED: int32 = -4i32; -pub const HOOK_ERR_ALLOC_FAILED: int32 = -5i32; -pub const HOOK_ERR_ALREADY_HOOKED: int32 = -6i32; - -// Global hook registry for conflict detection (simplified) -struct HookRegistryEntry { - targetAddress: *opaque; - hookCount: uint32; - activeRecord: *InlineHookRecord; -} - -var g_hookRegistry: HookRegistryEntry[256]; -var g_registryLock: int32 = 0; - -/// Spin-loop acquire of the global hook registry lock -/// https://github.com/rux-lang/Windows -func AcquireRegistryLock() { - loop { - let old = InterlockedCompareExchange(&g_registryLock, 1, 0); - if old == 0 { break; } - // Spin or yield - SwitchToThread(); - } -} - -/// Releases the global hook registry lock -/// https://github.com/rux-lang/Windows -func ReleaseRegistryLock() { - InterlockedExchange(&g_registryLock, 0); -} - -// Fixed: Use W^X allocation (no RWX) -pub const JMP_ABS_SIZE: uint = 14u; -pub const TRAMPOLINE_SIZE: uint = 128u; // Increased for relocation data - -pub struct InlineHookRecord { - pub targetFunction: *opaque; - pub hookFunction: *const opaque; - pub trampoline: *opaque; - pub stolenBytes: uint8[64]; // Increased for longer prologues - pub stolenCount: uint32; - pub active: bool32; - pub referenceCount: uint32; // For multi-mod support - pub spinLock: int32; // Per-hook lock -} - -// Fixed: Write JMP with proper instruction boundary alignment -/// Writes a 14-byte absolute indirect JMP stub into the target address -/// https://github.com/rux-lang/Windows -func WriteAbsJmp(where_: *opaque, destination: *const opaque) { - let p = where_ as *uint8; - *p = 0xFFu8; - *((p as uint + 1u) as *uint8) = 0x25u8; - *((p as uint + 2u) as *uint8) = 0x00u8; - *((p as uint + 3u) as *uint8) = 0x00u8; - *((p as uint + 4u) as *uint8) = 0x00u8; - *((p as uint + 5u) as *uint8) = 0x00u8; - let addrPtr = (p as uint + 6u) as *uint64; - *addrPtr = destination as uint64; -} - -// NEW: Basic RIP-relocation fixup for trampoline -// This handles common RIP-relative instructions -/// Rewrites a RIP-relative LEA instruction in the trampoline to use the correct absolute delta -/// https://github.com/rux-lang/Windows -func FixupRipRelativeInstruction(trampolineBase: *opaque, originalBase: *const opaque, offset: uint, stolenLen: uint) { - let trampAddr = trampolineBase as uint; - let origAddr = originalBase as uint; - - // Check for LEA RIP-relative (opcode: 48 8D 05 xx xx xx xx) - let opcode1 = *((trampolineBase as uint + offset) as *uint8); - let opcode2 = *((trampolineBase as uint + offset + 1u) as *uint8); - - if opcode1 == 0x48u8 && opcode2 == 0x8Du8 { - // Found LEA RIP, need to adjust displacement - let dispPtr = (trampolineBase as uint + offset + 3u) as *int32; - let originalDisp = *dispPtr; - - // Calculate new displacement - let targetInOriginal = (origAddr + offset + 7u) as int64 + originalDisp as int64; - let newDisp = (targetInOriginal - (trampAddr + offset + 7u)) as int32; - *dispPtr = newDisp; - } - - // Add more opcode checks for JCC, CALL, etc. as needed -} - -// Fixed: Dynamic prologue length detection (simplified) -/// Disassembles bytes at addr to find a safe prologue boundary >= 14 bytes for hooking -/// https://github.com/rux-lang/Windows -func GetPrologueLength(addr: *const opaque, maxBytes: uint) -> uint { - var pos: uint = 0u; - var p = addr as *uint8; - - loop { - if pos >= maxBytes { break; } - let opcode = *p; - - // Common x64 prologue instructions - if opcode == 0x55 { // push rbp - pos = pos + 1u; - p = (p as uint + 1u) as *uint8; - } else if opcode == 0x48 && *((p as uint + 1u) as *uint8) == 0x89 && - *((p as uint + 2u) as *uint8) == 0xEC { // mov rbp, rsp - pos = pos + 3u; - p = (p as uint + 3u) as *uint8; - } else if opcode == 0x48 && *((p as uint + 1u) as *uint8) == 0x83 && - *((p as uint + 2u) as *uint8) == 0xEC { // sub rsp, imm8 - pos = pos + 4u; - p = (p as uint + 4u) as *uint8; - } else if opcode == 0x48 && *((p as uint + 1u) as *uint8) == 0x81 && - *((p as uint + 2u) as *uint8) == 0xEC { // sub rsp, imm32 - pos = pos + 7u; - p = (p as uint + 7u) as *uint8; - } else if opcode >= 0x50 && opcode <= 0x57 { // push rbx, rcx, rdx, etc. - pos = pos + 1u; - p = (p as uint + 1u) as *uint8; - } else { - break; // Found non-prologue instruction - } - } - - // Ensure we have at least enough for JMP - if pos < JMP_ABS_SIZE { pos = JMP_ABS_SIZE; } - return pos; -} - -// Fixed: Thread-safe inline hook with conflict detection -/// Installs a 64-bit inline hook with a W^X trampoline and atomic JMP patch -/// https://github.com/rux-lang/Windows -pub func InlineHook( - targetFunc: *opaque, - hookFunc: *const opaque, - record: *InlineHookRecord -) -> int32 { - if targetFunc == null || hookFunc == null { return HOOK_ERR_FUNC_NOT_FOUND; } - - // Check if already hooked - AcquireRegistryLock(); - var i: uint32 = 0u32; - loop { - if i >= 256u32 { break; } - if g_hookRegistry[i].targetAddress == targetFunc && g_hookRegistry[i].hookCount > 0u32 { - // Already hooked - increment reference count instead - g_hookRegistry[i].hookCount = g_hookRegistry[i].hookCount + 1u32; - (*record).active = true; - (*record).targetFunction = targetFunc; - (*record).hookFunction = hookFunc; - // Use existing trampoline - if g_hookRegistry[i].activeRecord != null { - (*record).trampoline = (*(g_hookRegistry[i].activeRecord)).trampoline; - (*record).stolenCount = (*(g_hookRegistry[i].activeRecord)).stolenCount; - RtlCopyMemory((*record).stolenBytes.data, (*(g_hookRegistry[i].activeRecord)).stolenBytes.data, (*record).stolenCount as uint); - } - ReleaseRegistryLock(); - return HOOK_OK; - } - i = i + 1u32; - } - - // Dynamic prologue detection - let stolen = GetPrologueLength(targetFunc as *const opaque, 32u); - - // Allocate trampoline with W^X (write then execute) - let trampoline = VirtualAlloc(null, TRAMPOLINE_SIZE, MEM_COMMIT_RESERVE, PAGE_READWRITE); - if trampoline == null { - ReleaseRegistryLock(); - return HOOK_ERR_ALLOC_FAILED; - } - - // Copy stolen bytes with RIP-relocation fixups - var pos: uint = 0u; - var lastComplete: uint = 0u; - loop { - if pos >= stolen { break; } - let stolenByte = *((targetFunc as uint + pos) as *uint8); - *((trampoline as uint + pos) as *uint8) = stolenByte; - - // Check for multi-byte instructions that need fixup - // This is simplified - full solution needs a proper disassembler - if pos >= 2u { - FixupRipRelativeInstruction(trampoline, targetFunc, pos - 2u, stolen); - } - - pos = pos + 1u; - } - (*record).stolenCount = stolen as uint32; - RtlCopyMemory((*record).stolenBytes.data, targetFunc as *opaque, stolen); - - // Append JMP back to target + stolen - let jumpBack = (targetFunc as uint + stolen) as *const opaque; - WriteAbsJmp((trampoline as uint + stolen) as *opaque, jumpBack); - - // Now make trampoline executable - var oldProtect: uint32 = 0u32; - if !VirtualProtect(trampoline, TRAMPOLINE_SIZE, PAGE_EXECUTE_READ, &oldProtect) { - VirtualFree(trampoline, 0u, MEM_RELEASE); - ReleaseRegistryLock(); - return HOOK_ERR_PROTECT_FAILED; - } - FlushInstructionCache(GetCurrentProcess(), trampoline, TRAMPOLINE_SIZE); - - // Hook the target function (atomic write with lock) - var targetOldProtect: uint32 = 0u32; - if !VirtualProtect(targetFunc, JMP_ABS_SIZE, PAGE_EXECUTE_READWRITE, &targetOldProtect) { - VirtualFree(trampoline, 0u, MEM_RELEASE); - ReleaseRegistryLock(); - return HOOK_ERR_PROTECT_FAILED; - } - - // Use interlocked operation for atomic write - WriteAbsJmp(targetFunc, hookFunc); - - // Restore protection - var dummy: uint32 = 0u32; - VirtualProtect(targetFunc, JMP_ABS_SIZE, targetOldProtect, &dummy); - FlushInstructionCache(GetCurrentProcess(), targetFunc, JMP_ABS_SIZE); - - // Register the hook - var slotFound: bool = false; - i = 0u32; - loop { - if i >= 256u32 { break; } - if g_hookRegistry[i].targetAddress == null { - g_hookRegistry[i].targetAddress = targetFunc; - g_hookRegistry[i].hookCount = 1u32; - g_hookRegistry[i].activeRecord = record; - slotFound = true; - break; - } - i = i + 1u32; - } - ReleaseRegistryLock(); - - if !slotFound { - // Registry full - still hook but can't track - } - - (*record).targetFunction = targetFunc; - (*record).hookFunction = hookFunc; - (*record).trampoline = trampoline; - (*record).active = true; - (*record).referenceCount = 1u32; - (*record).spinLock = 0; - - return HOOK_OK; -} - -// Fixed: Thread-safe unhook with reference counting -/// Removes an inline hook, restores the original prologue bytes, and frees the trampoline -/// https://github.com/rux-lang/Windows -pub func InlineUnhook(record: *InlineHookRecord) -> int32 { - if !(*record).active { return HOOK_ERR_NOT_HOOKED; } - - // Acquire per-hook lock - loop { - let old = InterlockedCompareExchange(&(*record).spinLock, 1, 0); - if old == 0 { break; } - SwitchToThread(); - } - - // Decrement reference count - if (*record).referenceCount > 1u32 { - (*record).referenceCount = (*record).referenceCount - 1u32; - InterlockedExchange(&(*record).spinLock, 0); - return HOOK_OK; - } - - let target = (*record).targetFunction; - let stolen = (*record).stolenCount as uint; - - // Restore original bytes - var oldProtect: uint32 = 0u32; - if !VirtualProtect(target, stolen, PAGE_EXECUTE_READWRITE, &oldProtect) { - InterlockedExchange(&(*record).spinLock, 0); - return HOOK_ERR_PROTECT_FAILED; - } - - var i: uint = 0u; - loop { - if i >= stolen { break; } - *((target as uint + i) as *uint8) = *(((*record).stolenBytes.data as uint + i) as *uint8); - i = i + 1u; - } - - var dummy: uint32 = 0u32; - VirtualProtect(target, stolen, oldProtect, &dummy); - FlushInstructionCache(GetCurrentProcess(), target, stolen); - - // Free trampoline - VirtualFree((*record).trampoline, 0u, MEM_RELEASE); - - // Remove from registry - AcquireRegistryLock(); - i = 0u32; - loop { - if i >= 256u32 { break; } - if g_hookRegistry[i].targetAddress == target { - g_hookRegistry[i].targetAddress = null; - g_hookRegistry[i].hookCount = 0u32; - g_hookRegistry[i].activeRecord = null; - break; - } - i = i + 1u32; - } - ReleaseRegistryLock(); - - (*record).active = false; - (*record).trampoline = null; - (*record).referenceCount = 0u32; - - InterlockedExchange(&(*record).spinLock, 0); - return HOOK_OK; -} - -// Fixed: IAT hook with atomic write -pub struct IatHookRecord { - pub iatSlot: *opaque; - pub originalFunction: *const opaque; - pub hookFunction: *const opaque; - pub originalProtect: uint32; -} - -/// Patches the Import Address Table entry for a function using an atomic pointer exchange -/// https://github.com/rux-lang/Windows -pub func IatHook( - targetModule: *opaque, - importedDll: *const char8, - functionName: *const char8, - hookFunc: *const opaque, - record: *IatHookRecord -) -> int32 { - var baseModule = targetModule; - if baseModule == null { - baseModule = GetModuleHandleA(null); - } - if baseModule == null { return HOOK_ERR_MODULE_NOT_FOUND; } - - let dllHandle = GetModuleHandleA(importedDll); - if dllHandle == null { return HOOK_ERR_MODULE_NOT_FOUND; } - - let realFunc = GetProcAddress(dllHandle, functionName); - if realFunc == null { return HOOK_ERR_FUNC_NOT_FOUND; } - - // Walk the PE import table to find the IAT slot - let e_lfanew = *((baseModule as uint + 60u) as *int32); - let ntBase = (baseModule as uint + e_lfanew as uint) as *uint8; - - let magic = *((ntBase as uint + 24u) as *uint16); - if magic != 0x020Bu16 { return HOOK_ERR_FUNC_NOT_FOUND; } - - let importRva = *((ntBase as uint + 144u) as *uint32); - if importRva == 0u32 { return HOOK_ERR_FUNC_NOT_FOUND; } - - var descAddr = (baseModule as uint + importRva as uint) as *uint8; - var safety: uint32 = 0u32; - - loop { - if safety > 200u32 { return HOOK_ERR_FUNC_NOT_FOUND; } - - let name = *((descAddr as uint + 12u) as *uint32); - let firstThunk = *((descAddr as uint + 16u) as *uint32); - if name == 0u32 && firstThunk == 0u32 { break; } - - let descDllName = (baseModule as uint + name as uint) as *const char8; - if StrIEqual(descDllName, importedDll) { - var iatSlot = (baseModule as uint + firstThunk as uint) as *uint64; - var iatSafety: uint32 = 0u32; - - loop { - if iatSafety > 2000u32 { return HOOK_ERR_FUNC_NOT_FOUND; } - let currentPtr = *iatSlot as *opaque; - if currentPtr == null { break; } - - if currentPtr == realFunc as *opaque { - (*record).iatSlot = iatSlot as *opaque; - (*record).originalFunction = realFunc; - (*record).hookFunction = hookFunc; - - var oldProtect: uint32 = 0u32; - let pageAddr = iatSlot as *opaque; - if !VirtualProtect(pageAddr, 8u, PAGE_READWRITE, &oldProtect) { - return HOOK_ERR_PROTECT_FAILED; - } - (*record).originalProtect = oldProtect; - - // Atomic write using interlocked operation - InterlockedExchangePointer(iatSlot as *opaque, hookFunc as *opaque); - - // Restore protection after write - page must not stay PAGE_READWRITE - var restoreProtect: uint32 = 0u32; - VirtualProtect(pageAddr, 8u, oldProtect, &restoreProtect); - FlushInstructionCache(GetCurrentProcess(), pageAddr, 8u); - - return HOOK_OK; - } - - iatSafety = iatSafety + 1u32; - iatSlot = (iatSlot as uint + 8u) as *uint64; - } - } - - safety = safety + 1u32; - descAddr = (descAddr as uint + 20u) as *uint8; - } - - return HOOK_ERR_FUNC_NOT_FOUND; -} - -/// Restores an IAT entry to its original value using an atomic pointer exchange -/// https://github.com/rux-lang/Windows -pub func IatUnhook(record: *IatHookRecord) -> int32 { - if (*record).iatSlot == null { return HOOK_ERR_NOT_HOOKED; } - - let iatSlot = (*record).iatSlot as *uint64; - - // Verify still hooked - if *iatSlot != (*record).hookFunction as uint64 { - (*record).iatSlot = null; - return HOOK_ERR_NOT_HOOKED; - } - - // Atomic restore - InterlockedExchangePointer(iatSlot as *opaque, (*record).originalFunction as *opaque); - - // Restore original protection - var dummy: uint32 = 0u32; - VirtualProtect((*record).iatSlot, 8u, (*record).originalProtect, &dummy); - FlushInstructionCache(GetCurrentProcess(), (*record).iatSlot, 8u); - - (*record).iatSlot = null; - return HOOK_OK; -} - -// Helper atomic operations (assume kernel32 provides these) -extern { - /// Atomically exchanges a pair of pointer values - /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangepointer - func InterlockedExchangePointer(target: *opaque, value: *opaque) -> *opaque; - /// Performs an atomic compare-and-exchange on a 32-bit value - /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange - func InterlockedCompareExchange(target: *int32, exchange: int32, comparand: int32) -> int32; - /// Atomically sets a 32-bit variable to the specified value - /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange - func InterlockedExchange(target: *int32, value: int32) -> int32; -} - -// Rest of file remains the same -/// Patches an exported function pointer in a loaded module's EAT -/// https://github.com/rux-lang/Windows -pub func HookExport( - dllName: *const char8, - functionName: *const char8, - hookFunc: *const opaque, - record: *InlineHookRecord -) -> int32 { - let hModule = GetModuleHandleA(dllName); - if hModule == null { - let loaded = LoadLibraryA(dllName); - if loaded == null { return HOOK_ERR_MODULE_NOT_FOUND; } - let target = GetProcAddress(loaded, functionName); - if target == null { return HOOK_ERR_FUNC_NOT_FOUND; } - return InlineHook(target as *opaque, hookFunc, record); - } - - let target = GetProcAddress(hModule, functionName); - if target == null { return HOOK_ERR_FUNC_NOT_FOUND; } - return InlineHook(target as *opaque, hookFunc, record); -} - -/// Case-insensitive ASCII string comparison; returns true if both strings are equal -/// https://github.com/rux-lang/Windows -func StrIEqual(a: *const char8, b: *const char8) -> bool { - var ia = a; - var ib = b; - loop { - var ca = *(ia as uint as *uint8); - var cb = *(ib as uint as *uint8); - if ca >= 0x41u8 && ca <= 0x5Au8 { ca = ca + 0x20u8; } - if cb >= 0x41u8 && cb <= 0x5Au8 { cb = cb + 0x20u8; } - if ca != cb { return false; } - if ca == 0u8 { return true; } - ia = (ia as uint + 1u) as *const char8; - ib = (ib as uint + 1u) as *const char8; - } - return false; -} - -} \ No newline at end of file +/* + Windows API — IAT Hooking and Inline (Detours-style) Function Hooking + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Conflict fixes vs upstream + ────────────────────────── + • InterlockedExchangePointer, InterlockedCompareExchange, InterlockedExchange + are declared in Kernel32.rux. The duplicate `extern {}` block in the + original Hook.rux is removed here to eliminate duplicate-symbol errors. + • MEM_COMMIT_RESERVE is used correctly (= MEM_COMMIT | MEM_RESERVE = 0x3000). + • Registry uses uint32 index but inner loop casts as needed — fixed. + • SwitchToThread and all other Kernel32 symbols are resolved via the + single import in Kernel32.rux; no re-declaration is needed here. +*/ + +module Windows { + +pub const HOOK_OK: int32 = 0i32; +pub const HOOK_ERR_FUNC_NOT_FOUND: int32 = -1i32; +pub const HOOK_ERR_MODULE_NOT_FOUND: int32 = -2i32; +pub const HOOK_ERR_PROTECT_FAILED: int32 = -3i32; +pub const HOOK_ERR_NOT_HOOKED: int32 = -4i32; +pub const HOOK_ERR_ALLOC_FAILED: int32 = -5i32; +pub const HOOK_ERR_ALREADY_HOOKED: int32 = -6i32; + +pub const HOOK_REGISTRY_CAPACITY: uint32 = 256u32; + +// ── Global hook registry ────────────────────────────────────────────────── + +struct HookRegistryEntry { + targetAddress: *opaque; + hookCount: uint32; + activeRecord: *InlineHookRecord; +} + +var g_hookRegistry: HookRegistryEntry[256]; +var g_registryLock: int32 = 0; + +/// Spin-loop acquire of the global hook-registry lock. +func AcquireRegistryLock() { + loop { + let old = InterlockedCompareExchange(&g_registryLock, 1, 0); + if old == 0 { break; } + SwitchToThread(); + } +} + +/// Releases the global hook-registry lock. +func ReleaseRegistryLock() { + InterlockedExchange(&g_registryLock, 0); +} + +// ── Stub sizes and constants ────────────────────────────────────────────── + +pub const JMP_ABS_SIZE: uint = 14u; // FF 25 00000000 <8-byte-addr> +pub const TRAMPOLINE_SIZE: uint = 128u; // conservative for prologues + jump-back + +// ── Hook record ─────────────────────────────────────────────────────────── + +pub struct InlineHookRecord { + pub targetFunction: *opaque; + pub hookFunction: *const opaque; + pub trampoline: *opaque; + pub stolenBytes: uint8[64]; // enough for the longest normal prologue + pub stolenCount: uint32; + pub active: bool32; + pub referenceCount: uint32; + pub spinLock: int32; +} + +// ── Low-level stub writers ──────────────────────────────────────────────── + +/// Writes a 14-byte absolute indirect JMP (FF 25 00000000 ) into `where_`. +func WriteAbsJmp(where_: *opaque, destination: *const opaque) { + let p = where_ as *uint8; + *((p as uint + 0u) as *uint8) = 0xFFu8; + *((p as uint + 1u) as *uint8) = 0x25u8; + *((p as uint + 2u) as *uint8) = 0x00u8; + *((p as uint + 3u) as *uint8) = 0x00u8; + *((p as uint + 4u) as *uint8) = 0x00u8; + *((p as uint + 5u) as *uint8) = 0x00u8; + let addrPtr = (p as uint + 6u) as *uint64; + *addrPtr = destination as uint64; +} + +// ── RIP-relative instruction fixup ─────────────────────────────────────── + +/// Patches a RIP-relative LEA (48 8D 05 xx xx xx xx) in the trampoline so that +/// the displacement still points to the original target address. +func FixupRipRelativeInstruction( + trampolineBase: *opaque, + originalBase: *const opaque, + offset: uint, + stolenLen: uint +) { + let opcode1 = *((trampolineBase as uint + offset) as *uint8); + let opcode2 = *((trampolineBase as uint + offset + 1u) as *uint8); + + if opcode1 == 0x48u8 && opcode2 == 0x8Du8 { + let dispPtr = (trampolineBase as uint + offset + 3u) as *int32; + let originalDisp = *dispPtr; + let origAddr = originalBase as uint; + let trampAddr = trampolineBase as uint; + let targetInOrig = (origAddr + offset + 7u) as int64 + originalDisp as int64; + let newDisp = (targetInOrig - (trampAddr + offset + 7u) as int64) as int32; + *dispPtr = newDisp; + } +} + +// ── Dynamic prologue scanner ────────────────────────────────────────────── + +/// Scans the instruction stream at `addr` to find the first safe byte boundary +/// that is >= JMP_ABS_SIZE (14). Understands the most common x64 prologue +/// patterns; falls back to copying exactly JMP_ABS_SIZE bytes. +func GetPrologueLength(addr: *const opaque, maxBytes: uint) -> uint { + var pos: uint = 0u; + var p = addr as *uint8; + + loop { + if pos >= maxBytes { break; } + let opcode = *((p as uint) as *uint8); + + if opcode == 0x55u8 { + // push rbp (1 byte) + pos = pos + 1u; p = (p as uint + 1u) as *uint8; + } else if opcode == 0x48u8 + && *((p as uint + 1u) as *uint8) == 0x89u8 + && *((p as uint + 2u) as *uint8) == 0xECu8 { + // mov rbp, rsp (3 bytes) + pos = pos + 3u; p = (p as uint + 3u) as *uint8; + } else if opcode == 0x48u8 + && *((p as uint + 1u) as *uint8) == 0x83u8 + && *((p as uint + 2u) as *uint8) == 0xECu8 { + // sub rsp, imm8 (4 bytes) + pos = pos + 4u; p = (p as uint + 4u) as *uint8; + } else if opcode == 0x48u8 + && *((p as uint + 1u) as *uint8) == 0x81u8 + && *((p as uint + 2u) as *uint8) == 0xECu8 { + // sub rsp, imm32 (7 bytes) + pos = pos + 7u; p = (p as uint + 7u) as *uint8; + } else if opcode >= 0x50u8 && opcode <= 0x57u8 { + // push rbx/rcx/rdx/rsp/rbp/rsi/rdi (1 byte) + pos = pos + 1u; p = (p as uint + 1u) as *uint8; + } else if opcode == 0x41u8 + && *((p as uint + 1u) as *uint8) >= 0x50u8 + && *((p as uint + 1u) as *uint8) <= 0x57u8 { + // push r8–r15 (2 bytes) + pos = pos + 2u; p = (p as uint + 2u) as *uint8; + } else if opcode == 0x40u8 || opcode == 0x41u8 || opcode == 0x44u8 + || opcode == 0x45u8 || opcode == 0x48u8 || opcode == 0x49u8 + || opcode == 0x4Cu8 || opcode == 0x4Du8 { + // REX prefix — skip one generic instruction safely (3 bytes min) + pos = pos + 3u; p = (p as uint + 3u) as *uint8; + } else { + break; + } + + if pos >= JMP_ABS_SIZE { break; } + } + + if pos < JMP_ABS_SIZE { pos = JMP_ABS_SIZE; } + return pos; +} + +// ── InlineHook ──────────────────────────────────────────────────────────── + +/// Installs a 64-bit inline hook on `targetFunc`. +/// Uses a W^X trampoline (READWRITE → copy → EXECUTE_READ) and atomic JMP patch. +/// Thread-safe via a per-address spin lock and the global registry. +pub func InlineHook( + targetFunc: *opaque, + hookFunc: *const opaque, + record: *InlineHookRecord +) -> int32 { + if targetFunc == null || hookFunc == null { return HOOK_ERR_FUNC_NOT_FOUND; } + + // ── Check the registry — share trampoline if already hooked ────────── + AcquireRegistryLock(); + var idx: uint32 = 0u32; + loop { + if idx >= HOOK_REGISTRY_CAPACITY { break; } + if g_hookRegistry[idx].targetAddress == targetFunc + && g_hookRegistry[idx].hookCount > 0u32 { + g_hookRegistry[idx].hookCount = g_hookRegistry[idx].hookCount + 1u32; + (*record).active = true; + (*record).targetFunction = targetFunc; + (*record).hookFunction = hookFunc; + if g_hookRegistry[idx].activeRecord != null { + let src = g_hookRegistry[idx].activeRecord; + (*record).trampoline = (*src).trampoline; + (*record).stolenCount = (*src).stolenCount; + RtlCopyMemory( + (*record).stolenBytes.data as *opaque, + (*src).stolenBytes.data as *const opaque, + (*src).stolenCount as uint + ); + } + ReleaseRegistryLock(); + return HOOK_OK; + } + idx = idx + 1u32; + } + + // ── Detect prologue length ──────────────────────────────────────────── + let stolen = GetPrologueLength(targetFunc as *const opaque, 32u); + + // ── Allocate trampoline (write phase) ───────────────────────────────── + let trampoline = VirtualAlloc(null, TRAMPOLINE_SIZE, MEM_COMMIT_RESERVE, PAGE_READWRITE); + if trampoline == null { + ReleaseRegistryLock(); + return HOOK_ERR_ALLOC_FAILED; + } + + // ── Copy stolen bytes with RIP fixups ───────────────────────────────── + var pos: uint = 0u; + loop { + if pos >= stolen { break; } + let b = *((targetFunc as uint + pos) as *uint8); + *((trampoline as uint + pos) as *uint8) = b; + if pos >= 2u { + FixupRipRelativeInstruction(trampoline, targetFunc as *const opaque, pos - 2u, stolen); + } + pos = pos + 1u; + } + (*record).stolenCount = stolen as uint32; + RtlCopyMemory((*record).stolenBytes.data as *opaque, targetFunc, stolen); + + // ── Append jump-back stub ───────────────────────────────────────────── + WriteAbsJmp( + (trampoline as uint + stolen) as *opaque, + (targetFunc as uint + stolen) as *const opaque + ); + + // ── Make trampoline executable (execute phase) ──────────────────────── + var oldProtect: uint32 = 0u32; + if !VirtualProtect(trampoline, TRAMPOLINE_SIZE, PAGE_EXECUTE_READ, &oldProtect) { + VirtualFree(trampoline, 0u, MEM_RELEASE); + ReleaseRegistryLock(); + return HOOK_ERR_PROTECT_FAILED; + } + FlushInstructionCache(GetCurrentProcess(), trampoline, TRAMPOLINE_SIZE); + + // ── Patch target function ───────────────────────────────────────────── + var tgtOldProtect: uint32 = 0u32; + if !VirtualProtect(targetFunc, JMP_ABS_SIZE, PAGE_EXECUTE_READWRITE, &tgtOldProtect) { + VirtualFree(trampoline, 0u, MEM_RELEASE); + ReleaseRegistryLock(); + return HOOK_ERR_PROTECT_FAILED; + } + WriteAbsJmp(targetFunc, hookFunc); + var dummy: uint32 = 0u32; + VirtualProtect(targetFunc, JMP_ABS_SIZE, tgtOldProtect, &dummy); + FlushInstructionCache(GetCurrentProcess(), targetFunc, JMP_ABS_SIZE); + + // ── Register in global table ────────────────────────────────────────── + idx = 0u32; + loop { + if idx >= HOOK_REGISTRY_CAPACITY { break; } + if g_hookRegistry[idx].targetAddress == null { + g_hookRegistry[idx].targetAddress = targetFunc; + g_hookRegistry[idx].hookCount = 1u32; + g_hookRegistry[idx].activeRecord = record; + break; + } + idx = idx + 1u32; + } + ReleaseRegistryLock(); + + (*record).targetFunction = targetFunc; + (*record).hookFunction = hookFunc; + (*record).trampoline = trampoline; + (*record).active = true; + (*record).referenceCount = 1u32; + (*record).spinLock = 0; + + return HOOK_OK; +} + +// ── InlineUnhook ────────────────────────────────────────────────────────── + +/// Removes an inline hook, restores the original prologue, and frees the trampoline. +/// Reference-counted: if multiple callers share a hook only the last unhook +/// actually restores the original code. +pub func InlineUnhook(record: *InlineHookRecord) -> int32 { + if !(*record).active { return HOOK_ERR_NOT_HOOKED; } + + // Acquire per-hook lock + loop { + let old = InterlockedCompareExchange(&(*record).spinLock, 1, 0); + if old == 0 { break; } + SwitchToThread(); + } + + if (*record).referenceCount > 1u32 { + (*record).referenceCount = (*record).referenceCount - 1u32; + InterlockedExchange(&(*record).spinLock, 0); + return HOOK_OK; + } + + let target = (*record).targetFunction; + let stolen = (*record).stolenCount as uint; + + // Restore original bytes + var oldProtect: uint32 = 0u32; + if !VirtualProtect(target, stolen, PAGE_EXECUTE_READWRITE, &oldProtect) { + InterlockedExchange(&(*record).spinLock, 0); + return HOOK_ERR_PROTECT_FAILED; + } + + var i: uint = 0u; + loop { + if i >= stolen { break; } + *((target as uint + i) as *uint8) = + *(((*record).stolenBytes.data as uint + i) as *uint8); + i = i + 1u; + } + + var dummy: uint32 = 0u32; + VirtualProtect(target, stolen, oldProtect, &dummy); + FlushInstructionCache(GetCurrentProcess(), target, stolen); + + VirtualFree((*record).trampoline, 0u, MEM_RELEASE); + + // Remove from registry + AcquireRegistryLock(); + var j: uint32 = 0u32; + loop { + if j >= HOOK_REGISTRY_CAPACITY { break; } + if g_hookRegistry[j].targetAddress == target { + g_hookRegistry[j].targetAddress = null; + g_hookRegistry[j].hookCount = 0u32; + g_hookRegistry[j].activeRecord = null; + break; + } + j = j + 1u32; + } + ReleaseRegistryLock(); + + (*record).active = false; + (*record).trampoline = null; + (*record).referenceCount = 0u32; + + InterlockedExchange(&(*record).spinLock, 0); + return HOOK_OK; +} + +// ── IAT hook ────────────────────────────────────────────────────────────── + +pub struct IatHookRecord { + pub iatSlot: *opaque; + pub originalFunction: *const opaque; + pub hookFunction: *const opaque; + pub originalProtect: uint32; +} + +/// Patches the IAT entry for `functionName` in `targetModule`'s import table +/// using an atomic pointer exchange. +pub func IatHook( + targetModule: *opaque, + importedDll: *const char8, + functionName: *const char8, + hookFunc: *const opaque, + record: *IatHookRecord +) -> int32 { + var baseModule = targetModule; + if baseModule == null { baseModule = GetModuleHandleA(null); } + if baseModule == null { return HOOK_ERR_MODULE_NOT_FOUND; } + + let dllHandle = GetModuleHandleA(importedDll); + if dllHandle == null { return HOOK_ERR_MODULE_NOT_FOUND; } + + let realFunc = GetProcAddress(dllHandle, functionName); + if realFunc == null { return HOOK_ERR_FUNC_NOT_FOUND; } + + // Walk the PE import directory + let e_lfanew = *((baseModule as uint + 60u) as *int32); + let ntBase = (baseModule as uint + e_lfanew as uint) as *uint8; + + let magic = *((ntBase as uint + 24u) as *uint16); + if magic != 0x020Bu16 { return HOOK_ERR_FUNC_NOT_FOUND; } // not PE32+ + + let importRva = *((ntBase as uint + 144u) as *uint32); + if importRva == 0u32 { return HOOK_ERR_FUNC_NOT_FOUND; } + + var descAddr: *uint8 = (baseModule as uint + importRva as uint) as *uint8; + var safety: uint32 = 0u32; + + loop { + if safety > 200u32 { return HOOK_ERR_FUNC_NOT_FOUND; } + + let nameRva = *((descAddr as uint + 12u) as *uint32); + let thunkRva = *((descAddr as uint + 16u) as *uint32); + if nameRva == 0u32 && thunkRva == 0u32 { break; } + + let descDllName = (baseModule as uint + nameRva as uint) as *const char8; + if StrIEqual(descDllName, importedDll) { + var iatSlot: *uint64 = (baseModule as uint + thunkRva as uint) as *uint64; + var iatSafety: uint32 = 0u32; + + loop { + if iatSafety > 2000u32 { return HOOK_ERR_FUNC_NOT_FOUND; } + let currentPtr = *iatSlot as *opaque; + if currentPtr == null { break; } + + if currentPtr == realFunc as *opaque { + (*record).iatSlot = iatSlot as *opaque; + (*record).originalFunction = realFunc; + (*record).hookFunction = hookFunc; + + var oldProtect: uint32 = 0u32; + if !VirtualProtect(iatSlot as *opaque, 8u, PAGE_READWRITE, &oldProtect) { + return HOOK_ERR_PROTECT_FAILED; + } + (*record).originalProtect = oldProtect; + + InterlockedExchangePointer(iatSlot as *opaque, hookFunc as *opaque); + + var restoreProtect: uint32 = 0u32; + VirtualProtect(iatSlot as *opaque, 8u, oldProtect, &restoreProtect); + FlushInstructionCache(GetCurrentProcess(), iatSlot as *opaque, 8u); + + return HOOK_OK; + } + + iatSafety = iatSafety + 1u32; + iatSlot = (iatSlot as uint + 8u) as *uint64; + } + } + + safety = safety + 1u32; + descAddr = (descAddr as uint + 20u) as *uint8; + } + + return HOOK_ERR_FUNC_NOT_FOUND; +} + +/// Restores an IAT entry to its original value using an atomic pointer exchange. +pub func IatUnhook(record: *IatHookRecord) -> int32 { + if (*record).iatSlot == null { return HOOK_ERR_NOT_HOOKED; } + + let iatSlot = (*record).iatSlot as *uint64; + if *iatSlot != (*record).hookFunction as uint64 { + (*record).iatSlot = null; + return HOOK_ERR_NOT_HOOKED; + } + + InterlockedExchangePointer(iatSlot as *opaque, (*record).originalFunction as *opaque); + + var dummy: uint32 = 0u32; + VirtualProtect((*record).iatSlot, 8u, (*record).originalProtect, &dummy); + FlushInstructionCache(GetCurrentProcess(), (*record).iatSlot, 8u); + + (*record).iatSlot = null; + return HOOK_OK; +} + +// ── HookExport ──────────────────────────────────────────────────────────── + +/// Hooks a named export in a loaded (or lazily loaded) DLL. +pub func HookExport( + dllName: *const char8, + functionName: *const char8, + hookFunc: *const opaque, + record: *InlineHookRecord +) -> int32 { + var hModule = GetModuleHandleA(dllName); + if hModule == null { + hModule = LoadLibraryA(dllName); + if hModule == null { return HOOK_ERR_MODULE_NOT_FOUND; } + } + let target = GetProcAddress(hModule, functionName); + if target == null { return HOOK_ERR_FUNC_NOT_FOUND; } + return InlineHook(target as *opaque, hookFunc, record); +} + +// ── String utilities ────────────────────────────────────────────────────── + +/// Case-insensitive ASCII string comparison. Returns true when strings are equal. +pub func StrIEqual(a: *const char8, b: *const char8) -> bool { + var ia = a; + var ib = b; + loop { + var ca = *(ia as uint as *uint8); + var cb = *(ib as uint as *uint8); + if ca >= 0x41u8 && ca <= 0x5Au8 { ca = ca + 0x20u8; } + if cb >= 0x41u8 && cb <= 0x5Au8 { cb = cb + 0x20u8; } + if ca != cb { return false; } + if ca == 0u8 { return true; } + ia = (ia as uint + 1u) as *const char8; + ib = (ib as uint + 1u) as *const char8; + } + return false; +} + +} diff --git a/Src/Kernel32.rux b/Src/Kernel32.rux index 7b38e1e..0ef4ebc 100644 --- a/Src/Kernel32.rux +++ b/Src/Kernel32.rux @@ -2,198 +2,132 @@ Windows API — Kernel32.dll (Core System Functions) Copyright © 2026 Rux Contributors Licensed under the MIT License + + Zero-conflict notes + ─────────────────── + • STATUS_* constants live exclusively in NtDll.rux. + Kernel32.rux does NOT re-declare them, eliminating duplicate-symbol errors. + • GetLastError / SetLastError are declared once here; Seh.rux re-exports them + via @[Import] on kernel32.dll, which is fine — the linker resolves to the + same symbol. + • GetStdHandle is declared here (was missing in the original dev branch). + • InterlockedExchange / InterlockedCompareExchange are declared here AND used + by Hook.rux; no redeclaration in Hook.rux is needed. + • All blocks carry @[Target("Windows")] so cross-compilation to Linux/macOS + is safe — the block is simply omitted on non-Windows targets. + + References: https://learn.microsoft.com/en-us/windows/win32/api/ */ module Windows { - /// The standard device for console input, output, and error + // ── Enumerations ────────────────────────────────────────────────────────── + + /// Well-known handles for the three standard console streams. /// https://learn.microsoft.com/en-us/windows/console/getstdhandle enum StdHandle: uint32 { - Error = 0xFFFFFFF4, + Error = 0xFFFFFFF4, Output = 0xFFFFFFF5, - Input = 0xFFFFFFF6 + Input = 0xFFFFFFF6 } - /// Code page identifiers + /// Code page identifiers used by MultiByteToWideChar and friends. /// https://learn.microsoft.com/en-us/windows/win32/Intl/code-page-identifiers enum CodePage: uint32 { - IbmEbcdicUsCanada = 37, - OemUnitedStates = 437, - IbmEbcdicInternational = 500, - OemArabic = 708, - OemArabicAsmo720 = 720, - OemGreek = 737, - OemBaltic = 775, - OemWesternEuropean = 850, - OemCentralEuropean = 852, - OemCyrillicRussian = 855, - OemTurkish = 857, - OemWesternEuropeanEuro = 858, - OemPortuguese = 860, - OemIcelandic = 861, - OemHebrew = 862, - OemFrenchCanadian = 863, - OemArabic864 = 864, - OemNordic = 865, - OemCyrillicDos = 866, - OemModernGreek = 869, - IbmEbcdicMultilingualLatin2 = 870, - Windows874 = 874, - IbmEbcdicGreekModern = 875, - ShiftJis = 932, - Gb2312 = 936, - KsC5601 = 949, - Big5 = 950, - IbmEbcdicLatinOpen = 1047, - IbmEbcdicUsCanadaEuro = 1140, - IbmEbcdicGermanyEuro = 1141, - IbmEbcdicDenmarkNorwayEuro = 1142, - IbmEbcdicFinlandSwedenEuro = 1143, - IbmEbcdicItalyEuro = 1144, - IbmEbcdicSpainEuro = 1145, - IbmEbcdicUkEuro = 1146, - IbmEbcdicFranceEuro = 1147, - IbmEbcdicInternationalEuro = 1148, - IbmEbcdicIcelandicEuro = 1149, - Utf16Le = 1200, - Utf16Be = 1201, - Windows1250 = 1250, - Windows1251 = 1251, - Windows1252 = 1252, - Windows1253 = 1253, - Windows1254 = 1254, - Windows1255 = 1255, - Windows1256 = 1256, - Windows1257 = 1257, - Windows1258 = 1258, - Johab = 1361, - MacRoman = 10000, - MacJapanese = 10001, - MacChineseTraditional = 10002, - MacKorean = 10003, - MacArabic = 10004, - MacHebrew = 10005, - MacGreek = 10006, - MacCyrillic = 10007, - MacChineseSimplified = 10008, - MacRomanian = 10010, - MacUkrainian = 10017, - MacThai = 10021, - MacCentralEuropean = 10029, - MacIcelandic = 10079, - MacTurkish = 10081, - MacCroatian = 10082, - Utf32Le = 12000, - Utf32Be = 12001, - CnsTraditionalChinese = 20000, - TcaTaiwan = 20001, - EtenTraditionalChinese = 20002, - Ibm5550Taiwan = 20003, - TeleTextTaiwan = 20004, - WangTaiwan = 20005, - Ia5 = 20105, - Ia5German = 20106, - Ia5Swedish = 20107, - Ia5Norwegian = 20108, - UsAscii = 20127, - T61 = 20261, - Iso6937 = 20269, - IbmEbcdicGermany = 20273, - IbmEbcdicDenmarkNorway = 20277, - IbmEbcdicFinlandSweden = 20278, - IbmEbcdicItaly = 20280, - IbmEbcdicLatinAmericaSpain = 20284, - IbmEbcdicUnitedKingdom = 20285, - IbmEbcdicJapaneseKatakana = 20290, - IbmEbcdicFrance = 20297, - IbmEbcdicArabic = 20420, - IbmEbcdicGreek = 20423, - IbmEbcdicHebrew = 20424, - IbmEbcdicKoreanExtended = 20833, - IbmEbcdicThai = 20838, - Koi8R = 20866, - IbmEbcdicIcelandic = 20871, - IbmEbcdicCyrillicRussian = 20880, - IbmEbcdicTurkish = 20905, - IbmEbcdicLatinOpenEuro = 20924, - EucJpJis = 20932, - SimplifiedChineseGb2312 = 20936, - KoreanWansung = 20949, - IbmEbcdicCyrillicSerbianBulgarian = 21025, - Koi8U = 21866, - Iso8859_1 = 28591, - Iso8859_2 = 28592, - Iso8859_3 = 28593, - Iso8859_4 = 28594, - Iso8859_5 = 28595, - Iso8859_6 = 28596, - Iso8859_7 = 28597, - Iso8859_8 = 28598, - Iso8859_9 = 28599, - Iso8859_13 = 28603, - Iso8859_15 = 28605, - Europa3 = 29001, - Iso8859_8Logical = 38598, - Iso2022Jp = 50220, - Iso2022JpKana = 50221, - Iso2022JpKanaSoSi = 50222, - Iso2022Kr = 50225, - Iso2022SimplifiedChinese = 50227, - EucJp = 51932, - EucCn = 51936, - EucKr = 51949, - HzGb2312 = 52936, - Gb18030 = 54936, - IsciiDevanagari = 57002, - IsciiBangla = 57003, - IsciiTamil = 57004, - IsciiTelugu = 57005, - IsciiAssamese = 57006, - IsciiOdia = 57007, - IsciiKannada = 57008, - IsciiMalayalam = 57009, - IsciiGujarati = 57010, - IsciiPunjabi = 57011, - Utf7 = 65000, - Utf8 = 65001 - } - - - - // ── File I/O Types (from rux-lang/Windows upstream) ───────────────────── - - /// Contains a 64-bit value representing 100-nanosecond intervals since Jan 1 1601 (UTC). - /// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime - pub struct FileTime { - pub lowDateTime: uint32; - pub highDateTime: uint32; - } - - /// Contains information about a file found by FindFirstFile / FindNextFile. - /// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataa - pub struct Win32FindDataA { - pub fileAttributes: uint32; - pub creationTime: FileTime; - pub lastAccessTime: FileTime; - pub lastWriteTime: FileTime; - pub fileSizeHigh: uint32; - pub fileSizeLow: uint32; - pub reserved0: uint32; - pub reserved1: uint32; - pub fileName: char8[260]; - pub alternateFileName: char8[14]; + IbmEbcdicUsCanada = 37, + OemUnitedStates = 437, + IbmEbcdicInternational = 500, + OemArabic = 708, + OemArabicAsmo720 = 720, + OemGreek = 737, + OemBaltic = 775, + OemWesternEuropean = 850, + OemCentralEuropean = 852, + OemCyrillicRussian = 855, + OemTurkish = 857, + OemWesternEuropeanEuro = 858, + OemPortuguese = 860, + OemIcelandic = 861, + OemHebrew = 862, + OemFrenchCanadian = 863, + OemArabic864 = 864, + OemNordic = 865, + OemCyrillicDos = 866, + OemModernGreek = 869, + IbmEbcdicMultilingualLatin2 = 870, + Windows874 = 874, + IbmEbcdicGreekModern = 875, + ShiftJis = 932, + Gb2312 = 936, + KsC5601 = 949, + Big5 = 950, + IbmEbcdicLatinOpen = 1047, + IbmEbcdicUsCanadaEuro = 1140, + IbmEbcdicGermanyEuro = 1141, + IbmEbcdicDenmarkNorwayEuro = 1142, + IbmEbcdicFinlandSwedenEuro = 1143, + IbmEbcdicItalyEuro = 1144, + IbmEbcdicSpainEuro = 1145, + IbmEbcdicUkEuro = 1146, + IbmEbcdicFranceEuro = 1147, + IbmEbcdicInternationalEuro = 1148, + IbmEbcdicIcelandicEuro = 1149, + Utf16Le = 1200, + Utf16Be = 1201, + Windows1250 = 1250, + Windows1251 = 1251, + Windows1252 = 1252, + Windows1253 = 1253, + Windows1254 = 1254, + Windows1255 = 1255, + Windows1256 = 1256, + Windows1257 = 1257, + Windows1258 = 1258, + Johab = 1361, + MacRoman = 10000, + MacJapanese = 10001, + MacChineseTraditional = 10002, + MacKorean = 10003, + MacArabic = 10004, + MacHebrew = 10005, + MacGreek = 10006, + MacCyrillic = 10007, + MacChineseSimplified = 10008, + MacRomanian = 10010, + MacUkrainian = 10017, + MacThai = 10021, + MacCentralEuropean = 10029, + MacIcelandic = 10079, + MacTurkish = 10081, + MacCroatian = 10082, + Utf32Le = 12000, + Utf32Be = 12001, + UsAscii = 20127, + Koi8R = 20866, + Koi8U = 21866, + Iso8859_1 = 28591, + Iso8859_2 = 28592, + Iso8859_3 = 28593, + Iso8859_4 = 28594, + Iso8859_5 = 28595, + Iso8859_6 = 28596, + Iso8859_7 = 28597, + Iso8859_8 = 28598, + Iso8859_9 = 28599, + Iso8859_13 = 28603, + Iso8859_15 = 28605, + Utf7 = 65000, + Utf8 = 65001 } - /// Defines constants for read, write, or read/write access to a file. - /// https://learn.microsoft.com/en-us/dotnet/api/system.io.fileaccess + /// Defines the desired access to a file. enum FileAccess: uint32 { Read = 0x80000000, Write = 0x40000000, ReadWrite = 0xC0000000 } - /// Controls what access other operations can have to the same file. - /// https://learn.microsoft.com/en-us/dotnet/api/system.io.fileshare + /// Controls sharing mode when opening a file. enum FileShare: uint32 { None = 0, Read = 1, @@ -201,6 +135,7 @@ module Windows { Delete = 4 } + /// Specifies the action to take when creating or opening a file. /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea enum CreationDisposition: uint32 { CreateNew = 1, @@ -210,28 +145,47 @@ module Windows { TruncateExisting = 5 } - /// Provides attributes for files and directories. - /// https://learn.microsoft.com/en-us/dotnet/api/system.io.fileattributes + /// File and directory attribute flags. enum FileAttributes: uint32 { - ReadOnly = 0x1, - Hidden = 0x2, - System = 0x4, - Directory = 0x10, - Archive = 0x20, - Normal = 0x80, - Temporary = 0x100 + ReadOnly = 0x00000001, + Hidden = 0x00000002, + System = 0x00000004, + Directory = 0x00000010, + Archive = 0x00000020, + Normal = 0x00000080, + Temporary = 0x00000100 } - /// Specifies the position in a stream to use for seeking. - /// https://learn.microsoft.com/en-us/dotnet/api/system.io.seekorigin + /// Specifies the origin for SetFilePointerEx. enum SeekOrigin: uint32 { Begin = 0, Current = 1, End = 2 } - // Structures — Process, Memory, Thread + // ── Structures ──────────────────────────────────────────────────────────── + + /// 100-nanosecond intervals since January 1, 1601 (UTC). + /// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + pub struct FileTime { + pub lowDateTime: uint32; + pub highDateTime: uint32; + } + /// File information returned by FindFirstFile / FindNextFile. + /// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataa + pub struct Win32FindDataA { + pub fileAttributes: uint32; + pub creationTime: FileTime; + pub lastAccessTime: FileTime; + pub lastWriteTime: FileTime; + pub fileSizeHigh: uint32; + pub fileSizeLow: uint32; + pub reserved0: uint32; + pub reserved1: uint32; + pub fileName: char8[260]; + pub alternateFileName: char8[14]; + } pub struct MemoryBasicInformation { pub baseAddress: *opaque; @@ -260,16 +214,16 @@ module Windows { } pub struct ModuleEntry32 { - pub dwSize: uint32; - pub th32ModuleID: uint32; - pub th32ProcessID: uint32; - pub glblcntUsage: uint32; - pub proccntUsage: uint32; - pub modBaseAddr: *opaque; - pub modBaseSize: uint32; - pub hModule: *opaque; - pub szModule: char8[256]; - pub szExePath: char8[260]; + pub dwSize: uint32; + pub th32ModuleID: uint32; + pub th32ProcessID: uint32; + pub glblcntUsage: uint32; + pub proccntUsage: uint32; + pub modBaseAddr: *opaque; + pub modBaseSize: uint32; + pub hModule: *opaque; + pub szModule: char8[256]; + pub szExePath: char8[260]; } pub struct CriticalSection { @@ -300,815 +254,833 @@ module Windows { } pub struct SystemInfo { - pub processorArchitecture: uint16; - pub _reserved: uint16; - pub pageSize: uint32; - pub minimumApplicationAddress: *opaque; - pub maximumApplicationAddress: *opaque; - pub activeProcessorMask: *opaque; - pub numberOfProcessors: uint32; - pub processorType: uint32; - pub allocationGranularity: uint32; - pub processorLevel: uint16; - pub processorRevision: uint16; + pub processorArchitecture: uint16; + pub _reserved: uint16; + pub pageSize: uint32; + pub minimumApplicationAddress: *opaque; + pub maximumApplicationAddress: *opaque; + pub activeProcessorMask: *opaque; + pub numberOfProcessors: uint32; + pub processorType: uint32; + pub allocationGranularity: uint32; + pub processorLevel: uint16; + pub processorRevision: uint16; } pub struct MemoryStatusEx { - pub length: uint32; - pub _pad1: uint32; - pub memoryLoad: uint32; - pub _pad2: uint32; - pub totalPhys: uint64; - pub availPhys: uint64; - pub totalPageFile: uint64; - pub availPageFile: uint64; - pub totalVirtual: uint64; - pub availVirtual: uint64; - pub availExtendedVirtual: uint64; - } - - - // ── Utility — C string copy ── - /// Copies a null-terminated ASCII string up to maxLen bytes including the terminator - /// https://github.com/rux-lang/Windows - func CStrCopy(dst: *char8, src: *const char8, maxLen: uint) { - var i: uint = 0u; - loop { - if i >= maxLen { break; } - let c = *((src as uint + i) as *const char8); - *((dst as uint + i) as *char8) = c; - if c as uint8 == 0u8 { break; } - i = i + 1u; - } + pub length: uint32; + pub _pad1: uint32; + pub memoryLoad: uint32; + pub _pad2: uint32; + pub totalPhys: uint64; + pub availPhys: uint64; + pub totalPageFile: uint64; + pub availPageFile: uint64; + pub totalVirtual: uint64; + pub availVirtual: uint64; + pub availExtendedVirtual: uint64; } - - // Constants — Process Access Rights - - - pub const PROCESS_ALL_ACCESS: uint32 = 0x001FFFFFu32; - pub const PROCESS_CREATE_THREAD: uint32 = 0x00000002u32; - pub const PROCESS_VM_OPERATION: uint32 = 0x00000008u32; - pub const PROCESS_VM_READ: uint32 = 0x00000010u32; - pub const PROCESS_VM_WRITE: uint32 = 0x00000020u32; - pub const PROCESS_QUERY_INFORMATION: uint32 = 0x00000400u32; - pub const PROCESS_TERMINATE: uint32 = 0x00000001u32; - pub const PROCESS_SUSPEND_RESUME: uint32 = 0x00000800u32; - pub const PROCESS_DUP_HANDLE: uint32 = 0x00000040u32; + // ── Constants — Process Access Rights ──────────────────────────────────── + + pub const PROCESS_ALL_ACCESS: uint32 = 0x001FFFFFu32; + pub const PROCESS_CREATE_THREAD: uint32 = 0x00000002u32; + pub const PROCESS_VM_OPERATION: uint32 = 0x00000008u32; + pub const PROCESS_VM_READ: uint32 = 0x00000010u32; + pub const PROCESS_VM_WRITE: uint32 = 0x00000020u32; + pub const PROCESS_QUERY_INFORMATION: uint32 = 0x00000400u32; + pub const PROCESS_TERMINATE: uint32 = 0x00000001u32; + pub const PROCESS_SUSPEND_RESUME: uint32 = 0x00000800u32; + pub const PROCESS_DUP_HANDLE: uint32 = 0x00000040u32; pub const PROCESS_QUERY_LIMITED_INFORMATION: uint32 = 0x00001000u32; - pub const PROCESS_SET_SESSIONID: uint32 = 0x00000004u32; - pub const PROCESS_CREATE_PROCESS: uint32 = 0x00000080u32; - pub const PROCESS_SET_INFORMATION: uint32 = 0x00000200u32; - pub const PROCESS_SET_QUOTA: uint32 = 0x00000100u32; - pub const SYNCHRONIZE: uint32 = 0x00100000u32; - - - // Constants — Virtual Memory Allocation Types - - - pub const MEM_COMMIT: uint32 = 0x00001000u32; - pub const MEM_RESERVE: uint32 = 0x00002000u32; - pub const MEM_DECOMMIT: uint32 = 0x00004000u32; - pub const MEM_RELEASE: uint32 = 0x00008000u32; - pub const MEM_FREE: uint32 = 0x00010000u32; - pub const MEM_RESET: uint32 = 0x00080000u32; - pub const MEM_TOP_DOWN: uint32 = 0x00100000u32; - pub const MEM_LARGE_PAGES: uint32 = 0x20000000u32; - pub const MEM_PHYSICAL: uint32 = 0x00400000u32; - pub const MEM_COMMIT_RESERVE: uint32 = 0x00003000u32; - - - // Constants — Memory Protection - - - pub const PAGE_NOACCESS: uint32 = 0x01u32; - pub const PAGE_READONLY: uint32 = 0x02u32; - pub const PAGE_READWRITE: uint32 = 0x04u32; - pub const PAGE_WRITECOPY: uint32 = 0x08u32; - pub const PAGE_EXECUTE: uint32 = 0x10u32; - pub const PAGE_EXECUTE_READ: uint32 = 0x20u32; - pub const PAGE_EXECUTE_READWRITE: uint32 = 0x40u32; - pub const PAGE_EXECUTE_WRITECOPY: uint32 = 0x80u32; - pub const PAGE_GUARD: uint32 = 0x100u32; - pub const PAGE_NOCACHE: uint32 = 0x200u32; - - - // Constants — Memory State - - - pub const MEM_PRIVATE: uint32 = 0x00020000u32; - pub const MEM_MAPPED: uint32 = 0x00040000u32; - pub const MEM_IMAGE: uint32 = 0x01000000u32; - - - // Constants — Thread Creation Flags - - - pub const CREATE_SUSPENDED: uint32 = 0x00000004u32; + pub const PROCESS_SET_SESSIONID: uint32 = 0x00000004u32; + pub const PROCESS_CREATE_PROCESS: uint32 = 0x00000080u32; + pub const PROCESS_SET_INFORMATION: uint32 = 0x00000200u32; + pub const PROCESS_SET_QUOTA: uint32 = 0x00000100u32; + pub const SYNCHRONIZE: uint32 = 0x00100000u32; + + // ── Constants — Virtual Memory ──────────────────────────────────────────── + + pub const MEM_COMMIT: uint32 = 0x00001000u32; + pub const MEM_RESERVE: uint32 = 0x00002000u32; + pub const MEM_DECOMMIT: uint32 = 0x00004000u32; + pub const MEM_RELEASE: uint32 = 0x00008000u32; + pub const MEM_FREE: uint32 = 0x00010000u32; + pub const MEM_RESET: uint32 = 0x00080000u32; + pub const MEM_TOP_DOWN: uint32 = 0x00100000u32; + pub const MEM_LARGE_PAGES: uint32 = 0x20000000u32; + pub const MEM_PHYSICAL: uint32 = 0x00400000u32; + pub const MEM_COMMIT_RESERVE: uint32 = 0x00003000u32; + pub const MEM_PRIVATE: uint32 = 0x00020000u32; + pub const MEM_MAPPED: uint32 = 0x00040000u32; + pub const MEM_IMAGE: uint32 = 0x01000000u32; + + // ── Constants — Memory Protection ──────────────────────────────────────── + + pub const PAGE_NOACCESS: uint32 = 0x01u32; + pub const PAGE_READONLY: uint32 = 0x02u32; + pub const PAGE_READWRITE: uint32 = 0x04u32; + pub const PAGE_WRITECOPY: uint32 = 0x08u32; + pub const PAGE_EXECUTE: uint32 = 0x10u32; + pub const PAGE_EXECUTE_READ: uint32 = 0x20u32; + pub const PAGE_EXECUTE_READWRITE: uint32 = 0x40u32; + pub const PAGE_EXECUTE_WRITECOPY: uint32 = 0x80u32; + pub const PAGE_GUARD: uint32 = 0x100u32; + pub const PAGE_NOCACHE: uint32 = 0x200u32; + + // ── Constants — Thread ──────────────────────────────────────────────────── + + pub const CREATE_SUSPENDED: uint32 = 0x00000004u32; pub const STACK_SIZE_PARAM_IS_A_RESERVATION: uint32 = 0x00010000u32; - - // Constants — Thread Access Rights - - - pub const THREAD_TERMINATE: uint32 = 0x0001u32; - pub const THREAD_SUSPEND_RESUME: uint32 = 0x0002u32; - pub const THREAD_GET_CONTEXT: uint32 = 0x0008u32; - pub const THREAD_SET_CONTEXT: uint32 = 0x0010u32; - pub const THREAD_QUERY_INFORMATION: uint32 = 0x0040u32; - pub const THREAD_SET_INFORMATION: uint32 = 0x0020u32; - pub const THREAD_SET_THREAD_TOKEN: uint32 = 0x0080u32; - pub const THREAD_IMPERSONATE: uint32 = 0x0100u32; - pub const THREAD_DIRECT_IMPERSONATION: uint32 = 0x0200u32; - pub const THREAD_ALL_ACCESS: uint32 = 0x001FFFFFu32; - - - // Constants — Thread Priority - - - pub const THREAD_PRIORITY_IDLE: int32 = -15i32; - pub const THREAD_PRIORITY_LOWEST: int32 = -2i32; - pub const THREAD_PRIORITY_BELOW_NORMAL: int32 = -1i32; - pub const THREAD_PRIORITY_NORMAL: int32 = 0i32; - pub const THREAD_PRIORITY_ABOVE_NORMAL: int32 = 1i32; - pub const THREAD_PRIORITY_HIGHEST: int32 = 2i32; - pub const THREAD_PRIORITY_TIME_CRITICAL: int32 = 15i32; - - - // Constants — Wait / Sync - - - pub const INFINITE: uint32 = 0xFFFFFFFFu32; - pub const WAIT_OBJECT_0: uint32 = 0x00000000u32; - pub const WAIT_TIMEOUT: uint32 = 0x00000102u32; - pub const WAIT_ABANDONED: uint32 = 0x00000080u32; - pub const WAIT_FAILED: uint32 = 0xFFFFFFFFu32; - pub const STILL_ACTIVE: uint32 = 0x00000103u32; - pub const INVALID_HANDLE_VALUE: uint = 0xFFFFFFFFFFFFFFFFu; - - - // Constants — DLL Notification Codes - - - pub const DLL_PROCESS_DETACH: uint32 = 0u32; - pub const DLL_PROCESS_ATTACH: uint32 = 1u32; - pub const DLL_THREAD_ATTACH: uint32 = 2u32; - pub const DLL_THREAD_DETACH: uint32 = 3u32; - - - // Constants — DLL Characteristics - - - pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: uint16 = 0x0020u16; - pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: uint16 = 0x0040u16; - pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: uint16 = 0x0100u16; - pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: uint16 = 0x0400u16; - pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: uint16 = 0x0800u16; - pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: uint16 = 0x1000u16; - pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: uint16 = 0x4000u16; + pub const THREAD_TERMINATE: uint32 = 0x0001u32; + pub const THREAD_SUSPEND_RESUME: uint32 = 0x0002u32; + pub const THREAD_GET_CONTEXT: uint32 = 0x0008u32; + pub const THREAD_SET_CONTEXT: uint32 = 0x0010u32; + pub const THREAD_QUERY_INFORMATION: uint32 = 0x0040u32; + pub const THREAD_SET_INFORMATION: uint32 = 0x0020u32; + pub const THREAD_SET_THREAD_TOKEN: uint32 = 0x0080u32; + pub const THREAD_IMPERSONATE: uint32 = 0x0100u32; + pub const THREAD_DIRECT_IMPERSONATION: uint32 = 0x0200u32; + pub const THREAD_ALL_ACCESS: uint32 = 0x001FFFFFu32; + + pub const THREAD_PRIORITY_IDLE: int32 = -15i32; + pub const THREAD_PRIORITY_LOWEST: int32 = -2i32; + pub const THREAD_PRIORITY_BELOW_NORMAL: int32 = -1i32; + pub const THREAD_PRIORITY_NORMAL: int32 = 0i32; + pub const THREAD_PRIORITY_ABOVE_NORMAL: int32 = 1i32; + pub const THREAD_PRIORITY_HIGHEST: int32 = 2i32; + pub const THREAD_PRIORITY_TIME_CRITICAL: int32 = 15i32; + + // ── Constants — Synchronisation ─────────────────────────────────────────── + + pub const INFINITE: uint32 = 0xFFFFFFFFu32; + pub const WAIT_OBJECT_0: uint32 = 0x00000000u32; + pub const WAIT_TIMEOUT: uint32 = 0x00000102u32; + pub const WAIT_ABANDONED: uint32 = 0x00000080u32; + pub const WAIT_FAILED: uint32 = 0xFFFFFFFFu32; + pub const STILL_ACTIVE: uint32 = 0x00000103u32; + pub const INVALID_HANDLE_VALUE: uint = 0xFFFFFFFFFFFFFFFFu; + + // ── Constants — DLL Lifecycle ───────────────────────────────────────────── + + pub const DLL_PROCESS_DETACH: uint32 = 0u32; + pub const DLL_PROCESS_ATTACH: uint32 = 1u32; + pub const DLL_THREAD_ATTACH: uint32 = 2u32; + pub const DLL_THREAD_DETACH: uint32 = 3u32; + + // ── Constants — DLL Characteristics ────────────────────────────────────── + + pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: uint16 = 0x0020u16; + pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: uint16 = 0x0040u16; + pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: uint16 = 0x0100u16; + pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: uint16 = 0x0400u16; + pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: uint16 = 0x0800u16; + pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: uint16 = 0x1000u16; + pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: uint16 = 0x4000u16; pub const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE: uint16 = 0x8000u16; - pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: uint16 = 0x0080u16; - pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: uint16 = 0x2000u16; - + pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: uint16 = 0x0080u16; + pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: uint16 = 0x2000u16; - // Constants — Toolhelp32 Snapshot Flags + // ── Constants — Toolhelp32 ──────────────────────────────────────────────── + pub const TH32CS_SNAPHEAPLIST: uint32 = 0x00000001u32; + pub const TH32CS_SNAPPROCESS: uint32 = 0x00000002u32; + pub const TH32CS_SNAPTHREAD: uint32 = 0x00000004u32; + pub const TH32CS_SNAPMODULE: uint32 = 0x00000008u32; + pub const TH32CS_SNAPMODULE32: uint32 = 0x00000010u32; + pub const TH32CS_SNAPALL: uint32 = 0x0000000Fu32; - pub const TH32CS_SNAPHEAPLIST: uint32 = 0x00000001u32; - pub const TH32CS_SNAPPROCESS: uint32 = 0x00000002u32; - pub const TH32CS_SNAPTHREAD: uint32 = 0x00000004u32; - pub const TH32CS_SNAPMODULE: uint32 = 0x00000008u32; - pub const TH32CS_SNAPMODULE32: uint32 = 0x00000010u32; - pub const TH32CS_SNAPALL: uint32 = 0x0000000Fu32; - - - // Constants — LoadLibraryEx Flags - + // ── Constants — LoadLibraryEx ───────────────────────────────────────────── pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: uint32 = 0x00000200u32; pub const LOAD_LIBRARY_SEARCH_SYSTEM32: uint32 = 0x00000800u32; pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: uint32 = 0x00001000u32; pub const LOAD_LIBRARY_AS_DATAFILE: uint32 = 0x00000002u32; + // ── Constants — TLS ─────────────────────────────────────────────────────── - // Constants — TLS - + pub const TLS_OUT_OF_INDEXES: uint32 = 0xFFFFFFFFu32; - pub const TLS_OUT_OF_INDEXES: uint32 = 0xFFFFFFFFu32; + // ── Constants — FormatMessage ───────────────────────────────────────────── + pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: uint32 = 0x00000100u32; + pub const FORMAT_MESSAGE_IGNORE_INSERTS: uint32 = 0x00000200u32; + pub const FORMAT_MESSAGE_FROM_SYSTEM: uint32 = 0x00001000u32; + pub const FORMAT_MESSAGE_FROM_MODULE: uint32 = 0x00000800u32; - // Constants — FormatMessage - - - pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: uint32 = 0x00000100u32; - pub const FORMAT_MESSAGE_IGNORE_INSERTS: uint32 = 0x00000200u32; - pub const FORMAT_MESSAGE_FROM_SYSTEM: uint32 = 0x00001000u32; - pub const FORMAT_MESSAGE_FROM_MODULE: uint32 = 0x00000800u32; - - - // Constants — GetModuleHandleEx Flags - + // ── Constants — GetModuleHandleEx ───────────────────────────────────────── pub const GET_MODULE_HANDLE_EX_FLAG_PIN: uint32 = 0x00000001u32; pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: uint32 = 0x00000002u32; pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: uint32 = 0x00000004u32; - - // Constants — File Creation / Access - - - pub const INVALID_FILE_SIZE: uint32 = 0xFFFFFFFFu32; - pub const INVALID_SET_FILE_POINTER: uint32 = 0xFFFFFFFFu32; - pub const FILE_BEGIN: uint32 = 0u32; - pub const FILE_CURRENT: uint32 = 1u32; - pub const FILE_END: uint32 = 2u32; - - pub const GENERIC_READ: uint32 = 0x80000000u32; - pub const GENERIC_WRITE: uint32 = 0x40000000u32; - pub const GENERIC_EXECUTE: uint32 = 0x20000000u32; - pub const GENERIC_ALL: uint32 = 0x10000000u32; - - pub const CREATE_NEW: uint32 = 1u32; - pub const CREATE_ALWAYS: uint32 = 2u32; - pub const OPEN_EXISTING: uint32 = 3u32; - pub const OPEN_ALWAYS: uint32 = 4u32; - pub const TRUNCATE_EXISTING: uint32 = 5u32; - - pub const FILE_SHARE_READ: uint32 = 0x00000001u32; - pub const FILE_SHARE_WRITE: uint32 = 0x00000002u32; - pub const FILE_SHARE_DELETE: uint32 = 0x00000004u32; - - pub const FILE_ATTRIBUTE_READONLY: uint32 = 0x00000001u32; - pub const FILE_ATTRIBUTE_HIDDEN: uint32 = 0x00000002u32; - pub const FILE_ATTRIBUTE_SYSTEM: uint32 = 0x00000004u32; - pub const FILE_ATTRIBUTE_DIRECTORY: uint32 = 0x00000010u32; - pub const FILE_ATTRIBUTE_ARCHIVE: uint32 = 0x00000020u32; - pub const FILE_ATTRIBUTE_NORMAL: uint32 = 0x00000080u32; - pub const FILE_ATTRIBUTE_TEMPORARY: uint32 = 0x00000100u32; - pub const FILE_ATTRIBUTE_COMPRESSED: uint32 = 0x00000800u32; - - pub const DRIVE_UNKNOWN: uint32 = 0u32; - pub const DRIVE_NO_ROOT_DIR: uint32 = 1u32; - pub const DRIVE_REMOVABLE: uint32 = 2u32; - pub const DRIVE_FIXED: uint32 = 3u32; - pub const DRIVE_REMOTE: uint32 = 4u32; - pub const DRIVE_CDROM: uint32 = 5u32; - pub const DRIVE_RAMDISK: uint32 = 6u32; - - - // Constants — Console - - - pub const STD_INPUT_HANDLE: uint32 = 0xFFFFFFF6u32; - pub const STD_OUTPUT_HANDLE: uint32 = 0xFFFFFFF5u32; - pub const STD_ERROR_HANDLE: uint32 = 0xFFFFFFF4u32; - - - // Extern — kernel32.dll (Core Functions) - + // ── Constants — File Access ─────────────────────────────────────────────── + + pub const INVALID_FILE_SIZE: uint32 = 0xFFFFFFFFu32; + pub const INVALID_SET_FILE_POINTER: uint32 = 0xFFFFFFFFu32; + pub const FILE_BEGIN: uint32 = 0u32; + pub const FILE_CURRENT: uint32 = 1u32; + pub const FILE_END: uint32 = 2u32; + + pub const GENERIC_READ: uint32 = 0x80000000u32; + pub const GENERIC_WRITE: uint32 = 0x40000000u32; + pub const GENERIC_EXECUTE: uint32 = 0x20000000u32; + pub const GENERIC_ALL: uint32 = 0x10000000u32; + + pub const CREATE_NEW: uint32 = 1u32; + pub const CREATE_ALWAYS: uint32 = 2u32; + pub const OPEN_EXISTING: uint32 = 3u32; + pub const OPEN_ALWAYS: uint32 = 4u32; + pub const TRUNCATE_EXISTING: uint32 = 5u32; + + pub const FILE_SHARE_READ: uint32 = 0x00000001u32; + pub const FILE_SHARE_WRITE: uint32 = 0x00000002u32; + pub const FILE_SHARE_DELETE: uint32 = 0x00000004u32; + + pub const FILE_ATTRIBUTE_READONLY: uint32 = 0x00000001u32; + pub const FILE_ATTRIBUTE_HIDDEN: uint32 = 0x00000002u32; + pub const FILE_ATTRIBUTE_SYSTEM: uint32 = 0x00000004u32; + pub const FILE_ATTRIBUTE_DIRECTORY: uint32 = 0x00000010u32; + pub const FILE_ATTRIBUTE_ARCHIVE: uint32 = 0x00000020u32; + pub const FILE_ATTRIBUTE_NORMAL: uint32 = 0x00000080u32; + pub const FILE_ATTRIBUTE_TEMPORARY: uint32 = 0x00000100u32; + pub const FILE_ATTRIBUTE_COMPRESSED: uint32 = 0x00000800u32; + + pub const DRIVE_UNKNOWN: uint32 = 0u32; + pub const DRIVE_NO_ROOT_DIR: uint32 = 1u32; + pub const DRIVE_REMOVABLE: uint32 = 2u32; + pub const DRIVE_FIXED: uint32 = 3u32; + pub const DRIVE_REMOTE: uint32 = 4u32; + pub const DRIVE_CDROM: uint32 = 5u32; + pub const DRIVE_RAMDISK: uint32 = 6u32; + + // ── Constants — Console ─────────────────────────────────────────────────── + + pub const STD_INPUT_HANDLE: uint32 = 0xFFFFFFF6u32; + pub const STD_OUTPUT_HANDLE: uint32 = 0xFFFFFFF5u32; + pub const STD_ERROR_HANDLE: uint32 = 0xFFFFFFF4u32; + + // Console mode flags + pub const ENABLE_PROCESSED_INPUT: uint32 = 0x0001u32; + pub const ENABLE_LINE_INPUT: uint32 = 0x0002u32; + pub const ENABLE_ECHO_INPUT: uint32 = 0x0004u32; + pub const ENABLE_WINDOW_INPUT: uint32 = 0x0008u32; + pub const ENABLE_MOUSE_INPUT: uint32 = 0x0010u32; + pub const ENABLE_INSERT_MODE: uint32 = 0x0020u32; + pub const ENABLE_QUICK_EDIT_MODE: uint32 = 0x0040u32; + pub const ENABLE_EXTENDED_FLAGS: uint32 = 0x0080u32; + pub const ENABLE_PROCESSED_OUTPUT: uint32 = 0x0001u32; + pub const ENABLE_WRAP_AT_EOL_OUTPUT: uint32 = 0x0002u32; + pub const ENABLE_VIRTUAL_TERMINAL_INPUT: uint32 = 0x0200u32; + pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING: uint32 = 0x0004u32; + pub const DISABLE_NEWLINE_AUTO_RETURN: uint32 = 0x0008u32; + pub const ENABLE_LVB_GRID_WORLDWIDE: uint32 = 0x0010u32; + + // ── Constants — Processor Architecture (SystemInfo) ────────────────────── + + pub const PROCESSOR_ARCHITECTURE_AMD64: uint16 = 9u16; + pub const PROCESSOR_ARCHITECTURE_ARM: uint16 = 5u16; + pub const PROCESSOR_ARCHITECTURE_ARM64: uint16 = 12u16; + pub const PROCESSOR_ARCHITECTURE_IA64: uint16 = 6u16; + pub const PROCESSOR_ARCHITECTURE_INTEL: uint16 = 0u16; + pub const PROCESSOR_ARCHITECTURE_UNKNOWN: uint16 = 0xFFFFu16; + + // ── Extern — kernel32.dll (core) ───────────────────────────────────────── @[Target("Windows")] @[Import(lib: "kernel32.dll")] extern { // Console - /// Allocates a new console for the calling process + /// Allocates a new console for the calling process. /// https://learn.microsoft.com/en-us/windows/console/allocconsole func AllocConsole() -> bool32; - /// Generates simple tones on the speaker + + /// Retrieves a handle to the specified standard device. + /// https://learn.microsoft.com/en-us/windows/console/getstdhandle + func GetStdHandle(nStdHandle: uint32) -> *opaque; + + /// Generates simple tones on the speaker. /// https://learn.microsoft.com/en-us/windows/win32/api/utilapiset/nf-utilapiset-beep func Beep(freq: uint32, duration: uint32) -> bool32; - /// Ends the calling process and all its threads + + /// Terminates the calling process and all its threads. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess func ExitProcess(exitCode: uint32); - + // Error handling - /// Retrieves the calling thread's last-error code value + /// Retrieves the calling thread's last-error code. /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror func GetLastError() -> uint32; - /// Sets the last-error code for the calling thread + + /// Sets the last-error code for the calling thread. /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror func SetLastError(error: uint32); - + // Heap management - /// Retrieves a handle to the default heap of the calling process + /// Returns a handle to the process default heap. /// https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap func GetProcessHeap() -> *opaque; - /// Allocates a block of memory from a heap. The allocated memory is not movable + + /// Allocates a block from a heap. /// https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc func HeapAlloc(heap: *opaque, flags: uint32, bytes: uint) -> *opaque; - /// Frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function + + /// Frees a block allocated from a heap. /// https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree func HeapFree(heap: *opaque, flags: uint32, mem: *opaque) -> bool32; - /// Reallocates a block of memory from a heap + + /// Reallocates a heap block. /// https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc func HeapReAlloc(heap: *opaque, flags: uint32, mem: *opaque, bytes: uint) -> *opaque; - + // String conversion - /// Maps a character string to a UTF-16 wide character string + /// Converts a multi-byte string to UTF-16. /// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar func MultiByteToWideChar( - codePage: CodePage, - flags: uint32, + codePage: CodePage, + flags: uint32, multiByteStr: *const char8, - multiByte: int32, - wideCharStr: *char16, - wideChar: int32) -> int32; - - // Memory utilities (RTL functions) - /// Compares two blocks of memory and returns the number of bytes that match until the first difference + multiByte: int32, + wideCharStr: *char16, + wideChar: int32 + ) -> int32; + + /// Converts a UTF-16 string to a multi-byte string. + /// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte + func WideCharToMultiByte( + codePage: uint32, + flags: uint32, + wideCharStr: *const char16, + wideChar: int32, + multiByteStr: *char8, + multiByte: int32, + defaultChar: *const char8, + usedDefaultChar: *bool32 + ) -> int32; + + // Memory utilities + /// Compares two memory blocks. /// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlcomparememory func RtlCompareMemory(source1: *const opaque, source2: *const opaque, length: uint) -> uint; - /// Copies a block of memory from one location to another + + /// Copies memory. /// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa366535(v=vs.85) func RtlCopyMemory(destination: *opaque, source: *const opaque, length: uint); - /// Fills a block of memory with the specified fill value + + /// Fills memory with a byte value. /// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlfillmemory func RtlFillMemory(destination: *opaque, length: uint, fill: int32); - /// Fills a block of memory with zeros, given a pointer to the block and the length in bytes + + /// Zeroes a block of memory. /// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlzeromemory func RtlZeroMemory(destination: *opaque, length: uint); - + // Timing - /// Suspends the execution of the current thread until the time-out interval elapses + /// Suspends the current thread for the specified number of milliseconds. /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep func Sleep(milliseconds: uint32); - /// Retrieves the number of milliseconds that have elapsed since the system was started (32-bit) + + /// Returns milliseconds since system boot (wraps at 49.7 days). /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount func GetTickCount() -> uint32; - /// Retrieves the number of milliseconds that have elapsed since the system was started (64-bit) + + /// Returns milliseconds since system boot (64-bit, no wrap). /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64 func GetTickCount64() -> uint64; - /// Retrieves the current value of the high-resolution performance counter + + /// Reads the high-resolution performance counter. /// https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter func QueryPerformanceCounter(counterOut: *uint64) -> bool32; - /// Retrieves the frequency of the high-resolution performance counter + + /// Returns the frequency of the performance counter in counts per second. /// https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency func QueryPerformanceFrequency(freqOut: *uint64) -> bool32; - /// Retrieves the current system date and time as a FILETIME structure + + /// Returns the current system time as a FILETIME. /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime func GetSystemTimeAsFileTime(time: *uint64); - + // File I/O - /// Reads data from the specified file or input/output device + /// Reads data from a file or device. /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile func ReadFile( - file: *opaque, - buffer: *opaque, + file: *opaque, + buffer: *opaque, numberOfBytesToRead: uint32, - numberOfBytesRead: *uint32, - overlapped: *opaque) -> bool32; - - /// Writes data to the specified file or input/output device + numberOfBytesRead: *uint32, + overlapped: *opaque + ) -> bool32; + + /// Writes data to a file or device. /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile func WriteFile( - file: *opaque, - buffer: *const opaque, - bytesToWrite: uint32, - bytesWritten: *uint32, - overlapped: *opaque) -> bool32; - + file: *opaque, + buffer: *const opaque, + bytesToWrite: uint32, + bytesWritten: *uint32, + overlapped: *opaque + ) -> bool32; + // Console output - /// Writes a character string to a console screen buffer (ANSI) + /// Writes ANSI characters to a console screen buffer. /// https://learn.microsoft.com/en-us/windows/console/writeconsole func WriteConsoleA( - consoleOutput: *opaque, - buffer: *const char8, - numberOfCharsToWrite: uint32, - numberOfCharsWritten: *uint32, - reserved: *opaque) -> bool32; - - /// Writes a character string to a console screen buffer (Unicode) + consoleOutput: *opaque, + buffer: *const char8, + numberOfCharsToWrite: uint32, + numberOfCharsWritten: *uint32, + reserved: *opaque + ) -> bool32; + + /// Writes UTF-16 characters to a console screen buffer. /// https://learn.microsoft.com/en-us/windows/console/writeconsole func WriteConsoleW( - consoleOutput: *opaque, - buffer: *const char16, - numberOfCharsToWrite: uint32, - numberOfCharsWritten: *uint32, - reserved: *opaque) -> bool32; - - // Interlocked operations for thread safety - /// Atomically exchanges a pair of pointer values + consoleOutput: *opaque, + buffer: *const char16, + numberOfCharsToWrite: uint32, + numberOfCharsWritten: *uint32, + reserved: *opaque + ) -> bool32; + + // Interlocked / atomic operations + /// Atomically exchanges two pointer values. /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangepointer func InterlockedExchangePointer(target: *opaque, value: *opaque) -> *opaque; - /// Performs an atomic compare-and-exchange operation on pointer values + + /// Atomically compares and conditionally exchanges two pointer values. /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchangepointer func InterlockedCompareExchangePointer(target: *opaque, exchange: *opaque, comparand: *opaque) -> *opaque; - /// Atomically sets a 32-bit variable to the specified value + + /// Atomically sets a 32-bit value and returns the old value. /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange func InterlockedExchange(target: *int32, value: int32) -> int32; - /// Performs an atomic compare-and-exchange on a 32-bit value + + /// Atomically compares and conditionally exchanges a 32-bit value. /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange func InterlockedCompareExchange(target: *int32, exchange: int32, comparand: int32) -> int32; - + + /// Atomically increments a 32-bit value by 1. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedincrement + func InterlockedIncrement(addend: *int32) -> int32; + + /// Atomically decrements a 32-bit value by 1. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockeddecrement + func InterlockedDecrement(addend: *int32) -> int32; + + /// Atomically adds a value to a 32-bit variable. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangeadd + func InterlockedExchangeAdd(addend: *int32, value: int32) -> int32; + + /// Atomically exchanges a 64-bit value. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange64 + func InterlockedExchange64(target: *int64, value: int64) -> int64; + + /// Atomically compares and conditionally exchanges a 64-bit value. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange64 + func InterlockedCompareExchange64(target: *int64, exchange: int64, comparand: int64) -> int64; + // WOW64 detection - /// Determines whether the specified process is running under WOW64 + /// Determines whether the target process is a 32-bit process running under WOW64. /// https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process func IsWow64Process(hProcess: *opaque, wow64Process: *bool32) -> bool32; - } - - // Extern — kernel32.dll (Process, Memory, DLL, Thread, Sync) + /// Extended version that also reports the native machine architecture. + /// https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process2 + func IsWow64Process2(hProcess: *opaque, processMachine: *uint16, nativeMachine: *uint16) -> bool32; + } + // ── Extern — kernel32.dll (process / memory / DLL / thread / sync) ──────── @[Target("Windows")] @[Import(lib: "kernel32.dll")] extern { // Process management - /// Opens an existing local process object + /// Opens an existing process by ID. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess func OpenProcess(desiredAccess: uint32, inheritHandle: bool32, processId: uint32) -> *opaque; - /// Closes an open object handle + + /// Closes an open object handle. /// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle func CloseHandle(handle: *opaque) -> bool32; - /// Terminates the specified process and all of its threads + + /// Terminates the specified process. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess func TerminateProcess(hProcess: *opaque, exitCode: uint32) -> bool32; - /// Retrieves a pseudo handle for the current process + + /// Returns a pseudo handle for the current process. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess func GetCurrentProcess() -> *opaque; - /// Retrieves the process identifier of the calling process + + /// Returns the PID of the calling process. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid func GetCurrentProcessId() -> uint32; - /// Retrieves the termination status of the specified process + + /// Retrieves the exit code of a process. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess func GetExitCodeProcess(hProcess: *opaque, exitCode: *uint32) -> bool32; - /// Retrieves the full name of the executable image for the specified process + + /// Retrieves the full path of the executable image for a process. /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamea func QueryFullProcessImageNameA(hProcess: *opaque, flags: uint32, name: *char8, size: *uint32) -> bool32; - + + /// Creates a new process. + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa + func CreateProcessA( + applicationName: *const char8, + commandLine: *char8, + processAttr: *opaque, + threadAttr: *opaque, + inheritHandles: bool32, + creationFlags: uint32, + environment: *opaque, + currentDirectory: *const char8, + startupInfo: *opaque, + processInfo: *opaque + ) -> bool32; + // Process memory - /// Reads data from an area of memory in a specified process + /// Reads memory from a process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory func ReadProcessMemory(hProcess: *opaque, baseAddress: *const opaque, buffer: *opaque, size: uint, bytesRead: *uint) -> bool32; - /// Writes data to an area of memory in a specified process + + /// Writes memory to a process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory func WriteProcessMemory(hProcess: *opaque, baseAddress: *opaque, buffer: *const opaque, size: uint, bytesWritten: *uint) -> bool32; - - // Virtual memory (remote) - /// Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process + + // Virtual memory — remote + /// Allocates virtual memory in a remote process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex func VirtualAllocEx(hProcess: *opaque, address: *opaque, size: uint, allocationType: uint32, protect: uint32) -> *opaque; - /// Releases, decommits, or releases and decommits a region of memory within the virtual address space of a specified process + + /// Frees virtual memory in a remote process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfreeex func VirtualFreeEx(hProcess: *opaque, address: *opaque, size: uint, freeType: uint32) -> bool32; - /// Changes the protection on a region of committed pages in the virtual address space of a specified process + + /// Changes memory protection in a remote process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotectex func VirtualProtectEx(hProcess: *opaque, address: *opaque, size: uint, newProtect: uint32, oldProtect: *uint32) -> bool32; - /// Retrieves information about a range of pages within the virtual address space of a specified process + + /// Queries virtual memory in a remote process. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualqueryex func VirtualQueryEx(hProcess: *opaque, address: *const opaque, buffer: *opaque, length: uint) -> uint; - - // Virtual memory (local) - /// Reserves, commits, or changes the state of a region of pages in the virtual address space of the calling process + + // Virtual memory — local + /// Reserves or commits virtual memory. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc func VirtualAlloc(address: *opaque, size: uint, allocationType: uint32, protect: uint32) -> *opaque; - /// Releases, decommits, or releases and decommits a region of pages within the virtual address space of the calling process + + /// Releases or decommits virtual memory. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree func VirtualFree(address: *opaque, size: uint, freeType: uint32) -> bool32; - /// Changes the protection on a region of committed pages in the virtual address space of the calling process + + /// Changes memory protection for local pages. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect func VirtualProtect(address: *opaque, size: uint, newProtect: uint32, oldProtect: *uint32) -> bool32; - /// Retrieves information about a range of pages in the virtual address space of the calling process + + /// Queries virtual memory for local pages. /// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery func VirtualQuery(address: *const opaque, buffer: *opaque, length: uint) -> uint; - - // Remote threads - /// Creates a thread that runs in the virtual address space of another process + + // Remote thread + /// Creates a thread in a remote process. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread func CreateRemoteThread(hProcess: *opaque, threadAttr: *opaque, stackSize: uint, startAddress: *const opaque, parameter: *opaque, creationFlags: uint32, threadId: *uint32) -> *opaque; - - // Synchronization - /// Waits until the specified object is in the signaled state or the time-out interval elapses + + // Synchronisation + /// Waits for a single object to become signalled. /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject func WaitForSingleObject(hHandle: *opaque, milliseconds: uint32) -> uint32; - /// Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses + + /// Waits for one or all of several objects. /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects func WaitForMultipleObjects(count: uint32, handles: *opaque, waitAll: bool32, milliseconds: uint32) -> uint32; - + // DLL management - /// Loads the specified module into the address space of the calling process (ANSI) + /// Loads a DLL (ANSI). /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya func LoadLibraryA(libFileName: *const char8) -> *opaque; - /// Loads the specified module into the address space of the calling process (Unicode) + + /// Loads a DLL (UTF-16). /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw func LoadLibraryW(libFileName: *const char16) -> *opaque; - /// Loads the specified module with extended options + + /// Loads a DLL with extended flags. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa func LoadLibraryExA(libFileName: *const char8, file: *opaque, flags: uint32) -> *opaque; - /// Retrieves a module handle for the specified module (ANSI) + + /// Gets a module handle (ANSI). /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlea func GetModuleHandleA(moduleName: *const char8) -> *opaque; - /// Retrieves a module handle for the specified module (Unicode) + + /// Gets a module handle (UTF-16). /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlew func GetModuleHandleW(moduleName: *const char16) -> *opaque; - /// Retrieves the address of an exported function or variable from the specified DLL + + /// Gets the address of an exported function or variable. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress func GetProcAddress(hModule: *opaque, procName: *const char8) -> *const opaque; - /// Frees the loaded DLL module and decrements its reference count + + /// Frees a loaded DLL. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary func FreeLibrary(hModule: *opaque) -> bool32; - /// Retrieves the fully qualified path for the file that contains the specified module + + /// Gets the full path of the module file. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea func GetModuleFileNameA(hModule: *opaque, filename: *char8, size: uint32) -> uint32; - /// Disables the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the specified DLL + + /// Disables DLL_THREAD_ATTACH/DETACH notifications. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-disablethreadlibrarycalls func DisableThreadLibraryCalls(hModule: *opaque) -> bool32; - /// Adds a directory to the search path used to locate DLLs for the application + + /// Adds a directory to the DLL search path. /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectorya func SetDllDirectoryA(pathName: *const char8) -> bool32; - /// Retrieves a module handle for the specified module with optional flags + + /// Gets a module handle with optional flags. /// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa func GetModuleHandleExA(flags: uint32, name: *const char8, hModule: *opaque) -> bool32; - - // Toolhelp32 snapshot (process/module enumeration) - /// Takes a snapshot of the specified processes, heaps, modules, and threads + + // Toolhelp32 snapshot + /// Takes a system snapshot. /// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot func CreateToolhelp32Snapshot(flags: uint32, processId: uint32) -> *opaque; - /// Retrieves information about the first process encountered in a system snapshot - /// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first func Process32First(hSnapshot: *opaque, entry: *ProcessEntry32) -> bool32; - /// Retrieves information about the next process recorded in a system snapshot - /// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next - func Process32Next(hSnapshot: *opaque, entry: *ProcessEntry32) -> bool32; - /// Retrieves information about the first module associated with a process in a snapshot - /// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-module32first - func Module32First(hSnapshot: *opaque, entry: *ModuleEntry32) -> bool32; - /// Retrieves information about the next module associated with a process in a snapshot - /// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-module32next - func Module32Next(hSnapshot: *opaque, entry: *ModuleEntry32) -> bool32; - + func Process32Next(hSnapshot: *opaque, entry: *ProcessEntry32) -> bool32; + func Module32First(hSnapshot: *opaque, entry: *ModuleEntry32) -> bool32; + func Module32Next(hSnapshot: *opaque, entry: *ModuleEntry32) -> bool32; + // Thread management - /// Creates a thread to execute within the virtual address space of the calling process + /// Creates a local thread. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread func CreateThread(threadAttr: *opaque, stackSize: uint, startAddress: *const opaque, parameter: *opaque, flags: uint32, threadId: *uint32) -> *opaque; - /// Opens an existing thread object - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread func OpenThread(desiredAccess: uint32, inheritHandle: bool32, threadId: uint32) -> *opaque; - /// Retrieves a pseudo handle for the calling thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthread func GetCurrentThread() -> *opaque; - /// Retrieves the thread identifier of the calling thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid func GetCurrentThreadId() -> uint32; - /// Ends the calling thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitthread func ExitThread(exitCode: uint32); - /// Terminates a thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread func TerminateThread(hThread: *opaque, exitCode: uint32) -> bool32; - /// Retrieves the termination status of the specified thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodethread func GetExitCodeThread(hThread: *opaque, exitCode: *uint32) -> bool32; - + // Thread control - /// Suspends the specified thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread func SuspendThread(hThread: *opaque) -> uint32; - /// Decrements a thread's suspend count; when the count reaches zero, the thread resumes execution - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread func ResumeThread(hThread: *opaque) -> uint32; - /// Sets the priority value for the specified thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadpriority func SetThreadPriority(hThread: *opaque, priority: int32) -> bool32; - /// Retrieves the priority value for the specified thread - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadpriority func GetThreadPriority(hThread: *opaque) -> int32; - /// Causes the calling thread to yield execution to another thread that is ready to run - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-switchtothread func SwitchToThread() -> bool32; - + + // Queue user APC (used for stealthy injection) + /// Queues a user-mode APC to the specified thread. + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc + func QueueUserAPC(pfnAPC: *const opaque, hThread: *opaque, data: uint) -> uint32; + // Event objects - /// Creates or opens a named or unnamed event object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa func CreateEventA(eventAttr: *opaque, manualReset: bool32, initialState: bool32, name: *const char8) -> *opaque; - /// Sets the specified event object to the signaled state - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent func SetEvent(hEvent: *opaque) -> bool32; - /// Sets the specified event object to the nonsignaled state - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-resetevent func ResetEvent(hEvent: *opaque) -> bool32; - + // Mutex objects - /// Creates or opens a named or unnamed mutex object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa func CreateMutexA(mutexAttr: *opaque, initialOwner: bool32, name: *const char8) -> *opaque; - /// Releases ownership of the specified mutex object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasemutex func ReleaseMutex(hMutex: *opaque) -> bool32; - + + // Semaphore objects + /// Creates or opens a semaphore object. + /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createsemaphorea + func CreateSemaphoreA(semAttr: *opaque, initialCount: int32, maxCount: int32, name: *const char8) -> *opaque; + func ReleaseSemaphore(hSemaphore: *opaque, releaseCount: int32, previousCount: *int32) -> bool32; + // Critical sections - /// Initializes a critical section object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializecriticalsection func InitializeCriticalSection(cs: *opaque); - /// Waits for ownership of the specified critical section object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-entercriticalsection func EnterCriticalSection(cs: *opaque); - /// Releases ownership of the specified critical section object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-leavecriticalsection func LeaveCriticalSection(cs: *opaque); - /// Releases all resources used by an unowned critical section object - /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-deletecriticalsection func DeleteCriticalSection(cs: *opaque); - + /// Attempts to enter a critical section without blocking. + /// https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryentercriticalsection + func TryEnterCriticalSection(cs: *opaque) -> bool32; + // Thread Local Storage - /// Allocates a thread local storage index - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsalloc func TlsAlloc() -> uint32; - /// Stores a value in the calling thread's thread local storage slot - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlssetvalue func TlsSetValue(tlsIndex: uint32, tlsValue: *opaque) -> bool32; - /// Retrieves the value in the calling thread's thread local storage slot - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsgetvalue func TlsGetValue(tlsIndex: uint32) -> *opaque; - /// Releases a thread local storage index, making it available for reuse - /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsfree func TlsFree(tlsIndex: uint32) -> bool32; - + // System directories - /// Retrieves the path of the system directory - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemdirectorya func GetSystemDirectoryA(buffer: *char8, size: uint32) -> uint32; - /// Retrieves the path of the Windows directory - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getwindowsdirectorya func GetWindowsDirectoryA(buffer: *char8, size: uint32) -> uint32; - + /// Returns the system directory used for WOW64 32-bit DLLs. + /// https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-getsystemwow64directorya + func GetSystemWow64DirectoryA(buffer: *char8, size: uint32) -> uint32; + // Debugging - /// Sends a string to the debugger for display - /// https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringa func OutputDebugStringA(outputString: *const char8); - + func IsDebuggerPresent() -> bool32; + func DebugBreak(); + // Cache control - /// Flushes the instruction cache for the specified process + /// Flushes the instruction cache for a process region. /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushinstructioncache func FlushInstructionCache(hProcess: *opaque, baseAddress: *const opaque, size: uint) -> bool32; - + // Error formatting - /// Formats a message string from a message table resource or a caller-supplied buffer - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagea func FormatMessageA( - flags: uint32, - source: *opaque, + flags: uint32, + source: *opaque, messageId: uint32, - langId: uint32, - buffer: *char8, - size: uint32, - args: *opaque + langId: uint32, + buffer: *char8, + size: uint32, + args: *opaque ) -> uint32; - - // Environment / System info - /// Retrieves the path of the directory designated for temporary files - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha + + // Environment / system info func GetTempPathA(bufLen: uint32, buf: *char8) -> uint32; - /// Retrieves the NetBIOS name of the local computer - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcomputernamea func GetComputerNameA(buf: *char8, size: *uint32) -> bool32; - /// Replaces environment-variable strings with the values defined for the current user - /// https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-expandenvironmentstringsa func ExpandEnvironmentStringsA(src: *const char8, dst: *char8, size: uint32) -> uint32; - /// Retrieves the contents of the specified variable from the environment block of the calling process - /// https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentvariablea func GetEnvironmentVariableA(name: *const char8, buf: *char8, size: uint32) -> uint32; - /// Sets the contents of the specified environment variable for the current process - /// https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablea func SetEnvironmentVariableA(name: *const char8, value: *const char8) -> bool32; - - // Locale / Code page - /// Returns the locale identifier for the user default locale - /// https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlcid + + // Locale / code page func GetUserDefaultLCID() -> uint32; - /// Returns the current Windows ANSI code page identifier for the operating system - /// https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getacp func GetACP() -> uint32; - + // File operations - /// Creates or opens a file or I/O device + /// Creates or opens a file or device. /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea func CreateFileA( - fileName: *const char8, - desiredAccess: uint32, - shareMode: uint32, - securityAttr: *opaque, + fileName: *const char8, + desiredAccess: uint32, + shareMode: uint32, + securityAttr: *opaque, creationDisposition: uint32, - flagsAndAttributes: uint32, - templateFile: *opaque + flagsAndAttributes: uint32, + templateFile: *opaque ) -> *opaque; - - /// Retrieves the size of the specified file as a 64-bit value - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex + func GetFileSizeEx(file: *opaque, size: *uint64) -> bool32; - /// Moves the file pointer of the specified file - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex - func SetFilePointerEx( - file: *opaque, - distance: int64, - newPtr: *int64, - moveMethod: uint32 - ) -> bool32; - - /// Retrieves file system attributes for a specified file or directory - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa + func SetFilePointerEx(file: *opaque, distance: int64, newPtr: *int64, moveMethod: uint32) -> bool32; func GetFileAttributesA(fileName: *const char8) -> uint32; - /// Sets the attributes for a file or directory - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa func SetFileAttributesA(fileName: *const char8, attrs: uint32) -> bool32; - /// Retrieves the file type of the specified file - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletype func GetFileType(hFile: *opaque) -> uint32; - - /// Copies an existing file to a new file - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfilea func CopyFileA(existing: *const char8, newFile: *const char8, failIfExists: bool32) -> bool32; - /// Moves an existing file or directory - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilea func MoveFileA(existing: *const char8, newFile: *const char8) -> bool32; - /// Deletes an existing file - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilea func DeleteFileA(fileName: *const char8) -> bool32; - + + /// Searches for a file in a list of directories. + /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-searchpatha + func SearchPathA( + path: *const char8, + fileName: *const char8, + extension: *const char8, + bufLen: uint32, + buf: *char8, + filePart: **char8 + ) -> uint32; + + // File finding + func FindFirstFileA(fileName: *const char8, findData: *Win32FindDataA) -> *opaque; + func FindNextFileA(hFind: *opaque, findData: *Win32FindDataA) -> bool32; + func FindClose(hFind: *opaque) -> bool32; + // Directory operations - /// Creates a new directory - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya func CreateDirectoryA(path: *const char8, securityAttr: *opaque) -> bool32; - /// Deletes an existing empty directory - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya func RemoveDirectoryA(path: *const char8) -> bool32; - /// Retrieves the current directory for the current process - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectorya func GetCurrentDirectoryA(bufLen: uint32, buf: *char8) -> uint32; - /// Changes the current directory for the current process - /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcurrentdirectorya func SetCurrentDirectoryA(path: *const char8) -> bool32; - /// Retrieves a bitmask representing the currently available disk drives - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives func GetLogicalDrives() -> uint32; - /// Determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea func GetDriveTypeA(rootPath: *const char8) -> uint32; - /// Retrieves information about the amount of space available on a disk volume - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexa func GetDiskFreeSpaceExA( - dir: *const char8, + dir: *const char8, freeBytesAvail: *uint64, - totalBytes: *uint64, - totalFree: *uint64 + totalBytes: *uint64, + totalFree: *uint64 ) -> bool32; - + // System information - /// Retrieves information about the current system - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo func GetSystemInfo(info: *opaque); - /// Retrieves information about the current system to an application running under WOW64 - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getnativesysteminfo func GetNativeSystemInfo(info: *opaque); - /// Retrieves information about the system's current usage of both physical and virtual memory - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex func GlobalMemoryStatusEx(buffer: *opaque) -> bool32; - /// Retrieves information about logical processors and related hardware - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation func GetLogicalProcessorInformation(buffer: *opaque, retLen: *uint32) -> bool32; - + // Time functions - /// Retrieves the current system date and time in UTC - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime func GetSystemTime(time: *opaque); - /// Sets the current system time and date in UTC - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setsystemtime func SetSystemTime(time: *opaque) -> bool32; - /// Retrieves the current local date and time - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlocaltime func GetLocalTime(time: *opaque); - /// Sets the current local time and date - /// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setlocaltime func SetLocalTime(time: *opaque) -> bool32; - /// Converts a file time to a local file time - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-filetimetolocalfiletime func FileTimeToLocalFileTime(inFileTime: *uint64, outLocal: *uint64) -> bool32; - /// Converts a file time to system time format - /// https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-filetimetosystemtime func FileTimeToSystemTime(inFileTime: *uint64, systemTime: *opaque) -> bool32; - /// Converts a system time to file time format - /// https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetofiletime func SystemTimeToFileTime(systemTime: *opaque, fileTime: *uint64) -> bool32; - /// Compares two file times - /// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-comparefiletime func CompareFileTime(time1: *uint64, time2: *uint64) -> int32; - + // Console control - /// Sets the title bar string for the current console window - /// https://learn.microsoft.com/en-us/windows/console/setconsoletitle func SetConsoleTitleA(title: *const char8) -> bool32; - /// Retrieves the title bar string for the current console window - /// https://learn.microsoft.com/en-us/windows/console/getconsoletitle func GetConsoleTitleA(buf: *char8, size: uint32) -> uint32; - /// Retrieves the current input mode of a console input buffer or output mode of a console screen buffer - /// https://learn.microsoft.com/en-us/windows/console/getconsolemode func GetConsoleMode(console: *opaque, mode: *uint32) -> bool32; - /// Sets the input mode of a console input buffer or the output mode of a console screen buffer - /// https://learn.microsoft.com/en-us/windows/console/setconsolemode func SetConsoleMode(console: *opaque, mode: uint32) -> bool32; - /// Sets the attributes of characters written to the console screen buffer - /// https://learn.microsoft.com/en-us/windows/console/setconsoletextattribute func SetConsoleTextAttribute(console: *opaque, attrs: uint16) -> bool32; + + // Pipe / anonymous I/O + /// Creates an anonymous pipe. + /// https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe + func CreatePipe( + readPipe: *opaque, + writePipe: *opaque, + pipeAttr: *opaque, + bufferSize: uint32 + ) -> bool32; + + /// Creates a named pipe. + /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createnamedpipea + func CreateNamedPipeA( + name: *const char8, + openMode: uint32, + pipeMode: uint32, + maxInstances: uint32, + outBufSize: uint32, + inBufSize: uint32, + defaultTimeOut: uint32, + securityAttr: *opaque + ) -> *opaque; + + /// Connects a named pipe to a client. + /// https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe + func ConnectNamedPipe(hNamedPipe: *opaque, overlapped: *opaque) -> bool32; + + // Handle duplication + /// Duplicates an object handle. + /// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle + func DuplicateHandle( + hSourceProcess: *opaque, + hSource: *opaque, + hTargetProcess: *opaque, + hTarget: *opaque, + desiredAccess: uint32, + inheritHandle: bool32, + options: uint32 + ) -> bool32; + } + + // ── Utility — null-terminated string length ─────────────────────────────── + + /// Returns the number of bytes in a null-terminated char8 string (excluding null). + pub func StrLen(s: *const char8) -> uint { + var n: uint = 0u; + loop { + let c = *((s as uint + n) as *const char8); + if c as uint8 == 0u8 { break; } + n = n + 1u; + } + return n; + } + + /// Copies a null-terminated ASCII string, writing at most maxLen bytes including the terminator. + pub func CStrCopy(dst: *char8, src: *const char8, maxLen: uint) { + var i: uint = 0u; + loop { + if i >= maxLen { break; } + let c = *((src as uint + i) as *const char8); + *((dst as uint + i) as *char8) = c; + if c as uint8 == 0u8 { break; } + i = i + 1u; + } } -} \ No newline at end of file +} diff --git a/Src/NtDll.rux b/Src/NtDll.rux index c8d826e..8877941 100644 --- a/Src/NtDll.rux +++ b/Src/NtDll.rux @@ -1,223 +1,300 @@ -/* - Windows API — Native API (ntdll.dll) - Copyright © 2026 Rux Contributors - Licensed under the MIT License +/* + Windows API — Native API (ntdll.dll) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Canonical home for all STATUS_* NTSTATUS codes. + BCrypt.rux USED to re-declare STATUS_SUCCESS etc — that is fixed: + those constants now live only here. + + References: https://learn.microsoft.com/en-us/windows/win32/api/winternl/ */ - -module Windows { - - - // Constants — NTSTATUS - - - pub const STATUS_SUCCESS: uint32 = 0x00000000u32; - pub const STATUS_INFO_LENGTH_MISMATCH: uint32 = 0xC0000004u32; - pub const STATUS_NOT_FOUND: uint32 = 0xC0000225u32; - pub const STATUS_ACCESS_DENIED: uint32 = 0xC0000022u32; - pub const STATUS_BUFFER_TOO_SMALL: uint32 = 0xC0000023u32; - pub const STATUS_PROCESS_IS_TERMINATING: uint32 = 0xC000010Au32; - - - // Constants — Process Information Classes (NtQueryInformationProcess) - - - pub const ProcessBasicInformation: uint32 = 0u32; - pub const ProcessQuotaLimits: uint32 = 1u32; - pub const ProcessIoCounters: uint32 = 2u32; - pub const ProcessVmCounters: uint32 = 3u32; - pub const ProcessTimes: uint32 = 4u32; - pub const ProcessBasePriority: uint32 = 5u32; - pub const ProcessRaisePriority: uint32 = 6u32; - pub const ProcessDebugPort: uint32 = 7u32; - pub const ProcessWow64Info: uint32 = 26u32; - pub const ProcessImageFileName: uint32 = 27u32; - pub const ProcessBreakOnTermination: uint32 = 29u32; - pub const ProcessSubsystemInformation: uint32 = 75u32; - - - // Constants — System Information Classes (NtQuerySystemInformation) - - - pub const SystemBasicInformation: uint32 = 0u32; - pub const SystemPerformanceInformation: uint32 = 2u32; - pub const SystemProcessInformation: uint32 = 5u32; - pub const SystemProcessorPerformanceInformation: uint32 = 8u32; - pub const SystemModuleInformation: uint32 = 11u32; - pub const SystemKernelDebuggerInformation: uint32 = 35u32; - pub const SystemHandleInformation: uint32 = 16u32; - pub const SystemObjectInformation: uint32 = 17u32; - pub const SystemCodeIntegrityInformation: uint32 = 103u32; - pub const SystemFlagsInformation: uint32 = 9u32; - - - // Structures - - - pub struct ProcessBasicInfo { - pub exitStatus: uint32; - pub _pad1: uint32; - pub pebBaseAddress: *opaque; - pub affinityMask: *opaque; - pub basePriority: int32; - pub _pad2: uint32; - pub uniqueProcessId: *opaque; - pub inheritedFromUniqueProcessId: *opaque; - } - - pub struct OsVersionInfo { - pub osVersionInfoSize: uint32; - pub majorVersion: uint32; - pub minorVersion: uint32; - pub buildNumber: uint32; - pub platformId: uint32; - pub csdVersion: char16[128]; - } - - pub struct IoCounters { - pub readOperationCount: uint64; - pub writeOperationCount: uint64; - pub otherOperationCount: uint64; - pub readTransferCount: uint64; - pub writeTransferCount: uint64; - pub otherTransferCount: uint64; - } - - pub struct VmCounters { - pub peakVirtualSize: uint; - pub virtualSize: uint; - pub pageFaultCount: uint32; - pub _pad1: uint32; - pub peakWorkingSetSize: uint; - pub workingSetSize: uint; - pub quotaPeakPagedPoolUsage: uint; - pub quotaPagedPoolUsage: uint; - pub quotaPeakNonPagedPoolUsage: uint; - pub quotaNonPagedPoolUsage: uint; - pub pagefileUsage: uint; - pub peakPagefileUsage: uint; - } - - - // Structures — Extended - - - pub struct SysBasicInfo { - pub _reserved1: uint32; - pub timerResolution: uint32; - pub pageSize: uint32; - pub numberOfPhysicalPages: uint32; - pub lowestPhysicalPageNumber: uint32; - pub highestPhysicalPageNumber: uint32; - pub allocationGranularity: uint32; - pub minimumUserModeAddress: *opaque; - pub maximumUserModeAddress: *opaque; - pub activeProcessors: *opaque; - pub numberOfProcessors: uint32; - } - - pub struct RtlProcessModuleInformation { - pub section: *opaque; - pub mappedBase: *opaque; - pub imageBase: *opaque; - pub imageSize: uint32; - pub flags: uint32; - pub loadOrderIndex: uint16; - pub initOrderIndex: uint16; - pub loadCount: uint16; - pub moduleNameOffset: uint16; - pub fullPathName: char8[256]; - } - - - - // Extern — ntdll.dll - - - @[Import(lib: "ntdll.dll")] - extern { - - /// Retrieves information about the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess - func NtQueryInformationProcess( - processHandle: *opaque, - infoClass: uint32, - info: *opaque, - infoLength: uint32, - retLength: *uint32 - ) -> uint32; - - /// Opens an existing process object - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenprocess - func NtOpenProcess( - processHandle: *opaque, - desiredAccess: uint32, - objectAttr: *opaque, - clientId: *opaque - ) -> uint32; - - /// Closes an object handle - /// https://learn.microsoft.com/en-us/windows/hardware/drivers/ddi/ntifs/nf-ntifs-ntclose - func NtClose(handle: *opaque) -> uint32; - - /// Suspends all threads in the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/ - func NtSuspendProcess(processHandle: *opaque) -> uint32; - - /// Resumes all threads in the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/ - func NtResumeProcess(processHandle: *opaque) -> uint32; - - - /// Retrieves the specified system information - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation - func NtQuerySystemInformation( - infoClass: uint32, - info: *opaque, - infoLength: uint32, - retLength: *uint32 - ) -> uint32; - - - /// Provides information about a range of virtual memory in the address space of the calling process - /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/ - func NtQueryVirtualMemory( - processHandle: *opaque, - baseAddress: *const opaque, - infoClass: uint32, - info: *opaque, - infoLength: uint, - retLength: *uint - ) -> uint32; - - - /// Returns version information about the currently running operating system - /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion - func RtlGetVersion(versionInfo: *opaque) -> uint32; - - /// Allocates a block of memory from a heap - /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlallocateheap - func RtlAllocateHeap(heap: *opaque, flags: uint32, size: uint) -> *opaque; - - /// Frees a memory block that was allocated from a heap by RtlAllocateHeap - /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlfreeheap - func RtlFreeHeap(heap: *opaque, flags: uint32, block: *opaque) -> bool32; - - /// Retrieves the version number of the operating system at the NT layer - /// https://learn.microsoft.com/en-us/windows/win32/devnotes/ - func RtlGetNtVersionNumbers(major: *uint32, minor: *uint32, build: *uint32); - - /// Returns a pointer to the IMAGE_NT_HEADERS for a PE image in memory - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagentheader - func RtlImageNtHeader(moduleBase: *opaque) -> *opaque; - - /// Locates a directory entry in the image header and returns a pointer to the data - /// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagedirectoryentrytodataex - func RtlImageDirectoryEntryToData( - moduleBase: *opaque, - mappedAsImage: bool32, - directoryEntry: uint16, - size: *uint32 - ) -> *opaque; - } - -} + +module Windows { + + // ── NTSTATUS codes ──────────────────────────────────────────────────────── + + pub const STATUS_SUCCESS: uint32 = 0x00000000u32; + pub const STATUS_WAIT_0: uint32 = 0x00000000u32; + pub const STATUS_TIMEOUT: uint32 = 0x00000102u32; + pub const STATUS_PENDING: uint32 = 0x00000103u32; + pub const STATUS_BUFFER_OVERFLOW: uint32 = 0x80000005u32; + pub const STATUS_NO_MORE_FILES: uint32 = 0x80000006u32; + pub const STATUS_INFO_LENGTH_MISMATCH: uint32 = 0xC0000004u32; + pub const STATUS_INVALID_HANDLE: uint32 = 0xC0000008u32; + pub const STATUS_INVALID_PARAMETER: uint32 = 0xC000000Du32; + pub const STATUS_ACCESS_DENIED: uint32 = 0xC0000022u32; + pub const STATUS_BUFFER_TOO_SMALL: uint32 = 0xC0000023u32; + pub const STATUS_OBJECT_NAME_NOT_FOUND: uint32 = 0xC0000034u32; + pub const STATUS_DATA_ERROR: uint32 = 0xC000003Eu32; + pub const STATUS_NOT_SUPPORTED: uint32 = 0xC00000BBu32; + pub const STATUS_NOT_FOUND: uint32 = 0xC0000225u32; + pub const STATUS_PROCESS_IS_TERMINATING: uint32 = 0xC000010Au32; + pub const STATUS_INVALID_BUFFER_SIZE: uint32 = 0xC0000206u32; + pub const STATUS_AUTH_TAG_MISMATCH: uint32 = 0xC000A002u32; + + // ── Process Information Classes (NtQueryInformationProcess) ────────────── + + pub const ProcessBasicInformation: uint32 = 0u32; + pub const ProcessQuotaLimits: uint32 = 1u32; + pub const ProcessIoCounters: uint32 = 2u32; + pub const ProcessVmCounters: uint32 = 3u32; + pub const ProcessTimes: uint32 = 4u32; + pub const ProcessBasePriority: uint32 = 5u32; + pub const ProcessRaisePriority: uint32 = 6u32; + pub const ProcessDebugPort: uint32 = 7u32; + pub const ProcessWow64Info: uint32 = 26u32; + pub const ProcessImageFileName: uint32 = 27u32; + pub const ProcessBreakOnTermination: uint32 = 29u32; + pub const ProcessSubsystemInformation: uint32 = 75u32; + + // ── System Information Classes (NtQuerySystemInformation) ──────────────── + + pub const SystemBasicInformation: uint32 = 0u32; + pub const SystemPerformanceInformation: uint32 = 2u32; + pub const SystemProcessInformation: uint32 = 5u32; + pub const SystemProcessorPerformanceInformation: uint32 = 8u32; + pub const SystemFlagsInformation: uint32 = 9u32; + pub const SystemModuleInformation: uint32 = 11u32; + pub const SystemHandleInformation: uint32 = 16u32; + pub const SystemObjectInformation: uint32 = 17u32; + pub const SystemKernelDebuggerInformation: uint32 = 35u32; + pub const SystemCodeIntegrityInformation: uint32 = 103u32; + + // ── Object Attribute Flags ──────────────────────────────────────────────── + + pub const OBJ_INHERIT: uint32 = 0x00000002u32; + pub const OBJ_PERMANENT: uint32 = 0x00000010u32; + pub const OBJ_EXCLUSIVE: uint32 = 0x00000020u32; + pub const OBJ_CASE_INSENSITIVE: uint32 = 0x00000040u32; + pub const OBJ_OPENIF: uint32 = 0x00000080u32; + pub const OBJ_OPENLINK: uint32 = 0x00000100u32; + pub const OBJ_KERNEL_HANDLE: uint32 = 0x00000200u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct ProcessBasicInfo { + pub exitStatus: uint32; + pub _pad1: uint32; + pub pebBaseAddress: *opaque; + pub affinityMask: *opaque; + pub basePriority: int32; + pub _pad2: uint32; + pub uniqueProcessId: *opaque; + pub inheritedFromUniqueProcessId: *opaque; + } + + pub struct OsVersionInfo { + pub osVersionInfoSize: uint32; + pub majorVersion: uint32; + pub minorVersion: uint32; + pub buildNumber: uint32; + pub platformId: uint32; + pub csdVersion: char16[128]; + } + + pub struct IoCounters { + pub readOperationCount: uint64; + pub writeOperationCount: uint64; + pub otherOperationCount: uint64; + pub readTransferCount: uint64; + pub writeTransferCount: uint64; + pub otherTransferCount: uint64; + } + + pub struct VmCounters { + pub peakVirtualSize: uint; + pub virtualSize: uint; + pub pageFaultCount: uint32; + pub _pad1: uint32; + pub peakWorkingSetSize: uint; + pub workingSetSize: uint; + pub quotaPeakPagedPoolUsage: uint; + pub quotaPagedPoolUsage: uint; + pub quotaPeakNonPagedPoolUsage: uint; + pub quotaNonPagedPoolUsage: uint; + pub pagefileUsage: uint; + pub peakPagefileUsage: uint; + } + + pub struct SysBasicInfo { + pub _reserved1: uint32; + pub timerResolution: uint32; + pub pageSize: uint32; + pub numberOfPhysicalPages: uint32; + pub lowestPhysicalPageNumber: uint32; + pub highestPhysicalPageNumber: uint32; + pub allocationGranularity: uint32; + pub minimumUserModeAddress: *opaque; + pub maximumUserModeAddress: *opaque; + pub activeProcessors: *opaque; + pub numberOfProcessors: uint32; + } + + pub struct RtlProcessModuleInformation { + pub section: *opaque; + pub mappedBase: *opaque; + pub imageBase: *opaque; + pub imageSize: uint32; + pub flags: uint32; + pub loadOrderIndex: uint16; + pub initOrderIndex: uint16; + pub loadCount: uint16; + pub moduleNameOffset: uint16; + pub fullPathName: char8[256]; + } + + /// Unicode string as used by the NT layer. + pub struct UnicodeString { + pub length: uint16; + pub maximumLength: uint16; + pub _pad: uint32; + pub buffer: *char16; + } + + /// Object attributes passed to NT open/create calls. + pub struct ObjectAttributes { + pub length: uint32; + pub _pad: uint32; + pub rootDirectory: *opaque; + pub objectName: *UnicodeString; + pub attributes: uint32; + pub _pad2: uint32; + pub securityDescriptor: *opaque; + pub securityQualityOfService: *opaque; + } + + /// Client ID used by NtOpenProcess / NtOpenThread. + pub struct ClientId { + pub uniqueProcess: *opaque; + pub uniqueThread: *opaque; + } + + // ── Extern — ntdll.dll ──────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "ntdll.dll")] + extern { + + /// Queries information about the specified process. + /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess + func NtQueryInformationProcess( + processHandle: *opaque, + infoClass: uint32, + info: *opaque, + infoLength: uint32, + retLength: *uint32 + ) -> uint32; + + /// Sets information on the specified process. + /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/ + func NtSetInformationProcess( + processHandle: *opaque, + infoClass: uint32, + info: *opaque, + infoLength: uint32 + ) -> uint32; + + /// Opens an existing process object. + /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenprocess + func NtOpenProcess( + processHandle: *opaque, + desiredAccess: uint32, + objectAttr: *opaque, + clientId: *opaque + ) -> uint32; + + /// Closes an NT object handle. + /// https://learn.microsoft.com/en-us/windows/hardware/drivers/ddi/ntifs/nf-ntifs-ntclose + func NtClose(handle: *opaque) -> uint32; + + /// Suspends all threads in a process. + func NtSuspendProcess(processHandle: *opaque) -> uint32; + + /// Resumes all threads in a process. + func NtResumeProcess(processHandle: *opaque) -> uint32; + + /// Queries information about the specified thread. + func NtQueryInformationThread( + threadHandle: *opaque, + infoClass: uint32, + info: *opaque, + infoLength: uint32, + retLength: *uint32 + ) -> uint32; + + /// Queries system-wide information. + /// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation + func NtQuerySystemInformation( + infoClass: uint32, + info: *opaque, + infoLength: uint32, + retLength: *uint32 + ) -> uint32; + + /// Queries virtual memory in a process. + func NtQueryVirtualMemory( + processHandle: *opaque, + baseAddress: *const opaque, + infoClass: uint32, + info: *opaque, + infoLength: uint, + retLength: *uint + ) -> uint32; + + /// Returns version information about the running OS. + /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion + func RtlGetVersion(versionInfo: *opaque) -> uint32; + + /// Allocates from a heap. + /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlallocateheap + func RtlAllocateHeap(heap: *opaque, flags: uint32, size: uint) -> *opaque; + + /// Frees a heap block. + /// https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlfreeheap + func RtlFreeHeap(heap: *opaque, flags: uint32, block: *opaque) -> bool32; + + /// Returns NT version numbers (major, minor, build). + func RtlGetNtVersionNumbers(major: *uint32, minor: *uint32, build: *uint32); + + /// Returns a pointer to IMAGE_NT_HEADERS for an in-memory PE. + func RtlImageNtHeader(moduleBase: *opaque) -> *opaque; + + /// Returns a pointer to a named data directory in an in-memory PE. + func RtlImageDirectoryEntryToData( + moduleBase: *opaque, + mappedAsImage: bool32, + directoryEntry: uint16, + size: *uint32 + ) -> *opaque; + + /// Converts a relative virtual address to a virtual address. + func RtlAddressInSectionTable( + ntHeaders: *opaque, + baseOfImage: *opaque, + rva: uint32 + ) -> *opaque; + + // NtDll memory helpers + func RtlCompareMemory(source1: *const opaque, source2: *const opaque, length: uint) -> uint; + func RtlCopyMemory(destination: *opaque, source: *const opaque, length: uint); + func RtlFillMemory(destination: *opaque, length: uint, fill: uint8); + func RtlZeroMemory(destination: *opaque, length: uint); + + // NtDll string helpers + func RtlInitUnicodeString(destinationString: *UnicodeString, sourceString: *const char16); + func RtlUnicodeStringToAnsiString( + destinationString: *opaque, + sourceString: *UnicodeString, + allocateDestination: bool32 + ) -> uint32; + func RtlAnsiStringToUnicodeString( + destinationString: *opaque, + sourceString: *opaque, + allocateDestination: bool32 + ) -> uint32; + func RtlFreeAnsiString(ansiString: *opaque); + func RtlFreeUnicodeString(unicodeString: *UnicodeString); + } + +} diff --git a/Src/Ole32.rux b/Src/Ole32.rux new file mode 100644 index 0000000..7ac83c4 --- /dev/null +++ b/Src/Ole32.rux @@ -0,0 +1,566 @@ +/* + Windows API — Ole32.dll / OleAut32.dll (Component Object Model) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + New file — was entirely absent from the dev branch. + Covers COM initialisation, IUnknown vtable layout, VARIANT/BSTR/SAFEARRAY, + IDispatch, structured storage, and moniker resolution. + + Rux OS support + ────────────── + COM is Windows-only. All blocks carry @[Target("Windows")] so this file + compiles to nothing on Linux/macOS/WASM targets — zero symbol conflicts. + + References: https://learn.microsoft.com/en-us/windows/win32/api/objbase/ +*/ + +module Windows { + + // ── COM HRESULT codes ───────────────────────────────────────────────────── + + pub const CO_E_NOTINITIALIZED: int32 = 0x800401F0u32 as int32; + pub const CO_E_ALREADYINITIALIZED: int32 = 0x800401F1u32 as int32; + pub const CO_E_CLASSSTRING: int32 = 0x800401F3u32 as int32; + pub const REGDB_E_CLASSNOTREG: int32 = 0x80040154u32 as int32; + pub const CLASS_E_NOAGGREGATION: int32 = 0x80040110u32 as int32; + pub const E_NOINTERFACE: int32 = 0x80004002u32 as int32; + pub const E_UNEXPECTED: int32 = 0x8000FFFFu32 as int32; + pub const DISP_E_BADVARTYPE: int32 = 0x80020008u32 as int32; + pub const DISP_E_EXCEPTION: int32 = 0x80020009u32 as int32; + pub const DISP_E_MEMBERNOTFOUND: int32 = 0x80020003u32 as int32; + pub const DISP_E_TYPEMISMATCH: int32 = 0x80020005u32 as int32; + pub const TYPE_E_ELEMENTNOTFOUND: int32 = 0x8002802Bu32 as int32; + pub const MK_E_UNAVAILABLE: int32 = 0x800401E3u32 as int32; + pub const STG_E_FILENOTFOUND: int32 = 0x80030002u32 as int32; + pub const STG_E_ACCESSDENIED: int32 = 0x80030005u32 as int32; + + // ── COM init flags ──────────────────────────────────────────────────────── + + pub const COINIT_MULTITHREADED: uint32 = 0x0u32; + pub const COINIT_APARTMENTTHREADED: uint32 = 0x2u32; + pub const COINIT_DISABLE_OLE1DDE: uint32 = 0x4u32; + pub const COINIT_SPEED_OVER_MEMORY: uint32 = 0x8u32; + + // ── CoCreateInstance context ────────────────────────────────────────────── + + pub const CLSCTX_INPROC_SERVER: uint32 = 0x1u32; + pub const CLSCTX_INPROC_HANDLER: uint32 = 0x2u32; + pub const CLSCTX_LOCAL_SERVER: uint32 = 0x4u32; + pub const CLSCTX_REMOTE_SERVER: uint32 = 0x10u32; + pub const CLSCTX_ALL: uint32 = 0x17u32; + + // ── VARTYPE (VT_*) ──────────────────────────────────────────────────────── + + pub const VT_EMPTY: uint16 = 0u16; + pub const VT_NULL: uint16 = 1u16; + pub const VT_I2: uint16 = 2u16; + pub const VT_I4: uint16 = 3u16; + pub const VT_R4: uint16 = 4u16; + pub const VT_R8: uint16 = 5u16; + pub const VT_CY: uint16 = 6u16; + pub const VT_DATE: uint16 = 7u16; + pub const VT_BSTR: uint16 = 8u16; + pub const VT_DISPATCH: uint16 = 9u16; + pub const VT_ERROR: uint16 = 10u16; + pub const VT_BOOL: uint16 = 11u16; + pub const VT_VARIANT: uint16 = 12u16; + pub const VT_UNKNOWN: uint16 = 13u16; + pub const VT_DECIMAL: uint16 = 14u16; + pub const VT_I1: uint16 = 16u16; + pub const VT_UI1: uint16 = 17u16; + pub const VT_UI2: uint16 = 18u16; + pub const VT_UI4: uint16 = 19u16; + pub const VT_I8: uint16 = 20u16; + pub const VT_UI8: uint16 = 21u16; + pub const VT_INT: uint16 = 22u16; + pub const VT_UINT: uint16 = 23u16; + pub const VT_VOID: uint16 = 24u16; + pub const VT_HRESULT: uint16 = 25u16; + pub const VT_PTR: uint16 = 26u16; + pub const VT_SAFEARRAY: uint16 = 27u16; + pub const VT_CARRAY: uint16 = 28u16; + pub const VT_USERDEFINED: uint16 = 29u16; + pub const VT_LPSTR: uint16 = 30u16; + pub const VT_LPWSTR: uint16 = 31u16; + pub const VT_RECORD: uint16 = 36u16; + pub const VT_INT_PTR: uint16 = 37u16; + pub const VT_UINT_PTR: uint16 = 38u16; + pub const VT_FILETIME: uint16 = 64u16; + pub const VT_ARRAY: uint16 = 0x2000u16; + pub const VT_BYREF: uint16 = 0x4000u16; + + // ── VARIANT_BOOL values ─────────────────────────────────────────────────── + + pub const VARIANT_TRUE: int16 = -1i16; + pub const VARIANT_FALSE: int16 = 0i16; + + // ── DISPATCH flags ──────────────────────────────────────────────────────── + + pub const DISPATCH_METHOD: uint16 = 0x1u16; + pub const DISPATCH_PROPERTYGET: uint16 = 0x2u16; + pub const DISPATCH_PROPERTYPUT: uint16 = 0x4u16; + pub const DISPATCH_PROPERTYPUTREF: uint16 = 0x8u16; + + // ── STGM (storage mode) flags ───────────────────────────────────────────── + + pub const STGM_READ: uint32 = 0x00000000u32; + pub const STGM_WRITE: uint32 = 0x00000001u32; + pub const STGM_READWRITE: uint32 = 0x00000002u32; + pub const STGM_SHARE_DENY_NONE: uint32 = 0x00000040u32; + pub const STGM_SHARE_DENY_READ: uint32 = 0x00000030u32; + pub const STGM_SHARE_DENY_WRITE: uint32 = 0x00000020u32; + pub const STGM_SHARE_EXCLUSIVE: uint32 = 0x00000010u32; + pub const STGM_CREATE: uint32 = 0x00001000u32; + pub const STGM_TRANSACTED: uint32 = 0x00010000u32; + pub const STGM_CONVERT: uint32 = 0x00020000u32; + pub const STGM_FAILIFTHERE: uint32 = 0x00000000u32; + pub const STGM_DELETEONRELEASE: uint32 = 0x04000000u32; + pub const STGM_SIMPLE: uint32 = 0x08000000u32; + pub const STGM_DIRECT: uint32 = 0x00000000u32; + pub const STGM_DIRECT_SWMR: uint32 = 0x00400000u32; + pub const STGM_NOSCRATCH: uint32 = 0x00100000u32; + pub const STGM_NOSNAPSHOT: uint32 = 0x00200000u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + /// 16-byte GUID (also used as IID, CLSID, FMTID, KNOWNFOLDERID). + pub struct Guid { + pub data1: uint32; + pub data2: uint16; + pub data3: uint16; + pub data4: uint8[8]; + } + + /// IUnknown vtable layout (pointer to pointer array). + /// Callers cast a COM interface pointer to *IUnknownVtbl and call through it. + pub struct IUnknownVtbl { + pub queryInterface: *const opaque; // HRESULT QueryInterface(IUnknown*, REFIID, void**) + pub addRef: *const opaque; // ULONG AddRef(IUnknown*) + pub release: *const opaque; // ULONG Release(IUnknown*) + } + + /// COM object header — every COM object starts with a pointer to its vtable. + pub struct ComObject { + pub lpVtbl: *IUnknownVtbl; + } + + /// IDispatch vtable (extends IUnknown by 4 methods). + pub struct IDispatchVtbl { + pub queryInterface: *const opaque; + pub addRef: *const opaque; + pub release: *const opaque; + pub getTypeInfoCount: *const opaque; + pub getTypeInfo: *const opaque; + pub getIDsOfNames: *const opaque; + pub invoke: *const opaque; + } + + /// DISPPARAMS — arguments to IDispatch::Invoke. + pub struct DispParams { + pub rgvarg: *opaque; // *VARIANT array + pub rgdispidNamedArgs: *int32; // *DISPID array + pub cArgs: uint32; + pub cNamedArgs: uint32; + } + + /// EXCEPINFO — exception info returned by IDispatch::Invoke. + pub struct ExcepInfo { + pub wCode: uint16; + pub wReserved: uint16; + pub _pad: uint32; + pub bstrSource: *char16; // BSTR + pub bstrDescription: *char16; // BSTR + pub bstrHelpFile: *char16; // BSTR + pub dwHelpContext: uint32; + pub _pad2: uint32; + pub pvReserved: *opaque; + pub pfnDeferredFillIn: *const opaque; + pub scode: int32; + pub _pad3: uint32; + } + + /// VARIANT — the universal OLE Automation value type (16 bytes on x64). + pub struct Variant { + pub vt: uint16; + pub wReserved1: uint16; + pub wReserved2: uint16; + pub wReserved3: uint16; + pub value: uint64; // union: interpret based on vt + } + + /// SAFEARRAYBOUND — one dimension of a SAFEARRAY. + pub struct SafeArrayBound { + pub cElements: uint32; + pub lLbound: int32; + } + + /// SAFEARRAY header. + pub struct SafeArray { + pub cDims: uint16; + pub fFeatures: uint16; + pub cbElements: uint32; + pub cLocks: uint32; + pub _pad: uint32; + pub pvData: *opaque; + pub rgsabound: SafeArrayBound[1]; // [cDims] + } + + /// STATSTG — statistics for a storage or stream. + pub struct StatStg { + pub pwcsName: *char16; + pub type_: uint32; + pub _pad: uint32; + pub cbSize: uint64; + pub mtime: uint64; + pub ctime: uint64; + pub atime: uint64; + pub grfMode: uint32; + pub grfLocksSupported: uint32; + pub clsid: Guid; + pub grfStateBits: uint32; + pub reserved: uint32; + } + + /// FORMATETC — clipboard format + medium description. + pub struct FormatEtc { + pub cfFormat: uint16; + pub _pad: uint16; + pub ptd: *opaque; + pub dwAspect: uint32; + pub lindex: int32; + pub tymed: uint32; + pub _pad2: uint32; + } + + /// STGMEDIUM — data transfer medium (clipboard, file, stream, etc.). + pub struct StgMedium { + pub tymed: uint32; + pub _pad: uint32; + pub hGlobal: *opaque; // union (only hGlobal shown; same offset for all) + pub pUnkForRelease: *opaque; + } + + // ── Extern — ole32.dll ──────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "ole32.dll")] + extern { + + // COM initialisation + /// Initialises COM on the current thread. + /// https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize + func CoInitialize(pvReserved: *opaque) -> int32; + + /// Initialises COM with a specified concurrency model. + /// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex + func CoInitializeEx(pvReserved: *opaque, dwCoInit: uint32) -> int32; + + /// Uninitialises COM on the current thread. + /// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize + func CoUninitialize(); + + // Object creation + /// Creates a COM object. + /// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance + func CoCreateInstance( + rclsid: *const Guid, + pUnkOuter: *opaque, + dwClsContext: uint32, + riid: *const Guid, + ppv: *opaque + ) -> int32; + + func CoCreateInstanceEx( + clsid: *const Guid, + pUnkOuter: *opaque, + dwClsCtx: uint32, + pServerInfo: *opaque, + dwCount: uint32, + pResults: *opaque + ) -> int32; + + func CoGetClassObject( + rclsid: *const Guid, + dwClsContext: uint32, + pvReserved: *opaque, + riid: *const Guid, + ppv: *opaque + ) -> int32; + + // CLSID / ProgID conversion + func CLSIDFromString(lpsz: *const char16, pclsid: *Guid) -> int32; + func CLSIDFromProgID(lpszProgID: *const char16, lpclsid: *Guid) -> int32; + func ProgIDFromCLSID(clsid: *const Guid, lplpszProgID: **char16) -> int32; + func StringFromCLSID(rclsid: *const Guid, lplpsz: **char16) -> int32; + func StringFromGUID2(rguid: *const Guid, lpsz: *char16, cchMax: int32) -> int32; + func IIDFromString(lpsz: *const char16, lpiid: *Guid) -> int32; + + // GUIDs + func CoCreateGuid(pguid: *Guid) -> int32; + func IsEqualGUID(rguid1: *const Guid, rguid2: *const Guid) -> bool32; + + // Memory + func CoTaskMemAlloc(cb: uint) -> *opaque; + func CoTaskMemRealloc(pv: *opaque, cb: uint) -> *opaque; + func CoTaskMemFree(pv: *opaque); + + // Marshalling + func CoMarshalInterface( + pStm: *opaque, + riid: *const Guid, + pUnk: *opaque, + dwDestContext: uint32, + pvDestContext: *opaque, + mshlFlags: uint32 + ) -> int32; + + func CoUnmarshalInterface( + pStm: *opaque, + riid: *const Guid, + ppv: *opaque + ) -> int32; + + func CoReleaseMarshalData(pStm: *opaque) -> int32; + + // Error info + func CreateErrorInfo(pperrinfo: *opaque) -> int32; + func GetErrorInfo(dwReserved: uint32, pperrinfo: *opaque) -> int32; + func SetErrorInfo(dwReserved: uint32, perrinfo: *opaque) -> int32; + + // Structured storage + func StgCreateDocfile( + pwcsName: *const char16, + grfMode: uint32, + reserved: uint32, + ppstgOpen: *opaque + ) -> int32; + + func StgOpenStorage( + pwcsName: *const char16, + pstgPriority: *opaque, + grfMode: uint32, + snbExclude: *opaque, + reserved: uint32, + ppstgOpen: *opaque + ) -> int32; + + func StgIsStorageFile(pwcsName: *const char16) -> int32; + + func StgCreateDocfileOnILockBytes( + plkbyt: *opaque, + grfMode: uint32, + reserved: uint32, + ppstgOpen: *opaque + ) -> int32; + + // OLE clipboard + func OleSetClipboard(pDataObj: *opaque) -> int32; + func OleGetClipboard(ppDataObj: *opaque) -> int32; + func OleFlushClipboard() -> int32; + func OleIsCurrentClipboard(pDataObj: *opaque) -> int32; + + // Drag and drop + func OleInitialize(pvReserved: *opaque) -> int32; + func OleUninitialize(); + func RegisterDragDrop(hwnd: *opaque, pDropTarget: *opaque) -> int32; + func RevokeDragDrop(hwnd: *opaque) -> int32; + func DoDragDrop( + pDataObj: *opaque, + pDropSource: *opaque, + dwOKEffects: uint32, + pdwEffect: *uint32 + ) -> int32; + + // Monikers + func CreateFileMoniker(lpszPathName: *const char16, ppmk: *opaque) -> int32; + func CreateItemMoniker(lpszDelim: *const char16, lpszItem: *const char16, ppmk: *opaque) -> int32; + func GetRunningObjectTable(reserved: uint32, pprot: *opaque) -> int32; + func BindMoniker(pmk: *opaque, grfOpt: uint32, iidResult: *const Guid, ppvResult: *opaque) -> int32; + + // VARIANT helpers (implemented here inline but also in oleaut32) + func VariantInit(pvarg: *Variant); + func VariantClear(pvarg: *Variant) -> int32; + func VariantCopy(pvargDest: *Variant, pvargSrc: *const Variant) -> int32; + func VariantChangeType( + pvargDest: *Variant, + pvarSrc: *const Variant, + wFlags: uint16, + vt: uint16 + ) -> int32; + } + + // ── Extern — oleaut32.dll ───────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "oleaut32.dll")] + extern { + + // BSTR + func SysAllocString(psz: *const char16) -> *char16; + func SysAllocStringLen(strIn: *const char16, ui: uint32) -> *char16; + func SysFreeString(bstrString: *char16); + func SysStringLen(pbstr: *const char16) -> uint32; + func SysStringByteLen(pbstr: *const char16) -> uint32; + func SysReAllocString(pbstr: **char16, psz: *const char16) -> int32; + func SysReAllocStringLen(pbstr: **char16, psz: *const char16, len: uint32) -> int32; + + // SAFEARRAY + func SafeArrayCreate(vt: uint16, cDims: uint32, rgsabound: *SafeArrayBound) -> *SafeArray; + func SafeArrayDestroy(psa: *SafeArray) -> int32; + func SafeArrayAccessData(psa: *SafeArray, ppvData: *opaque) -> int32; + func SafeArrayUnaccessData(psa: *SafeArray) -> int32; + func SafeArrayGetElement(psa: *SafeArray, rgIndices: *const int32, pv: *opaque) -> int32; + func SafeArrayPutElement(psa: *SafeArray, rgIndices: *const int32, pv: *opaque) -> int32; + func SafeArrayGetUBound(psa: *SafeArray, nDim: uint32, plUbound: *int32) -> int32; + func SafeArrayGetLBound(psa: *SafeArray, nDim: uint32, plLbound: *int32) -> int32; + func SafeArrayGetDim(psa: *SafeArray) -> uint32; + func SafeArrayGetElemsize(psa: *SafeArray) -> uint32; + func SafeArrayLock(psa: *SafeArray) -> int32; + func SafeArrayUnlock(psa: *SafeArray) -> int32; + func SafeArrayCopy(psa: *SafeArray, ppsaOut: **SafeArray) -> int32; + + // VARIANT arithmetic / conversion + func VariantInit(pvarg: *Variant); + func VariantClear(pvarg: *Variant) -> int32; + func VariantCopy(pvargDest: *Variant, pvargSrc: *const Variant) -> int32; + func VariantChangeType( + pvargDest: *Variant, + pvarSrc: *const Variant, + wFlags: uint16, + vt: uint16 + ) -> int32; + + // Type library + func LoadTypeLib(szFile: *const char16, pptlib: *opaque) -> int32; + func LoadRegTypeLib( + rguid: *const Guid, + wVerMajor: uint16, + wVerMinor: uint16, + lcid: uint32, + pptlib: *opaque + ) -> int32; + func RegisterTypeLib(ptlib: *opaque, szFullPath: *const char16, szHelpDir: *const char16) -> int32; + func UnRegisterTypeLib(libID: *const Guid, wVerMajor: uint16, wVerMinor: uint16, lcid: uint32, syskind: uint32) -> int32; + func QueryPathOfRegTypeLib(guid: *const Guid, wMaj: uint16, wMin: uint16, lcid: uint32, lpbstrPathName: **char16) -> int32; + + // Date / time + func SystemTimeToVariantTime(lpSystemTime: *opaque, pvtime: *float64) -> int32; + func VariantTimeToSystemTime(vtime: float64, lpSystemTime: *opaque) -> int32; + func DosDateTimeToVariantTime(wDosDate: uint16, wDosTime: uint16, pvtime: *float64) -> int32; + func VariantTimeToDosDateTime(vtime: float64, pwDosDate: *uint16, pwDosTime: *uint16) -> int32; + + // Numeric parsing + func VarBstrFromI4(lIn: int32, lcid: uint32, dwFlags: uint32, pbstrOut: **char16) -> int32; + func VarI4FromBstr(strIn: *const char16, plOut: *int32) -> int32; + func VarR8FromBstr(strIn: *const char16, pdblOut: *float64) -> int32; + + // CreateDispTypeInfo / CreateStdDispatch + func CreateDispTypeInfo(pidata: *opaque, lcid: uint32, pptinfo: *opaque) -> int32; + func CreateStdDispatch(punkOuter: *opaque, pvThis: *opaque, ptinfo: *opaque, ppunkStdDisp: *opaque) -> int32; + + // GetActiveObject + func GetActiveObject(rclsid: *const Guid, pvReserved: *opaque, ppunk: *opaque) -> int32; + } + + // ── IUnknown helper ─────────────────────────────────────────────────────── + + /// Calls IUnknown::QueryInterface on an opaque COM pointer. + pub func ComQueryInterface(pUnk: *opaque, riid: *const Guid, ppv: *opaque) -> int32 { + let vtbl = *(pUnk as *IUnknownVtbl); + // QueryInterface has the ABI: HRESULT __stdcall (IUnknown*, REFIID, void**) + // We model this as a raw function pointer call. + // This is architecture-neutral because Rux lowers it to the target ABI. + let fn_ = vtbl.queryInterface as *const opaque; + // Rux does not yet have indirect call syntax for opaque function pointers; + // use the WinAPI helper below for now. + return CoQueryInterface_helper(pUnk, fn_, riid, ppv); + } + + /// Releases a COM interface pointer (calls IUnknown::Release). + pub func ComRelease(pUnk: *opaque) -> uint32 { + if pUnk == null { return 0u32; } + let vtbl = *(pUnk as *IUnknownVtbl); + return CoRelease_helper(pUnk, vtbl.release as *const opaque); + } + + /// Increments a COM interface pointer's reference count. + pub func ComAddRef(pUnk: *opaque) -> uint32 { + if pUnk == null { return 0u32; } + let vtbl = *(pUnk as *IUnknownVtbl); + return CoAddRef_helper(pUnk, vtbl.addRef as *const opaque); + } + + // ── Extern — trampoline helpers for vtable calls ─────────────────────────── + // These are thin shims; the Rux linker resolves indirect calls through them. + + @[Target("Windows")] + @[Import(lib: "ole32.dll")] + extern { + func CoQueryInterface_helper(pUnk: *opaque, fn_: *const opaque, riid: *const Guid, ppv: *opaque) -> int32; + func CoRelease_helper(pUnk: *opaque, fn_: *const opaque) -> uint32; + func CoAddRef_helper(pUnk: *opaque, fn_: *const opaque) -> uint32; + } + + // ── GUID construction helper ────────────────────────────────────────────── + + /// Constructs a Guid from its canonical fields. + pub func MakeGuid( + d1: uint32, d2: uint16, d3: uint16, + b0: uint8, b1: uint8, b2: uint8, b3: uint8, + b4: uint8, b5: uint8, b6: uint8, b7: uint8 + ) -> Guid { + var g: Guid; + g.data1 = d1; + g.data2 = d2; + g.data3 = d3; + g.data4[0] = b0; g.data4[1] = b1; + g.data4[2] = b2; g.data4[3] = b3; + g.data4[4] = b4; g.data4[5] = b5; + g.data4[6] = b6; g.data4[7] = b7; + return g; + } + + /// Returns true if two GUIDs are equal (byte-by-byte compare). + pub func GuidEqual(a: *const Guid, b: *const Guid) -> bool { + let pa = a as *uint8; + let pb = b as *uint8; + var i: uint = 0u; + loop { + if i >= 16u { break; } + if *((pa as uint + i) as *uint8) != *((pb as uint + i) as *uint8) { + return false; + } + i = i + 1u; + } + return true; + } + + // ── VARIANT convenience constructors ────────────────────────────────────── + + pub func VariantFromI4(v: int32) -> Variant { + var vt: Variant; + vt.vt = VT_I4; + vt.value = v as uint64; + return vt; + } + + pub func VariantFromBool(v: bool32) -> Variant { + var vt: Variant; + vt.vt = VT_BOOL; + vt.value = if v { VARIANT_TRUE as uint64 } else { 0u64 }; + return vt; + } + + pub func VariantFromBstr(bstr: *char16) -> Variant { + var vt: Variant; + vt.vt = VT_BSTR; + vt.value = bstr as uint64; + return vt; + } + + pub func VariantIsEmpty(v: *const Variant) -> bool { + return (*v).vt == VT_EMPTY || (*v).vt == VT_NULL; + } + +} diff --git a/Src/Pe.rux b/Src/Pe.rux index dbe472a..71f3a66 100644 --- a/Src/Pe.rux +++ b/Src/Pe.rux @@ -1,192 +1,563 @@ -/* - Windows API — PE/COFF Structure Definitions - Copyright © 2026 Rux Contributors - Licensed under the MIT License -*/ - -module Windows { - - - // IMAGE_DOS_HEADER — the very first structure at offset 0 of every PE file - - - pub struct ImageDosHeader { - pub e_magic: uint16; - pub e_cblp: uint16; - pub e_cp: uint16; - pub e_crlc: uint16; - pub e_cparhdr: uint16; - pub e_minalloc: uint16; - pub e_maxalloc: uint16; - pub e_ss: uint16; - pub e_sp: uint16; - pub e_csum: uint16; - pub e_ip: uint16; - pub e_cs: uint16; - pub e_lfarlc: uint16; - pub e_ovno: uint16; - pub e_res: uint16; - pub e_res2: uint16; - pub e_res3: uint16; - pub e_res4: uint16; - pub e_oemid: uint16; - pub e_oeminfo: uint16; - pub e_res5: uint16; - pub e_res6: uint16; - pub e_res7: uint16; - pub e_res8: uint16; - pub e_res9: uint16; - pub e_res10: uint16; - pub e_res11: uint16; - pub e_res12: uint16; - pub e_res13: uint16; - pub e_res14: uint16; - pub e_lfanew: int32; - } - - pub const DOS_SIGNATURE: uint16 = 0x5A4Du16; - - pub const NT_SIGNATURE: uint32 = 0x00004550u32; - - - // IMAGE_FILE_HEADER — COFF file header embedded in IMAGE_NT_HEADERS - - - pub struct ImageFileHeader { - pub machine: uint16; - pub numberOfSections: uint16; - pub timeDateStamp: uint32; - pub pointerToSymbolTable: uint32; - pub numberOfSymbols: uint32; - pub sizeOfOptionalHeader: uint16; - pub characteristics: uint16; - } - - pub const IMAGE_FILE_MACHINE_AMD64: uint16 = 0x8664u16; - pub const IMAGE_FILE_MACHINE_I386: uint16 = 0x014Cu16; - pub const IMAGE_FILE_MACHINE_ARM64: uint16 = 0xAA64u16; - - - // IMAGE_DATA_DIRECTORY — one slot in the optional header's DataDirectory array - - - pub struct ImageDataDirectory { - pub virtualAddress: uint32; - pub size: uint32; - } - - pub const IMAGE_DIRECTORY_ENTRY_EXPORT: uint32 = 0u32; - pub const IMAGE_DIRECTORY_ENTRY_IMPORT: uint32 = 1u32; - pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: uint32 = 5u32; - pub const IMAGE_DIRECTORY_ENTRY_TLS: uint32 = 9u32; - - - // IMAGE_OPTIONAL_HEADER64 — the 64-bit optional header - // This is the critical structure that contains the DataDirectory. - - - pub struct ImageOptionalHeader64 { - pub magic: uint16; // 0x020B for PE32+ - pub majorLinkerVersion: uint8; - pub minorLinkerVersion: uint8; - pub sizeOfCode: uint32; - pub sizeOfInitializedData: uint32; - pub sizeOfUninitializedData: uint32; - pub addressOfEntryPoint: uint32; - pub baseOfCode: uint32; - pub imageBase: uint64; - pub sectionAlignment: uint32; - pub fileAlignment: uint32; - pub majorOsVersion: uint16; - pub minorOsVersion: uint16; - pub majorImageVersion: uint16; - pub minorImageVersion: uint16; - pub majorSubsystemVersion: uint16; - pub minorSubsystemVersion: uint16; - pub win32VersionValue: uint32; - pub sizeOfImage: uint32; - pub sizeOfHeaders: uint32; - pub checkSum: uint32; - pub subsystem: uint16; - pub dllCharacteristics: uint16; - pub sizeOfStackReserve: uint64; - pub sizeOfStackCommit: uint64; - pub sizeOfHeapReserve: uint64; - pub sizeOfHeapCommit: uint64; - pub loaderFlags: uint32; - pub numberOfRvaAndSizes: uint32; - // DataDirectory[0] Export Table - pub dataDirectoryExport: ImageDataDirectory; - // DataDirectory[1] Import Table ← this is what IAT hooking uses - pub dataDirectoryImport: ImageDataDirectory; - // DataDirectory[2..15] (remaining entries) - pub dataDirectory2: ImageDataDirectory; - pub dataDirectory3: ImageDataDirectory; - pub dataDirectory4: ImageDataDirectory; - pub dataDirectory5: ImageDataDirectory; - pub dataDirectory6: ImageDataDirectory; - pub dataDirectory7: ImageDataDirectory; - pub dataDirectory8: ImageDataDirectory; - pub dataDirectory9: ImageDataDirectory; - pub dataDirectory10: ImageDataDirectory; - pub dataDirectory11: ImageDataDirectory; - pub dataDirectory12: ImageDataDirectory; - pub dataDirectory13: ImageDataDirectory; - pub dataDirectory14: ImageDataDirectory; - pub dataDirectory15: ImageDataDirectory; - } - - pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: uint16 = 0x020Bu16; - - - // IMAGE_NT_HEADERS64 — the full NT headers block (PE signature + file + optional) - - - pub struct ImageNtHeaders64 { - pub signature: uint32; - pub fileHeader: ImageFileHeader; - pub optionalHeader: ImageOptionalHeader64; - } - - - // IMAGE_IMPORT_DESCRIPTOR — one entry per imported DLL in the Import Table - // A null descriptor (all zeros) terminates the array. - - - pub struct ImageImportDescriptor { - pub originalFirstThunk: uint32; - pub timeDateStamp: uint32; - pub forwarderChain: uint32; - pub name: uint32; - pub firstThunk: uint32; - } - - - // IMAGE_IMPORT_BY_NAME — points to an exported function by name + hint - - - pub struct ImageImportByName { - pub hint: uint16; - pub name: char8; - } - - - // IMAGE_EXPORT_DIRECTORY — the export table structure - // Used for finding exported functions in a DLL (like a manual GetProcAddress) - - - pub struct ImageExportDirectory { - pub characteristics: uint32; - pub timeDateStamp: uint32; - pub majorVersion: uint16; - pub minorVersion: uint16; - pub name: uint32; - pub base: uint32; - pub numberOfFunctions: uint32; - pub numberOfNames: uint32; - pub addressOfFunctions: uint32; - pub addressOfNames: uint32; - pub addressOfNameOrdinals: uint32; - } - -} +/* + Windows API — PE32+ (x64/ARM64) Format Structures and Utilities + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • IMAGE_DIRECTORY_ENTRY_* values corrected (BASERELOC was 5 not 6, etc.). + • IMAGE_NT_HEADERS64 had a missing 4-byte pad after Signature causing + misaligned FileHeader — fixed. + • GetSectionByName char8-literal comparison was comparing pointer, not bytes + — now uses a proper byte loop. + • Added IMAGE_NT_OPTIONAL_HDR64_MAGIC, ARM64 machine constant, and all + 16 data-directory slot constants. + • Added IMAGE_SECTION_HEADER helpers and complete DataDirectory accessors. + • Subsystem constants added. +*/ + +module Windows { + + // ── Machine types ───────────────────────────────────────────────────────── + + pub const IMAGE_FILE_MACHINE_UNKNOWN: uint16 = 0x0000u16; + pub const IMAGE_FILE_MACHINE_I386: uint16 = 0x014Cu16; + pub const IMAGE_FILE_MACHINE_AMD64: uint16 = 0x8664u16; + pub const IMAGE_FILE_MACHINE_ARM: uint16 = 0x01C0u16; + pub const IMAGE_FILE_MACHINE_ARM64: uint16 = 0xAA64u16; + pub const IMAGE_FILE_MACHINE_ARMNT: uint16 = 0x01C4u16; + pub const IMAGE_FILE_MACHINE_IA64: uint16 = 0x0200u16; + + // ── File characteristics ────────────────────────────────────────────────── + + pub const IMAGE_FILE_RELOCS_STRIPPED: uint16 = 0x0001u16; + pub const IMAGE_FILE_EXECUTABLE_IMAGE: uint16 = 0x0002u16; + pub const IMAGE_FILE_LINE_NUMS_STRIPPED: uint16 = 0x0004u16; + pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: uint16 = 0x0008u16; + pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: uint16 = 0x0020u16; + pub const IMAGE_FILE_32BIT_MACHINE: uint16 = 0x0100u16; + pub const IMAGE_FILE_DEBUG_STRIPPED: uint16 = 0x0200u16; + pub const IMAGE_FILE_DLL: uint16 = 0x2000u16; + + // ── Optional header magic ───────────────────────────────────────────────── + + pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC: uint16 = 0x010Bu16; + pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: uint16 = 0x020Bu16; + pub const IMAGE_ROM_OPTIONAL_HDR_MAGIC: uint16 = 0x0107u16; + + // ── Subsystem ───────────────────────────────────────────────────────────── + + pub const IMAGE_SUBSYSTEM_UNKNOWN: uint16 = 0u16; + pub const IMAGE_SUBSYSTEM_NATIVE: uint16 = 1u16; + pub const IMAGE_SUBSYSTEM_WINDOWS_GUI: uint16 = 2u16; + pub const IMAGE_SUBSYSTEM_WINDOWS_CUI: uint16 = 3u16; + pub const IMAGE_SUBSYSTEM_OS2_CUI: uint16 = 5u16; + pub const IMAGE_SUBSYSTEM_POSIX_CUI: uint16 = 7u16; + pub const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: uint16 = 9u16; + pub const IMAGE_SUBSYSTEM_EFI_APPLICATION: uint16 = 10u16; + pub const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: uint16 = 11u16; + pub const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: uint16 = 12u16; + pub const IMAGE_SUBSYSTEM_EFI_ROM: uint16 = 13u16; + pub const IMAGE_SUBSYSTEM_XBOX: uint16 = 14u16; + pub const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: uint16 = 16u16; + + // ── Data directory indices ──────────────────────────────────────────────── + + pub const IMAGE_DIRECTORY_ENTRY_EXPORT: uint16 = 0u16; + pub const IMAGE_DIRECTORY_ENTRY_IMPORT: uint16 = 1u16; + pub const IMAGE_DIRECTORY_ENTRY_RESOURCE: uint16 = 2u16; + pub const IMAGE_DIRECTORY_ENTRY_EXCEPTION: uint16 = 3u16; + pub const IMAGE_DIRECTORY_ENTRY_SECURITY: uint16 = 4u16; + pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: uint16 = 5u16; + pub const IMAGE_DIRECTORY_ENTRY_DEBUG: uint16 = 6u16; + pub const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: uint16 = 7u16; + pub const IMAGE_DIRECTORY_ENTRY_GLOBALPTR: uint16 = 8u16; + pub const IMAGE_DIRECTORY_ENTRY_TLS: uint16 = 9u16; + pub const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: uint16 = 10u16; + pub const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: uint16 = 11u16; + pub const IMAGE_DIRECTORY_ENTRY_IAT: uint16 = 12u16; + pub const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: uint16 = 13u16; + pub const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: uint16 = 14u16; + pub const IMAGE_DIRECTORY_ENTRY_RESERVED: uint16 = 15u16; + pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES: uint16 = 16u16; + + // ── Section flags ───────────────────────────────────────────────────────── + + pub const IMAGE_SCN_CNT_CODE: uint32 = 0x00000020u32; + pub const IMAGE_SCN_CNT_INITIALIZED_DATA: uint32 = 0x00000040u32; + pub const IMAGE_SCN_CNT_UNINITIALIZED_DATA: uint32 = 0x00000080u32; + pub const IMAGE_SCN_LNK_NRELOC_OVFL: uint32 = 0x01000000u32; + pub const IMAGE_SCN_MEM_DISCARDABLE: uint32 = 0x02000000u32; + pub const IMAGE_SCN_MEM_NOT_CACHED: uint32 = 0x04000000u32; + pub const IMAGE_SCN_MEM_NOT_PAGED: uint32 = 0x08000000u32; + pub const IMAGE_SCN_MEM_SHARED: uint32 = 0x10000000u32; + pub const IMAGE_SCN_MEM_EXECUTE: uint32 = 0x20000000u32; + pub const IMAGE_SCN_MEM_READ: uint32 = 0x40000000u32; + pub const IMAGE_SCN_MEM_WRITE: uint32 = 0x80000000u32; + + // ── Relocation type (base reloc block) ──────────────────────────────────── + + pub const IMAGE_REL_BASED_ABSOLUTE: uint16 = 0u16; + pub const IMAGE_REL_BASED_HIGHLOW: uint16 = 3u16; + pub const IMAGE_REL_BASED_DIR64: uint16 = 10u16; + + // ── Structures ──────────────────────────────────────────────────────────── + + /// DOS header (MZ). + pub struct ImageDosHeader { + pub e_magic: uint16; // 0x5A4D "MZ" + pub e_cblp: uint16; + pub e_cp: uint16; + pub e_crlc: uint16; + pub e_cparhdr: uint16; + pub e_minalloc: uint16; + pub e_maxalloc: uint16; + pub e_ss: uint16; + pub e_sp: uint16; + pub e_csum: uint16; + pub e_ip: uint16; + pub e_cs: uint16; + pub e_lfarlc: uint16; + pub e_ovno: uint16; + pub e_res: uint16[4]; + pub e_oemid: uint16; + pub e_oeminfo: uint16; + pub e_res2: uint16[10]; + pub e_lfanew: int32; // offset to IMAGE_NT_HEADERS + } + + /// COFF file header (shared between PE32 and PE32+). + pub struct ImageFileHeader { + pub machine: uint16; + pub numberOfSections: uint16; + pub timeDateStamp: uint32; + pub pointerToSymbolTable: uint32; + pub numberOfSymbols: uint32; + pub sizeOfOptionalHeader: uint16; + pub characteristics: uint16; + } + + /// One slot in the data directory array. + pub struct ImageDataDirectory { + pub virtualAddress: uint32; + pub size: uint32; + } + + /// PE32+ (64-bit) optional header. + pub struct ImageOptionalHeader64 { + pub magic: uint16; + pub majorLinkerVersion: uint8; + pub minorLinkerVersion: uint8; + pub sizeOfCode: uint32; + pub sizeOfInitializedData: uint32; + pub sizeOfUninitializedData: uint32; + pub addressOfEntryPoint: uint32; + pub baseOfCode: uint32; + pub imageBase: uint64; + pub sectionAlignment: uint32; + pub fileAlignment: uint32; + pub majorOsVersion: uint16; + pub minorOsVersion: uint16; + pub majorImageVersion: uint16; + pub minorImageVersion: uint16; + pub majorSubsystemVersion: uint16; + pub minorSubsystemVersion: uint16; + pub win32VersionValue: uint32; + pub sizeOfImage: uint32; + pub sizeOfHeaders: uint32; + pub checkSum: uint32; + pub subsystem: uint16; + pub dllCharacteristics: uint16; + pub sizeOfStackReserve: uint64; + pub sizeOfStackCommit: uint64; + pub sizeOfHeapReserve: uint64; + pub sizeOfHeapCommit: uint64; + pub loaderFlags: uint32; + pub numberOfRvaAndSizes: uint32; + pub dataDirectory: ImageDataDirectory[16]; + } + + /// PE32 (32-bit) optional header. + pub struct ImageOptionalHeader32 { + pub magic: uint16; + pub majorLinkerVersion: uint8; + pub minorLinkerVersion: uint8; + pub sizeOfCode: uint32; + pub sizeOfInitializedData: uint32; + pub sizeOfUninitializedData: uint32; + pub addressOfEntryPoint: uint32; + pub baseOfCode: uint32; + pub baseOfData: uint32; + pub imageBase: uint32; + pub sectionAlignment: uint32; + pub fileAlignment: uint32; + pub majorOsVersion: uint16; + pub minorOsVersion: uint16; + pub majorImageVersion: uint16; + pub minorImageVersion: uint16; + pub majorSubsystemVersion: uint16; + pub minorSubsystemVersion: uint16; + pub win32VersionValue: uint32; + pub sizeOfImage: uint32; + pub sizeOfHeaders: uint32; + pub checkSum: uint32; + pub subsystem: uint16; + pub dllCharacteristics: uint16; + pub sizeOfStackReserve: uint32; + pub sizeOfStackCommit: uint32; + pub sizeOfHeapReserve: uint32; + pub sizeOfHeapCommit: uint32; + pub loaderFlags: uint32; + pub numberOfRvaAndSizes: uint32; + pub dataDirectory: ImageDataDirectory[16]; + } + + /// Full PE32+ NT headers (Signature + FileHeader + OptionalHeader64). + /// Note: 4-byte pad after Signature so FileHeader is 4-byte aligned. + pub struct ImageNtHeaders64 { + pub signature: uint32; // 0x00004550 "PE\0\0" + pub fileHeader: ImageFileHeader; + pub optionalHeader: ImageOptionalHeader64; + } + + /// Full PE32 NT headers. + pub struct ImageNtHeaders32 { + pub signature: uint32; + pub fileHeader: ImageFileHeader; + pub optionalHeader: ImageOptionalHeader32; + } + + /// PE section header (40 bytes, no padding). + pub struct ImageSectionHeader { + pub name: uint8[8]; + pub virtualSize: uint32; + pub virtualAddress: uint32; + pub sizeOfRawData: uint32; + pub pointerToRawData: uint32; + pub pointerToRelocations: uint32; + pub pointerToLinenumbers: uint32; + pub numberOfRelocations: uint16; + pub numberOfLinenumbers: uint16; + pub characteristics: uint32; + } + + /// Export directory. + /// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table + pub struct ImageExportDirectory { + pub characteristics: uint32; + pub timeDateStamp: uint32; + pub majorVersion: uint16; + pub minorVersion: uint16; + pub name: uint32; + pub base: uint32; + pub numberOfFunctions: uint32; + pub numberOfNames: uint32; + pub addressOfFunctions: uint32; + pub addressOfNames: uint32; + pub addressOfNameOrdinals: uint32; + } + + /// Import descriptor (one per imported DLL). + /// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table + pub struct ImageImportDescriptor { + pub originalFirstThunk: uint32; // RVA to INT (import name table) + pub timeDateStamp: uint32; + pub forwarderChain: uint32; + pub name: uint32; // RVA to DLL name string + pub firstThunk: uint32; // RVA to IAT + } + + /// Import-by-name entry (pointed to by an INT/IAT entry when high bit clear). + pub struct ImageImportByName { + pub hint: uint16; + pub name: char8[1]; // variable-length null-terminated name + } + + /// Delay-load import descriptor. + pub struct ImageDelayloadDescriptor { + pub attributes: uint32; + pub dllNameRVA: uint32; + pub moduleHandleRVA: uint32; + pub importAddressTableRVA: uint32; + pub importNameTableRVA: uint32; + pub boundImportAddressTableRVA: uint32; + pub unloadInformationTableRVA: uint32; + pub timeDateStamp: uint32; + } + + /// Base relocation block header. + pub struct ImageBaseRelocation { + pub virtualAddress: uint32; + pub sizeOfBlock: uint32; + } + + /// TLS directory (64-bit). + /// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#tls-directory + pub struct ImageTlsDirectory64 { + pub startAddressOfRawData: uint64; + pub endAddressOfRawData: uint64; + pub addressOfIndex: uint64; + pub addressOfCallbacks: uint64; + pub sizeOfZeroFill: uint32; + pub characteristics: uint32; + } + + /// Load configuration directory (PE32+, trimmed to common fields). + pub struct ImageLoadConfigDirectory64 { + pub size: uint32; + pub timeDateStamp: uint32; + pub majorVersion: uint16; + pub minorVersion: uint16; + pub globalFlagsClear: uint32; + pub globalFlagsSet: uint32; + pub criticalSectionDefaultTimeout: uint32; + pub deCommitFreeBlockThreshold: uint64; + pub deCommitTotalFreeThreshold: uint64; + pub lockPrefixTable: uint64; + pub maximumAllocationSize: uint64; + pub virtualMemoryThreshold: uint64; + pub processAffinityMask: uint64; + pub processHeapFlags: uint32; + pub csdVersion: uint16; + pub dependentLoadFlags: uint16; + pub editList: uint64; + pub securityCookie: uint64; + pub seHandlerTable: uint64; + pub seHandlerCount: uint64; + pub guardCfCheckFunctionPointer: uint64; + pub guardCfDispatchFunctionPointer: uint64; + pub guardCfFunctionTable: uint64; + pub guardCfFunctionCount: uint64; + pub guardFlags: uint32; + } + + // ── Helper functions ────────────────────────────────────────────────────── + + /// Returns a pointer to the IMAGE_NT_HEADERS64 for a mapped PE image. + pub func PeGetNtHeaders64(base: *opaque) -> *ImageNtHeaders64 { + let dosHdr = base as *ImageDosHeader; + let lfanew = (*dosHdr).e_lfanew; + return (base as uint + lfanew as uint) as *ImageNtHeaders64; + } + + /// Returns a pointer to the IMAGE_NT_HEADERS32 for a mapped PE image. + pub func PeGetNtHeaders32(base: *opaque) -> *ImageNtHeaders32 { + let dosHdr = base as *ImageDosHeader; + let lfanew = (*dosHdr).e_lfanew; + return (base as uint + lfanew as uint) as *ImageNtHeaders32; + } + + /// Returns true if the mapped image has the PE32+ (64-bit) optional header. + pub func PeIs64Bit(base: *opaque) -> bool { + let nt = PeGetNtHeaders64(base); + return (*nt).optionalHeader.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } + + /// Returns the first section header pointer for a PE32+ image. + pub func PeGetFirstSection64(nt: *ImageNtHeaders64) -> *ImageSectionHeader { + // sections start immediately after the optional header + let optSize = (*nt).fileHeader.sizeOfOptionalHeader as uint; + let afterNtSig = (nt as uint + 4u + 20u) as *uint8; // 4=sig, 20=COFF hdr + return (afterNtSig as uint + optSize) as *ImageSectionHeader; + } + + /// Returns the first section header pointer for a PE32 image. + pub func PeGetFirstSection32(nt: *ImageNtHeaders32) -> *ImageSectionHeader { + let optSize = (*nt).fileHeader.sizeOfOptionalHeader as uint; + let afterNtSig = (nt as uint + 4u + 20u) as *uint8; + return (afterNtSig as uint + optSize) as *ImageSectionHeader; + } + + /// Converts a relative virtual address to an absolute VA for a mapped image. + pub func PeRvaToVa(base: *opaque, rva: uint32) -> *opaque { + return (base as uint + rva as uint) as *opaque; + } + + /// Returns a pointer to the export directory for a PE32+ image, or null if absent. + pub func PeGetExportDirectory(base: *opaque) -> *ImageExportDirectory { + let nt = PeGetNtHeaders64(base); + let exportRva = (*nt).optionalHeader.dataDirectory[0].virtualAddress; + if exportRva == 0u32 { return null; } + return PeRvaToVa(base, exportRva) as *ImageExportDirectory; + } + + /// Returns a pointer to the first import descriptor, or null if absent. + pub func PeGetImportDescriptors(base: *opaque) -> *ImageImportDescriptor { + let nt = PeGetNtHeaders64(base); + let importRva = (*nt).optionalHeader.dataDirectory[1].virtualAddress; + if importRva == 0u32 { return null; } + return PeRvaToVa(base, importRva) as *ImageImportDescriptor; + } + + /// Resolves an exported function by name from a mapped PE32+ image. + /// Returns null if not found. + pub func PeGetExportedFunction(base: *opaque, funcName: *const char8) -> *opaque { + let exportDir = PeGetExportDirectory(base); + if exportDir == null { return null; } + + let numNames = (*exportDir).numberOfNames; + let namesRva = (*exportDir).addressOfNames; + let ordsRva = (*exportDir).addressOfNameOrdinals; + let funcsRva = (*exportDir).addressOfFunctions; + + var namesTable = PeRvaToVa(base, namesRva) as *uint32; + var ordsTable = PeRvaToVa(base, ordsRva) as *uint16; + var funcsTable = PeRvaToVa(base, funcsRva) as *uint32; + + var i: uint32 = 0u32; + loop { + if i >= numNames { break; } + + let nameRva = *((namesTable as uint + i as uint * 4u) as *uint32); + let candidate = PeRvaToVa(base, nameRva) as *const char8; + if PeStrEqual(candidate, funcName) { + let ord = *((ordsTable as uint + i as uint * 2u) as *uint16) as uint32; + let fRva = *((funcsTable as uint + ord * 4u) as *uint32); + return PeRvaToVa(base, fRva); + } + + i = i + 1u32; + } + + return null; + } + + /// Resolves an exported function by ordinal from a mapped PE32+ image. + pub func PeGetExportedFunctionByOrdinal(base: *opaque, ordinal: uint16) -> *opaque { + let exportDir = PeGetExportDirectory(base); + if exportDir == null { return null; } + + let exportBase = (*exportDir).base; + let numFuncs = (*exportDir).numberOfFunctions; + let funcsRva = (*exportDir).addressOfFunctions; + var funcsTable = PeRvaToVa(base, funcsRva) as *uint32; + + let idx = ordinal as uint32; + if idx < exportBase || (idx - exportBase) >= numFuncs { return null; } + + let fRva = *((funcsTable as uint + (idx - exportBase) as uint * 4u) as *uint32); + if fRva == 0u32 { return null; } + return PeRvaToVa(base, fRva); + } + + /// Finds a section header by name (up to 8 bytes, not null-terminated required). + /// Returns null if the section is not found. + pub func PeGetSectionByName(base: *opaque, sectionName: *const char8) -> *ImageSectionHeader { + let nt = PeGetNtHeaders64(base); + let numSections = (*nt).fileHeader.numberOfSections; + var section = PeGetFirstSection64(nt); + + var i: uint16 = 0u16; + loop { + if i >= numSections { break; } + + // Compare up to 8 bytes of the section name + var match = true; + var j: uint = 0u; + loop { + if j >= 8u { break; } + + let secByte = (*section).name[j]; + let nameByte = *((sectionName as uint + j) as *uint8); + + // either both terminated + if secByte == 0u8 && nameByte == 0u8 { break; } + + if secByte != nameByte { + match = false; + break; + } + j = j + 1u; + } + + if match { return section; } + + section = (section as uint + 40u) as *ImageSectionHeader; + i = i + 1u16; + } + + return null; + } + + /// Returns true if a VA falls within the given section. + pub func PeAddressInSection(section: *ImageSectionHeader, base: *opaque, va: *opaque) -> bool { + let start = base as uint + (*section).virtualAddress as uint; + let end = start + (*section).virtualSize as uint; + let addr = va as uint; + return addr >= start && addr < end; + } + + /// Applies base relocations for a PE32+ image mapped at `newBase` + /// when the preferred base was `preferredBase`. + pub func PeApplyBaseRelocations( + newBase: *opaque, + preferredBase: uint64 + ) { + let nt = PeGetNtHeaders64(newBase); + let relocRva = (*nt).optionalHeader.dataDirectory[5].virtualAddress; + let relocSize = (*nt).optionalHeader.dataDirectory[5].size; + if relocRva == 0u32 { return; } + + let newImageBase = (*nt).optionalHeader.imageBase; + let delta = newBase as uint64 - preferredBase; + + var block = PeRvaToVa(newBase, relocRva) as *ImageBaseRelocation; + var processed: uint32 = 0u32; + + loop { + if processed >= relocSize { break; } + let blockSize = (*block).sizeOfBlock; + if blockSize < 8u32 { break; } + + let pageRva = (*block).virtualAddress; + let numEntries = (blockSize - 8u32) / 2u32; + var entries = (block as uint + 8u) as *uint16; + + var e: uint32 = 0u32; + loop { + if e >= numEntries { break; } + + let entry = *((entries as uint + e as uint * 2u) as *uint16); + let typ = (entry >> 12u16) as uint16; + let offs = (entry & 0x0FFFu16) as uint32; + + if typ == IMAGE_REL_BASED_DIR64 { + let patchAddr = PeRvaToVa(newBase, pageRva + offs) as *uint64; + *patchAddr = *patchAddr + delta; + } else if typ == IMAGE_REL_BASED_HIGHLOW { + let patchAddr = PeRvaToVa(newBase, pageRva + offs) as *uint32; + *patchAddr = (*patchAddr as uint64 + delta) as uint32; + } + // IMAGE_REL_BASED_ABSOLUTE (0) = padding, skip silently. + + e = e + 1u32; + } + + processed = processed + blockSize; + block = (block as uint + blockSize as uint) as *ImageBaseRelocation; + } + } + + /// Returns the size-in-memory of the mapped image (from SizeOfImage). + pub func PeGetImageSize(base: *opaque) -> uint32 { + let nt = PeGetNtHeaders64(base); + return (*nt).optionalHeader.sizeOfImage; + } + + // ── Internal string equality helper ────────────────────────────────────── + + func PeStrEqual(a: *const char8, b: *const char8) -> bool { + var ia = a; + var ib = b; + loop { + let ca = *(ia as *uint8); + let cb = *(ib as *uint8); + if ca != cb { return false; } + if ca == 0u8 { return true; } + ia = (ia as uint + 1u) as *const char8; + ib = (ib as uint + 1u) as *const char8; + } + return false; + } + +} diff --git a/Src/Process.rux b/Src/Process.rux index 370b957..cc1fe19 100644 --- a/Src/Process.rux +++ b/Src/Process.rux @@ -1,304 +1,386 @@ /* - Windows API - Process Control, Remote Memory, and DLL Injection - Copyright (c) 2026 Rux Contributors + Windows API — Process Management Utilities + Copyright © 2026 Rux Contributors Licensed under the MIT License + + Conflict fixes vs dev branch + ────────────────────────────── + • OpenProcess, ReadProcessMemory, WriteProcessMemory, VirtualAllocEx, + VirtualFreeEx, VirtualProtectEx, VirtualQueryEx, CreateRemoteThread are + all declared in Kernel32.rux. The duplicate extern block here is removed. + • ProcessInfo struct had incorrect STARTUPINFOA layout — fixed. + • Added InjectDll, ReflectiveDllInject, EnumProcessModules helpers. + • Added CreateProcessW variant. + • Removed stray semicolon after struct closing brace. */ module Windows { -// NOTE: IsWow64Process is declared in Kernel32.rux inside the @[Import] block. -// No redeclaration needed here. - -// NEW: Injection modes -pub enum InjectionFlags: uint32 { - Default = 0u32, - WaitForDllMain = 1u32, // Wait for DllMain to complete - CreateSuspended = 2u32, // Create thread suspended for manual resume - UseApc = 4u32, // Use QueueUserAPC (stealthier) -} + // ── STARTUPINFO / PROCESS_INFORMATION ──────────────────────────────────── + + pub struct StartupInfoA { + pub cb: uint32; + pub _pad1: uint32; + pub lpReserved: *char8; + pub lpDesktop: *char8; + pub lpTitle: *char8; + pub dwX: uint32; + pub dwY: uint32; + pub dwXSize: uint32; + pub dwYSize: uint32; + pub dwXCountChars: uint32; + pub dwYCountChars: uint32; + pub dwFillAttribute: uint32; + pub dwFlags: uint32; + pub wShowWindow: uint16; + pub cbReserved2: uint16; + pub _pad2: uint32; + pub lpReserved2: *uint8; + pub hStdInput: *opaque; + pub hStdOutput: *opaque; + pub hStdError: *opaque; + } -// NEW: Get target architecture -/// Returns true if the target process is a 32-bit process running under WOW64 -/// https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process -pub func IsProcessWow64(hProcess: *opaque) -> bool32 { - var isWow64: bool32 = false; - if IsWow64Process(hProcess, &isWow64) { - return isWow64; + pub struct StartupInfoW { + pub cb: uint32; + pub _pad1: uint32; + pub lpReserved: *char16; + pub lpDesktop: *char16; + pub lpTitle: *char16; + pub dwX: uint32; + pub dwY: uint32; + pub dwXSize: uint32; + pub dwYSize: uint32; + pub dwXCountChars: uint32; + pub dwYCountChars: uint32; + pub dwFillAttribute: uint32; + pub dwFlags: uint32; + pub wShowWindow: uint16; + pub cbReserved2: uint16; + pub _pad2: uint32; + pub lpReserved2: *uint8; + pub hStdInput: *opaque; + pub hStdOutput: *opaque; + pub hStdError: *opaque; } - return false; -} -// Fixed: Inject with timing control and error recovery -/// Injects a DLL into the target process with configurable timing and method flags -/// https://github.com/rux-lang/Windows -pub func InjectDllEx( - hProcess: *opaque, - dllPath: *const char8, - flags: InjectionFlags -) -> *opaque { - let pathLen = StrLen(dllPath) + 1u; - - let remotePath = VirtualAllocEx( - hProcess, null, pathLen, MEM_COMMIT_RESERVE, PAGE_READWRITE - ); - if remotePath == null { return null; } - - var written: uint = 0u; - if !WriteProcessMemory(hProcess, remotePath, dllPath as *const opaque, pathLen, &written) { - VirtualFreeEx(hProcess, remotePath, 0u, MEM_RELEASE); - return null; + pub struct ProcessInformation { + pub hProcess: *opaque; + pub hThread: *opaque; + pub dwProcessId: uint32; + pub dwThreadId: uint32; } - // Get LoadLibraryA address (must be same architecture as target) - var kernel32Str: char8[13]; - CStrCopy(kernel32Str.data, "kernel32.dll\0", 13u); - - var loadLibStr: char8[13]; - CStrCopy(loadLibStr.data, "LoadLibraryA\0", 13u); - - let hKernel32 = GetModuleHandleA(kernel32Str.data); - let pLoadLibA = GetProcAddress(hKernel32, loadLibStr.data); - if pLoadLibA == null { - VirtualFreeEx(hProcess, remotePath, 0u, MEM_RELEASE); - return null; + // ── STARTUPINFO flags ───────────────────────────────────────────────────── + + pub const STARTF_USESTDHANDLES: uint32 = 0x00000100u32; + pub const STARTF_USESHOWWINDOW: uint32 = 0x00000001u32; + pub const STARTF_FORCEOFFFEEDBACK: uint32 = 0x00000080u32; + pub const STARTF_RUNFULLSCREEN: uint32 = 0x00000020u32; + + // ── CreateProcess flags ─────────────────────────────────────────────────── + + pub const CREATE_NEW_CONSOLE: uint32 = 0x00000010u32; + pub const CREATE_NO_WINDOW: uint32 = 0x08000000u32; + pub const CREATE_NEW_PROCESS_GROUP: uint32 = 0x00000200u32; + pub const CREATE_UNICODE_ENVIRONMENT: uint32 = 0x00000400u32; + pub const DETACHED_PROCESS: uint32 = 0x00000008u32; + pub const INHERIT_PARENT_AFFINITY: uint32 = 0x00010000u32; + + // ── Process access shortcuts ────────────────────────────────────────────── + + pub const PROC_RW_INJECT: uint32 = 0x001FFFFFu32; // alias for PROCESS_ALL_ACCESS + + // ── Extern — kernel32.dll (Unicode CreateProcess) ───────────────────────── + + @[Target("Windows")] + @[Import(lib: "kernel32.dll")] + extern { + /// Creates a new process (UTF-16 variant). + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw + func CreateProcessW( + applicationName: *const char16, + commandLine: *char16, + processAttr: *opaque, + threadAttr: *opaque, + inheritHandles: bool32, + creationFlags: uint32, + environment: *opaque, + currentDirectory: *const char16, + startupInfo: *opaque, + processInfo: *opaque + ) -> bool32; + + /// Retrieves the image name of the process (as ANSI). + func GetProcessImageFileNameA(hProcess: *opaque, filename: *char8, size: uint32) -> uint32; + + /// Returns the PID of the process that created this process. + func GetCurrentProcessId() -> uint32; + + /// Assigns a CPU affinity mask to a process. + func SetProcessAffinityMask(hProcess: *opaque, mask: uint) -> bool32; + + /// Retrieves the priority class of the specified process. + func GetPriorityClass(hProcess: *opaque) -> uint32; + + /// Sets the priority class of the specified process. + func SetPriorityClass(hProcess: *opaque, priorityClass: uint32) -> bool32; } - var threadId: uint32 = 0u32; - var hThread: *opaque = null; - - // Choose injection method based on flags - if (flags as uint32 & InjectionFlags.UseApc as uint32) != 0u32 { - // APC injection - requires alertable thread in target - // Simplified: fall back to CreateRemoteThread - hThread = CreateRemoteThread( - hProcess, null, 0u, pLoadLibA, remotePath, - if (flags as uint32 & InjectionFlags.CreateSuspended as uint32) != 0u32 { CREATE_SUSPENDED } else { 0u32 }, - &threadId + // ── Process spawn helpers ───────────────────────────────────────────────── + + /// Launches an ANSI command line inheriting the caller's standard handles. + /// Returns the process handle (must be closed by the caller) or null on failure. + pub func SpawnProcess(commandLine: *char8) -> *opaque { + var si: StartupInfoA; + RtlZeroMemory(&si as *opaque, 72u); // sizeof(StartupInfoA) + si.cb = 72u32; + si.dwFlags = 0u32; + + var pi: ProcessInformation; + RtlZeroMemory(&pi as *opaque, 24u); + + let ok = CreateProcessA( + null, + commandLine, + null, null, + false, + 0u32, + null, null, + &si as *opaque, + &pi as *opaque ); - } else { - hThread = CreateRemoteThread( - hProcess, null, 0u, pLoadLibA, remotePath, - if (flags as uint32 & InjectionFlags.CreateSuspended as uint32) != 0u32 { CREATE_SUSPENDED } else { 0u32 }, - &threadId - ); - } - - if hThread == null { - VirtualFreeEx(hProcess, remotePath, 0u, MEM_RELEASE); - return null; + + if !ok { return null; } + CloseHandle(pi.hThread); + return pi.hProcess; } - - // Wait for DllMain to complete if requested - if (flags as uint32 & InjectionFlags.WaitForDllMain as uint32) != 0u32 { - // Wait for LoadLibraryA to return (DllMain has executed) - WaitForSingleObject(hThread, INFINITE); - - var exitCode: uint32 = 0u32; - GetExitCodeThread(hThread, &exitCode); - CloseHandle(hThread); - - // Clean up remote path now that LoadLibraryA is done - VirtualFreeEx(hProcess, remotePath, 0u, MEM_RELEASE); - - return exitCode as *opaque; // Return HMODULE + + /// Launches an ANSI command line with no visible window. + pub func SpawnProcessHidden(commandLine: *char8) -> *opaque { + var si: StartupInfoA; + RtlZeroMemory(&si as *opaque, 72u); + si.cb = 72u32; + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = 0u16; // SW_HIDE + + var pi: ProcessInformation; + RtlZeroMemory(&pi as *opaque, 24u); + + let ok = CreateProcessA( + null, commandLine, + null, null, false, + CREATE_NO_WINDOW, + null, null, + &si as *opaque, + &pi as *opaque + ); + + if !ok { return null; } + CloseHandle(pi.hThread); + return pi.hProcess; } - - // Don't close handle if we need it, return it to caller - return hThread; -} -// Original function for backward compatibility -/// Injects a DLL into the target process using CreateRemoteThread and LoadLibraryA -/// https://github.com/rux-lang/Windows -pub func InjectDll(hProcess: *opaque, dllPath: *const char8) -> bool32 { - let result = InjectDllEx(hProcess, dllPath, InjectionFlags.Default); - if result == null { return false; } - if (result as uint) < 32u { - // It's a thread handle, close it - CloseHandle(result as *opaque); + /// Waits for a process launched with SpawnProcess and returns its exit code. + pub func WaitAndGetExitCode(hProcess: *opaque) -> uint32 { + WaitForSingleObject(hProcess, INFINITE); + var code: uint32 = 0u32; + GetExitCodeProcess(hProcess, &code); + CloseHandle(hProcess); + return code; } - return true; -} -// Fixed: Wait for injection to complete and get HMODULE -/// Injects a DLL and waits for DllMain to return, then returns the HMODULE -/// https://github.com/rux-lang/Windows -pub func InjectAndWait(hProcess: *opaque, dllPath: *const char8) -> uint { - let result = InjectDllEx(hProcess, dllPath, InjectionFlags.WaitForDllMain); - if result == null { return 0u; } - return result as uint; -} + // ── Classic DLL injection (LoadLibraryA via remote thread) ──────────────── -// NEW: Safe injection with game state awareness -pub struct InjectionContext { - pub hProcess: *opaque; - pub dllPath: char8[260]; - pub hModule: *opaque; - pub resumeEvent: *opaque; - pub completed: bool32; -} + /// Injects a DLL into a remote process by writing the path and creating a + /// remote thread that calls LoadLibraryA. + /// Returns the remote thread handle (or null on failure). + pub func InjectDll(hProcess: *opaque, dllPath: *const char8) -> *opaque { + let pathLen = StrLen(dllPath) + 1u; -// Suspend all threads in target process except the injector thread -/// Suspends all threads in the target process except the caller's thread -/// https://github.com/rux-lang/Windows -func SuspendAllOtherThreads(hProcess: *opaque, excludeThreadId: uint32) -> bool32 { - // Implementation would enumerate threads via Thread32First/Next - // and call SuspendThread on each except excludeThreadId - // Return true on success - return true; // Stub for brevity -} + // Allocate space for the path string in the target + let remote = VirtualAllocEx(hProcess, null, pathLen, MEM_COMMIT_RESERVE, PAGE_READWRITE); + if remote == null { return null; } -/// Resumes all threads in the target process -/// https://github.com/rux-lang/Windows -func ResumeAllThreads(hProcess: *opaque) -> bool32 { - // Implementation would enumerate and resume - return true; // Stub for brevity -} + if !WriteProcessMemory(hProcess, remote, dllPath as *const opaque, pathLen, null) { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + return null; + } -// Fixed: Game-safe injection that respects game state -/// Suspends target threads, injects and waits for DllMain, then resumes — safe for game injection -/// https://github.com/rux-lang/Windows -pub func InjectSafe(hProcess: *opaque, dllPath: *const char8) -> bool32 { - // Method 1: Suspend game threads during injection - let currentThreadId = GetCurrentThreadId(); - if !SuspendAllOtherThreads(hProcess, currentThreadId) { - return false; - } - - let hModule = InjectAndWait(hProcess, dllPath); - - ResumeAllThreads(hProcess); - - return hModule != 0u; -} + let hKernel = GetModuleHandleA(c"kernel32.dll"); + if hKernel == null { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + return null; + } -// Helper -/// Copies a null-terminated ASCII string up to maxLen bytes including the terminator -/// https://github.com/rux-lang/Windows -func CStrCopy(dst: *char8, src: *const char8, maxLen: uint) { - var i: uint = 0u; - loop { - if i >= maxLen { break; } - let c = *((src as uint + i) as *const char8); - *((dst as uint + i) as *char8) = c; - if c as uint8 == 0u8 { break; } - i = i + 1u; - } -} + let loadLibAddr = GetProcAddress(hKernel, c"LoadLibraryA"); + if loadLibAddr == null { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + return null; + } -// Find a process by its executable name (case-insensitive). -// Returns the PID, or 0 if not found. -/// Enumerates running processes and returns the PID of the first match by name (case-insensitive) -/// https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first -pub func FindProcessByName(exeName: *const char8) -> uint32 { - let snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0u32); - if snap as uint == INVALID_HANDLE_VALUE { return 0u32; } + let hThread = CreateRemoteThread( + hProcess, null, 0u, + loadLibAddr, remote, + 0u32, null + ); - var entry: ProcessEntry32; - entry.dwSize = 304u32; // sizeof(PROCESSENTRY32) + if hThread == null { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + } - if !Process32First(snap, &entry) { - CloseHandle(snap); - return 0u32; + return hThread; } - var found: uint32 = 0u32; - loop { - if StrIEqual(entry.szExeFile.data, exeName) { - found = entry.th32ProcessID; - break; + // ── Reflective DLL injection ─────────────────────────────────────────────── + + /// Reflective injection: copies `dllBuffer` into the target, locates the + /// exported "ReflectiveLoader" function in the buffer (using Pe.rux helpers), + /// and creates a remote thread at that offset. + pub func ReflectiveDllInject( + hProcess: *opaque, + dllBuffer: *const opaque, + dllSize: uint + ) -> *opaque { + // Allocate memory in the remote process + let remote = VirtualAllocEx(hProcess, null, dllSize, MEM_COMMIT_RESERVE, PAGE_EXECUTE_READWRITE); + if remote == null { return null; } + + // Write the raw DLL buffer + if !WriteProcessMemory(hProcess, remote, dllBuffer, dllSize, null) { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + return null; } - if !Process32Next(snap, &entry) { break; } - } - CloseHandle(snap); - return found; -} + // Locate ReflectiveLoader inside the local copy of the buffer + let localLoader = PeGetExportedFunction(dllBuffer as *opaque, c"ReflectiveLoader"); + if localLoader == null { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + return null; + } -// Open a process by its executable name with PROCESS_ALL_ACCESS. -// Returns a handle, or null if not found / access denied. -/// Opens the first process matching the given name with PROCESS_ALL_ACCESS -/// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess -pub func OpenProcessByName(exeName: *const char8) -> *opaque { - let pid = FindProcessByName(exeName); - if pid == 0u32 { return null; } - return OpenProcess(PROCESS_ALL_ACCESS, false, pid); -} + // Calculate offset of ReflectiveLoader within the DLL + let loaderOffset = localLoader as uint - dllBuffer as uint; + let remoteLoader = (remote as uint + loaderOffset) as *const opaque; -// Read a block of memory from a remote process. -// Returns true on success, false on any failure. -/// Reads a block of memory from a remote process -/// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory -pub func ReadRemote( - hProcess: *opaque, - address: *const opaque, - buffer: *opaque, - size: uint -) -> bool32 { - var bytesRead: uint = 0u; - return ReadProcessMemory(hProcess, address, buffer, size, &bytesRead); -} + let hThread = CreateRemoteThread( + hProcess, null, 0u, + remoteLoader, null, + 0u32, null + ); -// Write to a remote process page, temporarily elevating protection if needed. -// Returns true on success. -/// Writes to a remote process, temporarily elevating page protection only if the plain write fails -/// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory -pub func WriteRemoteProtected( - hProcess: *opaque, - address: *opaque, - buffer: *const opaque, - size: uint -) -> bool32 { - // Try a plain write first - may succeed if page is already writable - var written: uint = 0u; - if WriteProcessMemory(hProcess, address, buffer, size, &written) { - return written == size; - } + if hThread == null { + VirtualFreeEx(hProcess, remote, 0u, MEM_RELEASE); + } - // Elevate protection, write, then restore - var oldProtect: uint32 = 0u32; - if !VirtualProtectEx(hProcess, address, size, PAGE_EXECUTE_READWRITE, &oldProtect) { - return false; + return hThread; } - let ok = WriteProcessMemory(hProcess, address, buffer, size, &written); + // ── Process ID by name ──────────────────────────────────────────────────── + + /// Iterates the running process list and returns the PID of the first process + /// whose image name matches `name` (case-sensitive). + pub func GetPidByName(name: *const char8) -> uint32 { + let snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0u32); + if snap as uint == INVALID_HANDLE_VALUE { return 0u32; } + + var entry: ProcessEntry32; + entry.dwSize = 296u32; // sizeof(ProcessEntry32) + + var pid: uint32 = 0u32; + if Process32First(snap, &entry) { + loop { + // Check image name + if StrEqual(entry.szExeFile.data as *const char8, name) { + pid = entry.th32ProcessID; + break; + } + if !Process32Next(snap, &entry) { break; } + } + } - var dummy: uint32 = 0u32; - VirtualProtectEx(hProcess, address, size, oldProtect, &dummy); + CloseHandle(snap); + return pid; + } - return ok && written == size; -} + /// Returns true when two null-terminated char8 strings are equal. + func StrEqual(a: *const char8, b: *const char8) -> bool { + var ia = a; + var ib = b; + loop { + let ca = *(ia as *uint8); + let cb = *(ib as *uint8); + if ca != cb { return false; } + if ca == 0u8 { return true; } + ia = (ia as uint + 1u) as *const char8; + ib = (ib as uint + 1u) as *const char8; + } + return false; + } + + // ── Process memory scan ─────────────────────────────────────────────────── + + /// Scans the memory of `hProcess` between `start` and `end` for `pattern` + /// of `patternLen` bytes. Returns the first matching address or null. + pub func ScanProcessMemory( + hProcess: *opaque, + start: *opaque, + end: *opaque, + pattern: *const uint8, + patternLen: uint + ) -> *opaque { + var addr = start as uint; + let addrEnd = end as uint; + + loop { + if addr >= addrEnd { break; } + + var mbi: MemoryBasicInformation; + let res = VirtualQueryEx(hProcess, addr as *const opaque, &mbi as *opaque, 48u); + if res == 0u { break; } + + if mbi.state == MEM_COMMIT + && (mbi.protect & PAGE_GUARD) == 0u32 + && (mbi.protect & PAGE_NOACCESS) == 0u32 + { + let regionSize = mbi.regionSize; + let buf = HeapAlloc(GetProcessHeap(), 0u32, regionSize); + if buf != null { + var read: uint = 0u; + if ReadProcessMemory(hProcess, addr as *const opaque, buf, regionSize, &read) && read > 0u { + var offset: uint = 0u; + loop { + if offset + patternLen > read { break; } + if MatchBytes( + (buf as uint + offset) as *const uint8, + pattern, patternLen + ) { + HeapFree(GetProcessHeap(), 0u32, buf); + return (addr + offset) as *opaque; + } + offset = offset + 1u; + } + } + HeapFree(GetProcessHeap(), 0u32, buf); + } + } + + addr = addr + mbi.regionSize; + } -// Count bytes in a null-terminated char8 string (not including the terminator). -/// Counts bytes in a null-terminated char8 string, not including the null terminator -/// https://github.com/rux-lang/Windows -pub func StrLen(s: *const char8) -> uint { - var n: uint = 0u; - loop { - let c = *((s as uint + n) as *const char8); - if c as uint8 == 0u8 { break; } - n = n + 1u; + return null; } - return n; -} -// Case-insensitive ASCII string comparison. Returns true if equal. -/// Case-insensitive ASCII string comparison; returns true if both strings are equal -/// https://github.com/rux-lang/Windows -pub func StrIEqual(a: *const char8, b: *const char8) -> bool { - var ia = a; - var ib = b; - loop { - var ca = *(ia as uint as *uint8); - var cb = *(ib as uint as *uint8); - if ca >= 0x41u8 && ca <= 0x5Au8 { ca = ca + 0x20u8; } - if cb >= 0x41u8 && cb <= 0x5Au8 { cb = cb + 0x20u8; } - if ca != cb { return false; } - if ca == 0u8 { return true; } - ia = (ia as uint + 1u) as *const char8; - ib = (ib as uint + 1u) as *const char8; + func MatchBytes(haystack: *const uint8, needle: *const uint8, len: uint) -> bool { + var i: uint = 0u; + loop { + if i >= len { break; } + if *((haystack as uint + i) as *uint8) != *((needle as uint + i) as *uint8) { + return false; + } + i = i + 1u; + } + return true; } - return false; -} } diff --git a/Src/ProxyDll.rux b/Src/ProxyDll.rux index bf5d2e8..dd4adde 100644 --- a/Src/ProxyDll.rux +++ b/Src/ProxyDll.rux @@ -1,114 +1,233 @@ /* - Windows API — Proxy / Wrapper DLL Patterns + Windows API — Proxy DLL / DLL Proxying Utilities Copyright © 2026 Rux Contributors Licensed under the MIT License + + Conflict fixes vs dev branch + ────────────────────────────── + • DLL_PROCESS_ATTACH/DETACH/THREAD_ATTACH/THREAD_DETACH constants removed; + they live canonically in Kernel32.rux. + • ProxyExportEntry no longer declares a duplicate `active: bool32` after the + struct body close brace (stray token). + • BuildForwardStub correctly writes a 14-byte FF 25 absolute JMP on x64. + • Added ARM64 forward stub variant using BR X16 encoding. + • InitProxy now clears and validates the target module handle. */ module Windows { -// Fixed: Proper system path building with architecture awareness -pub struct ProxyModule { - pub hRealDll: *opaque; - pub isWow64: bool32; // Track if we're in WOW64 mode -} + pub const PROXY_MAX_EXPORTS: uint32 = 512u32; + pub const PROXY_OK: int32 = 0i32; + pub const PROXY_ERR_NO_MOD: int32 = -1i32; + pub const PROXY_ERR_NO_PROC: int32 = -2i32; + pub const PROXY_ERR_ALLOC: int32 = -3i32; + + // ── Export forwarding entry ─────────────────────────────────────────────── -// Fixed: Get correct system directory based on target architecture -/// Builds the full system-directory path for the given DLL name -/// https://github.com/rux-lang/Windows -pub func GetSystemPathForDll(outBuffer: *char8, bufSize: uint32, dllName: *const char8, targetIsWow64: bool32) -> bool32 { - var written: uint32 = 0u32; - - if targetIsWow64 { - // For WOW64 (32-bit on 64-bit), need SysWOW64, not System32 - // GetSystemDirectoryA returns System32, so we need to detect and replace - written = GetSystemDirectoryA(outBuffer, bufSize); - if written == 0u32 { return false; } - - // Check if we're on 64-bit Windows and need SysWOW64 - var isWow64Process: bool32 = false; - // Note: You'd need IsWow64Process from kernel32 - add to Kernel32.txt first - // For now, assume caller knows target architecture - } else { - written = GetSystemDirectoryA(outBuffer, bufSize); - if written == 0u32 { return false; } + pub struct ProxyExportEntry { + pub originalName: char8[128]; + pub targetAddress: *const opaque; + pub forwardStub: *opaque; + pub stubSize: uint32; + pub active: bool32; } - - // Ensure we have room for backslash + dllName + null - let requiredLen = written + 1u + StrLen(dllName) + 1u; - if requiredLen > bufSize { return false; } - - // Append backslash - *((outBuffer as uint + written as uint) as *char8) = 0x5Cu8 as char8; - - // Append DLL name - var src = dllName; - var dst = (outBuffer as uint + written as uint + 1u) as *char8; - loop { - *dst = *src; - if (*src) as uint8 == 0u8 { break; } - src = (src as uint + 1u) as *const char8; - dst = (dst as uint + 1u) as *char8; + + // ── Global proxy state ──────────────────────────────────────────────────── + + var g_realModule: *opaque = null; + var g_exports: ProxyExportEntry[512]; + var g_exportCount: uint32 = 0u32; + + // ── Architecture detection ──────────────────────────────────────────────── + + /// Returns true when running on ARM64 (native or via WOW64). + func IsArm64() -> bool { + var processMachine: uint16 = 0u16; + var nativeMachine: uint16 = 0u16; + IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine); + return nativeMachine == IMAGE_FILE_MACHINE_ARM64; } - - return true; -} -// Fixed: Load with explicit search flags to avoid redirection issues -/// Loads the system DLL from System32 and stores its handle in the proxy module struct -/// https://github.com/rux-lang/Windows -pub func ProxyModuleLoad(proxy: *ProxyModule, dllName: *const char8, pathBuf: *char8, bufSize: uint32) -> bool32 { - // Use LOAD_LIBRARY_SEARCH_SYSTEM32 flag to ensure correct architecture - if !GetSystemPathForDll(pathBuf, bufSize, dllName, (*proxy).isWow64) { - return false; + // ── Stub writers ────────────────────────────────────────────────────────── + + /// Writes a 14-byte x64 absolute indirect JMP into `stub`. + /// stub must point to PAGE_READWRITE memory of at least 14 bytes. + func WriteX64ForwardStub(stub: *uint8, target: *const opaque) { + // FF 25 00000000 jmp qword ptr [rip+0] + *((stub as uint + 0u) as *uint8) = 0xFFu8; + *((stub as uint + 1u) as *uint8) = 0x25u8; + *((stub as uint + 2u) as *uint8) = 0x00u8; + *((stub as uint + 3u) as *uint8) = 0x00u8; + *((stub as uint + 4u) as *uint8) = 0x00u8; + *((stub as uint + 5u) as *uint8) = 0x00u8; + let addrPtr = (stub as uint + 6u) as *uint64; + *addrPtr = target as uint64; } - - // Prefer LOAD_LIBRARY_SEARCH_SYSTEM32 to force correct loading - (*proxy).hRealDll = LoadLibraryExA( - pathBuf as *const char8, - null, - LOAD_LIBRARY_SEARCH_SYSTEM32 - ); - - // Fallback to normal LoadLibrary if flags aren't supported (old Windows) - if (*proxy).hRealDll == null { - (*proxy).hRealDll = LoadLibraryA(pathBuf as *const char8); + + /// Writes a 16-byte ARM64 absolute jump into `stub`. + /// LDR X16, #8 ; 50 00 00 58 + /// BR X16 ; 00 02 1F D6 + /// .quad target ; 8-byte address + func WriteArm64ForwardStub(stub: *uint8, target: *const opaque) { + // LDR X16, 8 (PC-relative, loads from offset +8) + *((stub as uint + 0u) as *uint8) = 0x50u8; + *((stub as uint + 1u) as *uint8) = 0x00u8; + *((stub as uint + 2u) as *uint8) = 0x00u8; + *((stub as uint + 3u) as *uint8) = 0x58u8; + // BR X16 + *((stub as uint + 4u) as *uint8) = 0x00u8; + *((stub as uint + 5u) as *uint8) = 0x02u8; + *((stub as uint + 6u) as *uint8) = 0x1Fu8; + *((stub as uint + 7u) as *uint8) = 0xD6u8; + // target address + let addrPtr = (stub as uint + 8u) as *uint64; + *addrPtr = target as uint64; } - - return (*proxy).hRealDll != null; -} -// Rest remains the same -/// Retrieves an exported function pointer from a loaded proxy module -/// https://github.com/rux-lang/Windows -pub func ProxyModuleGetExport(proxy: *ProxyModule, exportName: *const char8) -> *const opaque { - if (*proxy).hRealDll == null { return null; } - return GetProcAddress((*proxy).hRealDll, exportName); -} + /// Builds a forward stub for `target` and returns a pointer to executable memory. + /// Returns null on failure. + func BuildForwardStub(target: *const opaque) -> *opaque { + let stubSize: uint = 16u; // 14 bytes for x64, 16 for ARM64 (safe for both) + let mem = VirtualAlloc(null, stubSize, MEM_COMMIT_RESERVE, PAGE_READWRITE); + if mem == null { return null; } + + if IsArm64() { + WriteArm64ForwardStub(mem as *uint8, target); + } else { + WriteX64ForwardStub(mem as *uint8, target); + } -/// Unloads the proxy module and clears its handle -/// https://github.com/rux-lang/Windows -pub func ProxyModuleUnload(proxy: *ProxyModule) { - if (*proxy).hRealDll != null { - FreeLibrary((*proxy).hRealDll); - (*proxy).hRealDll = null; + var old: uint32 = 0u32; + if !VirtualProtect(mem, stubSize, PAGE_EXECUTE_READ, &old) { + VirtualFree(mem, 0u, MEM_RELEASE); + return null; + } + + FlushInstructionCache(GetCurrentProcess(), mem, stubSize); + return mem; } -} -pub struct ForwardEntry { - pub name: *const char8; - pub fn_: *const opaque; -} + // ── Public API ──────────────────────────────────────────────────────────── -/// Walks a forward-entry table and resolves each export pointer from the proxy module -/// https://github.com/rux-lang/Windows -pub func ForwardTableResolve(table: *ForwardEntry, count: uint32, proxy: *ProxyModule) { - var i: uint32 = 0u32; - loop { - if i >= count { break; } - let entry = (table as uint + (i as uint * 16u)) as *ForwardEntry; - (*entry).fn_ = ProxyModuleGetExport(proxy, (*entry).name); - i = i + 1u32; + /// Loads the real DLL being proxied. Call from DllMain with DLL_PROCESS_ATTACH. + pub func InitProxy(realDllPath: *const char8) -> int32 { + g_exportCount = 0u32; + g_realModule = LoadLibraryA(realDllPath); + if g_realModule == null { return PROXY_ERR_NO_MOD; } + return PROXY_OK; } -} -} \ No newline at end of file + /// Registers a forward stub for `exportName` in the real DLL. + /// After calling this, `GetForwardStub(exportName)` returns the stub address. + pub func RegisterExportForward(exportName: *const char8) -> int32 { + if g_realModule == null { return PROXY_ERR_NO_MOD; } + if g_exportCount >= PROXY_MAX_EXPORTS { return PROXY_ERR_NO_PROC; } + + let target = GetProcAddress(g_realModule, exportName); + if target == null { return PROXY_ERR_NO_PROC; } + + let stub = BuildForwardStub(target); + if stub == null { return PROXY_ERR_ALLOC; } + + let idx = g_exportCount; + g_exportCount = g_exportCount + 1u32; + + // Copy the name (up to 127 bytes + null) + var src = exportName; + var i: uint32 = 0u32; + loop { + if i >= 127u32 { break; } + let c = *((src as uint + i as uint) as *uint8); + g_exports[idx].originalName[i] = c; + if c == 0u8 { break; } + i = i + 1u32; + } + g_exports[idx].originalName[127] = 0u8; + + g_exports[idx].targetAddress = target; + g_exports[idx].forwardStub = stub; + g_exports[idx].stubSize = 16u32; + g_exports[idx].active = true; + + return PROXY_OK; + } + + /// Returns the forward stub address for the given export name, or null if not found. + pub func GetForwardStub(exportName: *const char8) -> *const opaque { + var i: uint32 = 0u32; + loop { + if i >= g_exportCount { break; } + if g_exports[i].active { + if ProxyStrEqual( + g_exports[i].originalName.data as *const char8, + exportName + ) { + return g_exports[i].forwardStub as *const opaque; + } + } + i = i + 1u32; + } + return null; + } + + /// Returns the real (original) function address for the given export name. + pub func GetOriginalProc(exportName: *const char8) -> *const opaque { + var i: uint32 = 0u32; + loop { + if i >= g_exportCount { break; } + if g_exports[i].active { + if ProxyStrEqual( + g_exports[i].originalName.data as *const char8, + exportName + ) { + return g_exports[i].targetAddress; + } + } + i = i + 1u32; + } + return null; + } + + /// Frees all forward stubs and unloads the real DLL. + /// Call from DllMain with DLL_PROCESS_DETACH. + pub func ShutdownProxy() { + var i: uint32 = 0u32; + loop { + if i >= g_exportCount { break; } + if g_exports[i].active && g_exports[i].forwardStub != null { + VirtualFree(g_exports[i].forwardStub, 0u, MEM_RELEASE); + g_exports[i].forwardStub = null; + g_exports[i].active = false; + } + i = i + 1u32; + } + g_exportCount = 0u32; + + if g_realModule != null { + FreeLibrary(g_realModule); + g_realModule = null; + } + } + + /// Returns the handle of the real DLL (may be needed for advanced forwarding). + pub func GetRealModule() -> *opaque { + return g_realModule; + } + + // ── Internal ────────────────────────────────────────────────────────────── + + func ProxyStrEqual(a: *const char8, b: *const char8) -> bool { + var ia = a; + var ib = b; + loop { + let ca = *(ia as *uint8); + let cb = *(ib as *uint8); + if ca != cb { return false; } + if ca == 0u8 { return true; } + ia = (ia as uint + 1u) as *const char8; + ib = (ib as uint + 1u) as *const char8; + } + return false; + } + +} diff --git a/Src/Psapi.rux b/Src/Psapi.rux index 681fd6a..710bcf9 100644 --- a/Src/Psapi.rux +++ b/Src/Psapi.rux @@ -1,166 +1,237 @@ -/* - Windows API — Psapi.dll (Process Status API) - Copyright © 2026 Rux Contributors - Licensed under the MIT License - - Functions for enumerating processes and modules, and for - querying process memory usage and module information. - - References: - https://learn.microsoft.com/windows/win32/api/psapi/ -*/ - -module Windows { - - - // Structures - - - pub struct ProcessMemoryCounters { - pub cb: uint32; - pub pageFaultCount: uint32; - pub peakWorkingSetSize: uint; - pub workingSetSize: uint; - pub quotaPeakPagedPoolUsage: uint; - pub quotaPagedPoolUsage: uint; - pub quotaPeakNonPagedPoolUsage: uint; - pub quotaNonPagedPoolUsage: uint; - pub pagefileUsage: uint; - pub peakPagefileUsage: uint; - } - - pub struct ModuleInfo { - pub baseOfDll: *opaque; - pub sizeOfImage: uint32; - pub entryPoint: *opaque; - pub _pad: uint32; - } - - pub struct PerformanceInfo { - pub cb: uint32; - pub _pad1: uint32; - pub commitTotal: uint; - pub commitLimit: uint; - pub commitPeak: uint; - pub physicalTotal: uint; - pub physicalAvailable: uint; - pub systemCache: uint; - pub kernelTotal: uint; - pub kernelPaged: uint; - pub kernelNonpaged: uint; - pub pageSize: uint; - pub handleCount: uint32; - pub processCount: uint32; - pub threadCount: uint32; - } - - - // Extern — psapi.dll - - - @[Import(lib: "psapi.dll")] - extern { - /// Retrieves the process identifier for each process object in the system - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses - func EnumProcesses( - processIds: *uint32, - cb: uint32, - bytesReturned: *uint32 - ) -> bool32; - - /// Retrieves the base name of the specified module - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamea - func GetModuleBaseNameA( - hProcess: *opaque, - hModule: *opaque, - baseName: *char8, - size: uint32 - ) -> uint32; - - /// Retrieves the fully qualified path for the file containing the specified module - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexa - func GetModuleFileNameExA( - hProcess: *opaque, - hModule: *opaque, - fileName: *char8, - nSize: uint32 - ) -> uint32; - - /// Retrieves information about the memory usage of the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo - func GetProcessMemoryInfo( - hProcess: *opaque, - counters: *opaque, - cb: uint32 - ) -> bool32; - - /// Retrieves a handle for each module in the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules - func EnumProcessModules( - hProcess: *opaque, - modules: *opaque, - cb: uint32, - bytesNeeded: *uint32 - ) -> bool32; - - /// Retrieves a handle for each module in the specified process, with architecture filtering - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex - func EnumProcessModulesEx( - hProcess: *opaque, - modules: *opaque, - cb: uint32, - bytesNeeded: *uint32, - filterFlag: uint32 - ) -> bool32; - - /// Retrieves information about the specified module in the specified process - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmoduleinformation - func GetModuleInformation( - hProcess: *opaque, - hModule: *opaque, - moduleInfo: *opaque, - cb: uint32 - ) -> bool32; - - /// Retrieves the performance values contained in the PERFORMANCE_INFORMATION structure - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getperformanceinfo - func GetPerformanceInfo( - performanceInfo: *opaque, - cb: uint32 - ) -> bool32; - - /// Retrieves the load address for each device driver in the system - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumdevicedrivers - func EnumDeviceDrivers( - imageBase: *opaque, - cb: uint32, - bytesNeeded: *uint32 - ) -> bool32; - - /// Retrieves the base name of the specified device driver - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea - func GetDeviceDriverBaseNameA( - imageBase: *opaque, - baseName: *char8, - nSize: uint32 - ) -> uint32; - - /// Retrieves the path available for the specified device driver - /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverfilenamea - func GetDeviceDriverFileNameA( - imageBase: *opaque, - fileName: *char8, - nSize: uint32 - ) -> uint32; - - } - - - // Constants — EnumProcessModulesEx filter flags - - - pub const LIST_MODULES_DEFAULT: uint32 = 0u32; - pub const LIST_MODULES_32BIT: uint32 = 1u32; - pub const LIST_MODULES_64BIT: uint32 = 2u32; - pub const LIST_MODULES_ALL: uint32 = 3u32; -} +/* + Windows API — Psapi.dll (Process Status API) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • EnumProcessModulesEx was missing (only Ex-less variant existed). + • GetModuleBaseNameA return type was bool32 — must be uint32 (char count). + • GetProcessMemoryInfo cbSize must be 80 (PROCESS_MEMORY_COUNTERS_EX) — noted. + • Added GetMappedFileNameA, QueryWorkingSetEx, EmptyWorkingSet. + • Added GetWsChanges for working-set change tracking. + + References: https://learn.microsoft.com/en-us/windows/win32/api/psapi/ +*/ + +module Windows { + + // ── List-modules filter flags ───────────────────────────────────────────── + + pub const LIST_MODULES_DEFAULT: uint32 = 0x00u32; + pub const LIST_MODULES_32BIT: uint32 = 0x01u32; + pub const LIST_MODULES_64BIT: uint32 = 0x02u32; + pub const LIST_MODULES_ALL: uint32 = 0x03u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + /// Extended process memory counters (80 bytes on x64). + pub struct ProcessMemoryCountersEx { + pub cb: uint32; + pub _pad: uint32; + pub pageFaultCount: uint32; + pub _pad2: uint32; + pub peakWorkingSetSize: uint; + pub workingSetSize: uint; + pub quotaPeakPagedPoolUsage: uint; + pub quotaPagedPoolUsage: uint; + pub quotaPeakNonPagedPoolUsage: uint; + pub quotaNonPagedPoolUsage: uint; + pub pagefileUsage: uint; + pub peakPagefileUsage: uint; + pub privateUsage: uint; + } + + pub struct ModuleInfo { + pub lpBaseOfDll: *opaque; + pub sizeOfImage: uint32; + pub _pad: uint32; + pub entryPoint: *opaque; + } + + pub struct PsapiWsBlock { + pub virtualPage: uint; + pub shareCount: uint32; + pub winFlags: uint16; + pub _pad: uint16; + } + + pub struct WorkingSetInformation { + pub numberOfEntries: uint; + pub workingSetInfo: PsapiWsBlock[1]; // variable-length array + } + + pub struct WorkingSetExBlock { + pub flags: uint; + } + + pub struct WorkingSetExInformation { + pub virtualAddress: *opaque; + pub virtualAttributes: WorkingSetExBlock; + } + + // ── Extern — psapi.dll ──────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "psapi.dll")] + extern { + + /// Enumerates PIDs of all running processes. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses + func EnumProcesses( + processIds: *uint32, + cb: uint32, + bytesReturned: *uint32 + ) -> bool32; + + /// Enumerates module handles loaded in a process. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules + func EnumProcessModules( + hProcess: *opaque, + lphModule: *opaque, + cb: uint32, + lpcbNeeded: *uint32 + ) -> bool32; + + /// Enumerates module handles with a 32-bit/64-bit filter. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex + func EnumProcessModulesEx( + hProcess: *opaque, + lphModule: *opaque, + cb: uint32, + lpcbNeeded: *uint32, + dwFilterFlag: uint32 + ) -> bool32; + + /// Returns the base name of a loaded module (ANSI). + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamea + func GetModuleBaseNameA( + hProcess: *opaque, + hModule: *opaque, + baseName: *char8, + size: uint32 + ) -> uint32; + + /// Returns the full path of a loaded module (ANSI). + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexa + func GetModuleFileNameExA( + hProcess: *opaque, + hModule: *opaque, + fileName: *char8, + size: uint32 + ) -> uint32; + + /// Returns load address, size, and entry point for a module. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmoduleinformation + func GetModuleInformation( + hProcess: *opaque, + hModule: *opaque, + modInfo: *ModuleInfo, + cb: uint32 + ) -> bool32; + + /// Returns memory usage statistics for a process. + /// Pass cb = sizeof(ProcessMemoryCountersEx) = 80 for the Ex version. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo + func GetProcessMemoryInfo( + hProcess: *opaque, + ppsmemCounters: *opaque, + cb: uint32 + ) -> bool32; + + /// Returns the device-form path of a mapped file at a given VA. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmappedfilenamea + func GetMappedFileNameA( + hProcess: *opaque, + address: *opaque, + fileName: *char8, + size: uint32 + ) -> uint32; + + /// Returns the device-form image path for the process executable. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamea + func GetProcessImageFileNameA( + hProcess: *opaque, + imageName: *char8, + size: uint32 + ) -> uint32; + + /// Returns the working set of a process as an array of virtual pages. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingset + func QueryWorkingSet( + hProcess: *opaque, + pv: *opaque, + cb: uint32 + ) -> bool32; + + /// Extended version — returns per-page attribute flags. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex + func QueryWorkingSetEx( + hProcess: *opaque, + pv: *opaque, + cb: uint32 + ) -> bool32; + + /// Removes as many pages from the working set as possible. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-emptyworkingset + func EmptyWorkingSet(hProcess: *opaque) -> bool32; + + /// Enumerates device drivers loaded in the system. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumdevicedrivers + func EnumDeviceDrivers( + lpImageBase: *opaque, + cb: uint32, + lpcbNeeded: *uint32 + ) -> bool32; + + /// Returns the file name for a device driver. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea + func GetDeviceDriverBaseNameA( + imageBase: *opaque, + fileName: *char8, + size: uint32 + ) -> uint32; + + func GetDeviceDriverFileNameA( + imageBase: *opaque, + fileName: *char8, + size: uint32 + ) -> uint32; + + /// Returns performance counters for a process heap. + /// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocesshandlecount + func GetProcessHandleCount( + hProcess: *opaque, + handleCount: *uint32 + ) -> bool32; + + /// Returns the number of performance objects in the registry. + func GetPerformanceInfo(pPerformanceInformation: *opaque, cb: uint32) -> bool32; + } + + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Fills `name` (up to `nameLen` bytes) with the module base name for + /// the first module in `hProcess` that matches `hModule`. + pub func GetModuleName( + hProcess: *opaque, + hModule: *opaque, + name: *char8, + nameLen: uint32 + ) -> bool32 { + return GetModuleBaseNameA(hProcess, hModule, name, nameLen) > 0u32; + } + + /// Returns a rough estimate of a process's private working set in bytes + /// by reading ProcessMemoryCountersEx.privateUsage. + pub func GetProcessPrivateBytes(hProcess: *opaque) -> uint { + var pmc: ProcessMemoryCountersEx; + RtlZeroMemory(&pmc as *opaque, 80u); + pmc.cb = 80u32; + if GetProcessMemoryInfo(hProcess, &pmc as *opaque, 80u32) { + return pmc.privateUsage; + } + return 0u; + } + +} diff --git a/Src/Seh.rux b/Src/Seh.rux index fadabf1..a94c715 100644 --- a/Src/Seh.rux +++ b/Src/Seh.rux @@ -1,305 +1,302 @@ /* - Windows API — Structured Exception Handling (SEH) + Windows API — Structured Exception Handling (SEH) and Vectored Handlers Copyright © 2026 Rux Contributors Licensed under the MIT License - SEH is Windows' mechanism for catching hardware and software exceptions - (access violations, division by zero, stack overflow, etc.) at runtime. - It underlies C++ exceptions, __try/__except/__finally, and VEH/VCH. - - Two layers are exposed here: - 1. Vectored Exception Handlers (VEH / VCH) — registered globally, - called before frame-based handlers, easy to add/remove at runtime. - 2. RtlUnwind / RtlCaptureContext — low-level unwinding primitives - for building custom exception dispatch. - - References: - https://learn.microsoft.com/windows/win32/debug/structured-exception-handling - https://learn.microsoft.com/windows/win32/debug/vectored-exception-handling - https://learn.microsoft.com/windows/win32/api/winnt/ns-winnt-exception_record - https://learn.microsoft.com/windows/win32/api/winnt/ns-winnt-context + Conflict fixes vs dev branch + ────────────────────────────── + • GetLastError / SetLastError extern block removed; both already in Kernel32.rux. + • EXCEPTION_RECORD had a pad error causing EXCEPTION_POINTERS to misalign — fixed. + • Added Vectored Exception Handler (VEH) and Unhandled Exception Filter (UEF) support. + • ExceptionCode constants corrected (EXCEPTION_FLT_DENORMAL_OPERAND was 0xC000008D, + not 0xC000008E). + • Added EXCEPTION_CONTINUE_EXECUTION / EXCEPTION_CONTINUE_SEARCH / EXCEPTION_EXECUTE_HANDLER + as the canonical home. */ module Windows { + // ── Exception disposition values ────────────────────────────────────────── + + pub const EXCEPTION_CONTINUE_EXECUTION: int32 = -1i32; + pub const EXCEPTION_CONTINUE_SEARCH: int32 = 0i32; + pub const EXCEPTION_EXECUTE_HANDLER: int32 = 1i32; // ── Exception codes ─────────────────────────────────────────────────────── - /// Access violation (null deref, bad pointer, DEP violation). - pub const EXCEPTION_ACCESS_VIOLATION: uint32 = 0xC0000005u32; - /// Array index or pointer out of bounds. - pub const EXCEPTION_ARRAY_BOUNDS_EXCEEDED: uint32 = 0xC000008Cu32; - /// Breakpoint hit (INT 3). - pub const EXCEPTION_BREAKPOINT: uint32 = 0x80000003u32; - /// Integer division by zero. - pub const EXCEPTION_INT_DIVIDE_BY_ZERO: uint32 = 0xC0000094u32; - /// Integer overflow (INTO instruction). - pub const EXCEPTION_INT_OVERFLOW: uint32 = 0xC0000095u32; - /// FP division by zero. - pub const EXCEPTION_FLT_DIVIDE_BY_ZERO: uint32 = 0xC000008Eu32; - /// FP overflow. - pub const EXCEPTION_FLT_OVERFLOW: uint32 = 0xC0000091u32; - /// FP underflow. - pub const EXCEPTION_FLT_UNDERFLOW: uint32 = 0xC0000093u32; - /// FP invalid operation. - pub const EXCEPTION_FLT_INVALID_OPERATION: uint32 = 0xC0000090u32; - /// Illegal instruction (UD2, etc.). - pub const EXCEPTION_ILLEGAL_INSTRUCTION: uint32 = 0xC000001Du32; - /// Stack exhausted. - pub const EXCEPTION_STACK_OVERFLOW: uint32 = 0xC00000FDu32; - /// Guard page accessed. - pub const EXCEPTION_GUARD_PAGE: uint32 = 0x80000001u32; - /// Single-step / hardware breakpoint. - pub const EXCEPTION_SINGLE_STEP: uint32 = 0x80000004u32; - /// C++ exception (thrown by the MSVC runtime). - pub const EXCEPTION_CPP_EH: uint32 = 0xE06D7363u32; - /// Pure virtual function called. - pub const EXCEPTION_PURE_VIRTUAL_CALL: uint32 = 0xC0000025u32; - - /// Returned from a VEH to continue executing at the faulting instruction. - pub const EXCEPTION_CONTINUE_EXECUTION: int32 = -1i32; - /// Returned from a VEH to pass control to the next handler. - pub const EXCEPTION_CONTINUE_SEARCH: int32 = 0i32; - /// Execute the __except block (frame-based SEH only). - pub const EXCEPTION_EXECUTE_HANDLER: int32 = 1i32; - - /// ExceptionFlags value when this is a non-continuable exception. - pub const EXCEPTION_NONCONTINUABLE: uint32 = 0x00000001u32; - /// ExceptionFlags value when unwinding is in progress. - pub const EXCEPTION_UNWINDING: uint32 = 0x00000002u32; - - - // ── EXCEPTION_RECORD — describes a thrown exception ─────────────────────── - - /// Describes a single exception. The ExceptionRecord field may chain to - /// a nested exception (e.g. an exception that occurred while handling another). - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/ns-winnt-exception_record + pub const EXCEPTION_ACCESS_VIOLATION: uint32 = 0xC0000005u32; + pub const EXCEPTION_ARRAY_BOUNDS_EXCEEDED: uint32 = 0xC000008Cu32; + pub const EXCEPTION_BREAKPOINT: uint32 = 0x80000003u32; + pub const EXCEPTION_DATATYPE_MISALIGNMENT: uint32 = 0x80000002u32; + pub const EXCEPTION_FLT_DENORMAL_OPERAND: uint32 = 0xC000008Du32; + pub const EXCEPTION_FLT_DIVIDE_BY_ZERO: uint32 = 0xC000008Eu32; + pub const EXCEPTION_FLT_INEXACT_RESULT: uint32 = 0xC000008Fu32; + pub const EXCEPTION_FLT_INVALID_OPERATION: uint32 = 0xC0000090u32; + pub const EXCEPTION_FLT_OVERFLOW: uint32 = 0xC0000091u32; + pub const EXCEPTION_FLT_STACK_CHECK: uint32 = 0xC0000092u32; + pub const EXCEPTION_FLT_UNDERFLOW: uint32 = 0xC0000093u32; + pub const EXCEPTION_ILLEGAL_INSTRUCTION: uint32 = 0xC000001Du32; + pub const EXCEPTION_IN_PAGE_ERROR: uint32 = 0xC0000006u32; + pub const EXCEPTION_INT_DIVIDE_BY_ZERO: uint32 = 0xC0000094u32; + pub const EXCEPTION_INT_OVERFLOW: uint32 = 0xC0000095u32; + pub const EXCEPTION_INVALID_DISPOSITION: uint32 = 0xC0000026u32; + pub const EXCEPTION_NONCONTINUABLE_EXCEPTION: uint32 = 0xC0000025u32; + pub const EXCEPTION_PRIV_INSTRUCTION: uint32 = 0xC0000096u32; + pub const EXCEPTION_SINGLE_STEP: uint32 = 0x80000004u32; + pub const EXCEPTION_STACK_OVERFLOW: uint32 = 0xC00000FDu32; + pub const EXCEPTION_GUARD_PAGE: uint32 = 0x80000001u32; + pub const EXCEPTION_INVALID_HANDLE: uint32 = 0xC0000008u32; + pub const EXCEPTION_POSSIBLE_DEADLOCK: uint32 = 0xC0000194u32; + pub const DBG_EXCEPTION_NOT_HANDLED: uint32 = 0x80010001u32; + pub const STATUS_HEAP_CORRUPTION: uint32 = 0xC0000374u32; + pub const STATUS_STACK_BUFFER_OVERRUN: uint32 = 0xC0000409u32; + + // ── Exception flags ─────────────────────────────────────────────────────── + + pub const EXCEPTION_NONCONTINUABLE: uint32 = 0x00000001u32; + pub const EXCEPTION_UNWINDING: uint32 = 0x00000002u32; + pub const EXCEPTION_EXIT_UNWIND: uint32 = 0x00000004u32; + pub const EXCEPTION_STACK_INVALID: uint32 = 0x00000008u32; + pub const EXCEPTION_NESTED_CALL: uint32 = 0x00000010u32; + pub const EXCEPTION_TARGET_UNWIND: uint32 = 0x00000020u32; + pub const EXCEPTION_COLLIDED_UNWIND: uint32 = 0x00000040u32; + pub const EXCEPTION_UNWIND: uint32 = 0x00000066u32; + + pub const EXCEPTION_MAXIMUM_PARAMETERS: uint32 = 15u32; + + // ── Context flags ───────────────────────────────────────────────────────── + + pub const CONTEXT_AMD64: uint32 = 0x00100000u32; + pub const CONTEXT_CONTROL: uint32 = 0x00100001u32; + pub const CONTEXT_INTEGER: uint32 = 0x00100002u32; + pub const CONTEXT_SEGMENTS: uint32 = 0x00100004u32; + pub const CONTEXT_FLOATING_POINT: uint32 = 0x00100008u32; + pub const CONTEXT_DEBUG_REGISTERS: uint32 = 0x00100010u32; + pub const CONTEXT_FULL: uint32 = 0x00100007u32; + pub const CONTEXT_ALL: uint32 = 0x0010003Fu32; + + pub const CONTEXT_ARM64: uint32 = 0x00400000u32; + pub const CONTEXT_ARM64_CONTROL: uint32 = 0x00400001u32; + pub const CONTEXT_ARM64_INTEGER: uint32 = 0x00400002u32; + pub const CONTEXT_ARM64_FLOATING_POINT: uint32 = 0x00400004u32; + pub const CONTEXT_ARM64_DEBUG: uint32 = 0x00400008u32; + pub const CONTEXT_ARM64_FULL: uint32 = 0x00400007u32; + + // ── Structures ──────────────────────────────────────────────────────────── + pub struct ExceptionRecord { - /// Exception code (EXCEPTION_ACCESS_VIOLATION, etc.) pub exceptionCode: uint32; - /// EXCEPTION_NONCONTINUABLE or EXCEPTION_UNWINDING. pub exceptionFlags: uint32; - /// Pointer to a nested ExceptionRecord, or null. - pub exceptionRecord: *opaque; - /// Address where the exception occurred. + pub exceptionRecord: *opaque; // pointer to nested ExceptionRecord pub exceptionAddress: *opaque; - /// Number of entries in exceptionInformation (0–15). pub numberParameters: uint32; - /// Extra info: for ACCESS_VIOLATION, [0] = 0 (read) or 1 (write), - /// [1] = faulting address. - pub exceptionInformation0: uint; - pub exceptionInformation1: uint; - pub exceptionInformation2: uint; - pub exceptionInformation3: uint; - pub exceptionInformation4: uint; - pub exceptionInformation5: uint; - pub exceptionInformation6: uint; - pub exceptionInformation7: uint; - pub exceptionInformation8: uint; - pub exceptionInformation9: uint; - pub exceptionInformationA: uint; - pub exceptionInformationB: uint; - pub exceptionInformationC: uint; - pub exceptionInformationD: uint; - pub exceptionInformationE: uint; + pub _pad: uint32; + pub exceptionInformation: uint[15]; } - /// EXCEPTION_POINTERS — passed to a VEH or UnhandledExceptionFilter. - /// Contains both the exception record and the CPU context at fault time. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/ns-winnt-exception_pointers pub struct ExceptionPointers { - /// The exception that was raised. - pub exceptionRecord: *ExceptionRecord; - /// The CPU register state at the point of the exception. - /// On x64 this is a CONTEXT structure (1232 bytes). Cast to *opaque - /// and pass to RtlCaptureContext / GetThreadContext as needed. - pub contextRecord: *opaque; + pub exceptionRecord: *ExceptionRecord; + pub contextRecord: *opaque; // CONTEXT — arch-specific } + /// M128A — 16-byte aligned XMM/SIMD register. + pub struct M128A { + pub low: uint64; + pub high: int64; + } - // ── Vectored Exception / Continue Handlers ──────────────────────────────── - // - // VEH handlers are called system-wide before frame-based SEH. - // VCH handlers are called after frame-based SEH, as a last resort. - // - // Handler signature (implement as a Rux func with this type): - // func MyHandler(info: *ExceptionPointers) -> int32 - // Return EXCEPTION_CONTINUE_EXECUTION to resume, EXCEPTION_CONTINUE_SEARCH - // to pass to the next handler. + /// x64 CONTEXT structure (layout matches WinNT.h for AMD64). + pub struct ContextAmd64 { + pub p1Home: uint64; + pub p2Home: uint64; + pub p3Home: uint64; + pub p4Home: uint64; + pub p5Home: uint64; + pub p6Home: uint64; + pub contextFlags: uint32; + pub mxCsr: uint32; + pub segCs: uint16; + pub segDs: uint16; + pub segEs: uint16; + pub segFs: uint16; + pub segGs: uint16; + pub segSs: uint16; + pub eFlags: uint32; + pub _pad1: uint32; + pub dr0: uint64; + pub dr1: uint64; + pub dr2: uint64; + pub dr3: uint64; + pub dr6: uint64; + pub dr7: uint64; + pub rax: uint64; + pub rcx: uint64; + pub rdx: uint64; + pub rbx: uint64; + pub rsp: uint64; + pub rbp: uint64; + pub rsi: uint64; + pub rdi: uint64; + pub r8: uint64; + pub r9: uint64; + pub r10: uint64; + pub r11: uint64; + pub r12: uint64; + pub r13: uint64; + pub r14: uint64; + pub r15: uint64; + pub rip: uint64; + pub xmmRegisters: M128A[16]; + pub vectorRegister: M128A[26]; + pub vectorControl: uint64; + pub debugControl: uint64; + pub lastBranchToRip: uint64; + pub lastBranchFromRip: uint64; + pub lastExceptionToRip: uint64; + pub lastExceptionFromRip: uint64; + } + /// ARM64 CONTEXT structure. + pub struct ContextArm64 { + pub contextFlags: uint32; + pub cpsr: uint32; + pub x: uint64[29]; // X0–X28 + pub fp: uint64; // X29 frame pointer + pub lr: uint64; // X30 link register + pub sp: uint64; + pub pc: uint64; + pub v: M128A[32]; // NEON/FP registers + pub fpcr: uint32; + pub fpsr: uint32; + pub bcr: uint32[8]; + pub bvr: uint64[8]; + pub wcr: uint32[2]; + pub wvr: uint64[2]; + } + + // ── Extern — kernel32.dll / ntdll.dll ──────────────────────────────────── + @[Target("Windows")] @[Import(lib: "kernel32.dll")] extern { - /// Registers a vectored exception handler. - /// - /// # Parameters - /// - `first` — non-zero to add at front of VEH list (called first), - /// zero to add at back (called last) - /// - `handler` — pointer to your handler function - /// - /// Returns an opaque handle; pass to RemoveVectoredExceptionHandler to unregister. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-addvectoredexceptionhandler - func AddVectoredExceptionHandler( - first: uint32, - handler: *const opaque - ) -> *opaque; - - /// Removes a previously registered VEH. - /// Returns non-zero on success. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-removevectoredexceptionhandler - func RemoveVectoredExceptionHandler(handler: *opaque) -> uint32; - - /// Registers a vectored continue handler (called after SEH, before unhandled crash). - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-addvectoredcontinuehandler - func AddVectoredContinueHandler( - first: uint32, - handler: *const opaque - ) -> *opaque; - - /// Removes a previously registered VCH. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-removevectoredcontinuehandler - func RemoveVectoredContinueHandler(handler: *opaque) -> uint32; - - /// Sets the unhandled exception filter — called as the last resort - /// before the process crashes and Windows shows the error dialog. - /// Return EXCEPTION_EXECUTE_HANDLER to suppress the crash dialog, - /// EXCEPTION_CONTINUE_SEARCH to let Windows handle it. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-setunhandledexceptionfilter - func SetUnhandledExceptionFilter( - topLevelExceptionFilter: *const opaque - ) -> *const opaque; + /// Installs an unhandled exception filter. + /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setunhandledexceptionfilter + func SetUnhandledExceptionFilter(topLevelExceptionFilter: *const opaque) -> *opaque; /// Raises an exception in the calling thread. - /// Does not return if the exception is non-continuable. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-raiseexception + /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-raiseexception func RaiseException( - exceptionCode: uint32, - exceptionFlags: uint32, - numberOfArguments: uint32, - arguments: *const uint + exceptionCode: uint32, + exceptionFlags: uint32, + nArgs: uint32, + arguments: *const uint ); - /// Returns the error code set by the last failing Win32 API call - /// in the calling thread. Equivalent to errno on POSIX. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror - func GetLastError() -> uint32; - - /// Sets the last-error code for the calling thread. - /// Useful when writing a function that must preserve the last error. - /// - /// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror - func SetLastError(errCode: uint32); - } - + /// Retrieves the CONTEXT record for the current thread. + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext + func GetThreadContext(hThread: *opaque, ctx: *opaque) -> bool32; - // ── Low-level unwinding ─────────────────────────────────────────────────── + /// Sets the CONTEXT record for the current thread. + /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadcontext + func SetThreadContext(hThread: *opaque, ctx: *const opaque) -> bool32; + } + @[Target("Windows")] @[Import(lib: "ntdll.dll")] extern { - /// Captures the current CPU register state into a CONTEXT block. - /// The CONTEXT must be 16-byte aligned. On x64, CONTEXT is 1232 bytes. - /// Pass a *opaque pointing to a suitably aligned, suitably sized buffer. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/nf-winnt-rtlcapturecontext - func RtlCaptureContext(contextRecord: *opaque); - - /// Initiates an unwind through the call stack, calling __finally blocks. - /// Used internally by the C runtime for exception propagation. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/nf-winnt-rtlunwind + /// Registers a vectored exception handler. + /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-addvectoredexceptionhandler + func RtlAddVectoredExceptionHandler(first: uint32, handler: *const opaque) -> *opaque; + + /// Removes a previously registered vectored exception handler. + /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-removevectoredexceptionhandler + func RtlRemoveVectoredExceptionHandler(handle: *opaque) -> uint32; + + /// Registers a vectored continue handler. + /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-addvectoredcontinuehandler + func RtlAddVectoredContinueHandler(first: uint32, handler: *const opaque) -> *opaque; + + /// Removes a vectored continue handler. + func RtlRemoveVectoredContinueHandler(handle: *opaque) -> uint32; + + /// Captures the current thread's context (NT native version). + func RtlCaptureContext(ctx: *opaque); + + /// Unwinds the call stack for SEH. func RtlUnwind( - targetFrame: *opaque, - targetIp: *opaque, - exceptionRecord: *ExceptionRecord, - returnValue: *opaque + targetFrame: *opaque, + targetIp: *opaque, + exceptionRecord: *opaque, + returnValue: *opaque ); - /// x64 version of RtlUnwind — required on AMD64. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/nf-winnt-rtlunwindex + /// x64/ARM64 unwind (includes the CONTEXT). func RtlUnwindEx( - targetFrame: *opaque, - targetIp: *opaque, - exceptionRecord: *ExceptionRecord, - returnValue: *opaque, - contextRecord: *opaque, - historyTable: *opaque + targetFrame: *opaque, + targetIp: *opaque, + exceptionRecord: *opaque, + returnValue: *opaque, + contextRecord: *opaque, + historyTable: *opaque ); - /// Walks the exception handler table to find the handler for a given PC. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry + /// Looks up the RUNTIME_FUNCTION entry for an instruction address. + /// https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry func RtlLookupFunctionEntry( - controlPc: uint, - imageBase: *uint, - historyTable: *opaque + controlPc: uint64, + imageBase: *uint64, + historytable: *opaque ) -> *opaque; - /// Maps a program counter value back to the module that contains it. - /// - /// https://learn.microsoft.com/windows/win32/api/winnt/nf-winnt-rtlpctofileheader - func RtlPcToFileHeader( - pcValue: *opaque, - baseOfImage: **opaque + /// Virtualises unwinding (used for non-standard frame layouts). + func RtlVirtualUnwind( + handlerType: uint32, + imageBase: uint64, + controlPc: uint64, + functionEntry: *opaque, + contextRecord: *opaque, + handlerData: *opaque, + establisherFrame: *uint64, + contextPointers: *opaque ) -> *opaque; - } + /// Raises an NT status exception. + func RtlRaiseStatus(status: uint32); + } - // ── Debug / crash helpers ───────────────────────────────────────────────── + // ── Re-exports via kernel32.dll (AddVectoredExceptionHandler) ──────────── + // kernel32 forwards to ntdll; expose the friendly names under the Win32 ABI. + @[Target("Windows")] @[Import(lib: "kernel32.dll")] extern { - /// Sends a string to the debugger (visible in debugger output windows). - /// Safe to call from any context; silently ignored if no debugger attached. - /// - /// https://learn.microsoft.com/windows/win32/api/debugapi/nf-debugapi-outputdebugstringa - func OutputDebugStringA(outputString: *const char8); - - /// Returns true if a user-mode debugger is attached to the current process. - /// - /// https://learn.microsoft.com/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent - func IsDebuggerPresent() -> bool32; - - /// Causes a breakpoint exception (INT 3) in the current process. - /// Use inside VEH handlers or when you want to break into the debugger. - /// - /// https://learn.microsoft.com/windows/win32/api/debugapi/nf-debugapi-debugbreak - func DebugBreak(); - - /// Raises EXCEPTION_BREAKPOINT in the target process. - /// - /// https://learn.microsoft.com/windows/win32/api/debugapi/nf-debugapi-debugbreakprocess - func DebugBreakProcess(process: *opaque) -> bool32; - - /// Writes a minidump (crash dump) to a file — requires DbgHelp.dll. - /// See DbgHelp.rux for MiniDumpWriteDump. + func AddVectoredExceptionHandler(first: uint32, handler: *const opaque) -> *opaque; + func RemoveVectoredExceptionHandler(handle: *opaque) -> uint32; + func AddVectoredContinueHandler(first: uint32, handler: *const opaque) -> *opaque; + func RemoveVectoredContinueHandler(handle: *opaque) -> uint32; + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + /// Returns true when an NTSTATUS / exception code indicates a fatal condition + /// (high two bits = 11, i.e. severity = error). + pub func IsErrorStatus(code: uint32) -> bool { + return (code >> 30u32) == 3u32; } + /// Returns true when an NTSTATUS is a warning (high two bits = 10). + pub func IsWarningStatus(code: uint32) -> bool { + return (code >> 30u32) == 2u32; + } + + /// Returns true when an NTSTATUS is informational (high two bits = 01). + pub func IsInfoStatus(code: uint32) -> bool { + return (code >> 30u32) == 1u32; + } - // ── Convenience wrapper ─────────────────────────────────────────────────── - - /// Installs a process-wide crash guard that calls `handler` for every - /// exception before the process crashes. Returns the VEH handle. - /// - /// # Example - /// func MyCrashHandler(info: *ExceptionPointers) -> int32 { - /// OutputDebugStringA("crash!\n\0"); - /// return EXCEPTION_CONTINUE_SEARCH; // let it crash normally - /// } - /// let guard = InstallCrashGuard(&MyCrashHandler as *const opaque); - /// // later: - /// RemoveVectoredExceptionHandler(guard); - pub func InstallCrashGuard(handler: *const opaque) -> *opaque { - return AddVectoredExceptionHandler(1u32, handler); + /// Returns true when an NTSTATUS indicates success (high two bits = 00). + pub func IsSuccessStatus(code: uint32) -> bool { + return (code >> 30u32) == 0u32; } } diff --git a/Src/Shell32.rux b/Src/Shell32.rux new file mode 100644 index 0000000..e070728 --- /dev/null +++ b/Src/Shell32.rux @@ -0,0 +1,325 @@ +/* + Windows API — Shell32.dll (Windows Shell) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + New file — was entirely absent from the dev branch. + Covers shell execution, file operations, known folders, system tray, + drag-and-drop, and shell notification. + + References: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ +*/ + +module Windows { + + // ── ShellExecute / ShellExecuteEx ───────────────────────────────────────── + + pub const SW_SHOWNORMAL_SHELL: int32 = 1i32; // alias for clarity in shell context + pub const SE_ERR_FNF: uint32 = 2u32; + pub const SE_ERR_PNF: uint32 = 3u32; + pub const SE_ERR_ACCESSDENIED: uint32 = 5u32; + pub const SE_ERR_OOM: uint32 = 8u32; + pub const SE_ERR_DLLNOTFOUND: uint32 = 32u32; + pub const SE_ERR_SHARE: uint32 = 26u32; + + // ── SHFileOperation wFunc ───────────────────────────────────────────────── + + pub const FO_MOVE: uint32 = 0x0001u32; + pub const FO_COPY: uint32 = 0x0002u32; + pub const FO_DELETE: uint32 = 0x0003u32; + pub const FO_RENAME: uint32 = 0x0004u32; + + // ── SHFileOperation fFlags ──────────────────────────────────────────────── + + pub const FOF_MULTIDESTFILES: uint16 = 0x0001u16; + pub const FOF_CONFIRMMOUSE: uint16 = 0x0002u16; + pub const FOF_SILENT: uint16 = 0x0004u16; + pub const FOF_RENAMEONCOLLISION: uint16 = 0x0008u16; + pub const FOF_NOCONFIRMATION: uint16 = 0x0010u16; + pub const FOF_WANTMAPPINGHANDLE: uint16 = 0x0020u16; + pub const FOF_ALLOWUNDO: uint16 = 0x0040u16; + pub const FOF_FILESONLY: uint16 = 0x0080u16; + pub const FOF_SIMPLEPROGRESS: uint16 = 0x0100u16; + pub const FOF_NOCONFIRMMKDIR: uint16 = 0x0200u16; + pub const FOF_NOERRORUI: uint16 = 0x0400u16; + pub const FOF_NOCOPYSECURITYATTRIBS: uint16 = 0x0800u16; + pub const FOF_NORECURSION: uint16 = 0x1000u16; + pub const FOF_NO_CONNECTED_ELEMENTS: uint16 = 0x2000u16; + pub const FOF_WANTNUKEWARNING: uint16 = 0x4000u16; + pub const FOF_NO_UI: uint16 = 0x0614u16; // SILENT|NOCONFIRMATION|NOERRORUI|NOCONFIRMMKDIR + + // ── SHGetKnownFolderPath (KNOWNFOLDERID GUIDs as byte arrays) ───────────── + // + // Callers must pass a pointer to the raw GUID bytes. + // Common GUIDs listed here as uint8[16] constants for convenience. + // + // FOLDERID_Desktop = {B4BFCC3A-DB2C-424C-B029-7FE99A87C641} + // FOLDERID_Documents = {FDD39AD0-238F-46AF-ADB4-6C85480369C7} + // FOLDERID_Downloads = {374DE290-123F-4565-9164-39C4925E467B} + // FOLDERID_LocalAppData = {F1B32785-6FBA-4FCF-9D55-7B8E7F157091} + // FOLDERID_RoamingAppData = {3EB685DB-65F9-4CF6-A03A-E3EF65729F3D} + // FOLDERID_ProgramFiles = {905E63B6-C1BF-494E-B29C-65B732D3D21A} + // FOLDERID_Windows = {F38BF404-1D43-42F2-9305-67DE0B28FC23} + // FOLDERID_System = {1AC14E77-02E7-4E5D-B744-2EB1AE5198B7} + // FOLDERID_Temp = {92C4DCD1-5195-4BCE-A3C4-4EB2B90BF7CC} + // + // These are too large for scalar constants; callers should define them + // as local byte arrays or use the SHGetSpecialFolderPathA fallback below. + + // ── CSIDL legacy constants (for SHGetSpecialFolderPathA) ────────────────── + + pub const CSIDL_DESKTOP: int32 = 0x0000i32; + pub const CSIDL_PROGRAMS: int32 = 0x0002i32; + pub const CSIDL_PERSONAL: int32 = 0x0005i32; + pub const CSIDL_FAVORITES: int32 = 0x0006i32; + pub const CSIDL_STARTUP: int32 = 0x0007i32; + pub const CSIDL_RECENT: int32 = 0x0008i32; + pub const CSIDL_SENDTO: int32 = 0x0009i32; + pub const CSIDL_STARTMENU: int32 = 0x000Bu32 as int32; + pub const CSIDL_DESKTOPDIRECTORY: int32 = 0x0010i32; + pub const CSIDL_DRIVES: int32 = 0x0011i32; + pub const CSIDL_NETWORK: int32 = 0x0012i32; + pub const CSIDL_TEMPLATES: int32 = 0x0015i32; + pub const CSIDL_APPDATA: int32 = 0x001Ai32; + pub const CSIDL_LOCAL_APPDATA: int32 = 0x001Ci32; + pub const CSIDL_WINDOWS: int32 = 0x0024i32; + pub const CSIDL_SYSTEM: int32 = 0x0025i32; + pub const CSIDL_PROGRAM_FILES: int32 = 0x0026i32; + pub const CSIDL_MYPICTURES: int32 = 0x0027i32; + pub const CSIDL_PROFILE: int32 = 0x0028i32; + pub const CSIDL_COMMON_PROGRAMS: int32 = 0x0017i32; + pub const CSIDL_COMMON_STARTMENU: int32 = 0x0016i32; + pub const CSIDL_COMMON_APPDATA: int32 = 0x0023i32; + pub const CSIDL_FLAG_CREATE: int32 = 0x8000i32; + + // ── SHGetKnownFolderPath flags ──────────────────────────────────────────── + + pub const KF_FLAG_DEFAULT: uint32 = 0x00000000u32; + pub const KF_FLAG_FORCE_APP_DATA_REDIRECTION: uint32 = 0x00080000u32; + pub const KF_FLAG_RETURN_FILTER_REDIRECTION_TARGET: uint32 = 0x00040000u32; + pub const KF_FLAG_FORCE_PACKAGE_REDIRECTION: uint32 = 0x00020000u32; + pub const KF_FLAG_NO_PACKAGE_REDIRECTION: uint32 = 0x00010000u32; + pub const KF_FLAG_FORCE_APPCONTAINER_REDIRECTION: uint32 = 0x00020000u32; + pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION: uint32 = 0x00010000u32; + pub const KF_FLAG_CREATE: uint32 = 0x00008000u32; + pub const KF_FLAG_DONT_VERIFY: uint32 = 0x00004000u32; + pub const KF_FLAG_DONT_UNEXPAND: uint32 = 0x00002000u32; + pub const KF_FLAG_NO_ALIAS: uint32 = 0x00001000u32; + pub const KF_FLAG_INIT: uint32 = 0x00000800u32; + pub const KF_FLAG_DEFAULT_PATH: uint32 = 0x00000400u32; + pub const KF_FLAG_NOT_PARENT_RELATIVE: uint32 = 0x00000200u32; + pub const KF_FLAG_SIMPLE_IDLIST: uint32 = 0x00000100u32; + pub const KF_FLAG_ALIAS_ONLY: uint32 = 0x80000000u32; + + // ── Tray icon messages ──────────────────────────────────────────────────── + + pub const NIM_ADD: uint32 = 0x00000000u32; + pub const NIM_MODIFY: uint32 = 0x00000001u32; + pub const NIM_DELETE: uint32 = 0x00000002u32; + pub const NIM_SETFOCUS: uint32 = 0x00000003u32; + pub const NIM_SETVERSION: uint32 = 0x00000004u32; + + pub const NIF_MESSAGE: uint32 = 0x00000001u32; + pub const NIF_ICON: uint32 = 0x00000002u32; + pub const NIF_TIP: uint32 = 0x00000004u32; + pub const NIF_STATE: uint32 = 0x00000008u32; + pub const NIF_INFO: uint32 = 0x00000010u32; + pub const NIF_GUID: uint32 = 0x00000020u32; + pub const NIF_REALTIME: uint32 = 0x00000040u32; + pub const NIF_SHOWTIP: uint32 = 0x00000080u32; + + pub const NIIF_NONE: uint32 = 0x00000000u32; + pub const NIIF_INFO: uint32 = 0x00000001u32; + pub const NIIF_WARNING: uint32 = 0x00000002u32; + pub const NIIF_ERROR: uint32 = 0x00000003u32; + pub const NIIF_NOSOUND: uint32 = 0x00000010u32; + pub const NIIF_LARGE_ICON: uint32 = 0x00000020u32; + + pub const NOTIFYICON_VERSION: uint32 = 3u32; + pub const NOTIFYICON_VERSION_4: uint32 = 4u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct ShFileOpStructA { + pub hwnd: *opaque; + pub wFunc: uint32; + pub _pad1: uint32; + pub pFrom: *const char8; + pub pTo: *const char8; + pub fFlags: uint16; + pub fAnyOperationsAborted: bool32; + pub _pad2: uint16; + pub hNameMappings: *opaque; + pub lpszProgressTitle: *const char8; + } + + pub struct ShellExecuteInfoA { + pub cbSize: uint32; + pub fMask: uint32; + pub hwnd: *opaque; + pub lpVerb: *const char8; + pub lpFile: *const char8; + pub lpParameters: *const char8; + pub lpDirectory: *const char8; + pub nShow: int32; + pub _pad: uint32; + pub hInstApp: *opaque; + pub lpIDList: *opaque; + pub lpClass: *const char8; + pub hkeyClass: uint; + pub dwHotKey: uint32; + pub _pad2: uint32; + pub hIcon: *opaque; + pub hProcess: *opaque; + } + + pub struct NotifyIconDataA { + pub cbSize: uint32; + pub _pad: uint32; + pub hWnd: *opaque; + pub uID: uint32; + pub uFlags: uint32; + pub uCallbackMessage: uint32; + pub _pad2: uint32; + pub hIcon: *opaque; + pub szTip: char8[128]; + pub dwState: uint32; + pub dwStateMask: uint32; + pub szInfo: char8[256]; + pub uTimeoutOrVersion: uint32; + pub szInfoTitle: char8[64]; + pub dwInfoFlags: uint32; + pub guidItem: uint8[16]; + pub hBalloonIcon: *opaque; + } + + // ── Extern — shell32.dll ────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "shell32.dll")] + extern { + + // Execution + /// Opens a file or application via the shell. + /// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea + func ShellExecuteA( + hwnd: *opaque, + lpOp: *const char8, + lpFile: *const char8, + lpParams: *const char8, + lpDir: *const char8, + nShowCmd: int32 + ) -> uint; + + /// Extended ShellExecute with full control. + /// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa + func ShellExecuteExA(pExecInfo: *ShellExecuteInfoA) -> bool32; + + // File operations + /// Performs file system operations (copy, move, delete, rename). + /// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa + func SHFileOperationA(lpFileOp: *ShFileOpStructA) -> int32; + + // Known folders / CSIDL + /// Legacy: retrieves the path of a CSIDL special folder. + /// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetspecialfolderpatha + func SHGetSpecialFolderPathA( + hwnd: *opaque, + pszPath: *char8, + csidl: int32, + fCreate: bool32 + ) -> bool32; + + /// Modern: retrieves the full path for a known folder by GUID. + /// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath + func SHGetKnownFolderPath( + rfid: *const uint8, // pointer to KNOWNFOLDERID (16-byte GUID) + dwFlags: uint32, + hToken: *opaque, + ppszPath: **char16 + ) -> int32; + + // ITEMIDLIST + func SHGetDesktopFolder(ppshf: *opaque) -> int32; + func SHParseDisplayName( + pszName: *const char16, + pbc: *opaque, + ppidl: *opaque, + sfgaoIn: uint32, + psfgaoOut: *uint32 + ) -> int32; + func ILFree(pidl: *opaque); + + // System tray + func Shell_NotifyIconA(dwMessage: uint32, lpData: *NotifyIconDataA) -> bool32; + func Shell_NotifyIconW(dwMessage: uint32, lpData: *opaque) -> bool32; + + // File info + func SHGetFileInfoA( + pszPath: *const char8, + dwFileAttributes: uint32, + psfi: *opaque, + cbFileInfo: uint32, + uFlags: uint32 + ) -> uint; + + // Environment + func SHGetPathFromIDListA(pidl: *opaque, pszPath: *char8) -> bool32; + + // App user model ID + func SetCurrentProcessExplicitAppUserModelID(appID: *const char16) -> int32; + func GetCurrentProcessExplicitAppUserModelID(appID: **char16) -> int32; + + // Progress / task bar + func SHCreateItemFromParsingName( + pszPath: *const char16, + pbc: *opaque, + riid: *const uint8, + ppv: *opaque + ) -> int32; + + // Misc + func SHCreateDirectoryExA(hwnd: *opaque, pszPath: *const char8, psa: *opaque) -> int32; + func SHCreateDirectoryExW(hwnd: *opaque, pszPath: *const char16, psa: *opaque) -> int32; + func SHDeleteKeyA(hKey: uint, subKey: *const char8) -> uint32; + func ShellAboutA(hWnd: *opaque, szApp: *const char8, szOtherStuff: *const char8, hIcon: *opaque) -> int32; + func ExtractIconA(hInst: *opaque, lpszExeFileName: *const char8, nIconIndex: uint32) -> *opaque; + func FindExecutableA(lpFile: *const char8, lpDirectory: *const char8, lpResult: *char8) -> uint; + func SHQueryRecycleBinA(pszRootPath: *const char8, pSHQueryRBInfo: *opaque) -> int32; + func SHEmptyRecycleBinA(hwnd: *opaque, pszRootPath: *const char8, dwFlags: uint32) -> int32; + + func CoTaskMemFree(pv: *opaque); // needed to free SHGetKnownFolderPath result + } + + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Opens a file with the default associated application. + pub func OpenWithShell(filePath: *const char8) -> bool32 { + let result = ShellExecuteA(null, c"open", filePath, null, null, SW_SHOWNORMAL_SHELL); + return result as uint > 32u; + } + + /// Runs a command as administrator (UAC elevation prompt). + pub func RunAsAdmin(exePath: *const char8, params: *const char8) -> bool32 { + var info: ShellExecuteInfoA; + RtlZeroMemory(&info as *opaque, 112u); // sizeof(ShellExecuteInfoA) + info.cbSize = 112u32; + info.fMask = 0x00000040u32; // SEE_MASK_NOCLOSEPROCESS + info.lpVerb = c"runas"; + info.lpFile = exePath; + info.lpParameters = params; + info.nShow = SW_SHOWNORMAL_SHELL; + return ShellExecuteExA(&info); + } + + /// Returns the LocalAppData path (e.g. C:\Users\User\AppData\Local). + pub func GetLocalAppDataPath(out: *char8, maxLen: uint32) -> bool32 { + return SHGetSpecialFolderPathA(null, out, CSIDL_LOCAL_APPDATA, false); + } + + /// Returns the current user's Documents path. + pub func GetDocumentsPath(out: *char8, maxLen: uint32) -> bool32 { + return SHGetSpecialFolderPathA(null, out, CSIDL_PERSONAL, false); + } + +} diff --git a/Src/User32.rux b/Src/User32.rux index 33bde01..f79f929 100644 --- a/Src/User32.rux +++ b/Src/User32.rux @@ -1,659 +1,525 @@ -/* - Windows API — User32.dll (Window Management, Dialogs, Input, Messaging) - Copyright © 2026 Rux Contributors - Licensed under the MIT License +/* + Windows API — User32.dll (Window Management, Messages, Input, Menus) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • WNDCLASSEXA: cbWndExtra / cbClsExtra byte-order fixed. + • PostQuitMessage / DispatchMessageA / TranslateMessage were missing. + • HWND_TOPMOST etc. are now correct negative-cast values. + • ShowWindow nCmdShow constants added (SW_HIDE, SW_SHOW, etc.). + • Added DPI-awareness, touch input, raw input, multi-monitor APIs. + • Corrected POINT / RECT structs — were using wrong field order in some places. + + References: https://learn.microsoft.com/en-us/windows/win32/api/winuser/ */ - -module Windows { - - - // Constants — MessageBox type flags - - - pub const MB_OK: uint32 = 0x00000000u32; - pub const MB_OKCANCEL: uint32 = 0x00000001u32; - pub const MB_YESNO: uint32 = 0x00000004u32; - pub const MB_YESNOCANCEL: uint32 = 0x00000003u32; - pub const MB_RETRYCANCEL: uint32 = 0x00000005u32; - pub const MB_ICONERROR: uint32 = 0x00000010u32; - pub const MB_ICONQUESTION: uint32 = 0x00000020u32; - pub const MB_ICONWARNING: uint32 = 0x00000030u32; - pub const MB_ICONINFORMATION: uint32 = 0x00000040u32; - - pub const IDOK: int32 = 1i32; - pub const IDCANCEL: int32 = 2i32; - pub const IDYES: int32 = 6i32; - pub const IDNO: int32 = 7i32; - - - // Constants — Window Styles (WS_*) - - - pub const WS_BORDER: uint32 = 0x00800000u32; - pub const WS_CAPTION: uint32 = 0x00C00000u32; - pub const WS_CHILD: uint32 = 0x40000000u32; - pub const WS_CHILDWINDOW: uint32 = 0x40000000u32; - pub const WS_CLIPCHILDREN: uint32 = 0x02000000u32; - pub const WS_CLIPSIBLINGS: uint32 = 0x04000000u32; - pub const WS_DISABLED: uint32 = 0x08000000u32; - pub const WS_DLGFRAME: uint32 = 0x00400000u32; - pub const WS_GROUP: uint32 = 0x00020000u32; - pub const WS_HSCROLL: uint32 = 0x00100000u32; - pub const WS_MAXIMIZE: uint32 = 0x01000000u32; - pub const WS_MAXIMIZEBOX: uint32 = 0x00010000u32; - pub const WS_MINIMIZE: uint32 = 0x20000000u32; - pub const WS_MINIMIZEBOX: uint32 = 0x00020000u32; - pub const WS_OVERLAPPED: uint32 = 0x00000000u32; - pub const WS_OVERLAPPEDWINDOW: uint32 = 0x00CF0000u32; - pub const WS_POPUP: uint32 = 0x80000000u32; - pub const WS_POPUPWINDOW: uint32 = 0x80880000u32; - pub const WS_SIZEFRAME: uint32 = 0x00040000u32; - pub const WS_SYSMENU: uint32 = 0x00080000u32; - pub const WS_TABSTOP: uint32 = 0x00010000u32; - pub const WS_VISIBLE: uint32 = 0x10000000u32; - pub const WS_VSCROLL: uint32 = 0x00200000u32; - - pub const WS_EX_ACCEPTFILES: uint32 = 0x00000010u32; - pub const WS_EX_APPWINDOW: uint32 = 0x00040000u32; - pub const WS_EX_CLIENTEDGE: uint32 = 0x00000200u32; - pub const WS_EX_COMPOSITED: uint32 = 0x02000000u32; - pub const WS_EX_CONTEXTHELP: uint32 = 0x00000400u32; - pub const WS_EX_DLGMODALFRAME: uint32 = 0x00000001u32; - pub const WS_EX_LAYERED: uint32 = 0x00080000u32; - pub const WS_EX_LAYOUTRTL: uint32 = 0x00400000u32; - pub const WS_EX_LEFTSCROLLBAR: uint32 = 0x00004000u32; - pub const WS_EX_MDICHILD: uint32 = 0x00000040u32; - pub const WS_EX_NOACTIVATE: uint32 = 0x08000000u32; - pub const WS_EX_NOINHERITLAYOUT: uint32 = 0x00100000u32; - pub const WS_EX_NOPARENTNOTIFY: uint32 = 0x00000004u32; - pub const WS_EX_OVERLAPPEDWINDOW: uint32 = 0x00000300u32; - pub const WS_EX_PALETTEWINDOW: uint32 = 0x00000188u32; - pub const WS_EX_RIGHTSCROLLBAR: uint32 = 0x00000000u32; - pub const WS_EX_STATICEDGE: uint32 = 0x00020000u32; - pub const WS_EX_TOOLWINDOW: uint32 = 0x00000080u32; - pub const WS_EX_TOPMOST: uint32 = 0x00000008u32; - pub const WS_EX_TRANSPARENT: uint32 = 0x00000020u32; - pub const WS_EX_WINDOWEDGE: uint32 = 0x00000100u32; - - - // Constants — SetWindowPos flags - - - pub const SWP_NOSIZE: uint32 = 0x0001u32; - pub const SWP_NOMOVE: uint32 = 0x0002u32; - pub const SWP_NOZORDER: uint32 = 0x0004u32; - pub const SWP_NOREDRAW: uint32 = 0x0008u32; - pub const SWP_NOACTIVATE: uint32 = 0x0010u32; - pub const SWP_FRAMECHANGED: uint32 = 0x0020u32; - pub const SWP_SHOWWINDOW: uint32 = 0x0040u32; - pub const SWP_HIDEWINDOW: uint32 = 0x0080u32; - pub const SWP_NOCOPYBITS: uint32 = 0x0100u32; - pub const SWP_NOOWNERZORDER: uint32 = 0x0200u32; - pub const SWP_NOSENDCHANGING: uint32 = 0x0400u32; - pub const SWP_DRAWFRAME: uint32 = 0x0020u32; - pub const SWP_NOREPOSITION: uint32 = 0x0200u32; - pub const SWP_DEFERERASE: uint32 = 0x2000u32; - pub const SWP_ASYNCWINDOWPOS: uint32 = 0x4000u32; - - pub const HWND_TOP: *opaque = (0u as uint) as *opaque; - pub const HWND_BOTTOM: *opaque = (1u as uint) as *opaque; - pub const HWND_TOPMOST: *opaque = (0xFFFFFFFFFFFFFFFFu as uint) as *opaque; - pub const HWND_NOTOPMOST: *opaque = (0xFFFFFFFFFFFFFFFEu as uint) as *opaque; - - - // Constants — ShowWindow commands - - - pub const SW_HIDE: int32 = 0i32; - pub const SW_SHOWNORMAL: int32 = 1i32; - pub const SW_SHOWMINIMIZED: int32 = 2i32; - pub const SW_SHOWMAXIMIZED: int32 = 3i32; - pub const SW_SHOWNOACTIVATE: int32 = 4i32; - pub const SW_SHOW: int32 = 5i32; - pub const SW_MINIMIZE: int32 = 6i32; - pub const SW_RESTORE: int32 = 9i32; - pub const SW_FORCEMINIMIZE: int32 = 11i32; - - - // Constants — Windows Messages (common subset) - - - pub const WM_NULL: uint32 = 0x0000u32; - pub const WM_CREATE: uint32 = 0x0001u32; - pub const WM_DESTROY: uint32 = 0x0002u32; - pub const WM_MOVE: uint32 = 0x0003u32; - pub const WM_SIZE: uint32 = 0x0005u32; - pub const WM_ACTIVATE: uint32 = 0x0006u32; - pub const WM_SETFOCUS: uint32 = 0x0007u32; - pub const WM_KILLFOCUS: uint32 = 0x0008u32; - pub const WM_ENABLE: uint32 = 0x000Au32; - pub const WM_SETREDRAW: uint32 = 0x000Bu32; - pub const WM_SETTEXT: uint32 = 0x000Cu32; - pub const WM_GETTEXT: uint32 = 0x000Du32; - pub const WM_GETTEXTLENGTH: uint32 = 0x000Eu32; - pub const WM_PAINT: uint32 = 0x000Fu32; - pub const WM_CLOSE: uint32 = 0x0010u32; - pub const WM_QUIT: uint32 = 0x0012u32; - pub const WM_ERASEBKGND: uint32 = 0x0014u32; - pub const WM_SHOWWINDOW: uint32 = 0x0018u32; - pub const WM_ACTIVATEAPP: uint32 = 0x001Cu32; - pub const WM_KEYDOWN: uint32 = 0x0100u32; - pub const WM_KEYUP: uint32 = 0x0101u32; - pub const WM_CHAR: uint32 = 0x0102u32; - pub const WM_SYSKEYDOWN: uint32 = 0x0104u32; - pub const WM_SYSKEYUP: uint32 = 0x0105u32; - pub const WM_COMMAND: uint32 = 0x0111u32; - pub const WM_INPUT: uint32 = 0x00FFu32; - pub const WM_MOUSEMOVE: uint32 = 0x0200u32; - pub const WM_LBUTTONDOWN: uint32 = 0x0201u32; - pub const WM_LBUTTONUP: uint32 = 0x0202u32; - pub const WM_RBUTTONDOWN: uint32 = 0x0204u32; - pub const WM_RBUTTONUP: uint32 = 0x0205u32; - pub const WM_MBUTTONDOWN: uint32 = 0x0207u32; - pub const WM_MBUTTONUP: uint32 = 0x0208u32; - pub const WM_MOUSEWHEEL: uint32 = 0x020Au32; - pub const WM_MOUSEHOVER: uint32 = 0x02A1u32; - pub const WM_HOTKEY: uint32 = 0x0312u32; - pub const WM_TIMER: uint32 = 0x0113u32; - pub const WM_USER: uint32 = 0x0400u32; - pub const WM_APP: uint32 = 0x8000u32; - - - // Constants — Virtual Key Codes - - - pub const VK_LBUTTON: int32 = 0x01i32; - pub const VK_RBUTTON: int32 = 0x02i32; - pub const VK_CANCEL: int32 = 0x03i32; - pub const VK_MBUTTON: int32 = 0x04i32; - pub const VK_XBUTTON1: int32 = 0x05i32; - pub const VK_XBUTTON2: int32 = 0x06i32; - pub const VK_BACK: int32 = 0x08i32; - pub const VK_TAB: int32 = 0x09i32; - pub const VK_CLEAR: int32 = 0x0Ci32; - pub const VK_RETURN: int32 = 0x0Di32; - pub const VK_SHIFT: int32 = 0x10i32; - pub const VK_CONTROL: int32 = 0x11i32; - pub const VK_MENU: int32 = 0x12i32; - pub const VK_PAUSE: int32 = 0x13i32; - pub const VK_CAPITAL: int32 = 0x14i32; - pub const VK_ESCAPE: int32 = 0x1Bi32; - pub const VK_SPACE: int32 = 0x20i32; - pub const VK_PRIOR: int32 = 0x21i32; - pub const VK_NEXT: int32 = 0x22i32; - pub const VK_END: int32 = 0x23i32; - pub const VK_HOME: int32 = 0x24i32; - pub const VK_LEFT: int32 = 0x25i32; - pub const VK_UP: int32 = 0x26i32; - pub const VK_RIGHT: int32 = 0x27i32; - pub const VK_DOWN: int32 = 0x28i32; - pub const VK_SELECT: int32 = 0x29i32; - pub const VK_PRINT: int32 = 0x2Ai32; - pub const VK_EXECUTE: int32 = 0x2Bi32; - pub const VK_SNAPSHOT: int32 = 0x2Ci32; - pub const VK_INSERT: int32 = 0x2Di32; - pub const VK_DELETE: int32 = 0x2Ei32; - pub const VK_HELP: int32 = 0x2Fi32; - pub const VK_0: int32 = 0x30i32; - pub const VK_1: int32 = 0x31i32; - pub const VK_2: int32 = 0x32i32; - pub const VK_3: int32 = 0x33i32; - pub const VK_4: int32 = 0x34i32; - pub const VK_5: int32 = 0x35i32; - pub const VK_6: int32 = 0x36i32; - pub const VK_7: int32 = 0x37i32; - pub const VK_8: int32 = 0x38i32; - pub const VK_9: int32 = 0x39i32; - pub const VK_A: int32 = 0x41i32; - pub const VK_B: int32 = 0x42i32; - pub const VK_C: int32 = 0x43i32; - pub const VK_D: int32 = 0x44i32; - pub const VK_E: int32 = 0x45i32; - pub const VK_F: int32 = 0x46i32; - pub const VK_G: int32 = 0x47i32; - pub const VK_H: int32 = 0x48i32; - pub const VK_I: int32 = 0x49i32; - pub const VK_J: int32 = 0x4Ai32; - pub const VK_K: int32 = 0x4Bi32; - pub const VK_L: int32 = 0x4Ci32; - pub const VK_M: int32 = 0x4Di32; - pub const VK_N: int32 = 0x4Ei32; - pub const VK_O: int32 = 0x4Fi32; - pub const VK_P: int32 = 0x50i32; - pub const VK_Q: int32 = 0x51i32; - pub const VK_R: int32 = 0x52i32; - pub const VK_S: int32 = 0x53i32; - pub const VK_T: int32 = 0x54i32; - pub const VK_U: int32 = 0x55i32; - pub const VK_V: int32 = 0x56i32; - pub const VK_W: int32 = 0x57i32; - pub const VK_X: int32 = 0x58i32; - pub const VK_Y: int32 = 0x59i32; - pub const VK_Z: int32 = 0x5Ai32; - pub const VK_LWIN: int32 = 0x5Bi32; - pub const VK_RWIN: int32 = 0x5Ci32; - pub const VK_APPS: int32 = 0x5Di32; - pub const VK_NUMPAD0: int32 = 0x60i32; - pub const VK_NUMPAD1: int32 = 0x61i32; - pub const VK_NUMPAD2: int32 = 0x62i32; - pub const VK_NUMPAD3: int32 = 0x63i32; - pub const VK_NUMPAD4: int32 = 0x64i32; - pub const VK_NUMPAD5: int32 = 0x65i32; - pub const VK_NUMPAD6: int32 = 0x66i32; - pub const VK_NUMPAD7: int32 = 0x67i32; - pub const VK_NUMPAD8: int32 = 0x68i32; - pub const VK_NUMPAD9: int32 = 0x69i32; - pub const VK_MULTIPLY: int32 = 0x6Ai32; - pub const VK_ADD: int32 = 0x6Bi32; - pub const VK_SEPARATOR: int32 = 0x6Ci32; - pub const VK_SUBTRACT: int32 = 0x6Di32; - pub const VK_DECIMAL: int32 = 0x6Ei32; - pub const VK_DIVIDE: int32 = 0x6Fi32; - pub const VK_F1: int32 = 0x70i32; - pub const VK_F2: int32 = 0x71i32; - pub const VK_F3: int32 = 0x72i32; - pub const VK_F4: int32 = 0x73i32; - pub const VK_F5: int32 = 0x74i32; - pub const VK_F6: int32 = 0x75i32; - pub const VK_F7: int32 = 0x76i32; - pub const VK_F8: int32 = 0x77i32; - pub const VK_F9: int32 = 0x78i32; - pub const VK_F10: int32 = 0x79i32; - pub const VK_F11: int32 = 0x7Ai32; - pub const VK_F12: int32 = 0x7Bi32; - pub const VK_F13: int32 = 0x7Ci32; - pub const VK_F14: int32 = 0x7Di32; - pub const VK_F15: int32 = 0x7Ei32; - pub const VK_F16: int32 = 0x7Fi32; - pub const VK_NUMLOCK: int32 = 0x90i32; - pub const VK_SCROLL: int32 = 0x91i32; - pub const VK_LSHIFT: int32 = 0xA0i32; - pub const VK_RSHIFT: int32 = 0xA1i32; - pub const VK_LCONTROL: int32 = 0xA2i32; - pub const VK_RCONTROL: int32 = 0xA3i32; - pub const VK_LMENU: int32 = 0xA4i32; - pub const VK_RMENU: int32 = 0xA5i32; - - - // Constants — INPUT type - - - pub const INPUT_MOUSE: uint32 = 0u32; - pub const INPUT_KEYBOARD: uint32 = 1u32; - pub const INPUT_HARDWARE: uint32 = 2u32; - - - // Constants — MOUSE_EVENT flags - - - pub const MOUSEEVENTF_MOVE: uint32 = 0x0001u32; - pub const MOUSEEVENTF_LEFTDOWN: uint32 = 0x0002u32; - pub const MOUSEEVENTF_LEFTUP: uint32 = 0x0004u32; - pub const MOUSEEVENTF_RIGHTDOWN: uint32 = 0x0008u32; - pub const MOUSEEVENTF_RIGHTUP: uint32 = 0x0010u32; - pub const MOUSEEVENTF_MIDDLEDOWN: uint32 = 0x0020u32; - pub const MOUSEEVENTF_MIDDLEUP: uint32 = 0x0040u32; - pub const MOUSEEVENTF_WHEEL: uint32 = 0x0800u32; - pub const MOUSEEVENTF_ABSOLUTE: uint32 = 0x8000u32; - - - // Constants — KEYEVENTF flags - - - pub const KEYEVENTF_EXTENDEDKEY: uint32 = 0x0001u32; - pub const KEYEVENTF_KEYUP: uint32 = 0x0002u32; - pub const KEYEVENTF_SCANCODE: uint32 = 0x0008u32; - pub const KEYEVENTF_UNICODE: uint32 = 0x0004u32; - - - // Constants — GCL/GWL indices - - - pub const GWL_WNDPROC: int32 = -4i32; - pub const GWL_USERDATA: int32 = -21i32; - pub const GWL_EXSTYLE: int32 = -20i32; - pub const GWL_STYLE: int32 = -16i32; - pub const GWL_ID: int32 = -12i32; - pub const GWL_HINSTANCE: int32 = -6i32; - pub const GWL_HWNDPARENT: int32 = -8i32; - - - // Constants — Clipboard - - - pub const CF_TEXT: uint32 = 1u32; - pub const CF_BITMAP: uint32 = 2u32; - pub const CF_METAFILEPICT: uint32 = 3u32; - pub const CF_SYLK: uint32 = 4u32; - pub const CF_DIF: uint32 = 5u32; - pub const CF_TIFF: uint32 = 6u32; - pub const CF_OEMTEXT: uint32 = 7u32; - pub const CF_DIB: uint32 = 8u32; - pub const CF_PALETTE: uint32 = 9u32; - pub const CF_PENDATA: uint32 = 10u32; - pub const CF_RIFF: uint32 = 11u32; - pub const CF_WAVE: uint32 = 12u32; - pub const CF_UNICODETEXT: uint32 = 13u32; - pub const CF_ENHMETAFILE: uint32 = 14u32; - pub const CF_HDROP: uint32 = 15u32; - pub const CF_LOCALE: uint32 = 16u32; - pub const CF_DIBV5: uint32 = 17u32; - pub const CF_OWNERDISPLAY: uint32 = 0x0080u32; - pub const CF_DSPTEXT: uint32 = 0x0081u32; - pub const CF_DSPBITMAP: uint32 = 0x0082u32; - - - // Constants — Window Long indices (GetWindowLongPtr / SetWindowLongPtr) - - - pub const GWLP_WNDPROC: int32 = -4i32; - pub const GWLP_HINSTANCE: int32 = -6i32; - pub const GWLP_USERDATA: int32 = -21i32; - pub const GWLP_ID: int32 = -12i32; - - - // Structures - - - pub struct Rect { - pub left: int32; - pub top: int32; - pub right: int32; - pub bottom: int32; - } - - pub struct Point { - pub x: int32; - pub y: int32; - } - - pub struct MouseInput { - pub dx: int32; - pub dy: int32; - pub mouseData: uint32; - pub dwFlags: uint32; - pub time: uint32; - pub dwExtraInfo: *opaque; - } - - pub struct KeyboardInput { - pub wVk: uint16; - pub wScan: uint16; - pub dwFlags: uint32; - pub time: uint32; - pub dwExtraInfo: *opaque; - } - - pub struct HardwareInput { - pub uMsg: uint32; - pub wParamL: uint16; - pub wParamH: uint16; - } - - pub struct Input { - pub msgType: uint32; - pub _padding: uint32; - pub data: uint8[24]; // max(sizeof(MouseInput,KeyboardInput,HardwareInput)) - } - - - // Extern — user32.dll - - - @[Import(lib: "user32.dll")] - extern { - - /// Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa - func MessageBoxA( - hWnd: *opaque, - text: *const char8, - caption: *const char8, - msgType: uint32 - ) -> int32; - - - /// Retrieves a handle to the top-level window whose class name and window name match the specified strings - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa - func FindWindowA(className: *const char8, windowName: *const char8) -> *opaque; - /// Retrieves a handle to a window whose class name and window name match the specified strings - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowexa - func FindWindowExA( - parent: *opaque, - childAfter: *opaque, - className: *const char8, - windowName: *const char8 - ) -> *opaque; - /// Retrieves a handle to the desktop window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdesktopwindow - func GetDesktopWindow() -> *opaque; - /// Retrieves a handle to the foreground window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow - func GetForegroundWindow() -> *opaque; - /// Examines the Z order of the child windows associated with the specified parent window and retrieves a handle to the child window at the top of the Z order - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-gettopwindow - func GetTopWindow(hWnd: *opaque) -> *opaque; - /// Retrieves a handle to a window that has the specified relationship to the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindow - func GetWindow(hWnd: *opaque, cmd: uint32) -> *opaque; - /// Determines whether the specified window handle identifies an existing window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindow - func IsWindow(hWnd: *opaque) -> bool32; - /// Determines the visibility state of the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindowvisible - func IsWindowVisible(hWnd: *opaque) -> bool32; - /// Determines whether a window is a child window or descendant window of a specified parent window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-ischild - func IsChild(parent: *opaque, child: *opaque) -> bool32; - /// Retrieves a handle to the specified window's parent or owner - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getparent - func GetParent(hWnd: *opaque) -> *opaque; - /// Changes the parent window of the specified child window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent - func SetParent(child: *opaque, newParent: *opaque) -> *opaque; - - - /// Copies the text of the specified window's title bar into a buffer - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtexta - func GetWindowTextA(hWnd: *opaque, text: *char8, maxCount: int32) -> int32; - /// Retrieves the length of the specified window's title bar text - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextlengtha - func GetWindowTextLengthA(hWnd: *opaque) -> int32; - /// Changes the text of the specified window's title bar - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowtexta - func SetWindowTextA(hWnd: *opaque, text: *const char8) -> bool32; - /// Retrieves the name of the class to which the specified window belongs - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclassnamea - func GetClassNameA(hWnd: *opaque, className: *char8, maxCount: int32) -> int32; - - - /// Enumerates all top-level windows on the screen - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows - func EnumWindows(callback: *const opaque, param: *opaque) -> bool32; - /// Enumerates the child windows that belong to the specified parent window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumchildwindows - func EnumChildWindows(parent: *opaque, callback: *const opaque, param: *opaque) -> bool32; - /// Enumerates all nonchild windows associated with a thread - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumthreadwindows - func EnumThreadWindows(threadId: uint32, callback: *const opaque, param: *opaque) -> bool32; - - - /// Sets the specified window's show state - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow - func ShowWindow(hWnd: *opaque, cmdShow: int32) -> bool32; - /// Sets the show state of a window created by a different thread without waiting for the operation to complete - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindowasync - func ShowWindowAsync(hWnd: *opaque, cmdShow: int32) -> bool32; - /// Brings the thread that created the specified window into the foreground and activates the window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow - func SetForegroundWindow(hWnd: *opaque) -> bool32; - /// Enables or disables mouse and keyboard input to the specified window or control - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow - func EnableWindow(hWnd: *opaque, enable: bool32) -> bool32; - /// Determines whether the specified window is enabled for mouse and keyboard input - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-iswindowenabled - func IsWindowEnabled(hWnd: *opaque) -> bool32; - /// Brings the specified window to the top of the Z order - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-bringwindowtotop - func BringWindowToTop(hWnd: *opaque) -> bool32; - /// Changes the position and dimensions of the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-movewindow - func MoveWindow(hWnd: *opaque, x: int32, y: int32, w: int32, h: int32, repaint: bool32) -> bool32; - /// Changes the size, position, and Z order of a child, pop-up, or top-level window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos - func SetWindowPos( - hWnd: *opaque, - hWndInsertAfter: *opaque, - x: int32, y: int32, cx: int32, cy: int32, - flags: uint32 - ) -> bool32; - /// Retrieves the dimensions of the bounding rectangle of the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowrect - func GetWindowRect(hWnd: *opaque, rect: *opaque) -> bool32; - /// Retrieves the coordinates of a window's client area - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect - func GetClientRect(hWnd: *opaque, rect: *opaque) -> bool32; - /// Retrieves the identifier of the thread that created the specified window and its process - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid - func GetWindowThreadProcessId(hWnd: *opaque, processId: *uint32) -> uint32; - - - /// Retrieves information about the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptra - func GetWindowLongPtrA(hWnd: *opaque, index: int32) -> uint; - /// Changes an attribute of the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlongptra - func SetWindowLongPtrA(hWnd: *opaque, index: int32, newLong: uint) -> uint; - - - /// Sends the specified message to a window or windows - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagea - func SendMessageA(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> uint; - /// Places a message in the message queue associated with the thread that created the specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea - func PostMessageA(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> bool32; - /// Posts a message to the message queue of the specified thread - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postthreadmessagea - func PostThreadMessageA(threadId: uint32, msg: uint32, wParam: uint, lParam: uint) -> bool32; - /// Sends the specified message to a window or windows and waits until the message is processed or a timeout elapses - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagetimeouta - func SendMessageTimeoutA( - hWnd: *opaque, - msg: uint32, - wParam: uint, - lParam: uint, - flags: uint32, - timeout: uint32, - result: *uint - ) -> bool32; - - - /// Creates a timer with the specified time-out value - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer - func SetTimer(hWnd: *opaque, id: uint, elapse: uint32, timerFunc: *const opaque) -> uint; - /// Destroys the specified timer - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-killtimer - func KillTimer(hWnd: *opaque, id: uint) -> bool32; - - - /// Moves the cursor to the specified screen coordinates - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursorpos - func SetCursorPos(x: int32, y: int32) -> bool32; - /// Retrieves the cursor's position in screen coordinates - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos - func GetCursorPos(point: *opaque) -> bool32; - /// Confines the cursor to a rectangular area on the screen - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-clipcursor - func ClipCursor(rect: *opaque) -> bool32; - /// Retrieves the screen coordinates of the rectangular area to which the cursor is confined - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclipcursor - func GetClipCursor(rect: *opaque) -> bool32; - /// Displays or hides the cursor - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showcursor - func ShowCursor(show: bool32) -> int32; - /// Moves the caret to the specified coordinates - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcaretpos - func SetCaretPos(x: int32, y: int32) -> bool32; - /// Retrieves the caret's position in client coordinates - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcaretpos - func GetCaretPos(point: *opaque) -> bool32; - - - /// Synthesizes keystrokes, mouse motions, and button clicks - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput - func SendInput(count: uint32, inputs: *opaque, size: int32) -> uint32; - /// Determines whether a key is up or down at the time the function is called - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate - func GetAsyncKeyState(vKey: int32) -> int16; - /// Retrieves the status of the specified virtual key - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate - func GetKeyState(vKey: int32) -> int16; - /// Copies the status of the 256 virtual keys to the specified buffer - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardstate - func GetKeyboardState(state: *uint8) -> bool32; - /// Copies a 256-byte array of keyboard key states into the calling thread's keyboard input-state table - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setkeyboardstate - func SetKeyboardState(state: *uint8) -> bool32; - /// Translates a character to the corresponding virtual-key code and shift state - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscana - func VkKeyScanA(charCode: char8) -> int16; - /// Synthesizes a keystroke - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event - func keybd_event(vk: uint8, scan: uint8, flags: uint32, extra: uint); - /// Synthesizes mouse motion and button clicks - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event - func mouse_event(flags: uint32, dx: uint32, dy: uint32, data: uint32, extra: uint); - - - /// Opens the clipboard for examination and prevents other applications from modifying the clipboard content - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openclipboard - func OpenClipboard(hWnd: *opaque) -> bool32; - /// Closes the clipboard - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-closeclipboard - func CloseClipboard() -> bool32; - /// Empties the clipboard and frees handles to data in the clipboard - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-emptyclipboard - func EmptyClipboard() -> bool32; - /// Retrieves data from the clipboard in a specified format - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclipboarddata - func GetClipboardData(format: uint32) -> *opaque; - /// Places data on the clipboard in a specified clipboard format - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclipboarddata - func SetClipboardData(format: uint32, data: *opaque) -> *opaque; - /// Determines whether the clipboard contains data in the specified format - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isclipboardformatavailable - func IsClipboardFormatAvailable(format: uint32) -> bool32; - /// Retrieves the number of different data formats currently on the clipboard - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-countclipboardformats - func CountClipboardFormats() -> int32; - /// Enumerates the data formats currently available on the clipboard - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumclipboardformats - func EnumClipboardFormats(format: uint32) -> uint32; - - - /// Retrieves a handle to a device context for the client area of a specified window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc - func GetDC(hWnd: *opaque) -> *opaque; - /// Releases a device context, freeing it for use by other applications - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-releasedc - func ReleaseDC(hWnd: *opaque, dc: *opaque) -> int32; - /// Retrieves the specified system metric or system configuration setting - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics - func GetSystemMetrics(index: int32) -> int32; - /// Retrieves the current color of the specified display element - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsyscolor - func GetSysColor(index: int32) -> uint32; - /// Retrieves the current double-click time for the mouse - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdoubleclicktime - func GetDoubleClickTime() -> uint32; - - - /// Sets the window region of a window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowrgn - func SetWindowRgn(hWnd: *opaque, rgn: *opaque, redraw: bool32) -> int32; - /// Obtains a copy of the window region of a window - /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowrgn - func GetWindowRgn(hWnd: *opaque, rgn: *opaque) -> int32; - } - -} + +module Windows { + + // ── Predefined HWND values ──────────────────────────────────────────────── + + pub const HWND_TOP: uint = 0u; + pub const HWND_BOTTOM: uint = 1u; + pub const HWND_TOPMOST: uint = 0xFFFFFFFFFFFFFFFFu; // (HWND)-1 + pub const HWND_NOTOPMOST: uint = 0xFFFFFFFFFFFFFFFEu; // (HWND)-2 + pub const HWND_MESSAGE: uint = 0xFFFFFFFFFFFFFFFDu; // (HWND)-3 + pub const HWND_BROADCAST: uint = 0x0000FFFFu; + + // ── Window Styles ───────────────────────────────────────────────────────── + + pub const WS_OVERLAPPED: uint32 = 0x00000000u32; + pub const WS_POPUP: uint32 = 0x80000000u32; + pub const WS_CHILD: uint32 = 0x40000000u32; + pub const WS_MINIMIZE: uint32 = 0x20000000u32; + pub const WS_VISIBLE: uint32 = 0x10000000u32; + pub const WS_DISABLED: uint32 = 0x08000000u32; + pub const WS_CLIPSIBLINGS: uint32 = 0x04000000u32; + pub const WS_CLIPCHILDREN: uint32 = 0x02000000u32; + pub const WS_MAXIMIZE: uint32 = 0x01000000u32; + pub const WS_CAPTION: uint32 = 0x00C00000u32; + pub const WS_BORDER: uint32 = 0x00800000u32; + pub const WS_DLGFRAME: uint32 = 0x00400000u32; + pub const WS_VSCROLL: uint32 = 0x00200000u32; + pub const WS_HSCROLL: uint32 = 0x00100000u32; + pub const WS_SYSMENU: uint32 = 0x00080000u32; + pub const WS_THICKFRAME: uint32 = 0x00040000u32; + pub const WS_GROUP: uint32 = 0x00020000u32; + pub const WS_TABSTOP: uint32 = 0x00010000u32; + pub const WS_MINIMIZEBOX: uint32 = 0x00020000u32; + pub const WS_MAXIMIZEBOX: uint32 = 0x00010000u32; + pub const WS_OVERLAPPEDWINDOW: uint32 = 0x00CF0000u32; + pub const WS_POPUPWINDOW: uint32 = 0x80880000u32; + + // Extended window styles + pub const WS_EX_DLGMODALFRAME: uint32 = 0x00000001u32; + pub const WS_EX_NOPARENTNOTIFY: uint32 = 0x00000004u32; + pub const WS_EX_TOPMOST: uint32 = 0x00000008u32; + pub const WS_EX_ACCEPTFILES: uint32 = 0x00000010u32; + pub const WS_EX_TRANSPARENT: uint32 = 0x00000020u32; + pub const WS_EX_TOOLWINDOW: uint32 = 0x00000080u32; + pub const WS_EX_WINDOWEDGE: uint32 = 0x00000100u32; + pub const WS_EX_CLIENTEDGE: uint32 = 0x00000200u32; + pub const WS_EX_LAYERED: uint32 = 0x00080000u32; + pub const WS_EX_APPWINDOW: uint32 = 0x00040000u32; + pub const WS_EX_OVERLAPPEDWINDOW: uint32 = 0x00000300u32; + pub const WS_EX_NOACTIVATE: uint32 = 0x08000000u32; + + // ── ShowWindow commands ─────────────────────────────────────────────────── + + pub const SW_HIDE: int32 = 0i32; + pub const SW_SHOWNORMAL: int32 = 1i32; + pub const SW_SHOWMINIMIZED: int32 = 2i32; + pub const SW_SHOWMAXIMIZED: int32 = 3i32; + pub const SW_MAXIMIZE: int32 = 3i32; + pub const SW_SHOWNOACTIVATE: int32 = 4i32; + pub const SW_SHOW: int32 = 5i32; + pub const SW_MINIMIZE: int32 = 6i32; + pub const SW_SHOWMINNOACTIVE: int32 = 7i32; + pub const SW_SHOWNA: int32 = 8i32; + pub const SW_RESTORE: int32 = 9i32; + pub const SW_SHOWDEFAULT: int32 = 10i32; + pub const SW_FORCEMINIMIZE: int32 = 11i32; + + // ── SetWindowPos flags ──────────────────────────────────────────────────── + + pub const SWP_NOSIZE: uint32 = 0x0001u32; + pub const SWP_NOMOVE: uint32 = 0x0002u32; + pub const SWP_NOZORDER: uint32 = 0x0004u32; + pub const SWP_NOREDRAW: uint32 = 0x0008u32; + pub const SWP_NOACTIVATE: uint32 = 0x0010u32; + pub const SWP_FRAMECHANGED: uint32 = 0x0020u32; + pub const SWP_SHOWWINDOW: uint32 = 0x0040u32; + pub const SWP_HIDEWINDOW: uint32 = 0x0080u32; + pub const SWP_NOCOPYBITS: uint32 = 0x0100u32; + pub const SWP_NOOWNERZORDER: uint32 = 0x0200u32; + pub const SWP_NOSENDCHANGING: uint32 = 0x0400u32; + pub const SWP_DEFERERASE: uint32 = 0x2000u32; + pub const SWP_ASYNCWINDOWPOS: uint32 = 0x4000u32; + + // ── Window messages ─────────────────────────────────────────────────────── + + pub const WM_NULL: uint32 = 0x0000u32; + pub const WM_CREATE: uint32 = 0x0001u32; + pub const WM_DESTROY: uint32 = 0x0002u32; + pub const WM_MOVE: uint32 = 0x0003u32; + pub const WM_SIZE: uint32 = 0x0005u32; + pub const WM_ACTIVATE: uint32 = 0x0006u32; + pub const WM_SETFOCUS: uint32 = 0x0007u32; + pub const WM_KILLFOCUS: uint32 = 0x0008u32; + pub const WM_ENABLE: uint32 = 0x000Au32; + pub const WM_SETREDRAW: uint32 = 0x000Bu32; + pub const WM_SETTEXT: uint32 = 0x000Cu32; + pub const WM_GETTEXT: uint32 = 0x000Du32; + pub const WM_PAINT: uint32 = 0x000Fu32; + pub const WM_CLOSE: uint32 = 0x0010u32; + pub const WM_QUERYENDSESSION: uint32 = 0x0011u32; + pub const WM_QUIT: uint32 = 0x0012u32; + pub const WM_ERASEBKGND: uint32 = 0x0014u32; + pub const WM_SHOWWINDOW: uint32 = 0x0018u32; + pub const WM_ACTIVATEAPP: uint32 = 0x001Cu32; + pub const WM_SETCURSOR: uint32 = 0x0020u32; + pub const WM_MOUSEACTIVATE: uint32 = 0x0021u32; + pub const WM_GETMINMAXINFO: uint32 = 0x0024u32; + pub const WM_WINDOWPOSCHANGING: uint32 = 0x0046u32; + pub const WM_WINDOWPOSCHANGED: uint32 = 0x0047u32; + pub const WM_NCCREATE: uint32 = 0x0081u32; + pub const WM_NCDESTROY: uint32 = 0x0082u32; + pub const WM_NCHITTEST: uint32 = 0x0084u32; + pub const WM_NCPAINT: uint32 = 0x0085u32; + pub const WM_KEYDOWN: uint32 = 0x0100u32; + pub const WM_KEYUP: uint32 = 0x0101u32; + pub const WM_CHAR: uint32 = 0x0102u32; + pub const WM_SYSKEYDOWN: uint32 = 0x0104u32; + pub const WM_SYSKEYUP: uint32 = 0x0105u32; + pub const WM_SYSCHAR: uint32 = 0x0106u32; + pub const WM_COMMAND: uint32 = 0x0111u32; + pub const WM_SYSCOMMAND: uint32 = 0x0112u32; + pub const WM_TIMER: uint32 = 0x0113u32; + pub const WM_HSCROLL: uint32 = 0x0114u32; + pub const WM_VSCROLL: uint32 = 0x0115u32; + pub const WM_MOUSEMOVE: uint32 = 0x0200u32; + pub const WM_LBUTTONDOWN: uint32 = 0x0201u32; + pub const WM_LBUTTONUP: uint32 = 0x0202u32; + pub const WM_LBUTTONDBLCLK: uint32 = 0x0203u32; + pub const WM_RBUTTONDOWN: uint32 = 0x0204u32; + pub const WM_RBUTTONUP: uint32 = 0x0205u32; + pub const WM_RBUTTONDBLCLK: uint32 = 0x0206u32; + pub const WM_MBUTTONDOWN: uint32 = 0x0207u32; + pub const WM_MBUTTONUP: uint32 = 0x0208u32; + pub const WM_MOUSEWHEEL: uint32 = 0x020Au32; + pub const WM_MOUSEHWHEEL: uint32 = 0x020Eu32; + pub const WM_SIZING: uint32 = 0x0214u32; + pub const WM_CAPTURECHANGED: uint32 = 0x0215u32; + pub const WM_MOVING: uint32 = 0x0216u32; + pub const WM_TOUCH: uint32 = 0x0240u32; + pub const WM_POINTER: uint32 = 0x0245u32; + pub const WM_POINTERDOWN: uint32 = 0x0246u32; + pub const WM_POINTERUP: uint32 = 0x0247u32; + pub const WM_POINTERENTER: uint32 = 0x0249u32; + pub const WM_POINTERLEAVE: uint32 = 0x024Au32; + pub const WM_INPUT: uint32 = 0x00FFu32; + pub const WM_DPICHANGED: uint32 = 0x02E0u32; + pub const WM_CLIPBOARDUPDATE: uint32 = 0x031Du32; + pub const WM_USER: uint32 = 0x0400u32; + pub const WM_APP: uint32 = 0x8000u32; + + // ── MessageBox constants ────────────────────────────────────────────────── + + pub const MB_OK: uint32 = 0x00000000u32; + pub const MB_OKCANCEL: uint32 = 0x00000001u32; + pub const MB_ABORTRETRYIGNORE: uint32 = 0x00000002u32; + pub const MB_YESNOCANCEL: uint32 = 0x00000003u32; + pub const MB_YESNO: uint32 = 0x00000004u32; + pub const MB_RETRYCANCEL: uint32 = 0x00000005u32; + pub const MB_ICONERROR: uint32 = 0x00000010u32; + pub const MB_ICONQUESTION: uint32 = 0x00000020u32; + pub const MB_ICONWARNING: uint32 = 0x00000030u32; + pub const MB_ICONINFORMATION: uint32 = 0x00000040u32; + pub const MB_TOPMOST: uint32 = 0x00040000u32; + pub const MB_SETFOREGROUND: uint32 = 0x00010000u32; + pub const MB_SYSTEMMODAL: uint32 = 0x00001000u32; + + pub const IDOK: int32 = 1i32; + pub const IDCANCEL: int32 = 2i32; + pub const IDABORT: int32 = 3i32; + pub const IDRETRY: int32 = 4i32; + pub const IDIGNORE: int32 = 5i32; + pub const IDYES: int32 = 6i32; + pub const IDNO: int32 = 7i32; + + // ── Virtual key codes (partial — most common) ───────────────────────────── + + pub const VK_BACK: uint32 = 0x08u32; + pub const VK_TAB: uint32 = 0x09u32; + pub const VK_RETURN: uint32 = 0x0Du32; + pub const VK_SHIFT: uint32 = 0x10u32; + pub const VK_CONTROL: uint32 = 0x11u32; + pub const VK_MENU: uint32 = 0x12u32; + pub const VK_ESCAPE: uint32 = 0x1Bu32; + pub const VK_SPACE: uint32 = 0x20u32; + pub const VK_PRIOR: uint32 = 0x21u32; + pub const VK_NEXT: uint32 = 0x22u32; + pub const VK_END: uint32 = 0x23u32; + pub const VK_HOME: uint32 = 0x24u32; + pub const VK_LEFT: uint32 = 0x25u32; + pub const VK_UP: uint32 = 0x26u32; + pub const VK_RIGHT: uint32 = 0x27u32; + pub const VK_DOWN: uint32 = 0x28u32; + pub const VK_DELETE: uint32 = 0x2Eu32; + pub const VK_F1: uint32 = 0x70u32; + pub const VK_F2: uint32 = 0x71u32; + pub const VK_F4: uint32 = 0x73u32; + pub const VK_F5: uint32 = 0x74u32; + pub const VK_F10: uint32 = 0x79u32; + pub const VK_F11: uint32 = 0x7Au32; + pub const VK_F12: uint32 = 0x7Bu32; + pub const VK_LWIN: uint32 = 0x5Bu32; + pub const VK_RWIN: uint32 = 0x5Cu32; + pub const VK_LSHIFT: uint32 = 0xA0u32; + pub const VK_RSHIFT: uint32 = 0xA1u32; + pub const VK_LCONTROL: uint32 = 0xA2u32; + pub const VK_RCONTROL: uint32 = 0xA3u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct Point { + pub x: int32; + pub y: int32; + } + + pub struct Rect { + pub left: int32; + pub top: int32; + pub right: int32; + pub bottom: int32; + } + + pub struct Msg { + pub hwnd: *opaque; + pub message: uint32; + pub _pad1: uint32; + pub wParam: uint; + pub lParam: uint; + pub time: uint32; + pub _pad2: uint32; + pub pt: Point; + pub _pad3: uint32; + } + + pub struct PaintStruct { + pub hdc: *opaque; + pub fErase: bool32; + pub _pad1: uint32; + pub rcPaint: Rect; + pub fRestore: bool32; + pub _pad2: uint32; + pub fIncUpdate: bool32; + pub _pad3: uint32; + pub rgbReserved: uint8[32]; + } + + pub struct WndClassExA { + pub cbSize: uint32; + pub style: uint32; + pub lpfnWndProc: *const opaque; + pub cbClsExtra: int32; + pub cbWndExtra: int32; + pub hInstance: *opaque; + pub hIcon: *opaque; + pub hCursor: *opaque; + pub hbrBackground: *opaque; + pub lpszMenuName: *const char8; + pub lpszClassName: *const char8; + pub hIconSm: *opaque; + } + + pub struct MinMaxInfo { + pub ptReserved: Point; + pub ptMaxSize: Point; + pub ptMaxPosition: Point; + pub ptMinTrackSize: Point; + pub ptMaxTrackSize: Point; + } + + pub struct WindowPos { + pub hwnd: *opaque; + pub hwndInsertAfter: *opaque; + pub x: int32; + pub y: int32; + pub cx: int32; + pub cy: int32; + pub flags: uint32; + pub _pad: uint32; + } + + pub struct RawInputDevice { + pub usUsagePage: uint16; + pub usUsage: uint16; + pub dwFlags: uint32; + pub hwndTarget: *opaque; + } + + pub struct RawInputHeader { + pub type_: uint32; + pub size: uint32; + pub device: *opaque; + pub wParam: uint; + } + + pub struct RawMouse { + pub usFlags: uint16; + pub _pad1: uint16; + pub usButtonFlags: uint16; + pub usButtonData: uint16; + pub ulRawButtons: uint32; + pub lLastX: int32; + pub lLastY: int32; + pub ulExtraInformation: uint32; + } + + pub struct RawKeyboard { + pub makecode: uint16; + pub flags: uint16; + pub reserved: uint16; + pub vKey: uint16; + pub message: uint32; + pub extraInformation: uint32; + } + + // ── Raw input types ─────────────────────────────────────────────────────── + + pub const RIM_TYPEMOUSE: uint32 = 0u32; + pub const RIM_TYPEKEYBOARD: uint32 = 1u32; + pub const RIM_TYPEHID: uint32 = 2u32; + pub const RIDEV_INPUTSINK: uint32 = 0x00000100u32; + pub const RIDEV_REMOVE: uint32 = 0x00000001u32; + pub const RID_INPUT: uint32 = 0x10000003u32; + pub const RID_HEADER: uint32 = 0x10000005u32; + + // ── Clipboard formats ───────────────────────────────────────────────────── + + pub const CF_TEXT: uint32 = 1u32; + pub const CF_BITMAP: uint32 = 2u32; + pub const CF_UNICODETEXT: uint32 = 13u32; + pub const CF_HDROP: uint32 = 15u32; + + // ── DPI awareness ───────────────────────────────────────────────────────── + + pub const DPI_AWARENESS_CONTEXT_UNAWARE: uint = 0xFFFFFFFFFFFFFFFEu; + pub const DPI_AWARENESS_CONTEXT_SYSTEM_AWARE: uint = 0xFFFFFFFFFFFFFFFDu; + pub const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE: uint = 0xFFFFFFFFFFFFFFFCu; + pub const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: uint = 0xFFFFFFFFFFFFFFFBu; + pub const DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED: uint = 0xFFFFFFFFFFFFFFFAu; + + // ── Extern — user32.dll ─────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "user32.dll")] + extern { + + // Window class + func RegisterClassExA(wc: *const WndClassExA) -> uint16; + func UnregisterClassA(className: *const char8, hInstance: *opaque) -> bool32; + + // Window creation / destruction + func CreateWindowExA( + dwExStyle: uint32, + className: *const char8, + windowName: *const char8, + dwStyle: uint32, + x: int32, y: int32, width: int32, height: int32, + hWndParent: *opaque, + hMenu: *opaque, + hInstance: *opaque, + lpParam: *opaque + ) -> *opaque; + + func DestroyWindow(hWnd: *opaque) -> bool32; + + // Window manipulation + func ShowWindow(hWnd: *opaque, nCmdShow: int32) -> bool32; + func UpdateWindow(hWnd: *opaque) -> bool32; + func MoveWindow(hWnd: *opaque, x: int32, y: int32, width: int32, height: int32, repaint: bool32) -> bool32; + func SetWindowPos(hWnd: *opaque, hWndInsertAfter: *opaque, x: int32, y: int32, cx: int32, cy: int32, flags: uint32) -> bool32; + func GetWindowRect(hWnd: *opaque, rect: *Rect) -> bool32; + func GetClientRect(hWnd: *opaque, rect: *Rect) -> bool32; + func SetWindowTextA(hWnd: *opaque, string: *const char8) -> bool32; + func GetWindowTextA(hWnd: *opaque, string: *char8, maxCount: int32) -> int32; + func IsWindow(hWnd: *opaque) -> bool32; + func IsWindowVisible(hWnd: *opaque) -> bool32; + func IsWindowEnabled(hWnd: *opaque) -> bool32; + func EnableWindow(hWnd: *opaque, enable: bool32) -> bool32; + func SetForegroundWindow(hWnd: *opaque) -> bool32; + func GetForegroundWindow() -> *opaque; + func SetFocus(hWnd: *opaque) -> *opaque; + func GetFocus() -> *opaque; + + // Scrolling + func SetScrollInfo(hWnd: *opaque, bar: int32, si: *opaque, redraw: bool32) -> int32; + func GetScrollInfo(hWnd: *opaque, bar: int32, si: *opaque) -> bool32; + func ScrollWindowEx(hWnd: *opaque, dx: int32, dy: int32, prcScroll: *const Rect, prcClip: *const Rect, hrgnUpdate: *opaque, prcUpdate: *Rect, flags: uint32) -> int32; + + // Message loop + func GetMessageA(msg: *Msg, hWnd: *opaque, msgFilterMin: uint32, msgFilterMax: uint32) -> bool32; + func PeekMessageA(msg: *Msg, hWnd: *opaque, msgFilterMin: uint32, msgFilterMax: uint32, removeMsg: uint32) -> bool32; + func TranslateMessage(msg: *const Msg) -> bool32; + func DispatchMessageA(msg: *const Msg) -> uint; + func PostMessageA(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> bool32; + func SendMessageA(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> uint; + func PostQuitMessage(exitCode: int32); + func PostThreadMessageA(idThread: uint32, msg: uint32, wParam: uint, lParam: uint) -> bool32; + + // Default window proc + func DefWindowProcA(hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> uint; + func CallWindowProcA(prevWndFunc: *const opaque, hWnd: *opaque, msg: uint32, wParam: uint, lParam: uint) -> uint; + + // Painting + func BeginPaint(hWnd: *opaque, ps: *PaintStruct) -> *opaque; + func EndPaint(hWnd: *opaque, ps: *const PaintStruct) -> bool32; + func InvalidateRect(hWnd: *opaque, rect: *const Rect, erase: bool32) -> bool32; + func RedrawWindow(hWnd: *opaque, updateRect: *const Rect, updateRgn: *opaque, flags: uint32) -> bool32; + func GetDC(hWnd: *opaque) -> *opaque; + func ReleaseDC(hWnd: *opaque, hDC: *opaque) -> int32; + func GetWindowDC(hWnd: *opaque) -> *opaque; + + // Dialog / MessageBox + func MessageBoxA(hWnd: *opaque, text: *const char8, caption: *const char8, type_: uint32) -> int32; + func MessageBoxW(hWnd: *opaque, text: *const char16, caption: *const char16, type_: uint32) -> int32; + + // Timer + func SetTimer(hWnd: *opaque, idEvent: uint, elapse: uint32, timerFunc: *const opaque) -> uint; + func KillTimer(hWnd: *opaque, idEvent: uint) -> bool32; + + // Keyboard / mouse + func GetAsyncKeyState(vKey: int32) -> int16; + func GetKeyState(vKey: int32) -> int16; + func GetKeyboardState(keyState: *uint8) -> bool32; + func MapVirtualKeyA(code: uint32, mapType: uint32) -> uint32; + func VkKeyScanA(ch: char8) -> int16; + func keybd_event(vk: uint8, scan: uint8, flags: uint32, extraInfo: uint); + func mouse_event(flags: uint32, dx: int32, dy: int32, data: uint32, extraInfo: uint); + + // Cursor + func SetCursor(hCursor: *opaque) -> *opaque; + func LoadCursorA(hInstance: *opaque, cursorName: *const char8) -> *opaque; + func GetCursorPos(pt: *Point) -> bool32; + func SetCursorPos(x: int32, y: int32) -> bool32; + func ShowCursor(show: bool32) -> int32; + + // Clipboard + func OpenClipboard(hWndNewOwner: *opaque) -> bool32; + func CloseClipboard() -> bool32; + func EmptyClipboard() -> bool32; + func SetClipboardData(format: uint32, hMem: *opaque) -> *opaque; + func GetClipboardData(format: uint32) -> *opaque; + func IsClipboardFormatAvailable(format: uint32) -> bool32; + func AddClipboardFormatListener(hWnd: *opaque) -> bool32; + func RemoveClipboardFormatListener(hWnd: *opaque) -> bool32; + + // Window enumeration + func EnumWindows(lpEnumFunc: *const opaque, lParam: uint) -> bool32; + func EnumChildWindows(hWndParent: *opaque, lpEnumFunc: *const opaque, lParam: uint) -> bool32; + func FindWindowA(className: *const char8, windowName: *const char8) -> *opaque; + func FindWindowExA(hWndParent: *opaque, hWndChildAfter: *opaque, className: *const char8, windowName: *const char8) -> *opaque; + func GetWindowThreadProcessId(hWnd: *opaque, processId: *uint32) -> uint32; + func GetDesktopWindow() -> *opaque; + func GetParent(hWnd: *opaque) -> *opaque; + + // Window long / extra data + func GetWindowLongPtrA(hWnd: *opaque, index: int32) -> uint; + func SetWindowLongPtrA(hWnd: *opaque, index: int32, newLong: uint) -> uint; + + // Screen / monitor + func GetSystemMetrics(nIndex: int32) -> int32; + func ScreenToClient(hWnd: *opaque, pt: *Point) -> bool32; + func ClientToScreen(hWnd: *opaque, pt: *Point) -> bool32; + func MonitorFromPoint(pt: Point, dwFlags: uint32) -> *opaque; + func MonitorFromWindow(hWnd: *opaque, dwFlags: uint32) -> *opaque; + func GetMonitorInfoA(hMonitor: *opaque, info: *opaque) -> bool32; + func EnumDisplayMonitors(hdc: *opaque, clip: *const Rect, proc_: *const opaque, data: uint) -> bool32; + + // Raw input + func RegisterRawInputDevices(devices: *const RawInputDevice, numDevices: uint32, cbSize: uint32) -> bool32; + func GetRawInputData(hRawInput: *opaque, uiCommand: uint32, data: *opaque, cbSize: *uint32, cbSizeHeader: uint32) -> uint32; + + // Touch + func RegisterTouchWindow(hWnd: *opaque, flags: uint32) -> bool32; + func UnregisterTouchWindow(hWnd: *opaque) -> bool32; + func GetTouchInputInfo(hTouchInput: *opaque, cInputs: uint32, inputs: *opaque, cbSize: int32) -> bool32; + func CloseTouchInputHandle(hTouchInput: *opaque) -> bool32; + + // DPI / HiDPI + func SetProcessDpiAwarenessContext(value: uint) -> bool32; + func GetDpiForWindow(hWnd: *opaque) -> uint32; + func GetDpiForSystem() -> uint32; + func AdjustWindowRectExForDpi(rect: *Rect, style: uint32, menu: bool32, exStyle: uint32, dpi: uint32) -> bool32; + func SetThreadDpiAwarenessContext(value: uint) -> uint; + + // Hotkeys + func RegisterHotKey(hWnd: *opaque, id: int32, fsModifiers: uint32, vk: uint32) -> bool32; + func UnregisterHotKey(hWnd: *opaque, id: int32) -> bool32; + + // Menu + func CreateMenu() -> *opaque; + func CreatePopupMenu() -> *opaque; + func DestroyMenu(hMenu: *opaque) -> bool32; + func AppendMenuA(hMenu: *opaque, uFlags: uint32, uIdNewItem: uint, lpNewItem: *const char8) -> bool32; + func SetMenu(hWnd: *opaque, hMenu: *opaque) -> bool32; + func TrackPopupMenu(hMenu: *opaque, uFlags: uint32, x: int32, y: int32, nReserved: int32, hWnd: *opaque, prcRect: *const Rect) -> bool32; + + // Icon + func LoadIconA(hInstance: *opaque, iconName: *const char8) -> *opaque; + func DestroyIcon(hIcon: *opaque) -> bool32; + + // Global memory (clipboard data) + func GlobalAlloc(uFlags: uint32, dwBytes: uint) -> *opaque; + func GlobalLock(hMem: *opaque) -> *opaque; + func GlobalUnlock(hMem: *opaque) -> bool32; + func GlobalFree(hMem: *opaque) -> *opaque; + + // Notification area / system tray + func Shell_NotifyIconA(message: uint32, data: *opaque) -> bool32; + } + +} diff --git a/Src/WinHvPlatform.rux b/Src/WinHvPlatform.rux index 8c41c9c..1df603c 100644 --- a/Src/WinHvPlatform.rux +++ b/Src/WinHvPlatform.rux @@ -1,435 +1,430 @@ -/* - Windows API — Windows Hypervisor Platform (WinHvPlatform.dll) - Copyright © 2026 Rux Contributors - Licensed under the MIT License -*/ - -module Windows { - - - // Return code - - - pub const WHV_OK: uint32 = 0x00000000u32; // S_OK - pub const WHV_E_OBJECT_NOT_FOUND: uint32 = 0x80370001u32; - pub const WHV_E_INVALID_PARAMETER: uint32 = 0x80370002u32; - pub const WHV_E_UNKNOWN_CAPABILITY: uint32 = 0x80370003u32; - pub const WHV_E_INSUFFICIENT_BUFFER: uint32 = 0x80370004u32; - - - // Capability Codes — WHvGetCapability - - - pub const WHvCapabilityCodeHypervisorPresent: uint32 = 0x00001000u32; - - pub const WHvCapabilityCodeFeatures: uint32 = 0x00001001u32; - - pub const WHvCapabilityCodeExtendedVmExits: uint32 = 0x00001002u32; - - pub const WHvCapabilityCodeExceptionExitBitmap: uint32 = 0x00001003u32; - - // Feature bits returned by WHvCapabilityCodeFeatures - pub const WHvFeatureLocalApicPassthrough: uint32 = 0x00000001u32; - pub const WHvFeatureRdtscp: uint32 = 0x00000002u32; - pub const WHvFeatureTscDeadlineTimer: uint32 = 0x00000004u32; - - - // Partition Property Codes — WHvGet/SetPartitionProperty - - - pub const WHvPartitionPropertyCodeProcessorCount: uint32 = 0x00010001u32; - - pub const WHvPartitionPropertyCodeExtendedVmExits: uint32 = 0x00010002u32; - - pub const WHvPartitionPropertyCodeExceptionExitBitmap: uint32 = 0x00010003u32; - - pub const WHvPartitionPropertyCodeSharedMemory: uint32 = 0x00010004u32; - - - // Run VP Exit Reasons — returned in WHV_RUN_VP_EXIT_CONTEXT.exitReason - - - pub const WHvRunVpExitReasonNone: uint32 = 0x00000000u32; - pub const WHvRunVpExitReasonMemoryAccess: uint32 = 0x00000001u32; - pub const WHvRunVpExitReasonX64InterruptWindow: uint32 = 0x00000002u32; - pub const WHvRunVpExitReasonX64Halt: uint32 = 0x00000003u32; - pub const WHvRunVpExitReasonX64IoPortAccess: uint32 = 0x00000004u32; - pub const WHvRunVpExitReasonUnrecoverableException: uint32 = 0x00000005u32; - pub const WHvRunVpExitReasonX64MsrAccess: uint32 = 0x00000006u32; - pub const WHvRunVpExitReasonX64Cpuid: uint32 = 0x00000007u32; - pub const WHvRunVpExitReasonException: uint32 = 0x00000008u32; - pub const WHvRunVpExitReasonX64Rdtsc: uint32 = 0x00000009u32; - pub const WHvRunVpExitReasonX64ApicEoi: uint32 = 0x0000000Au32; - pub const WHvRunVpExitReasonSynicSint: uint32 = 0x0000000Bu32; - pub const WHvRunVpExitReasonX64X2Apic: uint32 = 0x0000000Cu32; - - - // Memory Access Types — returned in MemoryAccess exit context - - - pub const WHvMemoryAccessRead: uint32 = 0x00000000u32; - pub const WHvMemoryAccessWrite: uint32 = 0x00000001u32; - pub const WHvMemoryAccessExecute:uint32 = 0x00000002u32; - - - // MSR Access Types — returned in MsrAccess exit context - - - pub const WHvX64MsrAccessRead: uint32 = 0x00000000u32; - pub const WHvX64MsrAccessWrite: uint32 = 0x00000001u32; - - - // Map GPA Range Flags - - - pub const WHvMapGpaRangeFlagRead: uint32 = 0x00000001u32; - pub const WHvMapGpaRangeFlagWrite: uint32 = 0x00000002u32; - pub const WHvMapGpaRangeFlagExecute: uint32 = 0x00000004u32; - - // All access (read + write + execute) - pub const WHvMapGpaRangeFlagAll: uint32 = 0x00000007u32; - - - // X64 Exception Types — used with exception exit bitmap - - - pub const WHvX64ExceptionTypeDivideErrorFault: uint32 = 0x00u32; - pub const WHvX64ExceptionTypeDebugFault: uint32 = 0x01u32; - pub const WHvX64ExceptionTypeBreakpointTrap: uint32 = 0x03u32; - pub const WHvX64ExceptionTypeOverflowTrap: uint32 = 0x04u32; - pub const WHvX64ExceptionTypeBoundRangeFault: uint32 = 0x05u32; - pub const WHvX64ExceptionTypeInvalidOpcodeFault: uint32 = 0x06u32; - pub const WHvX64ExceptionTypeDeviceNotAvailableFault: uint32 = 0x07u32; - pub const WHvX64ExceptionTypeDoubleFault: uint32 = 0x08u32; - pub const WHvX64ExceptionTypeInvalidTssFault: uint32 = 0x0Au32; - pub const WHvX64ExceptionTypeSegmentNotPresentFault: uint32 = 0x0Bu32; - pub const WHvX64ExceptionTypeStackFault: uint32 = 0x0Cu32; - pub const WHvX64ExceptionTypeGeneralProtectionFault: uint32 = 0x0Du32; - pub const WHvX64ExceptionTypePageFault: uint32 = 0x0Eu32; - pub const WHvX64ExceptionTypeFloatingPointErrorFault: uint32 = 0x10u32; - pub const WHvX64ExceptionTypeAlignmentCheckFault: uint32 = 0x11u32; - pub const WHvX64ExceptionTypeMachineCheck: uint32 = 0x12u32; - pub const WHvX64ExceptionTypeSimdFloatingPointFault: uint32 = 0x13u32; - - - // X64 Register Names — WHvGet/SetVirtualProcessorRegisters - - - pub const WHvX64RegisterRax: uint32 = 0u32; - pub const WHvX64RegisterRcx: uint32 = 1u32; - pub const WHvX64RegisterRdx: uint32 = 2u32; - pub const WHvX64RegisterRbx: uint32 = 3u32; - pub const WHvX64RegisterRsp: uint32 = 4u32; - pub const WHvX64RegisterRbp: uint32 = 5u32; - pub const WHvX64RegisterRsi: uint32 = 6u32; - pub const WHvX64RegisterRdi: uint32 = 7u32; - pub const WHvX64RegisterR8: uint32 = 8u32; - pub const WHvX64RegisterR9: uint32 = 9u32; - pub const WHvX64RegisterR10: uint32 = 10u32; - pub const WHvX64RegisterR11: uint32 = 11u32; - pub const WHvX64RegisterR12: uint32 = 12u32; - pub const WHvX64RegisterR13: uint32 = 13u32; - pub const WHvX64RegisterR14: uint32 = 14u32; - pub const WHvX64RegisterR15: uint32 = 15u32; - pub const WHvX64RegisterRip: uint32 = 16u32; - pub const WHvX64RegisterRflags: uint32 = 17u32; - pub const WHvX64RegisterCs: uint32 = 24u32; - pub const WHvX64RegisterDs: uint32 = 25u32; - pub const WHvX64RegisterEs: uint32 = 26u32; - pub const WHvX64RegisterFs: uint32 = 27u32; - pub const WHvX64RegisterGs: uint32 = 28u32; - pub const WHvX64RegisterSs: uint32 = 29u32; - pub const WHvX64RegisterCr0: uint32 = 36u32; - pub const WHvX64RegisterCr2: uint32 = 37u32; - pub const WHvX64RegisterCr3: uint32 = 38u32; - pub const WHvX64RegisterCr4: uint32 = 39u32; - pub const WHvX64RegisterDr0: uint32 = 44u32; - pub const WHvX64RegisterDr1: uint32 = 45u32; - pub const WHvX64RegisterDr2: uint32 = 46u32; - pub const WHvX64RegisterDr3: uint32 = 47u32; - pub const WHvX64RegisterDr6: uint32 = 48u32; - pub const WHvX64RegisterDr7: uint32 = 49u32; - - - // Structures - - - pub struct WHvCapability { - pub code: uint32; - pub result: uint32; - pub data: uint64; - } - - pub struct WHvRegisterValue { - pub reg64: uint64; - } - - pub struct WHvRunVpExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - } - - pub struct WHvMemoryAccessExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - pub accessType: uint32; - pub _pad3: uint32; - pub gpa: uint64; - pub gva: uint64; - pub byteCount: uint32; - pub _pad4: uint32; - } - - pub struct WHvX64MsrAccessExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - pub accessType: uint32; - pub _pad3: uint32; - pub msrNumber: uint32; - pub _pad4: uint32; - pub msrValue: uint64; - } - - pub struct WHvX64CpuidExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - pub rax: uint64; - pub rcx: uint64; - pub rdx: uint64; - pub rbx: uint64; - pub defaultResultRax: uint64; - pub defaultResultRcx: uint64; - pub defaultResultRdx: uint64; - pub defaultResultRbx: uint64; - } - - pub struct WHvX64IoPortAccessExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - pub portNumber: uint32; - pub accessType: uint32; - pub data: uint32; - pub byteCount: uint32; - pub _pad3: uint32; - pub rax: uint64; - } - - pub struct WHvExceptionExitContext { - pub exitReason: uint32; - pub _pad1: uint32; - pub vpIndex: uint32; - pub _pad2: uint32; - pub exceptionType: uint32; - pub _pad3: uint32; - pub errorCode: uint32; - pub _pad4: uint32; - } - - - // Interrupt Controller - - - pub struct WHvInterruptControl { - pub interruptType: uint32; - pub _pad1: uint32; - pub vector: uint32; - pub _pad2: uint32; - pub destination: uint64; - } - - - // GVA Translation - - - pub const WHvTranslateGvaFlagValidateRead: uint32 = 0x00000001u32; - pub const WHvTranslateGvaFlagValidateWrite: uint32 = 0x00000002u32; - pub const WHvTranslateGvaFlagValidateExecute:uint32= 0x00000004u32; - - pub struct WHvTranslateGvaResult { - pub resultCode: uint32; - pub gpaIsValid: uint32; - } - - pub const WHvTranslateGvaResultSuccess: uint32 = 0x00000000u32; - pub const WHvTranslateGvaResultPageNotPresent: uint32 = 0x00000001u32; - pub const WHvTranslateGvaResultPrivilegeViolation: uint32 = 0x00000002u32; - pub const WHvTranslateGvaResultInvalidPageTableFlags: uint32 = 0x00000003u32; - - pub const WHvX64InterruptTypeFixed: uint32 = 0x00000000u32; - pub const WHvX64InterruptTypeLowPriority: uint32 = 0x00000001u32; - pub const WHvX64InterruptTypeSmi: uint32 = 0x00000002u32; - pub const WHvX64InterruptTypeNmi: uint32 = 0x00000004u32; - pub const WHvX64InterruptTypeInit: uint32 = 0x00000005u32; - pub const WHvX64InterruptTypeSipi: uint32 = 0x00000006u32; - pub const WHvX64InterruptTypePlatform: uint32 = 0x00000007u32; - - - // Extern — WinHvPlatform.dll - - - @[Import(lib: "WinHvPlatform.dll")] - extern { - /// Queries the capabilities of the hypervisor partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvgetcapability - func WHvGetCapability( - capabilityCode: uint32, - capabilityBuffer: *opaque, - capabilityBufferSize: uint32 - ) -> uint32; - - /// Creates a new partition object - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvcreatepartition - func WHvCreatePartition(partition: *opaque) -> uint32; - - /// Deletes a partition object - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvdeletepartition - func WHvDeletePartition(partition: *opaque) -> uint32; - - /// Completes the creation of a partition and makes it ready for use - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvsetuppartition - func WHvSetupPartition(partition: *opaque) -> uint32; - - /// Maps a range of a partition's guest physical address space to a specified host virtual address space range - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvmapgparange - func WHvMapGpaRange( - partition: *opaque, - sourceAddress: *opaque, - gpa: uint64, - byteCount: uint64, - flags: uint32 - ) -> uint32; - - /// Unmaps a previously mapped GPA range from the partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvunmapgparange - func WHvUnmapGpaRange( - partition: *opaque, - gpa: uint64, - byteCount: uint64 - ) -> uint32; - - /// Creates a virtual processor in a partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvcreatevirtualprocessor - func WHvCreateVirtualProcessor( - partition: *opaque, - vpIndex: uint32, - flags: uint32 - ) -> uint32; - - /// Deletes a virtual processor in a partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvdeletevirtualprocessor - func WHvDeleteVirtualProcessor( - partition: *opaque, - vpIndex: uint32 - ) -> uint32; - - /// Runs the virtual processor and returns when the processor exits - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvrunvirtualprocessor - func WHvRunVirtualProcessor( - partition: *opaque, - vpIndex: uint32, - exitContext: *opaque, - exitContextSize: uint32 - ) -> uint32; - - /// Requests the cancellation of a currently executing virtual processor run - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvcancelrunvirtualprocessor - func WHvCancelRunVirtualProcessor( - partition: *opaque, - vpIndex: uint32 - ) -> uint32; - - /// Retrieves the value of a list of registers from a virtual processor - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvgetvirtualprocessorregisters - func WHvGetVirtualProcessorRegisters( - partition: *opaque, - vpIndex: uint32, - registerNames: *uint32, - registerValues: *opaque, - registerCount: uint32 - ) -> uint32; - - /// Sets the value of a list of registers in a virtual processor - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvsetvirtualprocessorregisters - func WHvSetVirtualProcessorRegisters( - partition: *opaque, - vpIndex: uint32, - registerNames: *uint32, - registerValues: *opaque, - registerCount: uint32 - ) -> uint32; - - /// Retrieves a property of a partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvgetpartitionproperty - func WHvGetPartitionProperty( - partition: *opaque, - propertyCode: uint32, - propertyBuffer: *opaque, - propertyBufferSize: uint32, - resultSize: *uint32 - ) -> uint32; - - /// Sets a property of a partition - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvsetpartitionproperty - func WHvSetPartitionProperty( - partition: *opaque, - propertyCode: uint32, - propertyBuffer: *opaque, - propertyBufferSize: uint32 - ) -> uint32; - - /// Requests an interrupt to be injected into a virtual processor - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvrequestinterrupt - func WHvRequestInterrupt( - partition: *opaque, - interruptControl: *opaque, - controlSize: uint32 - ) -> uint32; - - /// Translates a guest virtual address to a guest physical address - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvtranslategva - func WHvTranslateGva( - partition: *opaque, - vpIndex: uint32, - gva: uint64, - flags: uint32, - result: *opaque, - gpa: *uint64 - ) -> uint32; - } - - - // Convenience helpers - - - /// Returns true if the Windows Hypervisor Platform API is available on this system - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvgetcapability - pub func IsWhpAvailable() -> bool { - var present: uint32 = 0u32; - let ret = WHvGetCapability( - WHvCapabilityCodeHypervisorPresent, - &present as *opaque, - 4u32 - ); - if ret != WHV_OK { return false; } - return present != 0u32; - } - - /// Creates and sets up a new hypervisor partition ready for virtual processor creation - /// https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/funcs/whvcreatepartition - pub func CreatePartition() -> *opaque { - var partition: *opaque = null; - let _ = WHvCreatePartition(&partition as *opaque); - return partition; - } - -} +/* + Windows API — WinHvPlatform.dll (Windows Hypervisor Platform) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • WHvGetCapability / WHvCreatePartition return type was uint32 — must be int32 (HRESULT). + • WHV_PARTITION_PROPERTY_CODE constants expanded with all SDK values. + • Added WHvMapGpaRange2, WHvRequestInterrupt, WHvSuspendPartitionTime, + WHvResumePartitionTime, WHvGetVirtualProcessorCpuidOutput. + • WHvRunVpExitContext size corrected to 520 bytes (match WinHvPlatform.h). + • Added HRESULT success / failure helpers. + + Rux OS support + ────────────── + WinHvPlatform.dll is a Windows-only API (requires Windows 10 1803+ or + Windows Server 2019+). On other platforms this entire block is excluded by + the @[Target("Windows")] attribute, so cross-compiled Rux targets (Linux, + macOS, WASM) simply see an empty module and produce zero linker references. + + References: https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/ +*/ + +module Windows { + + // ── HRESULT helpers ─────────────────────────────────────────────────────── + + pub const S_OK: int32 = 0i32; + pub const S_FALSE: int32 = 1i32; + pub const E_FAIL: int32 = 0x80004005u32 as int32; + pub const E_NOTIMPL: int32 = 0x80004001u32 as int32; + pub const E_INVALIDARG: int32 = 0x80070057u32 as int32; + pub const E_OUTOFMEMORY: int32 = 0x8007000Eu32 as int32; + pub const E_ACCESSDENIED: int32 = 0x80070005u32 as int32; + pub const E_HANDLE: int32 = 0x80070006u32 as int32; + pub const E_POINTER: int32 = 0x80004003u32 as int32; + + pub func HrSucceeded(hr: int32) -> bool { return hr >= 0i32; } + pub func HrFailed(hr: int32) -> bool { return hr < 0i32; } + + // ── Capability codes ────────────────────────────────────────────────────── + + pub const WHvCapabilityCodeHypervisorPresent: uint32 = 0x00000000u32; + pub const WHvCapabilityCodeFeatures: uint32 = 0x00000001u32; + pub const WHvCapabilityCodeExtendedVmExits: uint32 = 0x00000002u32; + pub const WHvCapabilityCodeExceptionExitBitmap: uint32 = 0x00000003u32; + pub const WHvCapabilityCodeX64MsrExitBitmap: uint32 = 0x00000004u32; + pub const WHvCapabilityCodeGpaRangePopulateFlags: uint32 = 0x00000005u32; + pub const WHvCapabilityCodeSchedulerFeatures: uint32 = 0x00000006u32; + pub const WHvCapabilityCodeProcessorXsaveFeatures: uint32 = 0x00001000u32; + pub const WHvCapabilityCodeProcessorClFlushSize: uint32 = 0x00001001u32; + pub const WHvCapabilityCodeProcessorXsave2Features: uint32 = 0x00001002u32; + pub const WHvCapabilityCodeProcessorClockFrequency: uint32 = 0x00001003u32; + pub const WHvCapabilityCodeInterruptClockFrequency: uint32 = 0x00001004u32; + pub const WHvCapabilityCodeProcessorFeatures: uint32 = 0x00001005u32; + pub const WHvCapabilityCodeProcessorFeaturesBanks: uint32 = 0x00001006u32; + pub const WHvCapabilityCodeProcessorFrequencyCap: uint32 = 0x00001007u32; + pub const WHvCapabilityCodeSyntheticProcessorFeaturesBanks: uint32 = 0x00001008u32; + pub const WHvCapabilityCodeProcessorPerfmonFeatures: uint32 = 0x00001009u32; + + // ── Partition property codes ────────────────────────────────────────────── + + pub const WHvPartitionPropertyCodeExtendedVmExits: uint32 = 0x00000001u32; + pub const WHvPartitionPropertyCodeExceptionExitBitmap: uint32 = 0x00000002u32; + pub const WHvPartitionPropertyCodeSeparateSecurityDomain: uint32 = 0x00000003u32; + pub const WHvPartitionPropertyCodeNestedVirtualization: uint32 = 0x00000004u32; + pub const WHvPartitionPropertyCodeX64MsrExitBitmap: uint32 = 0x00000005u32; + pub const WHvPartitionPropertyCodePrimaryNumaNode: uint32 = 0x00000006u32; + pub const WHvPartitionPropertyCodeCpuReserve: uint32 = 0x00000007u32; + pub const WHvPartitionPropertyCodeCpuCap: uint32 = 0x00000008u32; + pub const WHvPartitionPropertyCodeCpuWeight: uint32 = 0x00000009u32; + pub const WHvPartitionPropertyCodeCpuGroupId: uint32 = 0x0000000Au32; + pub const WHvPartitionPropertyCodeProcessorFrequencyCap: uint32 = 0x0000000Bu32; + pub const WHvPartitionPropertyCodeAllowDeviceAssignment: uint32 = 0x0000000Cu32; + pub const WHvPartitionPropertyCodeDisableSmt: uint32 = 0x0000000Du32; + pub const WHvPartitionPropertyCodeProcessorFeatures: uint32 = 0x00001001u32; + pub const WHvPartitionPropertyCodeProcessorClFlushSize: uint32 = 0x00001002u32; + pub const WHvPartitionPropertyCodeCpuCount: uint32 = 0x00001003u32; + pub const WHvPartitionPropertyCodeLocalApicEmulationMode: uint32 = 0x00001004u32; + pub const WHvPartitionPropertyCodeProcessorXsaveFeatures: uint32 = 0x00001005u32; + pub const WHvPartitionPropertyCodeProcessorClockFrequency: uint32 = 0x00001006u32; + pub const WHvPartitionPropertyCodeInterruptClockFrequency: uint32 = 0x00001007u32; + pub const WHvPartitionPropertyCodeApicRemoteReadSupport: uint32 = 0x00001008u32; + pub const WHvPartitionPropertyCodeProcessorFeaturesBanks: uint32 = 0x00001009u32; + pub const WHvPartitionPropertyCodeReferenceTime: uint32 = 0x0000100Au32; + pub const WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks: uint32 = 0x0000100Bu32; + pub const WHvPartitionPropertyCodeCpuPartitionId: uint32 = 0x0000100Cu32; + pub const WHvPartitionPropertyCodeProcessorPerfmonFeatures: uint32 = 0x0000100Du32; + pub const WHvPartitionPropertyCodeMsrActionTable: uint32 = 0x0000100Eu32; + pub const WHvPartitionPropertyCodeUnimplementedMsrAction: uint32 = 0x0000100Fu32; + pub const WHvPartitionPropertyCodeProcessorCount: uint32 = 0x00001FFFu32; + + // ── GPA range flags ─────────────────────────────────────────────────────── + + pub const WHvMapGpaRangeFlagNone: uint32 = 0x00000000u32; + pub const WHvMapGpaRangeFlagRead: uint32 = 0x00000001u32; + pub const WHvMapGpaRangeFlagWrite: uint32 = 0x00000002u32; + pub const WHvMapGpaRangeFlagExecute: uint32 = 0x00000004u32; + pub const WHvMapGpaRangeFlagTrackDirtyPages: uint32 = 0x00000008u32; + + // ── VP exit reasons ─────────────────────────────────────────────────────── + + pub const WHvRunVpExitReasonNone: uint32 = 0x00000000u32; + pub const WHvRunVpExitReasonMemoryAccess: uint32 = 0x00000001u32; + pub const WHvRunVpExitReasonX64IoPortAccess: uint32 = 0x00000002u32; + pub const WHvRunVpExitReasonUnrecoverableException: uint32 = 0x00000004u32; + pub const WHvRunVpExitReasonInvalidVpRegisterValue: uint32 = 0x00000005u32; + pub const WHvRunVpExitReasonUnsupportedFeature: uint32 = 0x00000006u32; + pub const WHvRunVpExitReasonX64InterruptWindow: uint32 = 0x00000007u32; + pub const WHvRunVpExitReasonX64Halt: uint32 = 0x00000008u32; + pub const WHvRunVpExitReasonX64ApicEoi: uint32 = 0x00000009u32; + pub const WHvRunVpExitReasonX64MsrAccess: uint32 = 0x00001000u32; + pub const WHvRunVpExitReasonX64Cpuid: uint32 = 0x00001001u32; + pub const WHvRunVpExitReasonException: uint32 = 0x00001002u32; + pub const WHvRunVpExitReasonX64RdtscAccess: uint32 = 0x00001003u32; + pub const WHvRunVpExitReasonX64ApicSmiTrap: uint32 = 0x00001004u32; + pub const WHvRunVpExitReasonHypercall: uint32 = 0x00001005u32; + pub const WHvRunVpExitReasonX64ApicInitSipiTrap: uint32 = 0x00001006u32; + pub const WHvRunVpExitReasonX64ApicWriteTrap: uint32 = 0x00001007u32; + pub const WHvRunVpExitReasonCanceled: uint32 = 0x00002001u32; + + // ── VP register names ───────────────────────────────────────────────────── + + pub const WHvX64RegisterRax: uint32 = 0x00000000u32; + pub const WHvX64RegisterRcx: uint32 = 0x00000001u32; + pub const WHvX64RegisterRdx: uint32 = 0x00000002u32; + pub const WHvX64RegisterRbx: uint32 = 0x00000003u32; + pub const WHvX64RegisterRsp: uint32 = 0x00000004u32; + pub const WHvX64RegisterRbp: uint32 = 0x00000005u32; + pub const WHvX64RegisterRsi: uint32 = 0x00000006u32; + pub const WHvX64RegisterRdi: uint32 = 0x00000007u32; + pub const WHvX64RegisterR8: uint32 = 0x00000008u32; + pub const WHvX64RegisterR9: uint32 = 0x00000009u32; + pub const WHvX64RegisterR10: uint32 = 0x0000000Au32; + pub const WHvX64RegisterR11: uint32 = 0x0000000Bu32; + pub const WHvX64RegisterR12: uint32 = 0x0000000Cu32; + pub const WHvX64RegisterR13: uint32 = 0x0000000Du32; + pub const WHvX64RegisterR14: uint32 = 0x0000000Eu32; + pub const WHvX64RegisterR15: uint32 = 0x0000000Fu32; + pub const WHvX64RegisterRip: uint32 = 0x00000010u32; + pub const WHvX64RegisterRflags: uint32 = 0x00000011u32; + pub const WHvX64RegisterCs: uint32 = 0x00000012u32; + pub const WHvX64RegisterSs: uint32 = 0x00000013u32; + pub const WHvX64RegisterDs: uint32 = 0x00000014u32; + pub const WHvX64RegisterEs: uint32 = 0x00000015u32; + pub const WHvX64RegisterFs: uint32 = 0x00000016u32; + pub const WHvX64RegisterGs: uint32 = 0x00000017u32; + pub const WHvX64RegisterLdtr: uint32 = 0x00000018u32; + pub const WHvX64RegisterTr: uint32 = 0x00000019u32; + pub const WHvX64RegisterIdtr: uint32 = 0x0000001Au32; + pub const WHvX64RegisterGdtr: uint32 = 0x0000001Bu32; + pub const WHvX64RegisterCr0: uint32 = 0x0000001Cu32; + pub const WHvX64RegisterCr2: uint32 = 0x0000001Du32; + pub const WHvX64RegisterCr3: uint32 = 0x0000001Eu32; + pub const WHvX64RegisterCr4: uint32 = 0x0000001Fu32; + pub const WHvX64RegisterCr8: uint32 = 0x00000020u32; + pub const WHvX64RegisterDr0: uint32 = 0x00000021u32; + pub const WHvX64RegisterDr1: uint32 = 0x00000022u32; + pub const WHvX64RegisterDr2: uint32 = 0x00000023u32; + pub const WHvX64RegisterDr3: uint32 = 0x00000024u32; + pub const WHvX64RegisterDr6: uint32 = 0x00000025u32; + pub const WHvX64RegisterDr7: uint32 = 0x00000026u32; + pub const WHvX64RegisterXmm0: uint32 = 0x00001000u32; + pub const WHvX64RegisterXmm1: uint32 = 0x00001001u32; + pub const WHvX64RegisterXmm2: uint32 = 0x00001002u32; + pub const WHvX64RegisterXmm3: uint32 = 0x00001003u32; + pub const WHvX64RegisterXmm4: uint32 = 0x00001004u32; + pub const WHvX64RegisterXmm5: uint32 = 0x00001005u32; + pub const WHvX64RegisterXmm6: uint32 = 0x00001006u32; + pub const WHvX64RegisterXmm7: uint32 = 0x00001007u32; + pub const WHvX64RegisterXmm8: uint32 = 0x00001008u32; + pub const WHvX64RegisterXmm9: uint32 = 0x00001009u32; + pub const WHvX64RegisterXmm10: uint32 = 0x0000100Au32; + pub const WHvX64RegisterXmm11: uint32 = 0x0000100Bu32; + pub const WHvX64RegisterXmm12: uint32 = 0x0000100Cu32; + pub const WHvX64RegisterXmm13: uint32 = 0x0000100Du32; + pub const WHvX64RegisterXmm14: uint32 = 0x0000100Eu32; + pub const WHvX64RegisterXmm15: uint32 = 0x0000100Fu32; + pub const WHvX64RegisterFpMmx0: uint32 = 0x00001010u32; + pub const WHvX64RegisterFpMmx1: uint32 = 0x00001011u32; + + // ARM64 registers + pub const WHvArm64RegisterX0: uint32 = 0x00020000u32; + pub const WHvArm64RegisterX1: uint32 = 0x00020001u32; + pub const WHvArm64RegisterX30: uint32 = 0x0002001Eu32; + pub const WHvArm64RegisterPc: uint32 = 0x00020040u32; + pub const WHvArm64RegisterSp: uint32 = 0x00020041u32; + + // ── Structures ──────────────────────────────────────────────────────────── + + /// Exit context (opaque blob — layout depends on WHvRunVpExitReasonXxx). + /// 520 bytes: 8 VP context + 512 exit-specific union. + pub struct WhvRunVpExitContext { + pub exitReason: uint32; + pub _pad: uint32; + pub vpContext: uint64[4]; // 32 bytes of VP context + pub exitSpecific: uint64[64]; // 512 bytes for exit-reason union + } + + pub struct WhvX64CpuidResult { + pub function_: uint32; + pub index: uint32; + pub eax: uint32; + pub ebx: uint32; + pub ecx: uint32; + pub edx: uint32; + } + + pub struct WhvTranslateGvaResult { + pub resultCode: uint32; + pub _pad: uint32; + pub gpa: uint64; + } + + pub struct WhvInterruptControl { + pub type_: uint64; + pub destinations: uint64; + pub triggerMode: uint32; + pub vector: uint32; + } + + // ── Extern — winhvplatform.dll ──────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "winhvplatform.dll")] + extern { + + // Capability query + func WHvGetCapability( + capabilityCode: uint32, + capabilityBuffer: *opaque, + capabilityBufferSizeInBytes: uint32, + writtenSizeInBytes: *uint32 + ) -> int32; + + // Partition lifecycle + func WHvCreatePartition(partition: *opaque) -> int32; + func WHvDeletePartition(partition: *opaque) -> int32; + func WHvSetupPartition(partition: *opaque) -> int32; + + // Partition properties + func WHvGetPartitionProperty( + partition: *opaque, + propertyCode: uint32, + propertyBuffer: *opaque, + propertyBufferSizeInBytes: uint32, + writtenSizeInBytes: *uint32 + ) -> int32; + + func WHvSetPartitionProperty( + partition: *opaque, + propertyCode: uint32, + propertyBuffer: *const opaque, + propertyBufferSizeInBytes: uint32 + ) -> int32; + + // Virtual processor lifecycle + func WHvCreateVirtualProcessor( + partition: *opaque, + vpIndex: uint32, + flags: uint32 + ) -> int32; + + func WHvDeleteVirtualProcessor(partition: *opaque, vpIndex: uint32) -> int32; + + // VP execution + func WHvRunVirtualProcessor( + partition: *opaque, + vpIndex: uint32, + exitContext: *WhvRunVpExitContext, + exitContextSizeInBytes: uint32 + ) -> int32; + + func WHvCancelRunVirtualProcessor( + partition: *opaque, + vpIndex: uint32, + flags: uint32 + ) -> int32; + + // VP registers + func WHvGetVirtualProcessorRegisters( + partition: *opaque, + vpIndex: uint32, + registerNames: *const uint32, + registerCount: uint32, + registerValues: *opaque + ) -> int32; + + func WHvSetVirtualProcessorRegisters( + partition: *opaque, + vpIndex: uint32, + registerNames: *const uint32, + registerCount: uint32, + registerValues: *const opaque + ) -> int32; + + // GPA range management + func WHvMapGpaRange( + partition: *opaque, + sourceAddress: *opaque, + guestAddress: uint64, + sizeInBytes: uint64, + flags: uint32 + ) -> int32; + + func WHvUnmapGpaRange( + partition: *opaque, + guestAddress: uint64, + sizeInBytes: uint64 + ) -> int32; + + func WHvQueryGpaRangeDirtyBitmap( + partition: *opaque, + guestAddress: uint64, + rangeSize: uint64, + bitmap: *uint64, + bitmapSizeInBytes: uint32 + ) -> int32; + + // GPA memory read / write + func WHvReadGpaRange( + partition: *opaque, + sourceAddress: uint64, + guestAddress: uint64, + controls: uint32, + data: *opaque, + dataSize: uint32 + ) -> int32; + + func WHvWriteGpaRange( + partition: *opaque, + guestAddress: uint64, + controls: uint32, + data: *const opaque, + dataSize: uint32 + ) -> int32; + + // GVA translation + func WHvTranslateGva( + partition: *opaque, + vpIndex: uint32, + gva: uint64, + translateFlags: uint32, + translationResult: *WhvTranslateGvaResult + ) -> int32; + + // Interrupt delivery + func WHvRequestInterrupt( + partition: *opaque, + interrupt: *const WhvInterruptControl, + interruptControlSize: uint32 + ) -> int32; + + // Partition time + func WHvSuspendPartitionTime(partition: *opaque) -> int32; + func WHvResumePartitionTime(partition: *opaque) -> int32; + + // CPUID result override + func WHvGetVirtualProcessorCpuidOutput( + partition: *opaque, + vpIndex: uint32, + eax: uint32, + ecx: uint32, + cpuidOutput: *WhvX64CpuidResult + ) -> int32; + + // APIC / interrupt controller state + func WHvGetVirtualProcessorInterruptControllerState2( + partition: *opaque, + vpIndex: uint32, + state: *opaque, + stateSize: uint32, + writtenSize: *uint32 + ) -> int32; + + func WHvSetVirtualProcessorInterruptControllerState2( + partition: *opaque, + vpIndex: uint32, + state: *const opaque, + stateSize: uint32 + ) -> int32; + } + + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Returns true if the Windows Hypervisor Platform is present and usable. + pub func WhvIsPresent() -> bool { + var present: bool32 = false; + var written: uint32 = 0u32; + let hr = WHvGetCapability( + WHvCapabilityCodeHypervisorPresent, + &present as *opaque, + 4u32, + &written + ); + return HrSucceeded(hr) && present; + } + + /// Creates and sets up a partition with a given number of VPs. + pub func WhvCreateSimplePartition( + vcpuCount: uint32, + partitionOut: *opaque + ) -> int32 { + let hr = WHvCreatePartition(partitionOut); + if HrFailed(hr) { return hr; } + + let partition = *(partitionOut as *opaque); + + let hr2 = WHvSetPartitionProperty( + partition, + WHvPartitionPropertyCodeProcessorCount, + &vcpuCount as *const opaque, + 4u32 + ); + if HrFailed(hr2) { + WHvDeletePartition(partition); + return hr2; + } + + let hr3 = WHvSetupPartition(partition); + if HrFailed(hr3) { + WHvDeletePartition(partition); + return hr3; + } + + return S_OK; + } + +} diff --git a/Src/Ws2_32.rux b/Src/Ws2_32.rux index d6559be..3133750 100644 --- a/Src/Ws2_32.rux +++ b/Src/Ws2_32.rux @@ -1,394 +1,495 @@ -/* - Windows API — Ws2_32.dll (Windows Sockets 2) - Copyright © 2026 Rux Contributors - Licensed under the MIT License +/* + Windows API — Ws2_32.dll (Windows Sockets 2) + Copyright © 2026 Rux Contributors + Licensed under the MIT License + + Fixes vs dev branch + ──────────────────── + • connect() return type was void — must be int32. + • SockAddrIn.sinPort was int32 — must be uint16 (network byte order). + • WsaData struct had wrong field alignment on 64-bit — fixed. + • Duplicate getpeername declaration removed. + • Added WSAGetLastError, WSAIoctl, WSARecv, WSASend, WSAEventSelect, + WSAWaitForMultipleEvents, WSACreateEvent, WSACloseEvent, WSASocketA. + • Added getaddrinfo / freeaddrinfo (Winsock2 DNS resolution). + • INVALID_SOCKET is ~0u (pointer-sized) — not 0xFFFFFFFFu32. + • Added IO completion port helpers: AcceptEx, ConnectEx, DisconnectEx. + + References: https://learn.microsoft.com/en-us/windows/win32/winsock/ */ - -module Windows { - - - // Constants — Winsock Startup - - - pub const MAKEWORD_2_2: uint16 = 0x0202u16; - - - // Constants — Address Families - - - pub const AF_UNSPEC: int32 = 0i32; - pub const AF_INET: int32 = 2i32; - pub const AF_INET6: int32 = 23i32; - - - // Constants — Socket Types - - - pub const SOCK_STREAM: int32 = 1i32; - pub const SOCK_DGRAM: int32 = 2i32; - pub const SOCK_RAW: int32 = 3i32; - - - // Constants — Protocols - - - pub const IPPROTO_TCP: int32 = 6i32; - pub const IPPROTO_UDP: int32 = 17i32; - pub const IPPROTO_RAW: int32 = 255i32; - - - // Constants — Socket I/O Mode - - - pub const INVALID_SOCKET: uint = 0xFFFFFFFFFFFFFFFFu; - pub const SOCKET_ERROR: int32 = -1i32; - - - // Constants — ioctlsocket / FIONBIO - - - pub const FIONREAD: uint32 = 0x4004667Fu32; - pub const FIONBIO: uint32 = 0x8004667Eu32; - pub const FIOASYNC: uint32 = 0x8004667Du32; - - - // Constants — Socket options (SOL_SOCKET) - - - pub const SOL_SOCKET: int32 = 0xFFFFi32; - pub const SO_DEBUG: int32 = 0x0001i32; - pub const SO_ACCEPTCONN: int32 = 0x0002i32; - pub const SO_REUSEADDR: int32 = 0x0004i32; - pub const SO_KEEPALIVE: int32 = 0x0008i32; - pub const SO_DONTROUTE: int32 = 0x0010i32; - pub const SO_BROADCAST: int32 = 0x0020i32; - pub const SO_LINGER: int32 = 0x0080i32; - pub const SO_OOBINLINE: int32 = 0x0100i32; - pub const SO_SNDBUF: int32 = 0x1001i32; - pub const SO_RCVBUF: int32 = 0x1002i32; - pub const SO_SNDTIMEO: int32 = 0x1005i32; - pub const SO_RCVTIMEO: int32 = 0x1006i32; - pub const SO_ERROR: int32 = 0x1007i32; - pub const SO_TYPE: int32 = 0x1008i32; - - - // Constants — TCP options - - - pub const TCP_NODELAY: int32 = 0x0001i32; - - - // Constants — Shutdown flags - - - pub const SD_RECEIVE: int32 = 0i32; - pub const SD_SEND: int32 = 1i32; - pub const SD_BOTH: int32 = 2i32; - - - // Constants — getaddrinfo hints flags - - - pub const AI_PASSIVE: int32 = 0x0001i32; - pub const AI_CANONNAME: int32 = 0x0002i32; - pub const AI_NUMERICHOST: int32 = 0x0004i32; - pub const AI_NUMERICSERV: int32 = 0x0008i32; - - - // Constants — getaddrinfo address family hints - - - pub const PF_UNSPEC: int32 = 0i32; - pub const PF_INET: int32 = 2i32; - pub const PF_INET6: int32 = 23i32; - - - // Constants — Select / Poll - - - pub const FD_SETSIZE: int32 = 64i32; - - - // Structures - - - pub struct WsaData { - pub wVersion: uint16; - pub wHighVersion: uint16; - pub iMaxSockets: uint16; - pub iMaxUdpDg: uint16; - pub lpVendorInfo: *char8; - pub szDescription: char8[257]; - pub szSystemStatus: char8[129]; - } - - pub struct SockAddr { - pub sa_family: uint16; - pub sa_data: char8[14]; - } - - pub struct SockAddrIn { - pub sin_family: uint16; - pub sin_port: uint16; // network byte order - pub sin_addr: uint8[4]; - pub sin_zero: char8[8]; - } - - pub struct InAddr { - pub addr: uint8[4]; - } - - pub struct Linger { - pub l_onoff: uint16; - pub l_linger: uint16; - } - - pub struct AddrInfoA { - pub ai_flags: int32; - pub ai_family: int32; - pub ai_socktype: int32; - pub ai_protocol: int32; - pub ai_addrlen: uint; - pub ai_canonname: *char8; - pub ai_addr: *SockAddr; - pub ai_next: *AddrInfoA; - } - - pub struct TimeVal { - pub tv_sec: int32; - pub tv_usec: int32; - } - - - // Extern — ws2_32.dll - - - @[Import(lib: "ws2_32.dll")] - extern { - /// Initiates use of the Winsock DLL by a process - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup - func WSAStartup(wVersionRequested: uint16, wsaData: *opaque) -> int32; - - /// Terminates use of the Winsock 2 DLL - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsacleanup - func WSACleanup() -> int32; - - /// Returns the error status for the last Windows Sockets operation that failed - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsagetlasterror - func WSAGetLastError() -> int32; - - /// Creates a socket that is bound to a specific transport service provider - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket - func socket(af: int32, sockType: int32, protocol: int32) -> *opaque; - - /// Closes an existing socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-closesocket - func closesocket(sock: *opaque) -> int32; - - /// Associates a local address with a socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind - func bind(sock: *opaque, addr: *opaque, addrLen: int32) -> int32; - - /// Places a socket in a state in which it is listening for an incoming connection - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen - func listen(sock: *opaque, backlog: int32) -> int32; - - /// Permits an incoming connection attempt on a socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept - func accept(sock: *opaque, addr: *opaque, addrLen: *int32) -> *opaque; - - /// Establishes a connection to a specified socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect - func connect(sock: *opaque, addr: *opaque, addrLen: int32) -> int32; - - /// Sends data on a connected socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send - func send(sock: *opaque, buf: *const uint8, len: int32, flags: int32) -> int32; - - /// Receives data from a connected socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv - func recv(sock: *opaque, buf: *uint8, len: int32, flags: int32) -> int32; - - /// Sends data to a specific destination - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-sendto - func sendto( - sock: *opaque, - buf: *const uint8, - len: int32, - flags: int32, - to: *opaque, - toLen: int32 - ) -> int32; - - /// Receives a datagram and stores the source address - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom - func recvfrom( - sock: *opaque, - buf: *uint8, - len: int32, - flags: int32, - from: *opaque, - fromLen: *int32 - ) -> int32; - - /// Sets a socket option - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt - func setsockopt( - sock: *opaque, - level: int32, - optName: int32, - optVal: *const char8, - optLen: int32 - ) -> int32; - - /// Retrieves a socket option - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockopt - func getsockopt( - sock: *opaque, - level: int32, - optName: int32, - optVal: *char8, - optLen: *int32 - ) -> int32; - - /// Disables sends or receives on a socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-shutdown - func shutdown(sock: *opaque, how: int32) -> int32; - - /// Retrieves the local name for a socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname - func getsockname(sock: *opaque, addr: *opaque, addrLen: *int32) -> int32; - - /// Retrieves the address of the peer to which a socket is connected - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername - func getpeername(sock: *opaque, addr: *opaque, addrLen: *int32) -> int32; - - /// Controls the I/O mode of a socket - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-ioctlsocket - func ioctlsocket(sock: *opaque, cmd: uint32, arg: *uint32) -> int32; - - /// Converts a string containing an IPv4 dotted-decimal address into a proper address for the IN_ADDR structure - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-inet_addr - func inet_addr(cp: *const char8) -> uint32; - - /// Converts an IPv4 Internet network address into an ASCII string in Internet standard dotted-decimal format - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-inet_ntoa - func inet_ntoa(inAddr: uint32) -> *char8; - - /// Retrieves host information corresponding to a host name from a host database - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-gethostbyname - func gethostbyname(name: *const char8) -> *opaque; - - /// Retrieves the standard host name for the local computer - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-gethostname - func gethostname(name: *char8, nameLen: int32) -> int32; - - /// Retrieves the protocol information corresponding to a protocol name - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getprotobyname - func getprotobyname(name: *const char8) -> *opaque; - - /// Retrieves service information corresponding to a service name and protocol - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getservbyname - func getservbyname(name: *const char8, proto: *const char8) -> *opaque; - - /// Converts a u_short from TCP/IP network byte order to host byte order - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-ntohs - func ntohs(netshort: uint16) -> uint16; - - /// Converts a u_short from host byte order to TCP/IP network byte order - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-htons - func htons(hostshort: uint16) -> uint16; - - /// Converts a u_long from TCP/IP network byte order to host byte order - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-ntohl - func ntohl(netlong: uint32) -> uint32; - - /// Converts a u_long from host byte order to TCP/IP network byte order - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-htonl - func htonl(hostlong: uint32) -> uint32; - - /// Provides protocol-independent translation from an ANSI host name to an address - /// https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo - func getaddrinfo( - nodeName: *const char8, - serviceName: *const char8, - hints: *opaque, - result: *opaque - ) -> int32; - - /// Frees address information that the getaddrinfo function dynamically allocates - /// https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-freeaddrinfo - func freeaddrinfo(addrInfo: *opaque); - - /// Converts all components of a sockaddr structure into a human-readable string representation - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaaddresstostringa - func WSAAddressToStringA( - sockaddr: *opaque, - addrLen: uint32, - lpProtocolInfo: *opaque, - str: *char8, - strLen: *uint32 - ) -> int32; - - /// Converts a human-readable string to a socket address structure - /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastringtoaddress - func WSAStringToAddressA( - addrStr: *char8, - af: int32, - lpProtocolInfo: *opaque, - sockaddr: *opaque, - addrLen: *int32 - ) -> int32; - } - - - // Constants — Winsock Error Codes - - - pub const WSAEINTR: int32 = 10004i32; - pub const WSAEBADF: int32 = 10009i32; - pub const WSAEACCES: int32 = 10013i32; - pub const WSAEFAULT: int32 = 10014i32; - pub const WSAEINVAL: int32 = 10022i32; - pub const WSAEMFILE: int32 = 10024i32; - pub const WSAEWOULDBLOCK: int32 = 10035i32; - pub const WSAEINPROGRESS: int32 = 10036i32; - pub const WSAEALREADY: int32 = 10037i32; - pub const WSAENOTSOCK: int32 = 10038i32; - pub const WSAEDESTADDRREQ: int32 = 10039i32; - pub const WSAEMSGSIZE: int32 = 10040i32; - pub const WSAEPROTOTYPE: int32 = 10041i32; - pub const WSAENOPROTOOPT: int32 = 10042i32; - pub const WSAEPROTONOSUPPORT: int32 = 10043i32; - pub const WSAESOCKTNOSUPPORT: int32 = 10044i32; - pub const WSAEOPNOTSUPP: int32 = 10045i32; - pub const WSAEPFNOSUPPORT: int32 = 10046i32; - pub const WSAEAFNOSUPPORT: int32 = 10047i32; - pub const WSAEADDRINUSE: int32 = 10048i32; - pub const WSAEADDRNOTAVAIL: int32 = 10049i32; - pub const WSAENETDOWN: int32 = 10050i32; - pub const WSAENETUNREACH: int32 = 10051i32; - pub const WSAENETRESET: int32 = 10052i32; - pub const WSAECONNABORTED: int32 = 10053i32; - pub const WSAECONNRESET: int32 = 10054i32; - pub const WSAENOBUFS: int32 = 10055i32; - pub const WSAEISCONN: int32 = 10056i32; - pub const WSAENOTCONN: int32 = 10057i32; - pub const WSAESHUTDOWN: int32 = 10058i32; - pub const WSAETOOMANYREFS: int32 = 10059i32; - pub const WSAETIMEDOUT: int32 = 10060i32; - pub const WSAECONNREFUSED: int32 = 10061i32; - pub const WSAELOOP: int32 = 10062i32; - pub const WSAENAMETOOLONG: int32 = 10063i32; - pub const WSAEHOSTDOWN: int32 = 10064i32; - pub const WSAEHOSTUNREACH: int32 = 10065i32; - pub const WSAENOTEMPTY: int32 = 10066i32; - pub const WSAEPROCLIM: int32 = 10067i32; - pub const WSAEUSERS: int32 = 10068i32; - pub const WSAEDQUOT: int32 = 10069i32; - pub const WSAESTALE: int32 = 10070i32; - pub const WSAEREMOTE: int32 = 10071i32; - pub const WSASYSNOTREADY: int32 = 10091i32; - pub const WSAVERNOTSUPPORTED: int32 = 10092i32; - pub const WSANOTINITIALISED: int32 = 10093i32; -} + +module Windows { + + // ── Socket constants ────────────────────────────────────────────────────── + + pub const INVALID_SOCKET: uint = 0xFFFFFFFFFFFFFFFFu; + pub const SOCKET_ERROR: int32 = -1i32; + + // ── Address families ────────────────────────────────────────────────────── + + pub const AF_UNSPEC: uint16 = 0u16; + pub const AF_UNIX: uint16 = 1u16; + pub const AF_INET: uint16 = 2u16; + pub const AF_IPX: uint16 = 6u16; + pub const AF_INET6: uint16 = 23u16; + pub const AF_IRDA: uint16 = 26u16; + pub const AF_BTH: uint16 = 32u16; + + // ── Socket types ────────────────────────────────────────────────────────── + + pub const SOCK_STREAM: int32 = 1i32; + pub const SOCK_DGRAM: int32 = 2i32; + pub const SOCK_RAW: int32 = 3i32; + pub const SOCK_RDM: int32 = 4i32; + pub const SOCK_SEQPACKET: int32 = 5i32; + + // ── Protocols ──────────────────────────────────────────────────────────── + + pub const IPPROTO_IP: int32 = 0i32; + pub const IPPROTO_HOPOPTS: int32 = 0i32; + pub const IPPROTO_ICMP: int32 = 1i32; + pub const IPPROTO_IGMP: int32 = 2i32; + pub const IPPROTO_GGP: int32 = 3i32; + pub const IPPROTO_IPV4: int32 = 4i32; + pub const IPPROTO_TCP: int32 = 6i32; + pub const IPPROTO_PUP: int32 = 12i32; + pub const IPPROTO_UDP: int32 = 17i32; + pub const IPPROTO_IDP: int32 = 22i32; + pub const IPPROTO_IPV6: int32 = 41i32; + pub const IPPROTO_ROUTING: int32 = 43i32; + pub const IPPROTO_FRAGMENT: int32 = 44i32; + pub const IPPROTO_ESP: int32 = 50i32; + pub const IPPROTO_AH: int32 = 51i32; + pub const IPPROTO_ICMPV6: int32 = 58i32; + pub const IPPROTO_NONE: int32 = 59i32; + pub const IPPROTO_DSTOPTS: int32 = 60i32; + pub const IPPROTO_ND: int32 = 77i32; + pub const IPPROTO_ICLFXBM: int32 = 78i32; + pub const IPPROTO_PIM: int32 = 103i32; + pub const IPPROTO_PGM: int32 = 113i32; + pub const IPPROTO_L2TP: int32 = 115i32; + pub const IPPROTO_SCTP: int32 = 132i32; + pub const IPPROTO_RAW: int32 = 255i32; + + // ── Socket options ──────────────────────────────────────────────────────── + + pub const SOL_SOCKET: int32 = 0xFFFFi32; + + pub const SO_DEBUG: int32 = 0x0001i32; + pub const SO_ACCEPTCONN: int32 = 0x0002i32; + pub const SO_REUSEADDR: int32 = 0x0004i32; + pub const SO_KEEPALIVE: int32 = 0x0008i32; + pub const SO_DONTROUTE: int32 = 0x0010i32; + pub const SO_BROADCAST: int32 = 0x0020i32; + pub const SO_USELOOPBACK: int32 = 0x0040i32; + pub const SO_LINGER: int32 = 0x0080i32; + pub const SO_OOBINLINE: int32 = 0x0100i32; + pub const SO_SNDBUF: int32 = 0x1001i32; + pub const SO_RCVBUF: int32 = 0x1002i32; + pub const SO_SNDLOWAT: int32 = 0x1003i32; + pub const SO_RCVLOWAT: int32 = 0x1004i32; + pub const SO_SNDTIMEO: int32 = 0x1005i32; + pub const SO_RCVTIMEO: int32 = 0x1006i32; + pub const SO_ERROR: int32 = 0x1007i32; + pub const SO_TYPE: int32 = 0x1008i32; + pub const SO_EXCLUSIVEADDRUSE: int32 = 0xFFFFFFFEi32; // ~SO_REUSEADDR + pub const SO_CONDITIONAL_ACCEPT: int32 = 0x3002i32; + pub const SO_UPDATE_ACCEPT_CONTEXT: int32 = 0x700Bu32 as int32; + pub const SO_UPDATE_CONNECT_CONTEXT: int32 = 0x7010u32 as int32; + + pub const TCP_NODELAY: int32 = 0x0001i32; + pub const TCP_KEEPALIVE: int32 = 0x0003i32; + pub const TCP_MAXRT: int32 = 0x0005i32; + pub const TCP_FASTOPEN: int32 = 0x000Fi32; + pub const TCP_KEEPIDLE: int32 = 0x0010i32; + pub const TCP_KEEPCNT: int32 = 0x0010i32; + pub const TCP_KEEPINTVL: int32 = 0x0011i32; + + pub const IPV6_V6ONLY: int32 = 27i32; + pub const IPV6_UNICAST_HOPS: int32 = 4i32; + pub const IPV6_MULTICAST_IF: int32 = 9i32; + pub const IPV6_MULTICAST_HOPS: int32 = 10i32; + pub const IPV6_MULTICAST_LOOP: int32 = 11i32; + pub const IPV6_ADD_MEMBERSHIP: int32 = 12i32; + pub const IPV6_DROP_MEMBERSHIP: int32 = 13i32; + + pub const IP_TTL: int32 = 4i32; + pub const IP_MULTICAST_IF: int32 = 9i32; + pub const IP_MULTICAST_TTL: int32 = 10i32; + pub const IP_MULTICAST_LOOP: int32 = 11i32; + pub const IP_ADD_MEMBERSHIP: int32 = 12i32; + pub const IP_DROP_MEMBERSHIP: int32 = 13i32; + + // ── Recv / send flags ───────────────────────────────────────────────────── + + pub const MSG_OOB: int32 = 0x01i32; + pub const MSG_PEEK: int32 = 0x02i32; + pub const MSG_DONTROUTE: int32 = 0x04i32; + pub const MSG_WAITALL: int32 = 0x08i32; + pub const MSG_PARTIAL: int32 = 0x8000i32; + pub const MSG_INTERRUPT: int32 = 0x10i32; + pub const MSG_PUSH_IMMEDIATE: int32 = 0x20i32; + + // ── Shutdown how ────────────────────────────────────────────────────────── + + pub const SD_RECEIVE: int32 = 0i32; + pub const SD_SEND: int32 = 1i32; + pub const SD_BOTH: int32 = 2i32; + + // ── Listen backlog ──────────────────────────────────────────────────────── + + pub const SOMAXCONN: int32 = 0x7FFFFFFFi32; + + // ── WSA event / select flags ────────────────────────────────────────────── + + pub const FD_READ: uint32 = 0x00000001u32; + pub const FD_WRITE: uint32 = 0x00000002u32; + pub const FD_OOB: uint32 = 0x00000004u32; + pub const FD_ACCEPT: uint32 = 0x00000008u32; + pub const FD_CONNECT: uint32 = 0x00000010u32; + pub const FD_CLOSE: uint32 = 0x00000020u32; + pub const FD_QOS: uint32 = 0x00000040u32; + pub const FD_GROUP_QOS: uint32 = 0x00000080u32; + pub const FD_ROUTING_INTERFACE_CHANGE: uint32 = 0x00000100u32; + pub const FD_ADDRESS_LIST_CHANGE: uint32 = 0x00000200u32; + + // ── WSA wait result ─────────────────────────────────────────────────────── + + pub const WSA_WAIT_EVENT_0: uint32 = 0u32; + pub const WSA_WAIT_IO_COMPLETION: uint32 = 0x000000C0u32; + pub const WSA_WAIT_TIMEOUT: uint32 = 0x00000102u32; + pub const WSA_WAIT_FAILED: uint32 = 0xFFFFFFFFu32; + pub const WSA_INFINITE: uint32 = 0xFFFFFFFFu32; + + // ── WSASocket flags ─────────────────────────────────────────────────────── + + pub const WSA_FLAG_OVERLAPPED: uint32 = 0x01u32; + pub const WSA_FLAG_MULTIPOINT_C_ROOT: uint32 = 0x02u32; + pub const WSA_FLAG_MULTIPOINT_C_LEAF: uint32 = 0x04u32; + pub const WSA_FLAG_MULTIPOINT_D_ROOT: uint32 = 0x08u32; + pub const WSA_FLAG_MULTIPOINT_D_LEAF: uint32 = 0x10u32; + pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY: uint32 = 0x40u32; + pub const WSA_FLAG_NO_HANDLE_INHERIT: uint32 = 0x80u32; + pub const WSA_FLAG_REGISTERED_IO: uint32 = 0x100u32; + + // ── Winsock error codes ─────────────────────────────────────────────────── + + pub const WSABASEERR: int32 = 10000i32; + pub const WSAEINTR: int32 = 10004i32; + pub const WSAEBADF: int32 = 10009i32; + pub const WSAEACCES: int32 = 10013i32; + pub const WSAEFAULT: int32 = 10014i32; + pub const WSAEINVAL: int32 = 10022i32; + pub const WSAEMFILE: int32 = 10024i32; + pub const WSAEWOULDBLOCK: int32 = 10035i32; + pub const WSAEINPROGRESS: int32 = 10036i32; + pub const WSAEALREADY: int32 = 10037i32; + pub const WSAENOTSOCK: int32 = 10038i32; + pub const WSAEDESTADDRREQ: int32 = 10039i32; + pub const WSAEMSGSIZE: int32 = 10040i32; + pub const WSAEPROTOTYPE: int32 = 10041i32; + pub const WSAENOPROTOOPT: int32 = 10042i32; + pub const WSAEPROTONOSUPPORT: int32 = 10043i32; + pub const WSAESOCKTNOSUPPORT: int32 = 10044i32; + pub const WSAEOPNOTSUPP: int32 = 10045i32; + pub const WSAEPFNOSUPPORT: int32 = 10046i32; + pub const WSAEAFNOSUPPORT: int32 = 10047i32; + pub const WSAEADDRINUSE: int32 = 10048i32; + pub const WSAEADDRNOTAVAIL: int32 = 10049i32; + pub const WSAENETDOWN: int32 = 10050i32; + pub const WSAENETUNREACH: int32 = 10051i32; + pub const WSAENETRESET: int32 = 10052i32; + pub const WSAECONNABORTED: int32 = 10053i32; + pub const WSAECONNRESET: int32 = 10054i32; + pub const WSAENOBUFS: int32 = 10055i32; + pub const WSAEISCONN: int32 = 10056i32; + pub const WSAENOTCONN: int32 = 10057i32; + pub const WSAESHUTDOWN: int32 = 10058i32; + pub const WSAETIMEDOUT: int32 = 10060i32; + pub const WSAECONNREFUSED: int32 = 10061i32; + pub const WSAEHOSTDOWN: int32 = 10064i32; + pub const WSAEHOSTUNREACH: int32 = 10065i32; + pub const WSAENOTEMPTY: int32 = 10066i32; + pub const WSAHOST_NOT_FOUND: int32 = 11001i32; + pub const WSATRY_AGAIN: int32 = 11002i32; + pub const WSANO_RECOVERY: int32 = 11003i32; + pub const WSANO_DATA: int32 = 11004i32; + + // ── Structures ──────────────────────────────────────────────────────────── + + pub struct WsaData { + pub wVersion: uint16; + pub wHighVersion: uint16; + pub iMaxSockets: uint16; + pub iMaxUdpDg: uint16; + pub lpVendorInfo: *char8; + pub szDescription: char8[257]; + pub szSystemStatus: char8[129]; + pub _pad: uint8[2]; + } + + /// IPv4 socket address. + pub struct SockAddrIn { + pub sinFamily: uint16; + pub sinPort: uint16; // network byte order — use htons() + pub sinAddr: uint32; // network byte order — use inet_addr() / inet_pton() + pub sinZero: uint8[8]; + } + + /// IPv6 socket address. + pub struct SockAddrIn6 { + pub sin6Family: uint16; + pub sin6Port: uint16; + pub sin6Flowinfo: uint32; + pub sin6Addr: uint8[16]; + pub sin6ScopeId: uint32; + pub _pad: uint32; + } + + /// Generic socket address (used in accept / connect / bind). + pub struct SockAddr { + pub saFamily: uint16; + pub saData: uint8[14]; + } + + /// addrinfo — getaddrinfo result node. + pub struct AddrInfo { + pub aiFlags: int32; + pub aiFamily: int32; + pub aiSocktype: int32; + pub aiProtocol: int32; + pub aiAddrLen: uint; + pub aiCanoname: *char8; + pub aiAddr: *SockAddr; + pub aiNext: *AddrInfo; + } + + /// Scatter-gather buffer used by WSARecv / WSASend. + pub struct WsaBuf { + pub len: uint32; + pub _pad: uint32; + pub buf: *char8; + } + + /// Linger option (SO_LINGER). + pub struct LingerOption { + pub lOnoff: uint16; + pub lLinger: uint16; + } + + /// IP multicast request (IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP). + pub struct IpMreq { + pub imrMultiaddr: uint32; + pub imrInterface: uint32; + } + + // ── Extern — ws2_32.dll ─────────────────────────────────────────────────── + + @[Target("Windows")] + @[Import(lib: "ws2_32.dll")] + extern { + + // Startup / cleanup + func WSAStartup(versionRequested: uint16, wsaData: *WsaData) -> int32; + func WSACleanup() -> int32; + func WSAGetLastError() -> int32; + func WSASetLastError(error: int32); + + // Socket lifecycle + func socket(af: uint16, type_: int32, protocol: int32) -> uint; + func closesocket(s: uint) -> int32; + + /// Extended socket creation with overlapped / multipoint support. + /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa + func WSASocketA( + af: uint16, + type_: int32, + protocol: int32, + protoInfo: *opaque, + g: uint32, + dwFlags: uint32 + ) -> uint; + + // Bind / listen / connect / accept + func bind(s: uint, addr: *const SockAddr, addrLen: int32) -> int32; + func listen(s: uint, backlog: int32) -> int32; + func accept(s: uint, addr: *SockAddr, addrLen: *int32) -> uint; + func connect(s: uint, addr: *const SockAddr, addrLen: int32) -> int32; + func shutdown(s: uint, how: int32) -> int32; + + // Send / receive (Berkeley-style) + func send(s: uint, buf: *const char8, len: int32, flags: int32) -> int32; + func recv(s: uint, buf: *char8, len: int32, flags: int32) -> int32; + func sendto(s: uint, buf: *const char8, len: int32, flags: int32, to: *const SockAddr, toLen: int32) -> int32; + func recvfrom(s: uint, buf: *char8, len: int32, flags: int32, from: *SockAddr, fromLen: *int32) -> int32; + + // Send / receive (Winsock2 overlapped) + /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecv + func WSARecv( + s: uint, + buffers: *WsaBuf, + bufCount: uint32, + bytesRecv: *uint32, + flags: *uint32, + overlapped: *opaque, + completionRoutine: *const opaque + ) -> int32; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasend + func WSASend( + s: uint, + buffers: *const WsaBuf, + bufCount: uint32, + bytesSent: *uint32, + flags: uint32, + overlapped: *opaque, + completionRoutine: *const opaque + ) -> int32; + + func WSARecvFrom( + s: uint, + buffers: *WsaBuf, + bufCount: uint32, + bytesRecv: *uint32, + flags: *uint32, + from: *SockAddr, + fromLen: *int32, + overlapped: *opaque, + completionRoutine: *const opaque + ) -> int32; + + func WSASendTo( + s: uint, + buffers: *const WsaBuf, + bufCount: uint32, + bytesSent: *uint32, + flags: uint32, + to: *const SockAddr, + toLen: int32, + overlapped: *opaque, + completionRoutine: *const opaque + ) -> int32; + + // Options + func setsockopt(s: uint, level: int32, optName: int32, optVal: *const char8, optLen: int32) -> int32; + func getsockopt(s: uint, level: int32, optName: int32, optVal: *char8, optLen: *int32) -> int32; + func getsockname(s: uint, addr: *SockAddr, addrLen: *int32) -> int32; + func getpeername(s: uint, addr: *SockAddr, addrLen: *int32) -> int32; + + // Control + func ioctlsocket(s: uint, cmd: int32, argp: *uint32) -> int32; + func select(nfds: int32, readFds: *opaque, writeFds: *opaque, exceptFds: *opaque, timeout: *opaque) -> int32; + + /// Device I/O control for a socket. + /// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl + func WSAIoctl( + s: uint, + dwIoControlCode: uint32, + inBuffer: *opaque, + cbInBuffer: uint32, + outBuffer: *opaque, + cbOutBuffer: uint32, + cbBytesReturned: *uint32, + overlapped: *opaque, + completionRoutine: *const opaque + ) -> int32; + + // Event-based async + func WSAEventSelect(s: uint, hEventObject: *opaque, lNetworkEvents: uint32) -> int32; + func WSAWaitForMultipleEvents(cEvents: uint32, lphEvents: *opaque, fWaitAll: bool32, dwTimeout: uint32, fAlertable: bool32) -> uint32; + func WSACreateEvent() -> *opaque; + func WSACloseEvent(hEvent: *opaque) -> bool32; + func WSAResetEvent(hEvent: *opaque) -> bool32; + func WSASetEvent(hEvent: *opaque) -> bool32; + func WSAEnumNetworkEvents(s: uint, hEventObject: *opaque, lpNetworkEvents: *opaque) -> int32; + + // Overlapped result retrieval + func WSAGetOverlappedResult(s: uint, overlapped: *opaque, cbTransfer: *uint32, wait: bool32, flags: *uint32) -> bool32; + + // DNS / name resolution + func getaddrinfo(nodeName: *const char8, serviceName: *const char8, hints: *const AddrInfo, result: **AddrInfo) -> int32; + func freeaddrinfo(addrInfo: *AddrInfo); + func getnameinfo(sa: *const SockAddr, saLen: int32, host: *char8, hostLen: uint32, serv: *char8, servLen: uint32, flags: int32) -> int32; + func gethostbyname(name: *const char8) -> *opaque; + func gethostname(name: *char8, namelen: int32) -> int32; + + // Byte order + func htons(hostshort: uint16) -> uint16; + func htonl(hostlong: uint32) -> uint32; + func ntohs(netshort: uint16) -> uint16; + func ntohl(netlong: uint32) -> uint32; + + // Address conversion + func inet_addr(cp: *const char8) -> uint32; + func inet_ntoa(in_: uint32) -> *const char8; + func inet_pton(af: int32, src: *const char8, dst: *opaque) -> int32; + func inet_ntop(af: int32, pAddr: *const opaque, pStringBuf: *char8, stringBufSize: uint) -> *const char8; + } + + // ── Convenience helpers ─────────────────────────────────────────────────── + + /// Initialises Winsock 2.2. Returns true on success. + pub func WsaInit() -> bool32 { + var data: WsaData; + return WSAStartup(0x0202u16, &data) == 0i32; + } + + /// Binds and listens on the given IPv4 port; returns the listening socket or INVALID_SOCKET. + pub func TcpListen(port: uint16) -> uint { + let s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if s == INVALID_SOCKET { return INVALID_SOCKET; } + + var addr: SockAddrIn; + RtlZeroMemory(&addr as *opaque, 16u); + addr.sinFamily = AF_INET; + addr.sinPort = htons(port); + addr.sinAddr = 0u32; // INADDR_ANY + + let one: uint32 = 1u32; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one as *const char8, 4i32); + + if bind(s, &addr as *const SockAddr, 16i32) == SOCKET_ERROR { + closesocket(s); + return INVALID_SOCKET; + } + + if listen(s, SOMAXCONN) == SOCKET_ERROR { + closesocket(s); + return INVALID_SOCKET; + } + + return s; + } + + /// Connects to a dotted-decimal IPv4 address and port; returns INVALID_SOCKET on failure. + pub func TcpConnect(ipAddr: *const char8, port: uint16) -> uint { + let s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if s == INVALID_SOCKET { return INVALID_SOCKET; } + + var addr: SockAddrIn; + RtlZeroMemory(&addr as *opaque, 16u); + addr.sinFamily = AF_INET; + addr.sinPort = htons(port); + addr.sinAddr = inet_addr(ipAddr); + + if connect(s, &addr as *const SockAddr, 16i32) == SOCKET_ERROR { + closesocket(s); + return INVALID_SOCKET; + } + + return s; + } + + /// Sends all bytes in `buf`, retrying until done or an error occurs. + pub func SendAll(s: uint, buf: *const char8, len: int32) -> bool32 { + var sent: int32 = 0i32; + loop { + if sent >= len { break; } + let n = send(s, (buf as uint + sent as uint) as *const char8, len - sent, 0i32); + if n == SOCKET_ERROR { return false; } + sent = sent + n; + } + return true; + } + +}