system/windows
The Win32 calls the standard library needs.
Not the CRT: _write would be the shorter road, but it is an emulation layer
over these, and going through it means inheriting its buffering and its
descriptor table for no gain.
Types
Handle :: CPointer A Win32 HANDLE: an opaque kernel object, never dereferenced.
Coord :: struct COORD: a console cell position or size.
Field names are the C ones because a mirror copies BY NAME; the snake_case rule does not reach across the boundary.
Fields
X: i16 Y: i16 SmallRect :: struct SMALL_RECT: an inclusive rectangle of console cells.
Fields
Left: i16 Top: i16 Right: i16 Bottom: i16 ScreenBufferInfo :: struct CONSOLE_SCREEN_BUFFER_INFO. Mirrored WHOLE rather than as a prefix: every
member but wAttributes is itself a struct, so a prefix would have to stop
before the one that matters.
SecurityAttributes :: struct SECURITY_ATTRIBUTES, mirrored for the two members a pipe needs.
EVERY member, in order, not a prefix of the useful ones. The interpreter
lays a mirror out from its DECLARED fields alone, at natural alignment from
zero, so skipping lpSecurityDescriptor put bInheritHandle at 4 where C
has it at 16: the callee read a zero, made the pipe non-inheritable, and
reported success. Native was unaffected (the shim copies by name) which is
exactly what kept it invisible. The offset _Static_assert catches it now.
lpSecurityDescriptor is a u64 because it is RESERVED, never read: it
only has to occupy its eight bytes and stay zero, which is the NULL the call
wants.
Fields
nLength: u32 lpSecurityDescriptor: u64 bInheritHandle: i32 StartupInfo :: struct STARTUPINFOA, mirrored for the members a redirected child needs.
EVERY member up to hStdError, for the reason spelled out on
SecurityAttributes: eleven precede dwFlags in the real struct, and
naming only the useful ones put every one of them at the wrong offset in the
interpreter's block.
The reserved ones are machine words that stay zero, which is what
CreateProcess expects of a plain console child. cb must be
sizeof(STARTUPINFOA) (104 on x86_64) and is the one member the callee
validates.
Fields
cb: u32 lpReserved: u64 lpDesktop: u64 lpTitle: u64 dwX: u32 dwY: u32 dwXSize: u32 dwYSize: u32 dwXCountChars: u32 dwYCountChars: u32 dwFillAttribute: u32 dwFlags: u32 wShowWindow: u16 cbReserved2: u16 lpReserved2: u64 hStdInput: Handle hStdOutput: Handle hStdError: Handle ProcessInformation :: struct PROCESS_INFORMATION: what CreateProcess hands back.
Functions
get_active_processor_count :: fn(group: u16) -> u32 GetActiveProcessorCount. Logical processors active in group; 0 on
failure.
Parameters
| group | u16 | a processor group, or ALL_PROCESSOR_GROUPS. |
Returns
u32 get_module_file_name :: fn(module: CPointer | null, @c_out buf: u16[], size: u32) -> u32 GetModuleFileNameW. Writes the running module's path into buf and
returns its length; 0 on failure, or size exactly when it was truncated.
Parameters
| module | CPointer | null | null for the running executable. |
| buf | u16[] | No description. |
| size | u32 | No description. |
Returns
u32 get_current_directory :: fn(size: u32, @c_out buf: u16[]) -> u32 GetCurrentDirectoryW. Writes the working directory into buf and returns
its length; 0 on failure, or a length >= size when buf is too small.
Parameters
| size | u32 | buf's capacity in UTF-16 UNITS, not bytes. |
| buf | u16[] | receives the path, NUL-terminated. |
Returns
u32 set_current_directory :: fn(path: u16[]) -> i32 SetCurrentDirectoryW. Zero on failure.
Parameters
| path | u16[] | the new working directory, NUL-terminated UTF-16. |
Returns
i32 non-zero on success.get_temp_path :: fn(size: u32, @c_out buf: u16[]) -> u32 GetTempPathW. Writes the temp directory, trailing backslash included, into
buf. Returns its length, 0 on failure, or a length >= size when buf is
too small: in both of which cases nothing usable was written.
Parameters
| size | u32 | buf's capacity in UTF-16 UNITS, not bytes. |
| buf | u16[] | receives the path, NUL-terminated. |
Returns
u32 UTF-16 units written, excluding the NUL.create_directory :: fn(path: u16[], security: CPointer | null) -> bool CreateDirectoryW. False on failure, ERROR_ALREADY_EXISTS included: the
caller re-tests the path rather than reading GetLastError.
Parameters
| path | u16[] | directory to create. |
| security | CPointer | null | lpSecurityAttributes; null for the default descriptor. |
Returns
bool get_file_attributes_ex :: fn(path: u16[], level: i32, @c_out data: u32[]) -> bool GetFileAttributesExW. False when the path cannot be queried.
data crosses as the nine DWORDs of a WIN32_FILE_ATTRIBUTE_DATA, which
has no padding : ftLastWriteTime is cells 5 (low half) and 6 (high half).
Parameters
| path | u16[] | the path to query. |
| level | i32 | always GET_FILE_EX_INFO_STANDARD. |
| data | u32[] | receives the attribute data ; nine cells at least. |
Returns
bool whether the query succeeded.get_file_attributes :: fn(path: u16[]) -> u32 GetFileAttributesW. INVALID_FILE_ATTRIBUTES when the path cannot be
queried, which is how existence is tested, there being no access here.
Parameters
| path | u16[] | the path to query. |
Returns
u32 the attribute bitmask, or INVALID_FILE_ATTRIBUTES.delete_file :: fn(path: u16[]) -> i32 DeleteFileW. Zero on failure. Refuses a directory outright, which is the
behaviour std/io::remove_file promises.
Parameters
| path | u16[] | the file to delete. |
Returns
i32 non-zero on success.get_last_error :: fn() -> u32 GetLastError. The calling thread's last Win32 error code.
⚠️ Read it IMMEDIATELY after the call that failed: any Win32 call in between may overwrite it.
Returns
u32 the raw Win32 code ; 0 when nothing has failed.write_file :: fn(h: Handle, buf: u8[], count: u32, @c_out written: u32[], overlapped: CPointer | null) -> bool WriteFile. False on failure: the caller reads GetLastError.
written is Win32's lpNumberOfBytesWritten, which a synchronous call may
NOT pass as null.
written is a one-element array so the count READS BACK, the same shape
read_file uses. A @c_pointer scalar would not: the callee writes through
it and the value is discarded.
Parameters
| h | Handle | the device handle. |
| buf | u8[] | the bytes to write. |
| count | u32 | how many of them. |
| written | u32[] | scratch the callee fills with the byte count; unread. |
| overlapped | CPointer | null | always null here: this is the synchronous form. |
Returns
bool whether the write succeeded.multi_byte_to_wide_char :: fn(code_page: u32, flags: u32, src: string, src_len: i32, @c_out dst: u16[], dst_len: i32) -> i32 MultiByteToWideChar. With src_len of -1 the input is read up to its NUL
and the terminator is written too, so the result is usable as LPCWSTR.
Parameters
| code_page | u32 | No description. |
| flags | u32 | No description. |
| src | string | No description. |
| src_len | i32 | No description. |
| dst | u16[] | receives the UTF-16 units; may be empty when dst_len is 0. |
| dst_len | i32 | dst's capacity in UTF-16 units, or 0 to measure. |
Returns
i32 units written (or required, when measuring); 0 on failure.wide_char_to_multi_byte :: fn(code_page: u32, flags: u32, src: u16[], src_len: i32, @c_out dst: u8[], dst_len: i32, default_char: CPointer | null, used_default: CPointer | null) -> i32 WideCharToMultiByte. The two trailing lpDefaultChar / lpUsedDefaultChar
arguments must be null for CP_UTF8; Windows fails the call otherwise.
Parameters
| code_page | u32 | No description. |
| flags | u32 | No description. |
| src | u16[] | No description. |
| src_len | i32 | units to read, or -1 for a NUL-terminated input. |
| dst | u8[] | No description. |
| dst_len | i32 | dst's capacity in bytes, or 0 to measure. |
| default_char | CPointer | null | No description. |
| used_default | CPointer | null | No description. |
Returns
i32 bytes written (or required, when measuring); 0 on failure.create_file_w :: fn(path: u16[], access: u32, share: u32, security: CPointer | null, disposition: u32, flags: u32, template: CPointer | null) -> Handle CreateFileW. Returns INVALID_HANDLE_VALUE on failure: test it with
i64(h) == INVALID_HANDLE, never against null.
Unlike fopen there is no text mode, so nothing ever rewrites a \n.
Parameters
| path | u16[] | UTF-16, NUL-terminated. Prefix \\?\\ to pass MAX_PATH. |
| access | u32 | No description. |
| share | u32 | No description. |
| security | CPointer | null | lpSecurityAttributes; null for the default descriptor. |
| disposition | u32 | No description. |
| flags | u32 | No description. |
| template | CPointer | null | hTemplateFile; always null here. |
Returns
find_first_file :: fn(pattern: u16[], @c_out data: u8[]) -> Handle FindFirstFileW. The pattern is a directory path with \* appended.
Returns INVALID_HANDLE_VALUE on failure: test it with
i64(h) == INVALID_HANDLE, never against null.
Parameters
| pattern | u16[] | a NUL-terminated UTF-16 glob, from to_wide. |
| data | u8[] | FIND_DATA_BYTES of scratch the callee fills. |
Returns
Handle a search handle.find_data_name :: fn(data: u8[]) -> string The cFileName of a filled WIN32_FIND_DATAW, as a Vader string.
The Windows twin of system/posix::dirent_name, and it exists for the same
reason: reading a NAMED member of a C struct is the one step a Vader FFI call
cannot take for itself. It has to be a CALL, not a read of the struct: the
interpreter has no C layout but resolves an @extern by name out of the
running process. It carries the UTF-16 to UTF-8 conversion with it.
The bytes are valid until the next call, which is also cFileName's own
contract: find_next_file overwrites it. The shim interns before either.
Parameters
| data | u8[] | the buffer find_first_file filled. |
Returns
string the entry name.get_console_screen_buffer_info :: fn(h: Handle, @c_pointer @c_out info: ScreenBufferInfo) -> bool GetConsoleScreenBufferInfo. False when the handle is not a console.
srWindow is the VISIBLE window, which is what a width should be measured
from: the buffer (dwSize) is often far wider, and wrapping follows what is
on screen.
Parameters
| h | Handle | No description. |
| info | ScreenBufferInfo | No description. |
Returns
bool peek_named_pipe :: fn(h: Handle, buf: CPointer | null, size: u32, read: CPointer | null, @c_out available: u32[], message: CPointer | null) -> bool PeekNamedPipe. Reports how many bytes are readable WITHOUT consuming them.
It works on an anonymous pipe too, despite the name, which is what makes it the console-less way to ask "is there input". False when the handle is not a pipe (a console, a redirected file) or the peer closed it; a caller reads that as "go ahead and read", never as "idle".
Parameters
| h | Handle | No description. |
| buf | CPointer | null | always null here: we ask for the COUNT, not the bytes. |
| size | u32 | No description. |
| read | CPointer | null | always null, for the same reason. |
| available | u32[] | receives the byte count; a one-element array so it reads back. |
| message | CPointer | null | always null: only a message-mode pipe uses it. |
Returns
bool sleep_ms :: fn(ms: u32) -> void Sleep. Milliseconds, and it is the only wait Win32 offers without a handle.
Parameters
| ms | u32 | No description. |
create_pipe :: fn(@c_out read_end: u64[], @c_out write_end: u64[], @c_pointer attrs: SecurityAttributes, size: u32) -> bool CreatePipe.
The two ends are separate HANDLE* out-parameters, not one struct, so each
is its own one-word buffer. Read the handle back with ptr_at.
Parameters
| read_end | u64[] | a one-word buffer receiving the read end. |
| write_end | u64[] | a one-word buffer receiving the write end. |
| attrs | SecurityAttributes | a SecurityAttributes with bInheritHandle set. |
| size | u32 | suggested buffer size; 0 for the default. |
Returns
bool ptr_at :: fn(base: u64[], i: i64) -> Handle The i-th pointer-sized word of a lent buffer, as a handle.
CPointer cannot be built from an integer (T3010) and a lent array yields
integers, so a HANDLE an out-parameter wrote is otherwise unreachable.
Parameters
| base | u64[] | the buffer the callee filled. |
| i | i64 | the word index. |
Returns
set_handle_information :: fn(h: Handle, mask: u32, flags: u32) -> bool SetHandleInformation. Used to CLEAR the inherit flag on a pipe's read end.
The pipe is created inheritable so the child receives its write end; without this the child (and every sibling launched after it) also receives the READ ends, which are the parent's alone.
Parameters
| h | Handle | the handle to adjust. |
| mask | u32 | which flags to touch, HANDLE_FLAG_INHERIT here. |
| flags | u32 | their new value; 0 to clear. |
Returns
bool create_process :: fn(application: CPointer | null, @c_out command_line: u8[], proc_attrs: CPointer | null, thread_attrs: CPointer | null, inherit: bool, flags: u32, environment: CPointer | null, directory: CPointer | null, @c_pointer startup: StartupInfo, @c_pointer @c_out info: ProcessInformation) -> bool CreateProcessA. Launches command_line, inheriting the handles named in
startup.
The ANSI form: the argument vector is one command line by then, and the wide form would need it widened for nothing the child can see.
Parameters
| application | CPointer | null | null: the program is the first word of the line. |
| command_line | u8[] | the whole command line, which the callee MODIFIES. |
| proc_attrs | CPointer | null | null. |
| thread_attrs | CPointer | null | null. |
| inherit | bool | true, so the child receives the pipe ends. |
| flags | u32 | 0. |
| environment | CPointer | null | null: inherit the parent's. |
| directory | CPointer | null | null: inherit the parent's. |
| startup | StartupInfo | the redirected handles. |
| info | ProcessInformation | filled with the child's handles and ids. |
Returns
bool get_console_mode :: fn(h: Handle, @c_out mode: u32[]) -> bool GetConsoleMode. False when the handle is not a console, which is also how
a caller tests for one, a redirected stream having no mode to read.
Parameters
| h | Handle | No description. |
| mode | u32[] | receives the current mode; a one-element array so it reads back. |
Returns
bool write_console_w :: fn(h: Handle, text: u16[], count: u32, @c_out written: u32[], reserved: CPointer | null) -> bool WriteConsoleW: UTF-16 text to a console, which renders it whatever its code
page. False on failure, and on a handle that is not a console.
Parameters
| h | Handle | a console output handle. |
| text | u16[] | the UTF-16 units to write. |
| count | u32 | how many of them. |
| written | u32[] | scratch the callee fills with the units written; unread. |
| reserved | CPointer | null | always null. |
Returns
bool whether the write succeeded.read_console_w :: fn(h: Handle, @c_out text: u16[], count: u32, @c_out read: u32[], control: CPointer | null) -> bool ReadConsoleW: what was typed at a console, as UTF-16 whatever its code
page. False on failure, and on a handle that is not a console.
Parameters
| h | Handle | a console input handle. |
| text | u16[] | receives the UTF-16 units. |
| count | u32 | text's capacity in units. |
| read | u32[] | receives how many units were read. |
| control | CPointer | null | always null: no early wake-up on a control character. |
Returns
bool whether the read succeeded.read_file :: fn(h: Handle, @c_out buf: u8[], count: u32, @c_out read: u32[], overlapped: CPointer | null) -> bool ReadFile. False on failure; a synchronous read returning true with read
short of count has reached end of file.
Parameters
| h | Handle | No description. |
| buf | u8[] | No description. |
| count | u32 | No description. |
| read | u32[] | receives the byte count; a one-element array so it reads back: Win32 forbids null here on a synchronous call. |
| overlapped | CPointer | null | always null: this is the synchronous form. |
Returns
bool get_final_path_name_by_handle_w :: fn(h: Handle, @c_out buf: u16[], size: u32, flags: u32) -> u32 GetFinalPathNameByHandleW. Writes the path of the file h names, links
followed and NUL-terminated, into buf.
Parameters
| h | Handle | No description. |
| buf | u16[] | No description. |
| size | u32 | buf's capacity in UTF-16 UNITS, not bytes. |
| flags | u32 | VOLUME_NAME_DOS for a path that starts with a drive letter, behind the \\?\ prefix. |
Returns
u32 UTF-16 units written, excluding the NUL; 0 on failure, more than size (the capacity needed) when buf is too small.get_system_time_precise_as_file_time :: fn(@c_out ft: i64[]) -> void GetSystemTimePreciseAsFileTime. Fills ft with 100-ns ticks since 1601.
Parameters
| ft | i64[] | No description. |
query_performance_counter :: fn(@c_out counter: i64[]) -> bool QueryPerformanceCounter. Fills counter; false on failure.
Parameters
| counter | i64[] | No description. |
Returns
bool query_performance_frequency :: fn(@c_out freq: i64[]) -> bool QueryPerformanceFrequency. Fills freq with counts per second; false on failure.
Parameters
| freq | i64[] | No description. |
Returns
bool Constants
STD_OUTPUT_HANDLE: u32: 0xFFFF_FFF5 nStdHandle selectors. DWORD is unsigned, so the negative constants are
written in their two's-complement form.
STD_ERROR_HANDLE: u32: 0xFFFF_FFF4 See STD_OUTPUT_HANDLE.
STD_INPUT_HANDLE: u32: 0xFFFF_FFF6 See STD_OUTPUT_HANDLE.
ALL_PROCESSOR_GROUPS: u16: 0xFFFF ALL_PROCESSOR_GROUPS: asks GetActiveProcessorCount for every group, not
just the caller's (a group holds at most 64 processors).
FILE_ATTRIBUTE_DIRECTORY: u32: 0x10 FILE_ATTRIBUTE_DIRECTORY: set when the entry is a directory.
INVALID_FILE_ATTRIBUTES: u32: 0xFFFF_FFFF What GetFileAttributesW returns for a path it cannot query.
GET_FILE_EX_INFO_STANDARD: i32: 0 GetFileExInfoStandard, the GET_FILEEX_INFO_LEVELS that fills a
WIN32_FILE_ATTRIBUTE_DATA.
ERROR_FILE_NOT_FOUND: u32: 2 Win32 error codes std/io classifies. Unlike errno these are stable
across Windows versions, so they are plain literals.
ERROR_PATH_NOT_FOUND: u32: 3 ERROR_ACCESS_DENIED: u32: 5 ERROR_INVALID_HANDLE: u32: 6 ERROR_FILE_EXISTS: u32: 80 ERROR_BROKEN_PIPE: u32: 109 ERROR_DISK_FULL: u32: 112 ERROR_DIR_NOT_EMPTY: u32: 145 ERROR_ALREADY_EXISTS: u32: 183 CP_UTF8: u32: 65001 CP_UTF8: the code page identifier for UTF-8.
INVALID_HANDLE: i64: -1 INVALID_HANDLE_VALUE, as the integer i64(handle) yields. Win32 reports a
failed CreateFileW with this and NOT with NULL, which is why the handle is
tested through i64 rather than a CPointer | null.
GENERIC_READ: u32: 0x8000_0000 dwDesiredAccess bits.
GENERIC_WRITE: u32: 0x4000_0000 See GENERIC_READ.
FILE_SHARE_READ: u32: 0x1 dwShareMode: let other readers in while we hold the file.
FILE_SHARE_WRITE: u32: 0x2 See FILE_SHARE_READ.
FILE_SHARE_DELETE: u32: 0x4 See FILE_SHARE_READ: let a rename or a delete in too.
CREATE_ALWAYS: u32: 2 dwCreationDisposition: truncate an existing file, create it otherwise.
OPEN_EXISTING: u32: 3 See CREATE_ALWAYS: open only what already exists.
FILE_ATTRIBUTE_NORMAL: u32: 0x80 dwFlagsAndAttributes: no special semantics.
FILE_FLAG_BACKUP_SEMANTICS: u32: 0x0200_0000 dwFlagsAndAttributes: open a directory as well as a file.
FIND_DATA_BYTES: i64: 1024 Bytes to reserve for a WIN32_FIND_DATAW.
An OPAQUE buffer: Vader never looks inside it, FindFirstFileW fills it and
find_data_name reads the one member a listing needs. Nothing checks this
number (the callee writes sizeof(WIN32_FIND_DATAW) bytes whatever it says)
so it is taken HIGH on purpose. The real size is 592 on x86_64 (measured
against the mingw headers, and it is 320 for the ANSI twin); over-reserving
wastes a few hundred bytes on the stack, under-reserving corrupts.
⚠️ Do NOT narrow this to what one toolchain reports.
STARTF_USESTDHANDLES: u32: 0x0100 STARTF_USESTDHANDLES: hStdInput / hStdOutput / hStdError are used.
WAIT_OBJECT_0: u32: 0 WAIT_OBJECT_0: the object is signalled, i.e. the process has exited.
INFINITE: u32: 0xFFFF_FFFF INFINITE: a wait with no timeout.
HANDLE_FLAG_INHERIT: u32: 1 HANDLE_FLAG_INHERIT.
ENABLE_PROCESSED_INPUT: u32: 0x0001 Console INPUT mode bits raw mode turns off (line buffering, echo, and the translation of Ctrl-C into a signal) plus the one it turns on, so escape sequences arrive as bytes.
ENABLE_LINE_INPUT: u32: 0x0002 ENABLE_ECHO_INPUT: u32: 0x0004 ENABLE_VIRTUAL_TERMINAL_INPUT: u32: 0x0200 ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32: 0x0004 Bit enabling ANSI escape interpretation on a console output handle. Only with it set do escapes render rather than print literally.
FILE_TYPE_DISK: u32: 0x0001 What get_file_type answers for a file on disk.
VOLUME_NAME_DOS: u32: 0x0 See get_final_path_name_by_handle_w: a volume named by its drive letter.