zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 010bbcd0 (203982B) - Raw


      1 //! This file contains thin wrappers around Windows-specific APIs, with these
      2 //! specific goals in mind:
      3 //! * Convert "errno"-style error codes into Zig errors.
      4 //! * When null-terminated or WTF16LE byte buffers are required, provide APIs which accept
      5 //!   slices as well as APIs which accept null-terminated WTF16LE byte buffers.
      6 
      7 const builtin = @import("builtin");
      8 const std = @import("../std.zig");
      9 const mem = std.mem;
     10 const assert = std.debug.assert;
     11 const math = std.math;
     12 const maxInt = std.math.maxInt;
     13 const native_arch = builtin.cpu.arch;
     14 const UnexpectedError = std.posix.UnexpectedError;
     15 
     16 test {
     17     if (builtin.os.tag == .windows) {
     18         _ = @import("windows/test.zig");
     19     }
     20 }
     21 
     22 pub const advapi32 = @import("windows/advapi32.zig");
     23 pub const kernel32 = @import("windows/kernel32.zig");
     24 pub const ntdll = @import("windows/ntdll.zig");
     25 pub const ws2_32 = @import("windows/ws2_32.zig");
     26 pub const crypt32 = @import("windows/crypt32.zig");
     27 pub const nls = @import("windows/nls.zig");
     28 
     29 pub const self_process_handle = @as(HANDLE, @ptrFromInt(maxInt(usize)));
     30 
     31 const Self = @This();
     32 
     33 pub const OpenError = error{
     34     IsDir,
     35     NotDir,
     36     FileNotFound,
     37     NoDevice,
     38     AccessDenied,
     39     PipeBusy,
     40     PathAlreadyExists,
     41     Unexpected,
     42     NameTooLong,
     43     WouldBlock,
     44     NetworkNotFound,
     45     AntivirusInterference,
     46     BadPathName,
     47 };
     48 
     49 pub const OpenFileOptions = struct {
     50     access_mask: ACCESS_MASK,
     51     dir: ?HANDLE = null,
     52     sa: ?*SECURITY_ATTRIBUTES = null,
     53     share_access: ULONG = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
     54     creation: ULONG,
     55     /// If true, tries to open path as a directory.
     56     /// Defaults to false.
     57     filter: Filter = .file_only,
     58     /// If false, tries to open path as a reparse point without dereferencing it.
     59     /// Defaults to true.
     60     follow_symlinks: bool = true,
     61 
     62     pub const Filter = enum {
     63         /// Causes `OpenFile` to return `error.IsDir` if the opened handle would be a directory.
     64         file_only,
     65         /// Causes `OpenFile` to return `error.NotDir` if the opened handle would be a file.
     66         dir_only,
     67         /// `OpenFile` does not discriminate between opening files and directories.
     68         any,
     69     };
     70 };
     71 
     72 pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HANDLE {
     73     if (mem.eql(u16, sub_path_w, &[_]u16{'.'}) and options.filter == .file_only) {
     74         return error.IsDir;
     75     }
     76     if (mem.eql(u16, sub_path_w, &[_]u16{ '.', '.' }) and options.filter == .file_only) {
     77         return error.IsDir;
     78     }
     79 
     80     var result: HANDLE = undefined;
     81 
     82     const path_len_bytes = math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
     83     var nt_name = UNICODE_STRING{
     84         .Length = path_len_bytes,
     85         .MaximumLength = path_len_bytes,
     86         .Buffer = @constCast(sub_path_w.ptr),
     87     };
     88     var attr = OBJECT_ATTRIBUTES{
     89         .Length = @sizeOf(OBJECT_ATTRIBUTES),
     90         .RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(sub_path_w)) null else options.dir,
     91         .Attributes = if (options.sa) |ptr| blk: { // Note we do not use OBJ_CASE_INSENSITIVE here.
     92             const inherit: ULONG = if (ptr.bInheritHandle == TRUE) OBJ_INHERIT else 0;
     93             break :blk inherit;
     94         } else 0,
     95         .ObjectName = &nt_name,
     96         .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null,
     97         .SecurityQualityOfService = null,
     98     };
     99     var io: IO_STATUS_BLOCK = undefined;
    100     const blocking_flag: ULONG = FILE_SYNCHRONOUS_IO_NONALERT;
    101     const file_or_dir_flag: ULONG = switch (options.filter) {
    102         .file_only => FILE_NON_DIRECTORY_FILE,
    103         .dir_only => FILE_DIRECTORY_FILE,
    104         .any => 0,
    105     };
    106     // If we're not following symlinks, we need to ensure we don't pass in any synchronization flags such as FILE_SYNCHRONOUS_IO_NONALERT.
    107     const flags: ULONG = if (options.follow_symlinks) file_or_dir_flag | blocking_flag else file_or_dir_flag | FILE_OPEN_REPARSE_POINT;
    108 
    109     while (true) {
    110         const rc = ntdll.NtCreateFile(
    111             &result,
    112             options.access_mask,
    113             &attr,
    114             &io,
    115             null,
    116             FILE_ATTRIBUTE_NORMAL,
    117             options.share_access,
    118             options.creation,
    119             flags,
    120             null,
    121             0,
    122         );
    123         switch (rc) {
    124             .SUCCESS => return result,
    125             .OBJECT_NAME_INVALID => return error.BadPathName,
    126             .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
    127             .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
    128             .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
    129             .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
    130             .NO_MEDIA_IN_DEVICE => return error.NoDevice,
    131             .INVALID_PARAMETER => unreachable,
    132             .SHARING_VIOLATION => return error.AccessDenied,
    133             .ACCESS_DENIED => return error.AccessDenied,
    134             .PIPE_BUSY => return error.PipeBusy,
    135             .OBJECT_PATH_SYNTAX_BAD => unreachable,
    136             .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
    137             .FILE_IS_A_DIRECTORY => return error.IsDir,
    138             .NOT_A_DIRECTORY => return error.NotDir,
    139             .USER_MAPPED_FILE => return error.AccessDenied,
    140             .INVALID_HANDLE => unreachable,
    141             .DELETE_PENDING => {
    142                 // This error means that there *was* a file in this location on
    143                 // the file system, but it was deleted. However, the OS is not
    144                 // finished with the deletion operation, and so this CreateFile
    145                 // call has failed. There is not really a sane way to handle
    146                 // this other than retrying the creation after the OS finishes
    147                 // the deletion.
    148                 std.time.sleep(std.time.ns_per_ms);
    149                 continue;
    150             },
    151             .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference,
    152             else => return unexpectedStatus(rc),
    153         }
    154     }
    155 }
    156 
    157 pub fn GetCurrentProcess() HANDLE {
    158     const process_pseudo_handle: usize = @bitCast(@as(isize, -1));
    159     return @ptrFromInt(process_pseudo_handle);
    160 }
    161 
    162 pub fn GetCurrentProcessId() DWORD {
    163     return @truncate(@intFromPtr(teb().ClientId.UniqueProcess));
    164 }
    165 
    166 pub fn GetCurrentThread() HANDLE {
    167     const thread_pseudo_handle: usize = @bitCast(@as(isize, -2));
    168     return @ptrFromInt(thread_pseudo_handle);
    169 }
    170 
    171 pub fn GetCurrentThreadId() DWORD {
    172     return @truncate(@intFromPtr(teb().ClientId.UniqueThread));
    173 }
    174 
    175 pub fn GetLastError() Win32Error {
    176     return @enumFromInt(teb().LastErrorValue);
    177 }
    178 
    179 pub const CreatePipeError = error{ Unexpected, SystemResources };
    180 
    181 var npfs: ?HANDLE = null;
    182 
    183 /// A Zig wrapper around `NtCreateNamedPipeFile` and `NtCreateFile` syscalls.
    184 /// It implements similar behavior to `CreatePipe` and is meant to serve
    185 /// as a direct substitute for that call.
    186 pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {
    187     // Up to NT 5.2 (Windows XP/Server 2003), `CreatePipe` would generate a pipe similar to:
    188     //
    189     //      \??\pipe\Win32Pipes.{pid}.{count}
    190     //
    191     // where `pid` is the process id and count is a incrementing counter.
    192     // The implementation was changed after NT 6.0 (Vista) to open a handle to the Named Pipe File System
    193     // and use that as the root directory for `NtCreateNamedPipeFile`.
    194     // This object is visible under the NPFS but has no filename attached to it.
    195     //
    196     // This implementation replicates how `CreatePipe` works in modern Windows versions.
    197     const opt_dev_handle = @atomicLoad(?HANDLE, &npfs, .seq_cst);
    198     const dev_handle = opt_dev_handle orelse blk: {
    199         const str = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\NamedPipe\\");
    200         const len: u16 = @truncate(str.len * @sizeOf(u16));
    201         const name = UNICODE_STRING{
    202             .Length = len,
    203             .MaximumLength = len,
    204             .Buffer = @constCast(@ptrCast(str)),
    205         };
    206         const attrs = OBJECT_ATTRIBUTES{
    207             .ObjectName = @constCast(&name),
    208             .Length = @sizeOf(OBJECT_ATTRIBUTES),
    209             .RootDirectory = null,
    210             .Attributes = 0,
    211             .SecurityDescriptor = null,
    212             .SecurityQualityOfService = null,
    213         };
    214 
    215         var iosb: IO_STATUS_BLOCK = undefined;
    216         var handle: HANDLE = undefined;
    217         switch (ntdll.NtCreateFile(
    218             &handle,
    219             GENERIC_READ | SYNCHRONIZE,
    220             @constCast(&attrs),
    221             &iosb,
    222             null,
    223             0,
    224             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    225             FILE_OPEN,
    226             FILE_SYNCHRONOUS_IO_NONALERT,
    227             null,
    228             0,
    229         )) {
    230             .SUCCESS => {},
    231             // Judging from the ReactOS sources this is technically possible.
    232             .INSUFFICIENT_RESOURCES => return error.SystemResources,
    233             .INVALID_PARAMETER => unreachable,
    234             else => |e| return unexpectedStatus(e),
    235         }
    236         if (@cmpxchgStrong(?HANDLE, &npfs, null, handle, .seq_cst, .seq_cst)) |xchg| {
    237             CloseHandle(handle);
    238             break :blk xchg.?;
    239         } else break :blk handle;
    240     };
    241 
    242     const name = UNICODE_STRING{ .Buffer = null, .Length = 0, .MaximumLength = 0 };
    243     var attrs = OBJECT_ATTRIBUTES{
    244         .ObjectName = @constCast(&name),
    245         .Length = @sizeOf(OBJECT_ATTRIBUTES),
    246         .RootDirectory = dev_handle,
    247         .Attributes = OBJ_CASE_INSENSITIVE,
    248         .SecurityDescriptor = sattr.lpSecurityDescriptor,
    249         .SecurityQualityOfService = null,
    250     };
    251     if (sattr.bInheritHandle != 0) attrs.Attributes |= OBJ_INHERIT;
    252 
    253     // 120 second relative timeout in 100ns units.
    254     const default_timeout: LARGE_INTEGER = (-120 * std.time.ns_per_s) / 100;
    255     var iosb: IO_STATUS_BLOCK = undefined;
    256     var read: HANDLE = undefined;
    257     switch (ntdll.NtCreateNamedPipeFile(
    258         &read,
    259         GENERIC_READ | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
    260         &attrs,
    261         &iosb,
    262         FILE_SHARE_READ | FILE_SHARE_WRITE,
    263         FILE_CREATE,
    264         FILE_SYNCHRONOUS_IO_NONALERT,
    265         FILE_PIPE_BYTE_STREAM_TYPE,
    266         FILE_PIPE_BYTE_STREAM_MODE,
    267         FILE_PIPE_QUEUE_OPERATION,
    268         1,
    269         4096,
    270         4096,
    271         @constCast(&default_timeout),
    272     )) {
    273         .SUCCESS => {},
    274         .INVALID_PARAMETER => unreachable,
    275         .INSUFFICIENT_RESOURCES => return error.SystemResources,
    276         else => |e| return unexpectedStatus(e),
    277     }
    278     errdefer CloseHandle(read);
    279 
    280     attrs.RootDirectory = read;
    281 
    282     var write: HANDLE = undefined;
    283     switch (ntdll.NtCreateFile(
    284         &write,
    285         GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
    286         &attrs,
    287         &iosb,
    288         null,
    289         0,
    290         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    291         FILE_OPEN,
    292         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
    293         null,
    294         0,
    295     )) {
    296         .SUCCESS => {},
    297         .INVALID_PARAMETER => unreachable,
    298         .INSUFFICIENT_RESOURCES => return error.SystemResources,
    299         else => |e| return unexpectedStatus(e),
    300     }
    301 
    302     rd.* = read;
    303     wr.* = write;
    304 }
    305 
    306 pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {
    307     const nameW = try sliceToPrefixedFileW(null, name);
    308     return CreateEventExW(attributes, nameW.span().ptr, flags, desired_access);
    309 }
    310 
    311 pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: ?LPCWSTR, flags: DWORD, desired_access: DWORD) !HANDLE {
    312     const handle = kernel32.CreateEventExW(attributes, nameW, flags, desired_access);
    313     if (handle) |h| {
    314         return h;
    315     } else {
    316         switch (GetLastError()) {
    317             else => |err| return unexpectedError(err),
    318         }
    319     }
    320 }
    321 
    322 pub const DeviceIoControlError = error{
    323     AccessDenied,
    324     /// The volume does not contain a recognized file system. File system
    325     /// drivers might not be loaded, or the volume may be corrupt.
    326     UnrecognizedVolume,
    327     Unexpected,
    328 };
    329 
    330 /// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls.
    331 /// It implements similar behavior to `DeviceIoControl` and is meant to serve
    332 /// as a direct substitute for that call.
    333 /// TODO work out if we need to expose other arguments to the underlying syscalls.
    334 pub fn DeviceIoControl(
    335     h: HANDLE,
    336     ioControlCode: ULONG,
    337     in: ?[]const u8,
    338     out: ?[]u8,
    339 ) DeviceIoControlError!void {
    340     // Logic from: https://doxygen.reactos.org/d3/d74/deviceio_8c.html
    341     const is_fsctl = (ioControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM;
    342 
    343     var io: IO_STATUS_BLOCK = undefined;
    344     const in_ptr = if (in) |i| i.ptr else null;
    345     const in_len = if (in) |i| @as(ULONG, @intCast(i.len)) else 0;
    346     const out_ptr = if (out) |o| o.ptr else null;
    347     const out_len = if (out) |o| @as(ULONG, @intCast(o.len)) else 0;
    348 
    349     const rc = blk: {
    350         if (is_fsctl) {
    351             break :blk ntdll.NtFsControlFile(
    352                 h,
    353                 null,
    354                 null,
    355                 null,
    356                 &io,
    357                 ioControlCode,
    358                 in_ptr,
    359                 in_len,
    360                 out_ptr,
    361                 out_len,
    362             );
    363         } else {
    364             break :blk ntdll.NtDeviceIoControlFile(
    365                 h,
    366                 null,
    367                 null,
    368                 null,
    369                 &io,
    370                 ioControlCode,
    371                 in_ptr,
    372                 in_len,
    373                 out_ptr,
    374                 out_len,
    375             );
    376         }
    377     };
    378     switch (rc) {
    379         .SUCCESS => {},
    380         .PRIVILEGE_NOT_HELD => return error.AccessDenied,
    381         .ACCESS_DENIED => return error.AccessDenied,
    382         .INVALID_DEVICE_REQUEST => return error.AccessDenied, // Not supported by the underlying filesystem
    383         .INVALID_PARAMETER => unreachable,
    384         .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume,
    385         else => return unexpectedStatus(rc),
    386     }
    387 }
    388 
    389 pub fn GetOverlappedResult(h: HANDLE, overlapped: *OVERLAPPED, wait: bool) !DWORD {
    390     var bytes: DWORD = undefined;
    391     if (kernel32.GetOverlappedResult(h, overlapped, &bytes, @intFromBool(wait)) == 0) {
    392         switch (GetLastError()) {
    393             .IO_INCOMPLETE => if (!wait) return error.WouldBlock else unreachable,
    394             else => |err| return unexpectedError(err),
    395         }
    396     }
    397     return bytes;
    398 }
    399 
    400 pub const SetHandleInformationError = error{Unexpected};
    401 
    402 pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInformationError!void {
    403     if (kernel32.SetHandleInformation(h, mask, flags) == 0) {
    404         switch (GetLastError()) {
    405             else => |err| return unexpectedError(err),
    406         }
    407     }
    408 }
    409 
    410 pub const RtlGenRandomError = error{Unexpected};
    411 
    412 /// Call RtlGenRandom() instead of CryptGetRandom() on Windows
    413 /// https://github.com/rust-lang-nursery/rand/issues/111
    414 /// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
    415 pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
    416     var total_read: usize = 0;
    417     var buff: []u8 = output[0..];
    418     const max_read_size: ULONG = maxInt(ULONG);
    419 
    420     while (total_read < output.len) {
    421         const to_read: ULONG = @min(buff.len, max_read_size);
    422 
    423         if (advapi32.RtlGenRandom(buff.ptr, to_read) == 0) {
    424             return unexpectedError(GetLastError());
    425         }
    426 
    427         total_read += to_read;
    428         buff = buff[to_read..];
    429     }
    430 }
    431 
    432 pub const WaitForSingleObjectError = error{
    433     WaitAbandoned,
    434     WaitTimeOut,
    435     Unexpected,
    436 };
    437 
    438 pub fn WaitForSingleObject(handle: HANDLE, milliseconds: DWORD) WaitForSingleObjectError!void {
    439     return WaitForSingleObjectEx(handle, milliseconds, false);
    440 }
    441 
    442 pub fn WaitForSingleObjectEx(handle: HANDLE, milliseconds: DWORD, alertable: bool) WaitForSingleObjectError!void {
    443     switch (kernel32.WaitForSingleObjectEx(handle, milliseconds, @intFromBool(alertable))) {
    444         WAIT_ABANDONED => return error.WaitAbandoned,
    445         WAIT_OBJECT_0 => return,
    446         WAIT_TIMEOUT => return error.WaitTimeOut,
    447         WAIT_FAILED => switch (GetLastError()) {
    448             else => |err| return unexpectedError(err),
    449         },
    450         else => return error.Unexpected,
    451     }
    452 }
    453 
    454 pub fn WaitForMultipleObjectsEx(handles: []const HANDLE, waitAll: bool, milliseconds: DWORD, alertable: bool) !u32 {
    455     assert(handles.len > 0 and handles.len <= MAXIMUM_WAIT_OBJECTS);
    456     const nCount: DWORD = @as(DWORD, @intCast(handles.len));
    457     switch (kernel32.WaitForMultipleObjectsEx(
    458         nCount,
    459         handles.ptr,
    460         @intFromBool(waitAll),
    461         milliseconds,
    462         @intFromBool(alertable),
    463     )) {
    464         WAIT_OBJECT_0...WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS => |n| {
    465             const handle_index = n - WAIT_OBJECT_0;
    466             assert(handle_index < nCount);
    467             return handle_index;
    468         },
    469         WAIT_ABANDONED_0...WAIT_ABANDONED_0 + MAXIMUM_WAIT_OBJECTS => |n| {
    470             const handle_index = n - WAIT_ABANDONED_0;
    471             assert(handle_index < nCount);
    472             return error.WaitAbandoned;
    473         },
    474         WAIT_TIMEOUT => return error.WaitTimeOut,
    475         WAIT_FAILED => switch (GetLastError()) {
    476             else => |err| return unexpectedError(err),
    477         },
    478         else => return error.Unexpected,
    479     }
    480 }
    481 
    482 pub const CreateIoCompletionPortError = error{Unexpected};
    483 
    484 pub fn CreateIoCompletionPort(
    485     file_handle: HANDLE,
    486     existing_completion_port: ?HANDLE,
    487     completion_key: usize,
    488     concurrent_thread_count: DWORD,
    489 ) CreateIoCompletionPortError!HANDLE {
    490     const handle = kernel32.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
    491         switch (GetLastError()) {
    492             .INVALID_PARAMETER => unreachable,
    493             else => |err| return unexpectedError(err),
    494         }
    495     };
    496     return handle;
    497 }
    498 
    499 pub const PostQueuedCompletionStatusError = error{Unexpected};
    500 
    501 pub fn PostQueuedCompletionStatus(
    502     completion_port: HANDLE,
    503     bytes_transferred_count: DWORD,
    504     completion_key: usize,
    505     lpOverlapped: ?*OVERLAPPED,
    506 ) PostQueuedCompletionStatusError!void {
    507     if (kernel32.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
    508         switch (GetLastError()) {
    509             else => |err| return unexpectedError(err),
    510         }
    511     }
    512 }
    513 
    514 pub const GetQueuedCompletionStatusResult = enum {
    515     Normal,
    516     Aborted,
    517     Cancelled,
    518     EOF,
    519     Timeout,
    520 };
    521 
    522 pub fn GetQueuedCompletionStatus(
    523     completion_port: HANDLE,
    524     bytes_transferred_count: *DWORD,
    525     lpCompletionKey: *usize,
    526     lpOverlapped: *?*OVERLAPPED,
    527     dwMilliseconds: DWORD,
    528 ) GetQueuedCompletionStatusResult {
    529     if (kernel32.GetQueuedCompletionStatus(
    530         completion_port,
    531         bytes_transferred_count,
    532         lpCompletionKey,
    533         lpOverlapped,
    534         dwMilliseconds,
    535     ) == FALSE) {
    536         switch (GetLastError()) {
    537             .ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted,
    538             .OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Cancelled,
    539             .HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF,
    540             .WAIT_TIMEOUT => return GetQueuedCompletionStatusResult.Timeout,
    541             else => |err| {
    542                 if (std.debug.runtime_safety) {
    543                     @setEvalBranchQuota(2500);
    544                     std.debug.panic("unexpected error: {}\n", .{err});
    545                 }
    546             },
    547         }
    548     }
    549     return GetQueuedCompletionStatusResult.Normal;
    550 }
    551 
    552 pub const GetQueuedCompletionStatusError = error{
    553     Aborted,
    554     Cancelled,
    555     EOF,
    556     Timeout,
    557 } || UnexpectedError;
    558 
    559 pub fn GetQueuedCompletionStatusEx(
    560     completion_port: HANDLE,
    561     completion_port_entries: []OVERLAPPED_ENTRY,
    562     timeout_ms: ?DWORD,
    563     alertable: bool,
    564 ) GetQueuedCompletionStatusError!u32 {
    565     var num_entries_removed: u32 = 0;
    566 
    567     const success = kernel32.GetQueuedCompletionStatusEx(
    568         completion_port,
    569         completion_port_entries.ptr,
    570         @as(ULONG, @intCast(completion_port_entries.len)),
    571         &num_entries_removed,
    572         timeout_ms orelse INFINITE,
    573         @intFromBool(alertable),
    574     );
    575 
    576     if (success == FALSE) {
    577         return switch (GetLastError()) {
    578             .ABANDONED_WAIT_0 => error.Aborted,
    579             .OPERATION_ABORTED => error.Cancelled,
    580             .HANDLE_EOF => error.EOF,
    581             .WAIT_TIMEOUT => error.Timeout,
    582             else => |err| unexpectedError(err),
    583         };
    584     }
    585 
    586     return num_entries_removed;
    587 }
    588 
    589 pub fn CloseHandle(hObject: HANDLE) void {
    590     assert(ntdll.NtClose(hObject) == .SUCCESS);
    591 }
    592 
    593 pub fn FindClose(hFindFile: HANDLE) void {
    594     assert(kernel32.FindClose(hFindFile) != 0);
    595 }
    596 
    597 pub const ReadFileError = error{
    598     BrokenPipe,
    599     /// The specified network name is no longer available.
    600     ConnectionResetByPeer,
    601     OperationAborted,
    602     /// Unable to read file due to lock.
    603     LockViolation,
    604     Unexpected,
    605 };
    606 
    607 /// If buffer's length exceeds what a Windows DWORD integer can hold, it will be broken into
    608 /// multiple non-atomic reads.
    609 pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64) ReadFileError!usize {
    610     while (true) {
    611         const want_read_count: DWORD = @min(@as(DWORD, maxInt(DWORD)), buffer.len);
    612         var amt_read: DWORD = undefined;
    613         var overlapped_data: OVERLAPPED = undefined;
    614         const overlapped: ?*OVERLAPPED = if (offset) |off| blk: {
    615             overlapped_data = .{
    616                 .Internal = 0,
    617                 .InternalHigh = 0,
    618                 .DUMMYUNIONNAME = .{
    619                     .DUMMYSTRUCTNAME = .{
    620                         .Offset = @as(u32, @truncate(off)),
    621                         .OffsetHigh = @as(u32, @truncate(off >> 32)),
    622                     },
    623                 },
    624                 .hEvent = null,
    625             };
    626             break :blk &overlapped_data;
    627         } else null;
    628         if (kernel32.ReadFile(in_hFile, buffer.ptr, want_read_count, &amt_read, overlapped) == 0) {
    629             switch (GetLastError()) {
    630                 .IO_PENDING => unreachable,
    631                 .OPERATION_ABORTED => continue,
    632                 .BROKEN_PIPE => return 0,
    633                 .HANDLE_EOF => return 0,
    634                 .NETNAME_DELETED => return error.ConnectionResetByPeer,
    635                 .LOCK_VIOLATION => return error.LockViolation,
    636                 else => |err| return unexpectedError(err),
    637             }
    638         }
    639         return amt_read;
    640     }
    641 }
    642 
    643 pub const WriteFileError = error{
    644     SystemResources,
    645     OperationAborted,
    646     BrokenPipe,
    647     NotOpenForWriting,
    648     /// The process cannot access the file because another process has locked
    649     /// a portion of the file.
    650     LockViolation,
    651     /// The specified network name is no longer available.
    652     ConnectionResetByPeer,
    653     Unexpected,
    654 };
    655 
    656 pub fn WriteFile(
    657     handle: HANDLE,
    658     bytes: []const u8,
    659     offset: ?u64,
    660 ) WriteFileError!usize {
    661     var bytes_written: DWORD = undefined;
    662     var overlapped_data: OVERLAPPED = undefined;
    663     const overlapped: ?*OVERLAPPED = if (offset) |off| blk: {
    664         overlapped_data = .{
    665             .Internal = 0,
    666             .InternalHigh = 0,
    667             .DUMMYUNIONNAME = .{
    668                 .DUMMYSTRUCTNAME = .{
    669                     .Offset = @truncate(off),
    670                     .OffsetHigh = @truncate(off >> 32),
    671                 },
    672             },
    673             .hEvent = null,
    674         };
    675         break :blk &overlapped_data;
    676     } else null;
    677     const adjusted_len = math.cast(u32, bytes.len) orelse maxInt(u32);
    678     if (kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, overlapped) == 0) {
    679         switch (GetLastError()) {
    680             .INVALID_USER_BUFFER => return error.SystemResources,
    681             .NOT_ENOUGH_MEMORY => return error.SystemResources,
    682             .OPERATION_ABORTED => return error.OperationAborted,
    683             .NOT_ENOUGH_QUOTA => return error.SystemResources,
    684             .IO_PENDING => unreachable,
    685             .NO_DATA => return error.BrokenPipe,
    686             .INVALID_HANDLE => return error.NotOpenForWriting,
    687             .LOCK_VIOLATION => return error.LockViolation,
    688             .NETNAME_DELETED => return error.ConnectionResetByPeer,
    689             else => |err| return unexpectedError(err),
    690         }
    691     }
    692     return bytes_written;
    693 }
    694 
    695 pub const SetCurrentDirectoryError = error{
    696     NameTooLong,
    697     FileNotFound,
    698     NotDir,
    699     AccessDenied,
    700     NoDevice,
    701     BadPathName,
    702     Unexpected,
    703 };
    704 
    705 pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void {
    706     const path_len_bytes = math.cast(u16, path_name.len * 2) orelse return error.NameTooLong;
    707 
    708     var nt_name = UNICODE_STRING{
    709         .Length = path_len_bytes,
    710         .MaximumLength = path_len_bytes,
    711         .Buffer = @constCast(path_name.ptr),
    712     };
    713 
    714     const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name);
    715     switch (rc) {
    716         .SUCCESS => {},
    717         .OBJECT_NAME_INVALID => return error.BadPathName,
    718         .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
    719         .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
    720         .NO_MEDIA_IN_DEVICE => return error.NoDevice,
    721         .INVALID_PARAMETER => unreachable,
    722         .ACCESS_DENIED => return error.AccessDenied,
    723         .OBJECT_PATH_SYNTAX_BAD => unreachable,
    724         .NOT_A_DIRECTORY => return error.NotDir,
    725         else => return unexpectedStatus(rc),
    726     }
    727 }
    728 
    729 pub const GetCurrentDirectoryError = error{
    730     NameTooLong,
    731     Unexpected,
    732 };
    733 
    734 /// The result is a slice of `buffer`, indexed from 0.
    735 /// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
    736 pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
    737     var wtf16le_buf: [PATH_MAX_WIDE:0]u16 = undefined;
    738     const result = kernel32.GetCurrentDirectoryW(wtf16le_buf.len + 1, &wtf16le_buf);
    739     if (result == 0) {
    740         switch (GetLastError()) {
    741             else => |err| return unexpectedError(err),
    742         }
    743     }
    744     assert(result <= wtf16le_buf.len);
    745     const wtf16le_slice = wtf16le_buf[0..result];
    746     var end_index: usize = 0;
    747     var it = std.unicode.Wtf16LeIterator.init(wtf16le_slice);
    748     while (it.nextCodepoint()) |codepoint| {
    749         const seq_len = std.unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
    750         if (end_index + seq_len >= buffer.len)
    751             return error.NameTooLong;
    752         end_index += std.unicode.wtf8Encode(codepoint, buffer[end_index..]) catch unreachable;
    753     }
    754     return buffer[0..end_index];
    755 }
    756 
    757 pub const CreateSymbolicLinkError = error{
    758     AccessDenied,
    759     PathAlreadyExists,
    760     FileNotFound,
    761     NameTooLong,
    762     NoDevice,
    763     NetworkNotFound,
    764     BadPathName,
    765     /// The volume does not contain a recognized file system. File system
    766     /// drivers might not be loaded, or the volume may be corrupt.
    767     UnrecognizedVolume,
    768     Unexpected,
    769 };
    770 
    771 /// Needs either:
    772 /// - `SeCreateSymbolicLinkPrivilege` privilege
    773 /// or
    774 /// - Developer mode on Windows 10
    775 /// otherwise fails with `error.AccessDenied`. In which case `sym_link_path` may still
    776 /// be created on the file system but will lack reparse processing data applied to it.
    777 pub fn CreateSymbolicLink(
    778     dir: ?HANDLE,
    779     sym_link_path: []const u16,
    780     target_path: [:0]const u16,
    781     is_directory: bool,
    782 ) CreateSymbolicLinkError!void {
    783     const SYMLINK_DATA = extern struct {
    784         ReparseTag: ULONG,
    785         ReparseDataLength: USHORT,
    786         Reserved: USHORT,
    787         SubstituteNameOffset: USHORT,
    788         SubstituteNameLength: USHORT,
    789         PrintNameOffset: USHORT,
    790         PrintNameLength: USHORT,
    791         Flags: ULONG,
    792     };
    793 
    794     const symlink_handle = OpenFile(sym_link_path, .{
    795         .access_mask = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
    796         .dir = dir,
    797         .creation = FILE_CREATE,
    798         .filter = if (is_directory) .dir_only else .file_only,
    799     }) catch |err| switch (err) {
    800         error.IsDir => return error.PathAlreadyExists,
    801         error.NotDir => return error.Unexpected,
    802         error.WouldBlock => return error.Unexpected,
    803         error.PipeBusy => return error.Unexpected,
    804         error.AntivirusInterference => return error.Unexpected,
    805         else => |e| return e,
    806     };
    807     defer CloseHandle(symlink_handle);
    808 
    809     // Relevant portions of the documentation:
    810     // > Relative links are specified using the following conventions:
    811     // > - Root relative—for example, "\Windows\System32" resolves to "current drive:\Windows\System32".
    812     // > - Current working directory–relative—for example, if the current working directory is
    813     // >   C:\Windows\System32, "C:File.txt" resolves to "C:\Windows\System32\File.txt".
    814     // > Note: If you specify a current working directory–relative link, it is created as an absolute
    815     // > link, due to the way the current working directory is processed based on the user and the thread.
    816     // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
    817     var is_target_absolute = false;
    818     const final_target_path = target_path: {
    819         switch (getNamespacePrefix(u16, target_path)) {
    820             .none => switch (getUnprefixedPathType(u16, target_path)) {
    821                 // Rooted paths need to avoid getting put through wToPrefixedFileW
    822                 // (and they are treated as relative in this context)
    823                 // Note: It seems that rooted paths in symbolic links are relative to
    824                 //       the drive that the symbolic exists on, not to the CWD's drive.
    825                 //       So, if the symlink is on C:\ and the CWD is on D:\,
    826                 //       it will still resolve the path relative to the root of
    827                 //       the C:\ drive.
    828                 .rooted => break :target_path target_path,
    829                 // Keep relative paths relative, but anything else needs to get NT-prefixed.
    830                 else => if (!std.fs.path.isAbsoluteWindowsWTF16(target_path))
    831                     break :target_path target_path,
    832             },
    833             // Already an NT path, no need to do anything to it
    834             .nt => break :target_path target_path,
    835             else => {},
    836         }
    837         var prefixed_target_path = try wToPrefixedFileW(dir, target_path);
    838         // We do this after prefixing to ensure that drive-relative paths are treated as absolute
    839         is_target_absolute = std.fs.path.isAbsoluteWindowsWTF16(prefixed_target_path.span());
    840         break :target_path prefixed_target_path.span();
    841     };
    842 
    843     // prepare reparse data buffer
    844     var buffer: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
    845     const buf_len = @sizeOf(SYMLINK_DATA) + final_target_path.len * 4;
    846     const header_len = @sizeOf(ULONG) + @sizeOf(USHORT) * 2;
    847     const target_is_absolute = std.fs.path.isAbsoluteWindowsWTF16(final_target_path);
    848     const symlink_data = SYMLINK_DATA{
    849         .ReparseTag = IO_REPARSE_TAG_SYMLINK,
    850         .ReparseDataLength = @intCast(buf_len - header_len),
    851         .Reserved = 0,
    852         .SubstituteNameOffset = @intCast(final_target_path.len * 2),
    853         .SubstituteNameLength = @intCast(final_target_path.len * 2),
    854         .PrintNameOffset = 0,
    855         .PrintNameLength = @intCast(final_target_path.len * 2),
    856         .Flags = if (!target_is_absolute) SYMLINK_FLAG_RELATIVE else 0,
    857     };
    858 
    859     @memcpy(buffer[0..@sizeOf(SYMLINK_DATA)], std.mem.asBytes(&symlink_data));
    860     @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
    861     const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
    862     @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
    863     _ = try DeviceIoControl(symlink_handle, FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null);
    864 }
    865 
    866 pub const ReadLinkError = error{
    867     FileNotFound,
    868     NetworkNotFound,
    869     AccessDenied,
    870     Unexpected,
    871     NameTooLong,
    872     UnsupportedReparsePointType,
    873 };
    874 
    875 pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLinkError![]u8 {
    876     // Here, we use `NtCreateFile` to shave off one syscall if we were to use `OpenFile` wrapper.
    877     // With the latter, we'd need to call `NtCreateFile` twice, once for file symlink, and if that
    878     // failed, again for dir symlink. Omitting any mention of file/dir flags makes it possible
    879     // to open the symlink there and then.
    880     const path_len_bytes = math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
    881     var nt_name = UNICODE_STRING{
    882         .Length = path_len_bytes,
    883         .MaximumLength = path_len_bytes,
    884         .Buffer = @constCast(sub_path_w.ptr),
    885     };
    886     var attr = OBJECT_ATTRIBUTES{
    887         .Length = @sizeOf(OBJECT_ATTRIBUTES),
    888         .RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(sub_path_w)) null else dir,
    889         .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
    890         .ObjectName = &nt_name,
    891         .SecurityDescriptor = null,
    892         .SecurityQualityOfService = null,
    893     };
    894     var result_handle: HANDLE = undefined;
    895     var io: IO_STATUS_BLOCK = undefined;
    896 
    897     const rc = ntdll.NtCreateFile(
    898         &result_handle,
    899         FILE_READ_ATTRIBUTES | SYNCHRONIZE,
    900         &attr,
    901         &io,
    902         null,
    903         FILE_ATTRIBUTE_NORMAL,
    904         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    905         FILE_OPEN,
    906         FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT,
    907         null,
    908         0,
    909     );
    910     switch (rc) {
    911         .SUCCESS => {},
    912         .OBJECT_NAME_INVALID => unreachable,
    913         .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
    914         .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
    915         .NO_MEDIA_IN_DEVICE => return error.FileNotFound,
    916         .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
    917         .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
    918         .INVALID_PARAMETER => unreachable,
    919         .SHARING_VIOLATION => return error.AccessDenied,
    920         .ACCESS_DENIED => return error.AccessDenied,
    921         .PIPE_BUSY => return error.AccessDenied,
    922         .OBJECT_PATH_SYNTAX_BAD => unreachable,
    923         .OBJECT_NAME_COLLISION => unreachable,
    924         .FILE_IS_A_DIRECTORY => unreachable,
    925         else => return unexpectedStatus(rc),
    926     }
    927     defer CloseHandle(result_handle);
    928 
    929     var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(REPARSE_DATA_BUFFER)) = undefined;
    930     _ = DeviceIoControl(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]) catch |err| switch (err) {
    931         error.AccessDenied => return error.Unexpected,
    932         error.UnrecognizedVolume => return error.Unexpected,
    933         else => |e| return e,
    934     };
    935 
    936     const reparse_struct: *const REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf[0]));
    937     switch (reparse_struct.ReparseTag) {
    938         IO_REPARSE_TAG_SYMLINK => {
    939             const buf: *const SYMBOLIC_LINK_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
    940             const offset = buf.SubstituteNameOffset >> 1;
    941             const len = buf.SubstituteNameLength >> 1;
    942             const path_buf = @as([*]const u16, &buf.PathBuffer);
    943             const is_relative = buf.Flags & SYMLINK_FLAG_RELATIVE != 0;
    944             return parseReadlinkPath(path_buf[offset..][0..len], is_relative, out_buffer);
    945         },
    946         IO_REPARSE_TAG_MOUNT_POINT => {
    947             const buf: *const MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
    948             const offset = buf.SubstituteNameOffset >> 1;
    949             const len = buf.SubstituteNameLength >> 1;
    950             const path_buf = @as([*]const u16, &buf.PathBuffer);
    951             return parseReadlinkPath(path_buf[offset..][0..len], false, out_buffer);
    952         },
    953         else => |value| {
    954             std.debug.print("unsupported symlink type: {}", .{value});
    955             return error.UnsupportedReparsePointType;
    956         },
    957     }
    958 }
    959 
    960 /// Asserts that there is enough space is `out_buffer`.
    961 /// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
    962 fn parseReadlinkPath(path: []const u16, is_relative: bool, out_buffer: []u8) []u8 {
    963     const win32_namespace_path = path: {
    964         if (is_relative) break :path path;
    965         const win32_path = ntToWin32Namespace(path) catch |err| switch (err) {
    966             error.NameTooLong => unreachable,
    967             error.NotNtPath => break :path path,
    968         };
    969         break :path win32_path.span();
    970     };
    971     const out_len = std.unicode.wtf16LeToWtf8(out_buffer, win32_namespace_path);
    972     return out_buffer[0..out_len];
    973 }
    974 
    975 pub const DeleteFileError = error{
    976     FileNotFound,
    977     AccessDenied,
    978     NameTooLong,
    979     /// Also known as sharing violation.
    980     FileBusy,
    981     Unexpected,
    982     NotDir,
    983     IsDir,
    984     DirNotEmpty,
    985     NetworkNotFound,
    986 };
    987 
    988 pub const DeleteFileOptions = struct {
    989     dir: ?HANDLE,
    990     remove_dir: bool = false,
    991 };
    992 
    993 pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFileError!void {
    994     const create_options_flags: ULONG = if (options.remove_dir)
    995         FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
    996     else
    997         FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT; // would we ever want to delete the target instead?
    998 
    999     const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));
   1000     var nt_name = UNICODE_STRING{
   1001         .Length = path_len_bytes,
   1002         .MaximumLength = path_len_bytes,
   1003         // The Windows API makes this mutable, but it will not mutate here.
   1004         .Buffer = @constCast(sub_path_w.ptr),
   1005     };
   1006 
   1007     if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
   1008         // Windows does not recognize this, but it does work with empty string.
   1009         nt_name.Length = 0;
   1010     }
   1011     if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
   1012         // Can't remove the parent directory with an open handle.
   1013         return error.FileBusy;
   1014     }
   1015 
   1016     var attr = OBJECT_ATTRIBUTES{
   1017         .Length = @sizeOf(OBJECT_ATTRIBUTES),
   1018         .RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(sub_path_w)) null else options.dir,
   1019         .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
   1020         .ObjectName = &nt_name,
   1021         .SecurityDescriptor = null,
   1022         .SecurityQualityOfService = null,
   1023     };
   1024     var io: IO_STATUS_BLOCK = undefined;
   1025     var tmp_handle: HANDLE = undefined;
   1026     var rc = ntdll.NtCreateFile(
   1027         &tmp_handle,
   1028         SYNCHRONIZE | DELETE,
   1029         &attr,
   1030         &io,
   1031         null,
   1032         0,
   1033         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
   1034         FILE_OPEN,
   1035         create_options_flags,
   1036         null,
   1037         0,
   1038     );
   1039     switch (rc) {
   1040         .SUCCESS => {},
   1041         .OBJECT_NAME_INVALID => unreachable,
   1042         .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
   1043         .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
   1044         .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
   1045         .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
   1046         .INVALID_PARAMETER => unreachable,
   1047         .FILE_IS_A_DIRECTORY => return error.IsDir,
   1048         .NOT_A_DIRECTORY => return error.NotDir,
   1049         .SHARING_VIOLATION => return error.FileBusy,
   1050         .ACCESS_DENIED => return error.AccessDenied,
   1051         .DELETE_PENDING => return,
   1052         else => return unexpectedStatus(rc),
   1053     }
   1054     defer CloseHandle(tmp_handle);
   1055 
   1056     // FileDispositionInformationEx (and therefore FILE_DISPOSITION_POSIX_SEMANTICS and FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE)
   1057     // are only supported on NTFS filesystems, so the version check on its own is only a partial solution. To support non-NTFS filesystems
   1058     // like FAT32, we need to fallback to FileDispositionInformation if the usage of FileDispositionInformationEx gives
   1059     // us INVALID_PARAMETER.
   1060     // The same reasoning for win10_rs5 as in os.renameatW() applies (FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5).
   1061     var need_fallback = true;
   1062     if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs5)) {
   1063         // Deletion with posix semantics if the filesystem supports it.
   1064         var info = FILE_DISPOSITION_INFORMATION_EX{
   1065             .Flags = FILE_DISPOSITION_DELETE |
   1066                 FILE_DISPOSITION_POSIX_SEMANTICS |
   1067                 FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
   1068         };
   1069 
   1070         rc = ntdll.NtSetInformationFile(
   1071             tmp_handle,
   1072             &io,
   1073             &info,
   1074             @sizeOf(FILE_DISPOSITION_INFORMATION_EX),
   1075             .FileDispositionInformationEx,
   1076         );
   1077         switch (rc) {
   1078             .SUCCESS => return,
   1079             // INVALID_PARAMETER here means that the filesystem does not support FileDispositionInformationEx
   1080             .INVALID_PARAMETER => {},
   1081             // For all other statuses, fall down to the switch below to handle them.
   1082             else => need_fallback = false,
   1083         }
   1084     }
   1085     if (need_fallback) {
   1086         // Deletion with file pending semantics, which requires waiting or moving
   1087         // files to get them removed (from here).
   1088         var file_dispo = FILE_DISPOSITION_INFORMATION{
   1089             .DeleteFile = TRUE,
   1090         };
   1091 
   1092         rc = ntdll.NtSetInformationFile(
   1093             tmp_handle,
   1094             &io,
   1095             &file_dispo,
   1096             @sizeOf(FILE_DISPOSITION_INFORMATION),
   1097             .FileDispositionInformation,
   1098         );
   1099     }
   1100     switch (rc) {
   1101         .SUCCESS => {},
   1102         .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
   1103         .INVALID_PARAMETER => unreachable,
   1104         .CANNOT_DELETE => return error.AccessDenied,
   1105         .MEDIA_WRITE_PROTECTED => return error.AccessDenied,
   1106         .ACCESS_DENIED => return error.AccessDenied,
   1107         else => return unexpectedStatus(rc),
   1108     }
   1109 }
   1110 
   1111 pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
   1112 
   1113 pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
   1114     const old_path_w = try sliceToPrefixedFileW(null, old_path);
   1115     const new_path_w = try sliceToPrefixedFileW(null, new_path);
   1116     return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags);
   1117 }
   1118 
   1119 pub fn MoveFileExW(old_path: [*:0]const u16, new_path: [*:0]const u16, flags: DWORD) MoveFileError!void {
   1120     if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) {
   1121         switch (GetLastError()) {
   1122             .FILE_NOT_FOUND => return error.FileNotFound,
   1123             .ACCESS_DENIED => return error.AccessDenied,
   1124             else => |err| return unexpectedError(err),
   1125         }
   1126     }
   1127 }
   1128 
   1129 pub const GetStdHandleError = error{
   1130     NoStandardHandleAttached,
   1131     Unexpected,
   1132 };
   1133 
   1134 pub fn GetStdHandle(handle_id: DWORD) GetStdHandleError!HANDLE {
   1135     const handle = kernel32.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached;
   1136     if (handle == INVALID_HANDLE_VALUE) {
   1137         switch (GetLastError()) {
   1138             else => |err| return unexpectedError(err),
   1139         }
   1140     }
   1141     return handle;
   1142 }
   1143 
   1144 pub const SetFilePointerError = error{Unexpected};
   1145 
   1146 /// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_BEGIN`.
   1147 pub fn SetFilePointerEx_BEGIN(handle: HANDLE, offset: u64) SetFilePointerError!void {
   1148     // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]
   1149     // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."
   1150     // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex
   1151     const ipos = @as(LARGE_INTEGER, @bitCast(offset));
   1152     if (kernel32.SetFilePointerEx(handle, ipos, null, FILE_BEGIN) == 0) {
   1153         switch (GetLastError()) {
   1154             .INVALID_PARAMETER => unreachable,
   1155             .INVALID_HANDLE => unreachable,
   1156             else => |err| return unexpectedError(err),
   1157         }
   1158     }
   1159 }
   1160 
   1161 /// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_CURRENT`.
   1162 pub fn SetFilePointerEx_CURRENT(handle: HANDLE, offset: i64) SetFilePointerError!void {
   1163     if (kernel32.SetFilePointerEx(handle, offset, null, FILE_CURRENT) == 0) {
   1164         switch (GetLastError()) {
   1165             .INVALID_PARAMETER => unreachable,
   1166             .INVALID_HANDLE => unreachable,
   1167             else => |err| return unexpectedError(err),
   1168         }
   1169     }
   1170 }
   1171 
   1172 /// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_END`.
   1173 pub fn SetFilePointerEx_END(handle: HANDLE, offset: i64) SetFilePointerError!void {
   1174     if (kernel32.SetFilePointerEx(handle, offset, null, FILE_END) == 0) {
   1175         switch (GetLastError()) {
   1176             .INVALID_PARAMETER => unreachable,
   1177             .INVALID_HANDLE => unreachable,
   1178             else => |err| return unexpectedError(err),
   1179         }
   1180     }
   1181 }
   1182 
   1183 /// The SetFilePointerEx function with parameters to get the current offset.
   1184 pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
   1185     var result: LARGE_INTEGER = undefined;
   1186     if (kernel32.SetFilePointerEx(handle, 0, &result, FILE_CURRENT) == 0) {
   1187         switch (GetLastError()) {
   1188             .INVALID_PARAMETER => unreachable,
   1189             .INVALID_HANDLE => unreachable,
   1190             else => |err| return unexpectedError(err),
   1191         }
   1192     }
   1193     // Based on the docs for FILE_BEGIN, it seems that the returned signed integer
   1194     // should be interpreted as an unsigned integer.
   1195     return @as(u64, @bitCast(result));
   1196 }
   1197 
   1198 pub const QueryObjectNameError = error{
   1199     AccessDenied,
   1200     InvalidHandle,
   1201     NameTooLong,
   1202     Unexpected,
   1203 };
   1204 
   1205 pub fn QueryObjectName(handle: HANDLE, out_buffer: []u16) QueryObjectNameError![]u16 {
   1206     const out_buffer_aligned = mem.alignInSlice(out_buffer, @alignOf(OBJECT_NAME_INFORMATION)) orelse return error.NameTooLong;
   1207 
   1208     const info = @as(*OBJECT_NAME_INFORMATION, @ptrCast(out_buffer_aligned));
   1209     // buffer size is specified in bytes
   1210     const out_buffer_len = std.math.cast(ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(ULONG);
   1211     // last argument would return the length required for full_buffer, not exposed here
   1212     return switch (ntdll.NtQueryObject(handle, .ObjectNameInformation, info, out_buffer_len, null)) {
   1213         .SUCCESS => blk: {
   1214             // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0)
   1215             // if the object was "unnamed", not sure if this can happen for file handles
   1216             if (info.Name.MaximumLength == 0) break :blk error.Unexpected;
   1217             // resulting string length is specified in bytes
   1218             const path_length_unterminated = @divExact(info.Name.Length, 2);
   1219             break :blk info.Name.Buffer.?[0..path_length_unterminated];
   1220         },
   1221         .ACCESS_DENIED => error.AccessDenied,
   1222         .INVALID_HANDLE => error.InvalidHandle,
   1223         // triggered when the buffer is too small for the OBJECT_NAME_INFORMATION object (.INFO_LENGTH_MISMATCH),
   1224         // or if the buffer is too small for the file path returned (.BUFFER_OVERFLOW, .BUFFER_TOO_SMALL)
   1225         .INFO_LENGTH_MISMATCH, .BUFFER_OVERFLOW, .BUFFER_TOO_SMALL => error.NameTooLong,
   1226         else => |e| unexpectedStatus(e),
   1227     };
   1228 }
   1229 
   1230 test QueryObjectName {
   1231     if (builtin.os.tag != .windows)
   1232         return;
   1233 
   1234     //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.
   1235     var tmp = std.testing.tmpDir(.{});
   1236     defer tmp.cleanup();
   1237     const handle = tmp.dir.fd;
   1238     var out_buffer: [PATH_MAX_WIDE]u16 = undefined;
   1239 
   1240     const result_path = try QueryObjectName(handle, &out_buffer);
   1241     const required_len_in_u16 = result_path.len + @divExact(@intFromPtr(result_path.ptr) - @intFromPtr(&out_buffer), 2) + 1;
   1242     //insufficient size
   1243     try std.testing.expectError(error.NameTooLong, QueryObjectName(handle, out_buffer[0 .. required_len_in_u16 - 1]));
   1244     //exactly-sufficient size
   1245     _ = try QueryObjectName(handle, out_buffer[0..required_len_in_u16]);
   1246 }
   1247 
   1248 pub const GetFinalPathNameByHandleError = error{
   1249     AccessDenied,
   1250     BadPathName,
   1251     FileNotFound,
   1252     NameTooLong,
   1253     /// The volume does not contain a recognized file system. File system
   1254     /// drivers might not be loaded, or the volume may be corrupt.
   1255     UnrecognizedVolume,
   1256     Unexpected,
   1257 };
   1258 
   1259 /// Specifies how to format volume path in the result of `GetFinalPathNameByHandle`.
   1260 /// Defaults to DOS volume names.
   1261 pub const GetFinalPathNameByHandleFormat = struct {
   1262     volume_name: enum {
   1263         /// Format as DOS volume name
   1264         Dos,
   1265         /// Format as NT volume name
   1266         Nt,
   1267     } = .Dos,
   1268 };
   1269 
   1270 /// Returns canonical (normalized) path of handle.
   1271 /// Use `GetFinalPathNameByHandleFormat` to specify whether the path is meant to include
   1272 /// NT or DOS volume name (e.g., `\Device\HarddiskVolume0\foo.txt` versus `C:\foo.txt`).
   1273 /// If DOS volume name format is selected, note that this function does *not* prepend
   1274 /// `\\?\` prefix to the resultant path.
   1275 pub fn GetFinalPathNameByHandle(
   1276     hFile: HANDLE,
   1277     fmt: GetFinalPathNameByHandleFormat,
   1278     out_buffer: []u16,
   1279 ) GetFinalPathNameByHandleError![]u16 {
   1280     const final_path = QueryObjectName(hFile, out_buffer) catch |err| switch (err) {
   1281         // we assume InvalidHandle is close enough to FileNotFound in semantics
   1282         // to not further complicate the error set
   1283         error.InvalidHandle => return error.FileNotFound,
   1284         else => |e| return e,
   1285     };
   1286 
   1287     switch (fmt.volume_name) {
   1288         .Nt => {
   1289             // the returned path is already in .Nt format
   1290             return final_path;
   1291         },
   1292         .Dos => {
   1293             // parse the string to separate volume path from file path
   1294             const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\");
   1295 
   1296             // TODO find out if a path can start with something besides `\Device\<volume name>`,
   1297             // and if we need to handle it differently
   1298             // (i.e. how to determine the start and end of the volume name in that case)
   1299             if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected;
   1300 
   1301             const file_path_begin_index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable;
   1302             const volume_name_u16 = final_path[0..file_path_begin_index];
   1303             const device_name_u16 = volume_name_u16[expected_prefix.len..];
   1304             const file_name_u16 = final_path[file_path_begin_index..];
   1305 
   1306             // MUP is Multiple UNC Provider, and indicates that the path is a UNC
   1307             // path. In this case, the canonical UNC path can be gotten by just
   1308             // dropping the \Device\Mup\ and making sure the path begins with \\
   1309             if (mem.eql(u16, device_name_u16, std.unicode.utf8ToUtf16LeStringLiteral("Mup"))) {
   1310                 out_buffer[0] = '\\';
   1311                 mem.copyForwards(u16, out_buffer[1..][0..file_name_u16.len], file_name_u16);
   1312                 return out_buffer[0 .. 1 + file_name_u16.len];
   1313             }
   1314 
   1315             // Get DOS volume name. DOS volume names are actually symbolic link objects to the
   1316             // actual NT volume. For example:
   1317             // (NT) \Device\HarddiskVolume4 => (DOS) \DosDevices\C: == (DOS) C:
   1318             const MIN_SIZE = @sizeOf(MOUNTMGR_MOUNT_POINT) + MAX_PATH;
   1319             // We initialize the input buffer to all zeros for convenience since
   1320             // `DeviceIoControl` with `IOCTL_MOUNTMGR_QUERY_POINTS` expects this.
   1321             var input_buf: [MIN_SIZE]u8 align(@alignOf(MOUNTMGR_MOUNT_POINT)) = [_]u8{0} ** MIN_SIZE;
   1322             var output_buf: [MIN_SIZE * 4]u8 align(@alignOf(MOUNTMGR_MOUNT_POINTS)) = undefined;
   1323 
   1324             // This surprising path is a filesystem path to the mount manager on Windows.
   1325             // Source: https://stackoverflow.com/questions/3012828/using-ioctl-mountmgr-query-points
   1326             // This is the NT namespaced version of \\.\MountPointManager
   1327             const mgmt_path_u16 = std.unicode.utf8ToUtf16LeStringLiteral("\\??\\MountPointManager");
   1328             const mgmt_handle = OpenFile(mgmt_path_u16, .{
   1329                 .access_mask = SYNCHRONIZE,
   1330                 .share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
   1331                 .creation = FILE_OPEN,
   1332             }) catch |err| switch (err) {
   1333                 error.IsDir => return error.Unexpected,
   1334                 error.NotDir => return error.Unexpected,
   1335                 error.NoDevice => return error.Unexpected,
   1336                 error.AccessDenied => return error.Unexpected,
   1337                 error.PipeBusy => return error.Unexpected,
   1338                 error.PathAlreadyExists => return error.Unexpected,
   1339                 error.WouldBlock => return error.Unexpected,
   1340                 error.NetworkNotFound => return error.Unexpected,
   1341                 error.AntivirusInterference => return error.Unexpected,
   1342                 else => |e| return e,
   1343             };
   1344             defer CloseHandle(mgmt_handle);
   1345 
   1346             var input_struct: *MOUNTMGR_MOUNT_POINT = @ptrCast(&input_buf[0]);
   1347             input_struct.DeviceNameOffset = @sizeOf(MOUNTMGR_MOUNT_POINT);
   1348             input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2);
   1349             @memcpy(input_buf[@sizeOf(MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr)));
   1350 
   1351             DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, &input_buf, &output_buf) catch |err| switch (err) {
   1352                 error.AccessDenied => return error.Unexpected,
   1353                 else => |e| return e,
   1354             };
   1355             const mount_points_struct: *const MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]);
   1356 
   1357             const mount_points = @as(
   1358                 [*]const MOUNTMGR_MOUNT_POINT,
   1359                 @ptrCast(&mount_points_struct.MountPoints[0]),
   1360             )[0..mount_points_struct.NumberOfMountPoints];
   1361 
   1362             for (mount_points) |mount_point| {
   1363                 const symlink = @as(
   1364                     [*]const u16,
   1365                     @ptrCast(@alignCast(&output_buf[mount_point.SymbolicLinkNameOffset])),
   1366                 )[0 .. mount_point.SymbolicLinkNameLength / 2];
   1367 
   1368                 // Look for `\DosDevices\` prefix. We don't really care if there are more than one symlinks
   1369                 // with traditional DOS drive letters, so pick the first one available.
   1370                 var prefix_buf = std.unicode.utf8ToUtf16LeStringLiteral("\\DosDevices\\");
   1371                 const prefix = prefix_buf[0..prefix_buf.len];
   1372 
   1373                 if (mem.startsWith(u16, symlink, prefix)) {
   1374                     const drive_letter = symlink[prefix.len..];
   1375 
   1376                     if (out_buffer.len < drive_letter.len + file_name_u16.len) return error.NameTooLong;
   1377 
   1378                     @memcpy(out_buffer[0..drive_letter.len], drive_letter);
   1379                     mem.copyForwards(u16, out_buffer[drive_letter.len..][0..file_name_u16.len], file_name_u16);
   1380                     const total_len = drive_letter.len + file_name_u16.len;
   1381 
   1382                     // Validate that DOS does not contain any spurious nul bytes.
   1383                     if (mem.indexOfScalar(u16, out_buffer[0..total_len], 0)) |_| {
   1384                         return error.BadPathName;
   1385                     }
   1386 
   1387                     return out_buffer[0..total_len];
   1388                 } else if (mountmgrIsVolumeName(symlink)) {
   1389                     // If the symlink is a volume GUID like \??\Volume{383da0b0-717f-41b6-8c36-00500992b58d},
   1390                     // then it is a volume mounted as a path rather than a drive letter. We need to
   1391                     // query the mount manager again to get the DOS path for the volume.
   1392 
   1393                     // 49 is the maximum length accepted by mountmgrIsVolumeName
   1394                     const vol_input_size = @sizeOf(MOUNTMGR_TARGET_NAME) + (49 * 2);
   1395                     var vol_input_buf: [vol_input_size]u8 align(@alignOf(MOUNTMGR_TARGET_NAME)) = [_]u8{0} ** vol_input_size;
   1396                     // Note: If the path exceeds MAX_PATH, the Disk Management GUI doesn't accept the full path,
   1397                     // and instead if must be specified using a shortened form (e.g. C:\FOO~1\BAR~1\<...>).
   1398                     // However, just to be sure we can handle any path length, we use PATH_MAX_WIDE here.
   1399                     const min_output_size = @sizeOf(MOUNTMGR_VOLUME_PATHS) + (PATH_MAX_WIDE * 2);
   1400                     var vol_output_buf: [min_output_size]u8 align(@alignOf(MOUNTMGR_VOLUME_PATHS)) = undefined;
   1401 
   1402                     var vol_input_struct: *MOUNTMGR_TARGET_NAME = @ptrCast(&vol_input_buf[0]);
   1403                     vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2);
   1404                     @memcpy(@as([*]WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink);
   1405 
   1406                     DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, &vol_input_buf, &vol_output_buf) catch |err| switch (err) {
   1407                         error.AccessDenied => return error.Unexpected,
   1408                         else => |e| return e,
   1409                     };
   1410                     const volume_paths_struct: *const MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]);
   1411                     const volume_path = std.mem.sliceTo(@as(
   1412                         [*]const u16,
   1413                         &volume_paths_struct.MultiSz,
   1414                     )[0 .. volume_paths_struct.MultiSzLength / 2], 0);
   1415 
   1416                     if (out_buffer.len < volume_path.len + file_name_u16.len) return error.NameTooLong;
   1417 
   1418                     // `out_buffer` currently contains the memory of `file_name_u16`, so it can overlap with where
   1419                     // we want to place the filename before returning. Here are the possible overlapping cases:
   1420                     //
   1421                     // out_buffer:       [filename]
   1422                     //       dest: [___(a)___] [___(b)___]
   1423                     //
   1424                     // In the case of (a), we need to copy forwards, and in the case of (b) we need
   1425                     // to copy backwards. We also need to do this before copying the volume path because
   1426                     // it could overwrite the file_name_u16 memory.
   1427                     const file_name_dest = out_buffer[volume_path.len..][0..file_name_u16.len];
   1428                     const file_name_byte_offset = @intFromPtr(file_name_u16.ptr) - @intFromPtr(out_buffer.ptr);
   1429                     const file_name_index = file_name_byte_offset / @sizeOf(u16);
   1430                     if (volume_path.len > file_name_index)
   1431                         mem.copyBackwards(u16, file_name_dest, file_name_u16)
   1432                     else
   1433                         mem.copyForwards(u16, file_name_dest, file_name_u16);
   1434                     @memcpy(out_buffer[0..volume_path.len], volume_path);
   1435                     const total_len = volume_path.len + file_name_u16.len;
   1436 
   1437                     // Validate that DOS does not contain any spurious nul bytes.
   1438                     if (mem.indexOfScalar(u16, out_buffer[0..total_len], 0)) |_| {
   1439                         return error.BadPathName;
   1440                     }
   1441 
   1442                     return out_buffer[0..total_len];
   1443                 }
   1444             }
   1445 
   1446             // If we've ended up here, then something went wrong/is corrupted in the OS,
   1447             // so error out!
   1448             return error.FileNotFound;
   1449         },
   1450     }
   1451 }
   1452 
   1453 /// Equivalent to the MOUNTMGR_IS_VOLUME_NAME macro in mountmgr.h
   1454 fn mountmgrIsVolumeName(name: []const u16) bool {
   1455     return (name.len == 48 or (name.len == 49 and name[48] == mem.nativeToLittle(u16, '\\'))) and
   1456         name[0] == mem.nativeToLittle(u16, '\\') and
   1457         (name[1] == mem.nativeToLittle(u16, '?') or name[1] == mem.nativeToLittle(u16, '\\')) and
   1458         name[2] == mem.nativeToLittle(u16, '?') and
   1459         name[3] == mem.nativeToLittle(u16, '\\') and
   1460         mem.startsWith(u16, name[4..], std.unicode.utf8ToUtf16LeStringLiteral("Volume{")) and
   1461         name[19] == mem.nativeToLittle(u16, '-') and
   1462         name[24] == mem.nativeToLittle(u16, '-') and
   1463         name[29] == mem.nativeToLittle(u16, '-') and
   1464         name[34] == mem.nativeToLittle(u16, '-') and
   1465         name[47] == mem.nativeToLittle(u16, '}');
   1466 }
   1467 
   1468 test mountmgrIsVolumeName {
   1469     const L = std.unicode.utf8ToUtf16LeStringLiteral;
   1470     try std.testing.expect(mountmgrIsVolumeName(L("\\\\?\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));
   1471     try std.testing.expect(mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));
   1472     try std.testing.expect(mountmgrIsVolumeName(L("\\\\?\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}\\")));
   1473     try std.testing.expect(mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}\\")));
   1474     try std.testing.expect(!mountmgrIsVolumeName(L("\\\\.\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));
   1475     try std.testing.expect(!mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}\\foo")));
   1476     try std.testing.expect(!mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58}")));
   1477 }
   1478 
   1479 test GetFinalPathNameByHandle {
   1480     if (builtin.os.tag != .windows)
   1481         return;
   1482 
   1483     //any file will do
   1484     var tmp = std.testing.tmpDir(.{});
   1485     defer tmp.cleanup();
   1486     const handle = tmp.dir.fd;
   1487     var buffer: [PATH_MAX_WIDE]u16 = undefined;
   1488 
   1489     //check with sufficient size
   1490     const nt_path = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Nt }, &buffer);
   1491     _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, &buffer);
   1492 
   1493     const required_len_in_u16 = nt_path.len + @divExact(@intFromPtr(nt_path.ptr) - @intFromPtr(&buffer), 2) + 1;
   1494     //check with insufficient size
   1495     try std.testing.expectError(error.NameTooLong, GetFinalPathNameByHandle(handle, .{ .volume_name = .Nt }, buffer[0 .. required_len_in_u16 - 1]));
   1496     try std.testing.expectError(error.NameTooLong, GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0 .. required_len_in_u16 - 1]));
   1497 
   1498     //check with exactly-sufficient size
   1499     _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Nt }, buffer[0..required_len_in_u16]);
   1500     _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0..required_len_in_u16]);
   1501 }
   1502 
   1503 pub const GetFileSizeError = error{Unexpected};
   1504 
   1505 pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
   1506     var file_size: LARGE_INTEGER = undefined;
   1507     if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) {
   1508         switch (GetLastError()) {
   1509             else => |err| return unexpectedError(err),
   1510         }
   1511     }
   1512     return @as(u64, @bitCast(file_size));
   1513 }
   1514 
   1515 pub const GetFileAttributesError = error{
   1516     FileNotFound,
   1517     PermissionDenied,
   1518     Unexpected,
   1519 };
   1520 
   1521 pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
   1522     const filename_w = try sliceToPrefixedFileW(null, filename);
   1523     return GetFileAttributesW(filename_w.span().ptr);
   1524 }
   1525 
   1526 pub fn GetFileAttributesW(lpFileName: [*:0]const u16) GetFileAttributesError!DWORD {
   1527     const rc = kernel32.GetFileAttributesW(lpFileName);
   1528     if (rc == INVALID_FILE_ATTRIBUTES) {
   1529         switch (GetLastError()) {
   1530             .FILE_NOT_FOUND => return error.FileNotFound,
   1531             .PATH_NOT_FOUND => return error.FileNotFound,
   1532             .ACCESS_DENIED => return error.PermissionDenied,
   1533             else => |err| return unexpectedError(err),
   1534         }
   1535     }
   1536     return rc;
   1537 }
   1538 
   1539 pub fn WSAStartup(majorVersion: u8, minorVersion: u8) !ws2_32.WSADATA {
   1540     var wsadata: ws2_32.WSADATA = undefined;
   1541     return switch (ws2_32.WSAStartup((@as(WORD, minorVersion) << 8) | majorVersion, &wsadata)) {
   1542         0 => wsadata,
   1543         else => |err_int| switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
   1544             .WSASYSNOTREADY => return error.SystemNotAvailable,
   1545             .WSAVERNOTSUPPORTED => return error.VersionNotSupported,
   1546             .WSAEINPROGRESS => return error.BlockingOperationInProgress,
   1547             .WSAEPROCLIM => return error.ProcessFdQuotaExceeded,
   1548             else => |err| return unexpectedWSAError(err),
   1549         },
   1550     };
   1551 }
   1552 
   1553 pub fn WSACleanup() !void {
   1554     return switch (ws2_32.WSACleanup()) {
   1555         0 => {},
   1556         ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
   1557             .WSANOTINITIALISED => return error.NotInitialized,
   1558             .WSAENETDOWN => return error.NetworkNotAvailable,
   1559             .WSAEINPROGRESS => return error.BlockingOperationInProgress,
   1560             else => |err| return unexpectedWSAError(err),
   1561         },
   1562         else => unreachable,
   1563     };
   1564 }
   1565 
   1566 var wsa_startup_mutex: std.Thread.Mutex = .{};
   1567 
   1568 pub fn callWSAStartup() !void {
   1569     wsa_startup_mutex.lock();
   1570     defer wsa_startup_mutex.unlock();
   1571 
   1572     // Here we could use a flag to prevent multiple threads to prevent
   1573     // multiple calls to WSAStartup, but it doesn't matter. We're globally
   1574     // leaking the resource intentionally, and the mutex already prevents
   1575     // data races within the WSAStartup function.
   1576     _ = WSAStartup(2, 2) catch |err| switch (err) {
   1577         error.SystemNotAvailable => return error.SystemResources,
   1578         error.VersionNotSupported => return error.Unexpected,
   1579         error.BlockingOperationInProgress => return error.Unexpected,
   1580         error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
   1581         error.Unexpected => return error.Unexpected,
   1582     };
   1583 }
   1584 
   1585 /// Microsoft requires WSAStartup to be called to initialize, or else
   1586 /// WSASocketW will return WSANOTINITIALISED.
   1587 /// Since this is a standard library, we do not have the luxury of
   1588 /// putting initialization code anywhere, because we would not want
   1589 /// to pay the cost of calling WSAStartup if there ended up being no
   1590 /// networking. Also, if Zig code is used as a library, Zig is not in
   1591 /// charge of the start code, and we couldn't put in any initialization
   1592 /// code even if we wanted to.
   1593 /// The documentation for WSAStartup mentions that there must be a
   1594 /// matching WSACleanup call. It is not possible for the Zig Standard
   1595 /// Library to honor this for the same reason - there is nowhere to put
   1596 /// deinitialization code.
   1597 /// So, API users of the zig std lib have two options:
   1598 ///  * (recommended) The simple, cross-platform way: just call `WSASocketW`
   1599 ///    and don't worry about it. Zig will call WSAStartup() in a thread-safe
   1600 ///    manner and never deinitialize networking. This is ideal for an
   1601 ///    application which has the capability to do networking.
   1602 ///  * The getting-your-hands-dirty way: call `WSAStartup()` before doing
   1603 ///    networking, so that the error handling code for WSANOTINITIALISED never
   1604 ///    gets run, which then allows the application or library to call `WSACleanup()`.
   1605 ///    This could make sense for a library, which has init and deinit
   1606 ///    functions for the whole library's lifetime.
   1607 pub fn WSASocketW(
   1608     af: i32,
   1609     socket_type: i32,
   1610     protocol: i32,
   1611     protocolInfo: ?*ws2_32.WSAPROTOCOL_INFOW,
   1612     g: ws2_32.GROUP,
   1613     dwFlags: DWORD,
   1614 ) !ws2_32.SOCKET {
   1615     var first = true;
   1616     while (true) {
   1617         const rc = ws2_32.WSASocketW(af, socket_type, protocol, protocolInfo, g, dwFlags);
   1618         if (rc == ws2_32.INVALID_SOCKET) {
   1619             switch (ws2_32.WSAGetLastError()) {
   1620                 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
   1621                 .WSAEMFILE => return error.ProcessFdQuotaExceeded,
   1622                 .WSAENOBUFS => return error.SystemResources,
   1623                 .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,
   1624                 .WSANOTINITIALISED => {
   1625                     if (!first) return error.Unexpected;
   1626                     first = false;
   1627                     try callWSAStartup();
   1628                     continue;
   1629                 },
   1630                 else => |err| return unexpectedWSAError(err),
   1631             }
   1632         }
   1633         return rc;
   1634     }
   1635 }
   1636 
   1637 pub fn bind(s: ws2_32.SOCKET, name: *const ws2_32.sockaddr, namelen: ws2_32.socklen_t) i32 {
   1638     return ws2_32.bind(s, name, @as(i32, @intCast(namelen)));
   1639 }
   1640 
   1641 pub fn listen(s: ws2_32.SOCKET, backlog: u31) i32 {
   1642     return ws2_32.listen(s, backlog);
   1643 }
   1644 
   1645 pub fn closesocket(s: ws2_32.SOCKET) !void {
   1646     switch (ws2_32.closesocket(s)) {
   1647         0 => {},
   1648         ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
   1649             else => |err| return unexpectedWSAError(err),
   1650         },
   1651         else => unreachable,
   1652     }
   1653 }
   1654 
   1655 pub fn accept(s: ws2_32.SOCKET, name: ?*ws2_32.sockaddr, namelen: ?*ws2_32.socklen_t) ws2_32.SOCKET {
   1656     assert((name == null) == (namelen == null));
   1657     return ws2_32.accept(s, name, @as(?*i32, @ptrCast(namelen)));
   1658 }
   1659 
   1660 pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
   1661     return ws2_32.getsockname(s, name, @as(*i32, @ptrCast(namelen)));
   1662 }
   1663 
   1664 pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
   1665     return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
   1666 }
   1667 
   1668 pub fn sendmsg(
   1669     s: ws2_32.SOCKET,
   1670     msg: *const ws2_32.WSAMSG,
   1671     flags: u32,
   1672 ) i32 {
   1673     var bytes_send: DWORD = undefined;
   1674     if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
   1675         return ws2_32.SOCKET_ERROR;
   1676     } else {
   1677         return @as(i32, @as(u31, @intCast(bytes_send)));
   1678     }
   1679 }
   1680 
   1681 pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
   1682     var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = @constCast(buf) };
   1683     var bytes_send: DWORD = undefined;
   1684     if (ws2_32.WSASendTo(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_send, flags, to, @as(i32, @intCast(to_len)), null, null) == ws2_32.SOCKET_ERROR) {
   1685         return ws2_32.SOCKET_ERROR;
   1686     } else {
   1687         return @as(i32, @as(u31, @intCast(bytes_send)));
   1688     }
   1689 }
   1690 
   1691 pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 {
   1692     var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = buf };
   1693     var bytes_received: DWORD = undefined;
   1694     var flags_inout = flags;
   1695     if (ws2_32.WSARecvFrom(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_received, &flags_inout, from, @as(?*i32, @ptrCast(from_len)), null, null) == ws2_32.SOCKET_ERROR) {
   1696         return ws2_32.SOCKET_ERROR;
   1697     } else {
   1698         return @as(i32, @as(u31, @intCast(bytes_received)));
   1699     }
   1700 }
   1701 
   1702 pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 {
   1703     return ws2_32.WSAPoll(fds, n, timeout);
   1704 }
   1705 
   1706 pub fn WSAIoctl(
   1707     s: ws2_32.SOCKET,
   1708     dwIoControlCode: DWORD,
   1709     inBuffer: ?[]const u8,
   1710     outBuffer: []u8,
   1711     overlapped: ?*OVERLAPPED,
   1712     completionRoutine: ?ws2_32.LPWSAOVERLAPPED_COMPLETION_ROUTINE,
   1713 ) !DWORD {
   1714     var bytes: DWORD = undefined;
   1715     switch (ws2_32.WSAIoctl(
   1716         s,
   1717         dwIoControlCode,
   1718         if (inBuffer) |i| i.ptr else null,
   1719         if (inBuffer) |i| @as(DWORD, @intCast(i.len)) else 0,
   1720         outBuffer.ptr,
   1721         @as(DWORD, @intCast(outBuffer.len)),
   1722         &bytes,
   1723         overlapped,
   1724         completionRoutine,
   1725     )) {
   1726         0 => {},
   1727         ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
   1728             else => |err| return unexpectedWSAError(err),
   1729         },
   1730         else => unreachable,
   1731     }
   1732     return bytes;
   1733 }
   1734 
   1735 const GetModuleFileNameError = error{Unexpected};
   1736 
   1737 pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) GetModuleFileNameError![:0]u16 {
   1738     const rc = kernel32.GetModuleFileNameW(hModule, buf_ptr, buf_len);
   1739     if (rc == 0) {
   1740         switch (GetLastError()) {
   1741             else => |err| return unexpectedError(err),
   1742         }
   1743     }
   1744     return buf_ptr[0..rc :0];
   1745 }
   1746 
   1747 pub const TerminateProcessError = error{ PermissionDenied, Unexpected };
   1748 
   1749 pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {
   1750     if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {
   1751         switch (GetLastError()) {
   1752             Win32Error.ACCESS_DENIED => return error.PermissionDenied,
   1753             else => |err| return unexpectedError(err),
   1754         }
   1755     }
   1756 }
   1757 
   1758 pub const VirtualAllocError = error{Unexpected};
   1759 
   1760 pub fn VirtualAlloc(addr: ?LPVOID, size: usize, alloc_type: DWORD, flProtect: DWORD) VirtualAllocError!LPVOID {
   1761     return kernel32.VirtualAlloc(addr, size, alloc_type, flProtect) orelse {
   1762         switch (GetLastError()) {
   1763             else => |err| return unexpectedError(err),
   1764         }
   1765     };
   1766 }
   1767 
   1768 pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
   1769     assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
   1770 }
   1771 
   1772 pub const VirtualProtectError = error{
   1773     InvalidAddress,
   1774     Unexpected,
   1775 };
   1776 
   1777 pub fn VirtualProtect(lpAddress: ?LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: *DWORD) VirtualProtectError!void {
   1778     // ntdll takes an extra level of indirection here
   1779     var addr = lpAddress;
   1780     var size = dwSize;
   1781     switch (ntdll.NtProtectVirtualMemory(self_process_handle, &addr, &size, flNewProtect, lpflOldProtect)) {
   1782         .SUCCESS => {},
   1783         .INVALID_ADDRESS => return error.InvalidAddress,
   1784         else => |st| return unexpectedStatus(st),
   1785     }
   1786 }
   1787 
   1788 pub fn VirtualProtectEx(handle: HANDLE, addr: ?LPVOID, size: SIZE_T, new_prot: DWORD) VirtualProtectError!DWORD {
   1789     var old_prot: DWORD = undefined;
   1790     var out_addr = addr;
   1791     var out_size = size;
   1792     switch (ntdll.NtProtectVirtualMemory(
   1793         handle,
   1794         &out_addr,
   1795         &out_size,
   1796         new_prot,
   1797         &old_prot,
   1798     )) {
   1799         .SUCCESS => return old_prot,
   1800         .INVALID_ADDRESS => return error.InvalidAddress,
   1801         // TODO: map errors
   1802         else => |rc| return unexpectedStatus(rc),
   1803     }
   1804 }
   1805 
   1806 pub const VirtualQueryError = error{Unexpected};
   1807 
   1808 pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQueryError!SIZE_T {
   1809     const rc = kernel32.VirtualQuery(lpAddress, lpBuffer, dwLength);
   1810     if (rc == 0) {
   1811         switch (GetLastError()) {
   1812             else => |err| return unexpectedError(err),
   1813         }
   1814     }
   1815 
   1816     return rc;
   1817 }
   1818 
   1819 pub const SetConsoleTextAttributeError = error{Unexpected};
   1820 
   1821 pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
   1822     if (kernel32.SetConsoleTextAttribute(hConsoleOutput, wAttributes) == 0) {
   1823         switch (GetLastError()) {
   1824             else => |err| return unexpectedError(err),
   1825         }
   1826     }
   1827 }
   1828 
   1829 pub fn SetConsoleCtrlHandler(handler_routine: ?HANDLER_ROUTINE, add: bool) !void {
   1830     const success = kernel32.SetConsoleCtrlHandler(
   1831         handler_routine,
   1832         if (add) TRUE else FALSE,
   1833     );
   1834 
   1835     if (success == FALSE) {
   1836         return switch (GetLastError()) {
   1837             else => |err| unexpectedError(err),
   1838         };
   1839     }
   1840 }
   1841 
   1842 pub fn SetFileCompletionNotificationModes(handle: HANDLE, flags: UCHAR) !void {
   1843     const success = kernel32.SetFileCompletionNotificationModes(handle, flags);
   1844     if (success == FALSE) {
   1845         return switch (GetLastError()) {
   1846             else => |err| unexpectedError(err),
   1847         };
   1848     }
   1849 }
   1850 
   1851 pub const GetEnvironmentStringsError = error{OutOfMemory};
   1852 
   1853 pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*:0]u16 {
   1854     return kernel32.GetEnvironmentStringsW() orelse return error.OutOfMemory;
   1855 }
   1856 
   1857 pub fn FreeEnvironmentStringsW(penv: [*:0]u16) void {
   1858     assert(kernel32.FreeEnvironmentStringsW(penv) != 0);
   1859 }
   1860 
   1861 pub const GetEnvironmentVariableError = error{
   1862     EnvironmentVariableNotFound,
   1863     Unexpected,
   1864 };
   1865 
   1866 pub fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: [*]u16, nSize: DWORD) GetEnvironmentVariableError!DWORD {
   1867     const rc = kernel32.GetEnvironmentVariableW(lpName, lpBuffer, nSize);
   1868     if (rc == 0) {
   1869         switch (GetLastError()) {
   1870             .ENVVAR_NOT_FOUND => return error.EnvironmentVariableNotFound,
   1871             else => |err| return unexpectedError(err),
   1872         }
   1873     }
   1874     return rc;
   1875 }
   1876 
   1877 pub const CreateProcessError = error{
   1878     FileNotFound,
   1879     AccessDenied,
   1880     InvalidName,
   1881     NameTooLong,
   1882     InvalidExe,
   1883     Unexpected,
   1884 };
   1885 
   1886 pub fn CreateProcessW(
   1887     lpApplicationName: ?LPCWSTR,
   1888     lpCommandLine: ?LPWSTR,
   1889     lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
   1890     lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
   1891     bInheritHandles: BOOL,
   1892     dwCreationFlags: DWORD,
   1893     lpEnvironment: ?*anyopaque,
   1894     lpCurrentDirectory: ?LPCWSTR,
   1895     lpStartupInfo: *STARTUPINFOW,
   1896     lpProcessInformation: *PROCESS_INFORMATION,
   1897 ) CreateProcessError!void {
   1898     if (kernel32.CreateProcessW(
   1899         lpApplicationName,
   1900         lpCommandLine,
   1901         lpProcessAttributes,
   1902         lpThreadAttributes,
   1903         bInheritHandles,
   1904         dwCreationFlags,
   1905         lpEnvironment,
   1906         lpCurrentDirectory,
   1907         lpStartupInfo,
   1908         lpProcessInformation,
   1909     ) == 0) {
   1910         switch (GetLastError()) {
   1911             .FILE_NOT_FOUND => return error.FileNotFound,
   1912             .PATH_NOT_FOUND => return error.FileNotFound,
   1913             .ACCESS_DENIED => return error.AccessDenied,
   1914             .INVALID_PARAMETER => unreachable,
   1915             .INVALID_NAME => return error.InvalidName,
   1916             .FILENAME_EXCED_RANGE => return error.NameTooLong,
   1917             // These are all the system errors that are mapped to ENOEXEC by
   1918             // the undocumented _dosmaperr (old CRT) or __acrt_errno_map_os_error
   1919             // (newer CRT) functions. Their code can be found in crt/src/dosmap.c (old SDK)
   1920             // or urt/misc/errno.cpp (newer SDK) in the Windows SDK.
   1921             .BAD_FORMAT,
   1922             .INVALID_STARTING_CODESEG, // MIN_EXEC_ERROR in errno.cpp
   1923             .INVALID_STACKSEG,
   1924             .INVALID_MODULETYPE,
   1925             .INVALID_EXE_SIGNATURE,
   1926             .EXE_MARKED_INVALID,
   1927             .BAD_EXE_FORMAT,
   1928             .ITERATED_DATA_EXCEEDS_64k,
   1929             .INVALID_MINALLOCSIZE,
   1930             .DYNLINK_FROM_INVALID_RING,
   1931             .IOPL_NOT_ENABLED,
   1932             .INVALID_SEGDPL,
   1933             .AUTODATASEG_EXCEEDS_64k,
   1934             .RING2SEG_MUST_BE_MOVABLE,
   1935             .RELOC_CHAIN_XEEDS_SEGLIM,
   1936             .INFLOOP_IN_RELOC_CHAIN, // MAX_EXEC_ERROR in errno.cpp
   1937             // This one is not mapped to ENOEXEC but it is possible, for example
   1938             // when calling CreateProcessW on a plain text file with a .exe extension
   1939             .EXE_MACHINE_TYPE_MISMATCH,
   1940             => return error.InvalidExe,
   1941             else => |err| return unexpectedError(err),
   1942         }
   1943     }
   1944 }
   1945 
   1946 pub const LoadLibraryError = error{
   1947     FileNotFound,
   1948     Unexpected,
   1949 };
   1950 
   1951 pub fn LoadLibraryW(lpLibFileName: [*:0]const u16) LoadLibraryError!HMODULE {
   1952     return kernel32.LoadLibraryW(lpLibFileName) orelse {
   1953         switch (GetLastError()) {
   1954             .FILE_NOT_FOUND => return error.FileNotFound,
   1955             .PATH_NOT_FOUND => return error.FileNotFound,
   1956             .MOD_NOT_FOUND => return error.FileNotFound,
   1957             else => |err| return unexpectedError(err),
   1958         }
   1959     };
   1960 }
   1961 
   1962 pub const LoadLibraryFlags = enum(DWORD) {
   1963     none = 0,
   1964     dont_resolve_dll_references = 0x00000001,
   1965     load_ignore_code_authz_level = 0x00000010,
   1966     load_library_as_datafile = 0x00000002,
   1967     load_library_as_datafile_exclusive = 0x00000040,
   1968     load_library_as_image_resource = 0x00000020,
   1969     load_library_search_application_dir = 0x00000200,
   1970     load_library_search_default_dirs = 0x00001000,
   1971     load_library_search_dll_load_dir = 0x00000100,
   1972     load_library_search_system32 = 0x00000800,
   1973     load_library_search_user_dirs = 0x00000400,
   1974     load_with_altered_search_path = 0x00000008,
   1975     load_library_require_signed_target = 0x00000080,
   1976     load_library_safe_current_dirs = 0x00002000,
   1977 };
   1978 
   1979 pub fn LoadLibraryExW(lpLibFileName: [*:0]const u16, dwFlags: LoadLibraryFlags) LoadLibraryError!HMODULE {
   1980     return kernel32.LoadLibraryExW(lpLibFileName, null, @intFromEnum(dwFlags)) orelse {
   1981         switch (GetLastError()) {
   1982             .FILE_NOT_FOUND => return error.FileNotFound,
   1983             .PATH_NOT_FOUND => return error.FileNotFound,
   1984             .MOD_NOT_FOUND => return error.FileNotFound,
   1985             else => |err| return unexpectedError(err),
   1986         }
   1987     };
   1988 }
   1989 
   1990 pub fn FreeLibrary(hModule: HMODULE) void {
   1991     assert(kernel32.FreeLibrary(hModule) != 0);
   1992 }
   1993 
   1994 pub fn QueryPerformanceFrequency() u64 {
   1995     // "On systems that run Windows XP or later, the function will always succeed"
   1996     // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancefrequency
   1997     var result: LARGE_INTEGER = undefined;
   1998     assert(ntdll.RtlQueryPerformanceFrequency(&result) != 0);
   1999     // The kernel treats this integer as unsigned.
   2000     return @as(u64, @bitCast(result));
   2001 }
   2002 
   2003 pub fn QueryPerformanceCounter() u64 {
   2004     // "On systems that run Windows XP or later, the function will always succeed"
   2005     // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancecounter
   2006     var result: LARGE_INTEGER = undefined;
   2007     assert(ntdll.RtlQueryPerformanceCounter(&result) != 0);
   2008     // The kernel treats this integer as unsigned.
   2009     return @as(u64, @bitCast(result));
   2010 }
   2011 
   2012 pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*anyopaque, Context: ?*anyopaque) void {
   2013     assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
   2014 }
   2015 
   2016 pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *anyopaque) void {
   2017     assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0);
   2018 }
   2019 
   2020 pub fn HeapDestroy(hHeap: HANDLE) void {
   2021     assert(kernel32.HeapDestroy(hHeap) != 0);
   2022 }
   2023 
   2024 pub fn LocalFree(hMem: HLOCAL) void {
   2025     assert(kernel32.LocalFree(hMem) == null);
   2026 }
   2027 
   2028 pub const SetFileTimeError = error{Unexpected};
   2029 
   2030 pub fn SetFileTime(
   2031     hFile: HANDLE,
   2032     lpCreationTime: ?*const FILETIME,
   2033     lpLastAccessTime: ?*const FILETIME,
   2034     lpLastWriteTime: ?*const FILETIME,
   2035 ) SetFileTimeError!void {
   2036     const rc = kernel32.SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
   2037     if (rc == 0) {
   2038         switch (GetLastError()) {
   2039             else => |err| return unexpectedError(err),
   2040         }
   2041     }
   2042 }
   2043 
   2044 pub const LockFileError = error{
   2045     SystemResources,
   2046     WouldBlock,
   2047 } || UnexpectedError;
   2048 
   2049 pub fn LockFile(
   2050     FileHandle: HANDLE,
   2051     Event: ?HANDLE,
   2052     ApcRoutine: ?*IO_APC_ROUTINE,
   2053     ApcContext: ?*anyopaque,
   2054     IoStatusBlock: *IO_STATUS_BLOCK,
   2055     ByteOffset: *const LARGE_INTEGER,
   2056     Length: *const LARGE_INTEGER,
   2057     Key: ?*ULONG,
   2058     FailImmediately: BOOLEAN,
   2059     ExclusiveLock: BOOLEAN,
   2060 ) !void {
   2061     const rc = ntdll.NtLockFile(
   2062         FileHandle,
   2063         Event,
   2064         ApcRoutine,
   2065         ApcContext,
   2066         IoStatusBlock,
   2067         ByteOffset,
   2068         Length,
   2069         Key,
   2070         FailImmediately,
   2071         ExclusiveLock,
   2072     );
   2073     switch (rc) {
   2074         .SUCCESS => return,
   2075         .INSUFFICIENT_RESOURCES => return error.SystemResources,
   2076         .LOCK_NOT_GRANTED => return error.WouldBlock,
   2077         .ACCESS_VIOLATION => unreachable, // bad io_status_block pointer
   2078         else => return unexpectedStatus(rc),
   2079     }
   2080 }
   2081 
   2082 pub const UnlockFileError = error{
   2083     RangeNotLocked,
   2084 } || UnexpectedError;
   2085 
   2086 pub fn UnlockFile(
   2087     FileHandle: HANDLE,
   2088     IoStatusBlock: *IO_STATUS_BLOCK,
   2089     ByteOffset: *const LARGE_INTEGER,
   2090     Length: *const LARGE_INTEGER,
   2091     Key: ?*ULONG,
   2092 ) !void {
   2093     const rc = ntdll.NtUnlockFile(FileHandle, IoStatusBlock, ByteOffset, Length, Key);
   2094     switch (rc) {
   2095         .SUCCESS => return,
   2096         .RANGE_NOT_LOCKED => return error.RangeNotLocked,
   2097         .ACCESS_VIOLATION => unreachable, // bad io_status_block pointer
   2098         else => return unexpectedStatus(rc),
   2099     }
   2100 }
   2101 
   2102 /// This is a workaround for the C backend until zig has the ability to put
   2103 /// C code in inline assembly.
   2104 extern fn zig_x86_windows_teb() callconv(.c) *anyopaque;
   2105 extern fn zig_x86_64_windows_teb() callconv(.c) *anyopaque;
   2106 
   2107 pub fn teb() *TEB {
   2108     return switch (native_arch) {
   2109         .x86 => blk: {
   2110             if (builtin.zig_backend == .stage2_c) {
   2111                 break :blk @ptrCast(@alignCast(zig_x86_windows_teb()));
   2112             } else {
   2113                 break :blk asm (
   2114                     \\ movl %%fs:0x18, %[ptr]
   2115                     : [ptr] "=r" (-> *TEB),
   2116                 );
   2117             }
   2118         },
   2119         .x86_64 => blk: {
   2120             if (builtin.zig_backend == .stage2_c) {
   2121                 break :blk @ptrCast(@alignCast(zig_x86_64_windows_teb()));
   2122             } else {
   2123                 break :blk asm (
   2124                     \\ movq %%gs:0x30, %[ptr]
   2125                     : [ptr] "=r" (-> *TEB),
   2126                 );
   2127             }
   2128         },
   2129         .thumb => asm (
   2130             \\ mrc p15, 0, %[ptr], c13, c0, 2
   2131             : [ptr] "=r" (-> *TEB),
   2132         ),
   2133         .aarch64 => asm (
   2134             \\ mov %[ptr], x18
   2135             : [ptr] "=r" (-> *TEB),
   2136         ),
   2137         else => @compileError("unsupported arch"),
   2138     };
   2139 }
   2140 
   2141 pub fn peb() *PEB {
   2142     return teb().ProcessEnvironmentBlock;
   2143 }
   2144 
   2145 /// A file time is a 64-bit value that represents the number of 100-nanosecond
   2146 /// intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated
   2147 /// Universal Time (UTC).
   2148 /// This function returns the number of nanoseconds since the canonical epoch,
   2149 /// which is the POSIX one (Jan 01, 1970 AD).
   2150 pub fn fromSysTime(hns: i64) i128 {
   2151     const adjusted_epoch: i128 = hns + std.time.epoch.windows * (std.time.ns_per_s / 100);
   2152     return adjusted_epoch * 100;
   2153 }
   2154 
   2155 pub fn toSysTime(ns: i128) i64 {
   2156     const hns = @divFloor(ns, 100);
   2157     return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100);
   2158 }
   2159 
   2160 pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 {
   2161     const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
   2162     return fromSysTime(hns);
   2163 }
   2164 
   2165 /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME.
   2166 pub fn nanoSecondsToFileTime(ns: i128) FILETIME {
   2167     const adjusted: u64 = @bitCast(toSysTime(ns));
   2168     return FILETIME{
   2169         .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)),
   2170         .dwLowDateTime = @as(u32, @truncate(adjusted)),
   2171     };
   2172 }
   2173 
   2174 /// Compares two WTF16 strings using the equivalent functionality of
   2175 /// `RtlEqualUnicodeString` (with case insensitive comparison enabled).
   2176 /// This function can be called on any target.
   2177 pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool {
   2178     if (@inComptime() or builtin.os.tag != .windows) {
   2179         // This function compares the strings code unit by code unit (aka u16-to-u16),
   2180         // so any length difference implies inequality. In other words, there's no possible
   2181         // conversion that changes the number of WTF-16 code units needed for the uppercase/lowercase
   2182         // version in the conversion table since only codepoints <= max(u16) are eligible
   2183         // for conversion at all.
   2184         if (a.len != b.len) return false;
   2185 
   2186         for (a, b) |a_c, b_c| {
   2187             // The slices are always WTF-16 LE, so need to convert the elements to native
   2188             // endianness for the uppercasing
   2189             const a_c_native = std.mem.littleToNative(u16, a_c);
   2190             const b_c_native = std.mem.littleToNative(u16, b_c);
   2191             if (a_c != b_c and nls.upcaseW(a_c_native) != nls.upcaseW(b_c_native)) {
   2192                 return false;
   2193             }
   2194         }
   2195         return true;
   2196     }
   2197     // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a
   2198     // redundant copy of the uppercase data.
   2199     const a_bytes = @as(u16, @intCast(a.len * 2));
   2200     const a_string = UNICODE_STRING{
   2201         .Length = a_bytes,
   2202         .MaximumLength = a_bytes,
   2203         .Buffer = @constCast(a.ptr),
   2204     };
   2205     const b_bytes = @as(u16, @intCast(b.len * 2));
   2206     const b_string = UNICODE_STRING{
   2207         .Length = b_bytes,
   2208         .MaximumLength = b_bytes,
   2209         .Buffer = @constCast(b.ptr),
   2210     };
   2211     return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
   2212 }
   2213 
   2214 /// Compares two WTF-8 strings using the equivalent functionality of
   2215 /// `RtlEqualUnicodeString` (with case insensitive comparison enabled).
   2216 /// This function can be called on any target.
   2217 /// Assumes `a` and `b` are valid WTF-8.
   2218 pub fn eqlIgnoreCaseWtf8(a: []const u8, b: []const u8) bool {
   2219     // A length equality check is not possible here because there are
   2220     // some codepoints that have a different length uppercase UTF-8 representations
   2221     // than their lowercase counterparts, e.g. U+0250 (2 bytes) <-> U+2C6F (3 bytes).
   2222     // There are 7 such codepoints in the uppercase data used by Windows.
   2223 
   2224     var a_wtf8_it = std.unicode.Wtf8View.initUnchecked(a).iterator();
   2225     var b_wtf8_it = std.unicode.Wtf8View.initUnchecked(b).iterator();
   2226 
   2227     // Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a
   2228     // redundant copy of the uppercase data.
   2229     const upcaseImpl = switch (builtin.os.tag) {
   2230         .windows => if (@inComptime()) nls.upcaseW else ntdll.RtlUpcaseUnicodeChar,
   2231         else => nls.upcaseW,
   2232     };
   2233 
   2234     while (true) {
   2235         const a_cp = a_wtf8_it.nextCodepoint() orelse break;
   2236         const b_cp = b_wtf8_it.nextCodepoint() orelse return false;
   2237 
   2238         if (a_cp <= std.math.maxInt(u16) and b_cp <= std.math.maxInt(u16)) {
   2239             if (a_cp != b_cp and upcaseImpl(@intCast(a_cp)) != upcaseImpl(@intCast(b_cp))) {
   2240                 return false;
   2241             }
   2242         } else if (a_cp != b_cp) {
   2243             return false;
   2244         }
   2245     }
   2246     // Make sure there are no leftover codepoints in b
   2247     if (b_wtf8_it.nextCodepoint() != null) return false;
   2248 
   2249     return true;
   2250 }
   2251 
   2252 fn testEqlIgnoreCase(comptime expect_eql: bool, comptime a: []const u8, comptime b: []const u8) !void {
   2253     try std.testing.expectEqual(expect_eql, eqlIgnoreCaseWtf8(a, b));
   2254     try std.testing.expectEqual(expect_eql, eqlIgnoreCaseWTF16(
   2255         std.unicode.utf8ToUtf16LeStringLiteral(a),
   2256         std.unicode.utf8ToUtf16LeStringLiteral(b),
   2257     ));
   2258 
   2259     try comptime std.testing.expect(expect_eql == eqlIgnoreCaseWtf8(a, b));
   2260     try comptime std.testing.expect(expect_eql == eqlIgnoreCaseWTF16(
   2261         std.unicode.utf8ToUtf16LeStringLiteral(a),
   2262         std.unicode.utf8ToUtf16LeStringLiteral(b),
   2263     ));
   2264 }
   2265 
   2266 test "eqlIgnoreCaseWTF16/Wtf8" {
   2267     try testEqlIgnoreCase(true, "\x01 a B Λ ɐ", "\x01 A b λ Ɐ");
   2268     // does not do case-insensitive comparison for codepoints >= U+10000
   2269     try testEqlIgnoreCase(false, "𐓏", "𐓷");
   2270 }
   2271 
   2272 pub const PathSpace = struct {
   2273     data: [PATH_MAX_WIDE:0]u16,
   2274     len: usize,
   2275 
   2276     pub fn span(self: *const PathSpace) [:0]const u16 {
   2277         return self.data[0..self.len :0];
   2278     }
   2279 };
   2280 
   2281 /// The error type for `removeDotDirsSanitized`
   2282 pub const RemoveDotDirsError = error{TooManyParentDirs};
   2283 
   2284 /// Removes '.' and '..' path components from a "sanitized relative path".
   2285 /// A "sanitized path" is one where:
   2286 ///    1) all forward slashes have been replaced with back slashes
   2287 ///    2) all repeating back slashes have been collapsed
   2288 ///    3) the path is a relative one (does not start with a back slash)
   2289 pub fn removeDotDirsSanitized(comptime T: type, path: []T) RemoveDotDirsError!usize {
   2290     std.debug.assert(path.len == 0 or path[0] != '\\');
   2291 
   2292     var write_idx: usize = 0;
   2293     var read_idx: usize = 0;
   2294     while (read_idx < path.len) {
   2295         if (path[read_idx] == '.') {
   2296             if (read_idx + 1 == path.len)
   2297                 return write_idx;
   2298 
   2299             const after_dot = path[read_idx + 1];
   2300             if (after_dot == '\\') {
   2301                 read_idx += 2;
   2302                 continue;
   2303             }
   2304             if (after_dot == '.' and (read_idx + 2 == path.len or path[read_idx + 2] == '\\')) {
   2305                 if (write_idx == 0) return error.TooManyParentDirs;
   2306                 std.debug.assert(write_idx >= 2);
   2307                 write_idx -= 1;
   2308                 while (true) {
   2309                     write_idx -= 1;
   2310                     if (write_idx == 0) break;
   2311                     if (path[write_idx] == '\\') {
   2312                         write_idx += 1;
   2313                         break;
   2314                     }
   2315                 }
   2316                 if (read_idx + 2 == path.len)
   2317                     return write_idx;
   2318                 read_idx += 3;
   2319                 continue;
   2320             }
   2321         }
   2322 
   2323         // skip to the next path separator
   2324         while (true) : (read_idx += 1) {
   2325             if (read_idx == path.len)
   2326                 return write_idx;
   2327             path[write_idx] = path[read_idx];
   2328             write_idx += 1;
   2329             if (path[read_idx] == '\\')
   2330                 break;
   2331         }
   2332         read_idx += 1;
   2333     }
   2334     return write_idx;
   2335 }
   2336 
   2337 /// Normalizes a Windows path with the following steps:
   2338 ///     1) convert all forward slashes to back slashes
   2339 ///     2) collapse duplicate back slashes
   2340 ///     3) remove '.' and '..' directory parts
   2341 /// Returns the length of the new path.
   2342 pub fn normalizePath(comptime T: type, path: []T) RemoveDotDirsError!usize {
   2343     mem.replaceScalar(T, path, '/', '\\');
   2344     const new_len = mem.collapseRepeatsLen(T, path, '\\');
   2345 
   2346     const prefix_len: usize = init: {
   2347         if (new_len >= 1 and path[0] == '\\') break :init 1;
   2348         if (new_len >= 2 and path[1] == ':')
   2349             break :init if (new_len >= 3 and path[2] == '\\') @as(usize, 3) else @as(usize, 2);
   2350         break :init 0;
   2351     };
   2352 
   2353     return prefix_len + try removeDotDirsSanitized(T, path[prefix_len..new_len]);
   2354 }
   2355 
   2356 pub const Wtf8ToPrefixedFileWError = error{InvalidWtf8} || Wtf16ToPrefixedFileWError;
   2357 
   2358 /// Same as `sliceToPrefixedFileW` but accepts a pointer
   2359 /// to a null-terminated WTF-8 encoded path.
   2360 /// https://simonsapin.github.io/wtf-8/
   2361 pub fn cStrToPrefixedFileW(dir: ?HANDLE, s: [*:0]const u8) Wtf8ToPrefixedFileWError!PathSpace {
   2362     return sliceToPrefixedFileW(dir, mem.sliceTo(s, 0));
   2363 }
   2364 
   2365 /// Same as `wToPrefixedFileW` but accepts a WTF-8 encoded path.
   2366 /// https://simonsapin.github.io/wtf-8/
   2367 pub fn sliceToPrefixedFileW(dir: ?HANDLE, path: []const u8) Wtf8ToPrefixedFileWError!PathSpace {
   2368     var temp_path: PathSpace = undefined;
   2369     temp_path.len = try std.unicode.wtf8ToWtf16Le(&temp_path.data, path);
   2370     temp_path.data[temp_path.len] = 0;
   2371     return wToPrefixedFileW(dir, temp_path.span());
   2372 }
   2373 
   2374 pub const Wtf16ToPrefixedFileWError = error{
   2375     AccessDenied,
   2376     BadPathName,
   2377     FileNotFound,
   2378     NameTooLong,
   2379     Unexpected,
   2380 };
   2381 
   2382 /// Converts the `path` to WTF16, null-terminated. If the path contains any
   2383 /// namespace prefix, or is anything but a relative path (rooted, drive relative,
   2384 /// etc) the result will have the NT-style prefix `\??\`.
   2385 ///
   2386 /// Similar to RtlDosPathNameToNtPathName_U with a few differences:
   2387 /// - Does not allocate on the heap.
   2388 /// - Relative paths are kept as relative unless they contain too many ..
   2389 ///   components, in which case they are resolved against the `dir` if it
   2390 ///   is non-null, or the CWD if it is null.
   2391 /// - Special case device names like COM1, NUL, etc are not handled specially (TODO)
   2392 /// - . and space are not stripped from the end of relative paths (potential TODO)
   2393 pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) Wtf16ToPrefixedFileWError!PathSpace {
   2394     const nt_prefix = [_]u16{ '\\', '?', '?', '\\' };
   2395     switch (getNamespacePrefix(u16, path)) {
   2396         // TODO: Figure out a way to design an API that can avoid the copy for .nt,
   2397         //       since it is always returned fully unmodified.
   2398         .nt, .verbatim => {
   2399             var path_space: PathSpace = undefined;
   2400             path_space.data[0..nt_prefix.len].* = nt_prefix;
   2401             const len_after_prefix = path.len - nt_prefix.len;
   2402             @memcpy(path_space.data[nt_prefix.len..][0..len_after_prefix], path[nt_prefix.len..]);
   2403             path_space.len = path.len;
   2404             path_space.data[path_space.len] = 0;
   2405             return path_space;
   2406         },
   2407         .local_device, .fake_verbatim => {
   2408             var path_space: PathSpace = undefined;
   2409             const path_byte_len = ntdll.RtlGetFullPathName_U(
   2410                 path.ptr,
   2411                 path_space.data.len * 2,
   2412                 &path_space.data,
   2413                 null,
   2414             );
   2415             if (path_byte_len == 0) {
   2416                 // TODO: This may not be the right error
   2417                 return error.BadPathName;
   2418             } else if (path_byte_len / 2 > path_space.data.len) {
   2419                 return error.NameTooLong;
   2420             }
   2421             path_space.len = path_byte_len / 2;
   2422             // Both prefixes will be normalized but retained, so all
   2423             // we need to do now is replace them with the NT prefix
   2424             path_space.data[0..nt_prefix.len].* = nt_prefix;
   2425             return path_space;
   2426         },
   2427         .none => {
   2428             const path_type = getUnprefixedPathType(u16, path);
   2429             var path_space: PathSpace = undefined;
   2430             relative: {
   2431                 if (path_type == .relative) {
   2432                     // TODO: Handle special case device names like COM1, AUX, NUL, CONIN$, CONOUT$, etc.
   2433                     //       See https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
   2434 
   2435                     // TODO: Potentially strip all trailing . and space characters from the
   2436                     //       end of the path. This is something that both RtlDosPathNameToNtPathName_U
   2437                     //       and RtlGetFullPathName_U do. Technically, trailing . and spaces
   2438                     //       are allowed, but such paths may not interact well with Windows (i.e.
   2439                     //       files with these paths can't be deleted from explorer.exe, etc).
   2440                     //       This could be something that normalizePath may want to do.
   2441 
   2442                     @memcpy(path_space.data[0..path.len], path);
   2443                     // Try to normalize, but if we get too many parent directories,
   2444                     // then we need to start over and use RtlGetFullPathName_U instead.
   2445                     path_space.len = normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) {
   2446                         error.TooManyParentDirs => break :relative,
   2447                     };
   2448                     path_space.data[path_space.len] = 0;
   2449                     return path_space;
   2450                 }
   2451             }
   2452             // We now know we are going to return an absolute NT path, so
   2453             // we can unconditionally prefix it with the NT prefix.
   2454             path_space.data[0..nt_prefix.len].* = nt_prefix;
   2455             if (path_type == .root_local_device) {
   2456                 // `\\.` and `\\?` always get converted to `\??\` exactly, so
   2457                 // we can just stop here
   2458                 path_space.len = nt_prefix.len;
   2459                 path_space.data[path_space.len] = 0;
   2460                 return path_space;
   2461             }
   2462             const path_buf_offset = switch (path_type) {
   2463                 // UNC paths will always start with `\\`. However, we want to
   2464                 // end up with something like `\??\UNC\server\share`, so to get
   2465                 // RtlGetFullPathName to write into the spot we want the `server`
   2466                 // part to end up, we need to provide an offset such that
   2467                 // the `\\` part gets written where the `C\` of `UNC\` will be
   2468                 // in the final NT path.
   2469                 .unc_absolute => nt_prefix.len + 2,
   2470                 else => nt_prefix.len,
   2471             };
   2472             const buf_len: u32 = @intCast(path_space.data.len - path_buf_offset);
   2473             const path_to_get: [:0]const u16 = path_to_get: {
   2474                 // If dir is null, then we don't need to bother with GetFinalPathNameByHandle because
   2475                 // RtlGetFullPathName_U will resolve relative paths against the CWD for us.
   2476                 if (path_type != .relative or dir == null) {
   2477                     break :path_to_get path;
   2478                 }
   2479                 // We can also skip GetFinalPathNameByHandle if the handle matches
   2480                 // the handle returned by fs.cwd()
   2481                 if (dir.? == std.fs.cwd().fd) {
   2482                     break :path_to_get path;
   2483                 }
   2484                 // At this point, we know we have a relative path that had too many
   2485                 // `..` components to be resolved by normalizePath, so we need to
   2486                 // convert it into an absolute path and let RtlGetFullPathName_U
   2487                 // canonicalize it. We do this by getting the path of the `dir`
   2488                 // and appending the relative path to it.
   2489                 var dir_path_buf: [PATH_MAX_WIDE:0]u16 = undefined;
   2490                 const dir_path = GetFinalPathNameByHandle(dir.?, .{}, &dir_path_buf) catch |err| switch (err) {
   2491                     // This mapping is not correct; it is actually expected
   2492                     // that calling GetFinalPathNameByHandle might return
   2493                     // error.UnrecognizedVolume, and in fact has been observed
   2494                     // in the wild. The problem is that wToPrefixedFileW was
   2495                     // never intended to make *any* OS syscall APIs. It's only
   2496                     // supposed to convert a string to one that is eligible to
   2497                     // be used in the ntdll syscalls.
   2498                     //
   2499                     // To solve this, this function needs to no longer call
   2500                     // GetFinalPathNameByHandle under any conditions, or the
   2501                     // calling function needs to get reworked to not need to
   2502                     // call this function.
   2503                     //
   2504                     // This may involve making breaking API changes.
   2505                     error.UnrecognizedVolume => return error.Unexpected,
   2506                     else => |e| return e,
   2507                 };
   2508                 if (dir_path.len + 1 + path.len > PATH_MAX_WIDE) {
   2509                     return error.NameTooLong;
   2510                 }
   2511                 // We don't have to worry about potentially doubling up path separators
   2512                 // here since RtlGetFullPathName_U will handle canonicalizing it.
   2513                 dir_path_buf[dir_path.len] = '\\';
   2514                 @memcpy(dir_path_buf[dir_path.len + 1 ..][0..path.len], path);
   2515                 const full_len = dir_path.len + 1 + path.len;
   2516                 dir_path_buf[full_len] = 0;
   2517                 break :path_to_get dir_path_buf[0..full_len :0];
   2518             };
   2519             const path_byte_len = ntdll.RtlGetFullPathName_U(
   2520                 path_to_get.ptr,
   2521                 buf_len * 2,
   2522                 path_space.data[path_buf_offset..].ptr,
   2523                 null,
   2524             );
   2525             if (path_byte_len == 0) {
   2526                 // TODO: This may not be the right error
   2527                 return error.BadPathName;
   2528             } else if (path_byte_len / 2 > buf_len) {
   2529                 return error.NameTooLong;
   2530             }
   2531             path_space.len = path_buf_offset + (path_byte_len / 2);
   2532             if (path_type == .unc_absolute) {
   2533                 // Now add in the UNC, the `C` should overwrite the first `\` of the
   2534                 // FullPathName, ultimately resulting in `\??\UNC\<the rest of the path>`
   2535                 std.debug.assert(path_space.data[path_buf_offset] == '\\');
   2536                 std.debug.assert(path_space.data[path_buf_offset + 1] == '\\');
   2537                 const unc = [_]u16{ 'U', 'N', 'C' };
   2538                 path_space.data[nt_prefix.len..][0..unc.len].* = unc;
   2539             }
   2540             return path_space;
   2541         },
   2542     }
   2543 }
   2544 
   2545 pub const NamespacePrefix = enum {
   2546     none,
   2547     /// `\\.\` (path separators can be `\` or `/`)
   2548     local_device,
   2549     /// `\\?\`
   2550     /// When converted to an NT path, everything past the prefix is left
   2551     /// untouched and `\\?\` is replaced by `\??\`.
   2552     verbatim,
   2553     /// `\\?\` without all path separators being `\`.
   2554     /// This seems to be recognized as a prefix, but the 'verbatim' aspect
   2555     /// is not respected (i.e. if `//?/C:/foo` is converted to an NT path,
   2556     /// it will become `\??\C:\foo` [it will be canonicalized and the //?/ won't
   2557     /// be treated as part of the final path])
   2558     fake_verbatim,
   2559     /// `\??\`
   2560     nt,
   2561 };
   2562 
   2563 /// If `T` is `u16`, then `path` should be encoded as WTF-16LE.
   2564 pub fn getNamespacePrefix(comptime T: type, path: []const T) NamespacePrefix {
   2565     if (path.len < 4) return .none;
   2566     var all_backslash = switch (mem.littleToNative(T, path[0])) {
   2567         '\\' => true,
   2568         '/' => false,
   2569         else => return .none,
   2570     };
   2571     all_backslash = all_backslash and switch (mem.littleToNative(T, path[3])) {
   2572         '\\' => true,
   2573         '/' => false,
   2574         else => return .none,
   2575     };
   2576     switch (mem.littleToNative(T, path[1])) {
   2577         '?' => if (mem.littleToNative(T, path[2]) == '?' and all_backslash) return .nt else return .none,
   2578         '\\' => {},
   2579         '/' => all_backslash = false,
   2580         else => return .none,
   2581     }
   2582     return switch (mem.littleToNative(T, path[2])) {
   2583         '?' => if (all_backslash) .verbatim else .fake_verbatim,
   2584         '.' => .local_device,
   2585         else => .none,
   2586     };
   2587 }
   2588 
   2589 test getNamespacePrefix {
   2590     try std.testing.expectEqual(NamespacePrefix.none, getNamespacePrefix(u8, ""));
   2591     try std.testing.expectEqual(NamespacePrefix.nt, getNamespacePrefix(u8, "\\??\\"));
   2592     try std.testing.expectEqual(NamespacePrefix.none, getNamespacePrefix(u8, "/??/"));
   2593     try std.testing.expectEqual(NamespacePrefix.none, getNamespacePrefix(u8, "/??\\"));
   2594     try std.testing.expectEqual(NamespacePrefix.none, getNamespacePrefix(u8, "\\?\\\\"));
   2595     try std.testing.expectEqual(NamespacePrefix.local_device, getNamespacePrefix(u8, "\\\\.\\"));
   2596     try std.testing.expectEqual(NamespacePrefix.local_device, getNamespacePrefix(u8, "\\\\./"));
   2597     try std.testing.expectEqual(NamespacePrefix.local_device, getNamespacePrefix(u8, "/\\./"));
   2598     try std.testing.expectEqual(NamespacePrefix.local_device, getNamespacePrefix(u8, "//./"));
   2599     try std.testing.expectEqual(NamespacePrefix.none, getNamespacePrefix(u8, "/.//"));
   2600     try std.testing.expectEqual(NamespacePrefix.verbatim, getNamespacePrefix(u8, "\\\\?\\"));
   2601     try std.testing.expectEqual(NamespacePrefix.fake_verbatim, getNamespacePrefix(u8, "\\/?\\"));
   2602     try std.testing.expectEqual(NamespacePrefix.fake_verbatim, getNamespacePrefix(u8, "\\/?/"));
   2603     try std.testing.expectEqual(NamespacePrefix.fake_verbatim, getNamespacePrefix(u8, "//?/"));
   2604 }
   2605 
   2606 pub const UnprefixedPathType = enum {
   2607     unc_absolute,
   2608     drive_absolute,
   2609     drive_relative,
   2610     rooted,
   2611     relative,
   2612     root_local_device,
   2613 };
   2614 
   2615 /// Get the path type of a path that is known to not have any namespace prefixes
   2616 /// (`\\?\`, `\\.\`, `\??\`).
   2617 /// If `T` is `u16`, then `path` should be encoded as WTF-16LE.
   2618 pub fn getUnprefixedPathType(comptime T: type, path: []const T) UnprefixedPathType {
   2619     if (path.len < 1) return .relative;
   2620 
   2621     if (std.debug.runtime_safety) {
   2622         std.debug.assert(getNamespacePrefix(T, path) == .none);
   2623     }
   2624 
   2625     const windows_path = std.fs.path.PathType.windows;
   2626     if (windows_path.isSep(T, mem.littleToNative(T, path[0]))) {
   2627         // \x
   2628         if (path.len < 2 or !windows_path.isSep(T, mem.littleToNative(T, path[1]))) return .rooted;
   2629         // exactly \\. or \\? with nothing trailing
   2630         if (path.len == 3 and (mem.littleToNative(T, path[2]) == '.' or mem.littleToNative(T, path[2]) == '?')) return .root_local_device;
   2631         // \\x
   2632         return .unc_absolute;
   2633     } else {
   2634         // x
   2635         if (path.len < 2 or mem.littleToNative(T, path[1]) != ':') return .relative;
   2636         // x:\
   2637         if (path.len > 2 and windows_path.isSep(T, mem.littleToNative(T, path[2]))) return .drive_absolute;
   2638         // x:
   2639         return .drive_relative;
   2640     }
   2641 }
   2642 
   2643 test getUnprefixedPathType {
   2644     try std.testing.expectEqual(UnprefixedPathType.relative, getUnprefixedPathType(u8, ""));
   2645     try std.testing.expectEqual(UnprefixedPathType.relative, getUnprefixedPathType(u8, "x"));
   2646     try std.testing.expectEqual(UnprefixedPathType.relative, getUnprefixedPathType(u8, "x\\"));
   2647     try std.testing.expectEqual(UnprefixedPathType.root_local_device, getUnprefixedPathType(u8, "//."));
   2648     try std.testing.expectEqual(UnprefixedPathType.root_local_device, getUnprefixedPathType(u8, "/\\?"));
   2649     try std.testing.expectEqual(UnprefixedPathType.root_local_device, getUnprefixedPathType(u8, "\\\\?"));
   2650     try std.testing.expectEqual(UnprefixedPathType.unc_absolute, getUnprefixedPathType(u8, "\\\\x"));
   2651     try std.testing.expectEqual(UnprefixedPathType.unc_absolute, getUnprefixedPathType(u8, "//x"));
   2652     try std.testing.expectEqual(UnprefixedPathType.rooted, getUnprefixedPathType(u8, "\\x"));
   2653     try std.testing.expectEqual(UnprefixedPathType.rooted, getUnprefixedPathType(u8, "/"));
   2654     try std.testing.expectEqual(UnprefixedPathType.drive_relative, getUnprefixedPathType(u8, "x:"));
   2655     try std.testing.expectEqual(UnprefixedPathType.drive_relative, getUnprefixedPathType(u8, "x:abc"));
   2656     try std.testing.expectEqual(UnprefixedPathType.drive_relative, getUnprefixedPathType(u8, "x:a/b/c"));
   2657     try std.testing.expectEqual(UnprefixedPathType.drive_absolute, getUnprefixedPathType(u8, "x:\\"));
   2658     try std.testing.expectEqual(UnprefixedPathType.drive_absolute, getUnprefixedPathType(u8, "x:\\abc"));
   2659     try std.testing.expectEqual(UnprefixedPathType.drive_absolute, getUnprefixedPathType(u8, "x:/a/b/c"));
   2660 }
   2661 
   2662 /// Similar to `RtlNtPathNameToDosPathName` but does not do any heap allocation.
   2663 /// The possible transformations are:
   2664 ///   \??\C:\Some\Path -> C:\Some\Path
   2665 ///   \??\UNC\server\share\foo -> \\server\share\foo
   2666 /// If the path does not have the NT namespace prefix, then `error.NotNtPath` is returned.
   2667 ///
   2668 /// Functionality is based on the ReactOS test cases found here:
   2669 /// https://github.com/reactos/reactos/blob/master/modules/rostests/apitests/ntdll/RtlNtPathNameToDosPathName.c
   2670 ///
   2671 /// `path` should be encoded as WTF-16LE.
   2672 pub fn ntToWin32Namespace(path: []const u16) !PathSpace {
   2673     if (path.len > PATH_MAX_WIDE) return error.NameTooLong;
   2674 
   2675     var path_space: PathSpace = undefined;
   2676     const namespace_prefix = getNamespacePrefix(u16, path);
   2677     switch (namespace_prefix) {
   2678         .nt => {
   2679             var dest_index: usize = 0;
   2680             var after_prefix = path[4..]; // after the `\??\`
   2681             // The prefix \??\UNC\ means this is a UNC path, in which case the
   2682             // `\??\UNC\` should be replaced by `\\` (two backslashes)
   2683             // TODO: the "UNC" should technically be matched case-insensitively, but
   2684             //       it's unlikely to matter since most/all paths passed into this
   2685             //       function will have come from the OS meaning it should have
   2686             //       the 'canonical' uppercase UNC.
   2687             const is_unc = after_prefix.len >= 4 and
   2688                 std.mem.eql(u16, after_prefix[0..3], std.unicode.utf8ToUtf16LeStringLiteral("UNC")) and
   2689                 std.fs.path.PathType.windows.isSep(u16, std.mem.littleToNative(u16, after_prefix[3]));
   2690             if (is_unc) {
   2691                 path_space.data[0] = comptime std.mem.nativeToLittle(u16, '\\');
   2692                 dest_index += 1;
   2693                 // We want to include the last `\` of `\??\UNC\`
   2694                 after_prefix = path[7..];
   2695             }
   2696             @memcpy(path_space.data[dest_index..][0..after_prefix.len], after_prefix);
   2697             path_space.len = dest_index + after_prefix.len;
   2698             path_space.data[path_space.len] = 0;
   2699             return path_space;
   2700         },
   2701         else => return error.NotNtPath,
   2702     }
   2703 }
   2704 
   2705 test ntToWin32Namespace {
   2706     const L = std.unicode.utf8ToUtf16LeStringLiteral;
   2707 
   2708     try testNtToWin32Namespace(L("UNC"), L("\\??\\UNC"));
   2709     try testNtToWin32Namespace(L("\\\\"), L("\\??\\UNC\\"));
   2710     try testNtToWin32Namespace(L("\\\\path1"), L("\\??\\UNC\\path1"));
   2711     try testNtToWin32Namespace(L("\\\\path1\\path2"), L("\\??\\UNC\\path1\\path2"));
   2712 
   2713     try testNtToWin32Namespace(L(""), L("\\??\\"));
   2714     try testNtToWin32Namespace(L("C:"), L("\\??\\C:"));
   2715     try testNtToWin32Namespace(L("C:\\"), L("\\??\\C:\\"));
   2716     try testNtToWin32Namespace(L("C:\\test"), L("\\??\\C:\\test"));
   2717     try testNtToWin32Namespace(L("C:\\test\\"), L("\\??\\C:\\test\\"));
   2718 
   2719     try std.testing.expectError(error.NotNtPath, ntToWin32Namespace(L("foo")));
   2720     try std.testing.expectError(error.NotNtPath, ntToWin32Namespace(L("C:\\test")));
   2721     try std.testing.expectError(error.NotNtPath, ntToWin32Namespace(L("\\\\.\\test")));
   2722 }
   2723 
   2724 fn testNtToWin32Namespace(expected: []const u16, path: []const u16) !void {
   2725     const converted = try ntToWin32Namespace(path);
   2726     try std.testing.expectEqualSlices(u16, expected, converted.span());
   2727 }
   2728 
   2729 fn getFullPathNameW(path: [*:0]const u16, out: []u16) !usize {
   2730     const result = kernel32.GetFullPathNameW(path, @as(u32, @intCast(out.len)), out.ptr, null);
   2731     if (result == 0) {
   2732         switch (GetLastError()) {
   2733             else => |err| return unexpectedError(err),
   2734         }
   2735     }
   2736     return result;
   2737 }
   2738 
   2739 inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID {
   2740     return (s << 10) | p;
   2741 }
   2742 
   2743 /// Loads a Winsock extension function in runtime specified by a GUID.
   2744 pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: GUID) !T {
   2745     var function: T = undefined;
   2746     var num_bytes: DWORD = undefined;
   2747 
   2748     const rc = ws2_32.WSAIoctl(
   2749         sock,
   2750         ws2_32.SIO_GET_EXTENSION_FUNCTION_POINTER,
   2751         &guid,
   2752         @sizeOf(GUID),
   2753         @as(?*anyopaque, @ptrFromInt(@intFromPtr(&function))),
   2754         @sizeOf(T),
   2755         &num_bytes,
   2756         null,
   2757         null,
   2758     );
   2759 
   2760     if (rc == ws2_32.SOCKET_ERROR) {
   2761         return switch (ws2_32.WSAGetLastError()) {
   2762             .WSAEOPNOTSUPP => error.OperationNotSupported,
   2763             .WSAENOTSOCK => error.FileDescriptorNotASocket,
   2764             else => |err| unexpectedWSAError(err),
   2765         };
   2766     }
   2767 
   2768     if (num_bytes != @sizeOf(T)) {
   2769         return error.ShortRead;
   2770     }
   2771 
   2772     return function;
   2773 }
   2774 
   2775 /// Call this when you made a windows DLL call or something that does SetLastError
   2776 /// and you get an unexpected error.
   2777 pub fn unexpectedError(err: Win32Error) UnexpectedError {
   2778     if (std.posix.unexpected_error_tracing) {
   2779         // 614 is the length of the longest windows error description
   2780         var buf_wstr: [614:0]WCHAR = undefined;
   2781         const len = kernel32.FormatMessageW(
   2782             FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
   2783             null,
   2784             err,
   2785             MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT),
   2786             &buf_wstr,
   2787             buf_wstr.len,
   2788             null,
   2789         );
   2790         std.debug.print("error.Unexpected: GetLastError({}): {}\n", .{
   2791             @intFromEnum(err),
   2792             std.unicode.fmtUtf16Le(buf_wstr[0..len]),
   2793         });
   2794         std.debug.dumpCurrentStackTrace(@returnAddress());
   2795     }
   2796     return error.Unexpected;
   2797 }
   2798 
   2799 pub fn unexpectedWSAError(err: ws2_32.WinsockError) UnexpectedError {
   2800     return unexpectedError(@as(Win32Error, @enumFromInt(@intFromEnum(err))));
   2801 }
   2802 
   2803 /// Call this when you made a windows NtDll call
   2804 /// and you get an unexpected status.
   2805 pub fn unexpectedStatus(status: NTSTATUS) UnexpectedError {
   2806     if (std.posix.unexpected_error_tracing) {
   2807         std.debug.print("error.Unexpected NTSTATUS=0x{x}\n", .{@intFromEnum(status)});
   2808         std.debug.dumpCurrentStackTrace(@returnAddress());
   2809     }
   2810     return error.Unexpected;
   2811 }
   2812 
   2813 pub const Win32Error = @import("windows/win32error.zig").Win32Error;
   2814 pub const NTSTATUS = @import("windows/ntstatus.zig").NTSTATUS;
   2815 pub const LANG = @import("windows/lang.zig");
   2816 pub const SUBLANG = @import("windows/sublang.zig");
   2817 
   2818 /// The standard input device. Initially, this is the console input buffer, CONIN$.
   2819 pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
   2820 
   2821 /// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
   2822 pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
   2823 
   2824 /// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
   2825 pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
   2826 
   2827 /// Deprecated; use `std.builtin.CallingConvention.winapi` instead.
   2828 pub const WINAPI: std.builtin.CallingConvention = .winapi;
   2829 
   2830 pub const BOOL = c_int;
   2831 pub const BOOLEAN = BYTE;
   2832 pub const BYTE = u8;
   2833 pub const CHAR = u8;
   2834 pub const UCHAR = u8;
   2835 pub const FLOAT = f32;
   2836 pub const HANDLE = *anyopaque;
   2837 pub const HCRYPTPROV = ULONG_PTR;
   2838 pub const ATOM = u16;
   2839 pub const HBRUSH = *opaque {};
   2840 pub const HCURSOR = *opaque {};
   2841 pub const HICON = *opaque {};
   2842 pub const HINSTANCE = *opaque {};
   2843 pub const HMENU = *opaque {};
   2844 pub const HMODULE = *opaque {};
   2845 pub const HWND = *opaque {};
   2846 pub const HDC = *opaque {};
   2847 pub const HGLRC = *opaque {};
   2848 pub const FARPROC = *opaque {};
   2849 pub const PROC = *opaque {};
   2850 pub const INT = c_int;
   2851 pub const LPCSTR = [*:0]const CHAR;
   2852 pub const LPCVOID = *const anyopaque;
   2853 pub const LPSTR = [*:0]CHAR;
   2854 pub const LPVOID = *anyopaque;
   2855 pub const LPWSTR = [*:0]WCHAR;
   2856 pub const LPCWSTR = [*:0]const WCHAR;
   2857 pub const PVOID = *anyopaque;
   2858 pub const PWSTR = [*:0]WCHAR;
   2859 pub const PCWSTR = [*:0]const WCHAR;
   2860 /// Allocated by SysAllocString, freed by SysFreeString
   2861 pub const BSTR = [*:0]WCHAR;
   2862 pub const SIZE_T = usize;
   2863 pub const UINT = c_uint;
   2864 pub const ULONG_PTR = usize;
   2865 pub const LONG_PTR = isize;
   2866 pub const DWORD_PTR = ULONG_PTR;
   2867 pub const WCHAR = u16;
   2868 pub const WORD = u16;
   2869 pub const DWORD = u32;
   2870 pub const DWORD64 = u64;
   2871 pub const LARGE_INTEGER = i64;
   2872 pub const ULARGE_INTEGER = u64;
   2873 pub const USHORT = u16;
   2874 pub const SHORT = i16;
   2875 pub const ULONG = u32;
   2876 pub const LONG = i32;
   2877 pub const ULONG64 = u64;
   2878 pub const ULONGLONG = u64;
   2879 pub const LONGLONG = i64;
   2880 pub const HLOCAL = HANDLE;
   2881 pub const LANGID = c_ushort;
   2882 
   2883 pub const WPARAM = usize;
   2884 pub const LPARAM = LONG_PTR;
   2885 pub const LRESULT = LONG_PTR;
   2886 
   2887 pub const va_list = *opaque {};
   2888 
   2889 pub const TCHAR = @compileError("Deprecated: choose between `CHAR` or `WCHAR` directly instead.");
   2890 pub const LPTSTR = @compileError("Deprecated: choose between `LPSTR` or `LPWSTR` directly instead.");
   2891 pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWSTR` directly instead.");
   2892 pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead.");
   2893 pub const PCTSTR = @compileError("Deprecated: choose between `PCSTR` or `PCWSTR` directly instead.");
   2894 
   2895 pub const TRUE = 1;
   2896 pub const FALSE = 0;
   2897 
   2898 pub const DEVICE_TYPE = ULONG;
   2899 pub const FILE_DEVICE_BEEP: DEVICE_TYPE = 0x0001;
   2900 pub const FILE_DEVICE_CD_ROM: DEVICE_TYPE = 0x0002;
   2901 pub const FILE_DEVICE_CD_ROM_FILE_SYSTEM: DEVICE_TYPE = 0x0003;
   2902 pub const FILE_DEVICE_CONTROLLER: DEVICE_TYPE = 0x0004;
   2903 pub const FILE_DEVICE_DATALINK: DEVICE_TYPE = 0x0005;
   2904 pub const FILE_DEVICE_DFS: DEVICE_TYPE = 0x0006;
   2905 pub const FILE_DEVICE_DISK: DEVICE_TYPE = 0x0007;
   2906 pub const FILE_DEVICE_DISK_FILE_SYSTEM: DEVICE_TYPE = 0x0008;
   2907 pub const FILE_DEVICE_FILE_SYSTEM: DEVICE_TYPE = 0x0009;
   2908 pub const FILE_DEVICE_INPORT_PORT: DEVICE_TYPE = 0x000a;
   2909 pub const FILE_DEVICE_KEYBOARD: DEVICE_TYPE = 0x000b;
   2910 pub const FILE_DEVICE_MAILSLOT: DEVICE_TYPE = 0x000c;
   2911 pub const FILE_DEVICE_MIDI_IN: DEVICE_TYPE = 0x000d;
   2912 pub const FILE_DEVICE_MIDI_OUT: DEVICE_TYPE = 0x000e;
   2913 pub const FILE_DEVICE_MOUSE: DEVICE_TYPE = 0x000f;
   2914 pub const FILE_DEVICE_MULTI_UNC_PROVIDER: DEVICE_TYPE = 0x0010;
   2915 pub const FILE_DEVICE_NAMED_PIPE: DEVICE_TYPE = 0x0011;
   2916 pub const FILE_DEVICE_NETWORK: DEVICE_TYPE = 0x0012;
   2917 pub const FILE_DEVICE_NETWORK_BROWSER: DEVICE_TYPE = 0x0013;
   2918 pub const FILE_DEVICE_NETWORK_FILE_SYSTEM: DEVICE_TYPE = 0x0014;
   2919 pub const FILE_DEVICE_NULL: DEVICE_TYPE = 0x0015;
   2920 pub const FILE_DEVICE_PARALLEL_PORT: DEVICE_TYPE = 0x0016;
   2921 pub const FILE_DEVICE_PHYSICAL_NETCARD: DEVICE_TYPE = 0x0017;
   2922 pub const FILE_DEVICE_PRINTER: DEVICE_TYPE = 0x0018;
   2923 pub const FILE_DEVICE_SCANNER: DEVICE_TYPE = 0x0019;
   2924 pub const FILE_DEVICE_SERIAL_MOUSE_PORT: DEVICE_TYPE = 0x001a;
   2925 pub const FILE_DEVICE_SERIAL_PORT: DEVICE_TYPE = 0x001b;
   2926 pub const FILE_DEVICE_SCREEN: DEVICE_TYPE = 0x001c;
   2927 pub const FILE_DEVICE_SOUND: DEVICE_TYPE = 0x001d;
   2928 pub const FILE_DEVICE_STREAMS: DEVICE_TYPE = 0x001e;
   2929 pub const FILE_DEVICE_TAPE: DEVICE_TYPE = 0x001f;
   2930 pub const FILE_DEVICE_TAPE_FILE_SYSTEM: DEVICE_TYPE = 0x0020;
   2931 pub const FILE_DEVICE_TRANSPORT: DEVICE_TYPE = 0x0021;
   2932 pub const FILE_DEVICE_UNKNOWN: DEVICE_TYPE = 0x0022;
   2933 pub const FILE_DEVICE_VIDEO: DEVICE_TYPE = 0x0023;
   2934 pub const FILE_DEVICE_VIRTUAL_DISK: DEVICE_TYPE = 0x0024;
   2935 pub const FILE_DEVICE_WAVE_IN: DEVICE_TYPE = 0x0025;
   2936 pub const FILE_DEVICE_WAVE_OUT: DEVICE_TYPE = 0x0026;
   2937 pub const FILE_DEVICE_8042_PORT: DEVICE_TYPE = 0x0027;
   2938 pub const FILE_DEVICE_NETWORK_REDIRECTOR: DEVICE_TYPE = 0x0028;
   2939 pub const FILE_DEVICE_BATTERY: DEVICE_TYPE = 0x0029;
   2940 pub const FILE_DEVICE_BUS_EXTENDER: DEVICE_TYPE = 0x002a;
   2941 pub const FILE_DEVICE_MODEM: DEVICE_TYPE = 0x002b;
   2942 pub const FILE_DEVICE_VDM: DEVICE_TYPE = 0x002c;
   2943 pub const FILE_DEVICE_MASS_STORAGE: DEVICE_TYPE = 0x002d;
   2944 pub const FILE_DEVICE_SMB: DEVICE_TYPE = 0x002e;
   2945 pub const FILE_DEVICE_KS: DEVICE_TYPE = 0x002f;
   2946 pub const FILE_DEVICE_CHANGER: DEVICE_TYPE = 0x0030;
   2947 pub const FILE_DEVICE_SMARTCARD: DEVICE_TYPE = 0x0031;
   2948 pub const FILE_DEVICE_ACPI: DEVICE_TYPE = 0x0032;
   2949 pub const FILE_DEVICE_DVD: DEVICE_TYPE = 0x0033;
   2950 pub const FILE_DEVICE_FULLSCREEN_VIDEO: DEVICE_TYPE = 0x0034;
   2951 pub const FILE_DEVICE_DFS_FILE_SYSTEM: DEVICE_TYPE = 0x0035;
   2952 pub const FILE_DEVICE_DFS_VOLUME: DEVICE_TYPE = 0x0036;
   2953 pub const FILE_DEVICE_SERENUM: DEVICE_TYPE = 0x0037;
   2954 pub const FILE_DEVICE_TERMSRV: DEVICE_TYPE = 0x0038;
   2955 pub const FILE_DEVICE_KSEC: DEVICE_TYPE = 0x0039;
   2956 pub const FILE_DEVICE_FIPS: DEVICE_TYPE = 0x003a;
   2957 pub const FILE_DEVICE_INFINIBAND: DEVICE_TYPE = 0x003b;
   2958 // TODO: missing values?
   2959 pub const FILE_DEVICE_VMBUS: DEVICE_TYPE = 0x003e;
   2960 pub const FILE_DEVICE_CRYPT_PROVIDER: DEVICE_TYPE = 0x003f;
   2961 pub const FILE_DEVICE_WPD: DEVICE_TYPE = 0x0040;
   2962 pub const FILE_DEVICE_BLUETOOTH: DEVICE_TYPE = 0x0041;
   2963 pub const FILE_DEVICE_MT_COMPOSITE: DEVICE_TYPE = 0x0042;
   2964 pub const FILE_DEVICE_MT_TRANSPORT: DEVICE_TYPE = 0x0043;
   2965 pub const FILE_DEVICE_BIOMETRIC: DEVICE_TYPE = 0x0044;
   2966 pub const FILE_DEVICE_PMI: DEVICE_TYPE = 0x0045;
   2967 pub const FILE_DEVICE_EHSTOR: DEVICE_TYPE = 0x0046;
   2968 pub const FILE_DEVICE_DEVAPI: DEVICE_TYPE = 0x0047;
   2969 pub const FILE_DEVICE_GPIO: DEVICE_TYPE = 0x0048;
   2970 pub const FILE_DEVICE_USBEX: DEVICE_TYPE = 0x0049;
   2971 pub const FILE_DEVICE_CONSOLE: DEVICE_TYPE = 0x0050;
   2972 pub const FILE_DEVICE_NFP: DEVICE_TYPE = 0x0051;
   2973 pub const FILE_DEVICE_SYSENV: DEVICE_TYPE = 0x0052;
   2974 pub const FILE_DEVICE_VIRTUAL_BLOCK: DEVICE_TYPE = 0x0053;
   2975 pub const FILE_DEVICE_POINT_OF_SERVICE: DEVICE_TYPE = 0x0054;
   2976 pub const FILE_DEVICE_STORAGE_REPLICATION: DEVICE_TYPE = 0x0055;
   2977 pub const FILE_DEVICE_TRUST_ENV: DEVICE_TYPE = 0x0056;
   2978 pub const FILE_DEVICE_UCM: DEVICE_TYPE = 0x0057;
   2979 pub const FILE_DEVICE_UCMTCPCI: DEVICE_TYPE = 0x0058;
   2980 pub const FILE_DEVICE_PERSISTENT_MEMORY: DEVICE_TYPE = 0x0059;
   2981 pub const FILE_DEVICE_NVDIMM: DEVICE_TYPE = 0x005a;
   2982 pub const FILE_DEVICE_HOLOGRAPHIC: DEVICE_TYPE = 0x005b;
   2983 pub const FILE_DEVICE_SDFXHCI: DEVICE_TYPE = 0x005c;
   2984 
   2985 /// https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/buffer-descriptions-for-i-o-control-codes
   2986 pub const TransferType = enum(u2) {
   2987     METHOD_BUFFERED = 0,
   2988     METHOD_IN_DIRECT = 1,
   2989     METHOD_OUT_DIRECT = 2,
   2990     METHOD_NEITHER = 3,
   2991 };
   2992 
   2993 pub const FILE_ANY_ACCESS = 0;
   2994 pub const FILE_READ_ACCESS = 1;
   2995 pub const FILE_WRITE_ACCESS = 2;
   2996 
   2997 /// https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes
   2998 pub fn CTL_CODE(deviceType: u16, function: u12, method: TransferType, access: u2) DWORD {
   2999     return (@as(DWORD, deviceType) << 16) |
   3000         (@as(DWORD, access) << 14) |
   3001         (@as(DWORD, function) << 2) |
   3002         @intFromEnum(method);
   3003 }
   3004 
   3005 pub const INVALID_HANDLE_VALUE = @as(HANDLE, @ptrFromInt(maxInt(usize)));
   3006 
   3007 pub const INVALID_FILE_ATTRIBUTES = @as(DWORD, maxInt(DWORD));
   3008 
   3009 pub const FILE_ALL_INFORMATION = extern struct {
   3010     BasicInformation: FILE_BASIC_INFORMATION,
   3011     StandardInformation: FILE_STANDARD_INFORMATION,
   3012     InternalInformation: FILE_INTERNAL_INFORMATION,
   3013     EaInformation: FILE_EA_INFORMATION,
   3014     AccessInformation: FILE_ACCESS_INFORMATION,
   3015     PositionInformation: FILE_POSITION_INFORMATION,
   3016     ModeInformation: FILE_MODE_INFORMATION,
   3017     AlignmentInformation: FILE_ALIGNMENT_INFORMATION,
   3018     NameInformation: FILE_NAME_INFORMATION,
   3019 };
   3020 
   3021 pub const FILE_BASIC_INFORMATION = extern struct {
   3022     CreationTime: LARGE_INTEGER,
   3023     LastAccessTime: LARGE_INTEGER,
   3024     LastWriteTime: LARGE_INTEGER,
   3025     ChangeTime: LARGE_INTEGER,
   3026     FileAttributes: ULONG,
   3027 };
   3028 
   3029 pub const FILE_STANDARD_INFORMATION = extern struct {
   3030     AllocationSize: LARGE_INTEGER,
   3031     EndOfFile: LARGE_INTEGER,
   3032     NumberOfLinks: ULONG,
   3033     DeletePending: BOOLEAN,
   3034     Directory: BOOLEAN,
   3035 };
   3036 
   3037 pub const FILE_INTERNAL_INFORMATION = extern struct {
   3038     IndexNumber: LARGE_INTEGER,
   3039 };
   3040 
   3041 pub const FILE_EA_INFORMATION = extern struct {
   3042     EaSize: ULONG,
   3043 };
   3044 
   3045 pub const FILE_ACCESS_INFORMATION = extern struct {
   3046     AccessFlags: ACCESS_MASK,
   3047 };
   3048 
   3049 pub const FILE_POSITION_INFORMATION = extern struct {
   3050     CurrentByteOffset: LARGE_INTEGER,
   3051 };
   3052 
   3053 pub const FILE_END_OF_FILE_INFORMATION = extern struct {
   3054     EndOfFile: LARGE_INTEGER,
   3055 };
   3056 
   3057 pub const FILE_MODE_INFORMATION = extern struct {
   3058     Mode: ULONG,
   3059 };
   3060 
   3061 pub const FILE_ALIGNMENT_INFORMATION = extern struct {
   3062     AlignmentRequirement: ULONG,
   3063 };
   3064 
   3065 pub const FILE_NAME_INFORMATION = extern struct {
   3066     FileNameLength: ULONG,
   3067     FileName: [1]WCHAR,
   3068 };
   3069 
   3070 pub const FILE_DISPOSITION_INFORMATION_EX = extern struct {
   3071     /// combination of FILE_DISPOSITION_* flags
   3072     Flags: ULONG,
   3073 };
   3074 
   3075 const FILE_DISPOSITION_DO_NOT_DELETE: ULONG = 0x00000000;
   3076 const FILE_DISPOSITION_DELETE: ULONG = 0x00000001;
   3077 const FILE_DISPOSITION_POSIX_SEMANTICS: ULONG = 0x00000002;
   3078 const FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK: ULONG = 0x00000004;
   3079 const FILE_DISPOSITION_ON_CLOSE: ULONG = 0x00000008;
   3080 const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: ULONG = 0x00000010;
   3081 
   3082 // FILE_RENAME_INFORMATION.Flags
   3083 pub const FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001;
   3084 pub const FILE_RENAME_POSIX_SEMANTICS = 0x00000002;
   3085 pub const FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE = 0x00000004;
   3086 pub const FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE = 0x00000008;
   3087 pub const FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE = 0x00000010;
   3088 pub const FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE = 0x00000020;
   3089 pub const FILE_RENAME_PRESERVE_AVAILABLE_SPACE = 0x00000030;
   3090 pub const FILE_RENAME_IGNORE_READONLY_ATTRIBUTE = 0x00000040;
   3091 pub const FILE_RENAME_FORCE_RESIZE_TARGET_SR = 0x00000080;
   3092 pub const FILE_RENAME_FORCE_RESIZE_SOURCE_SR = 0x00000100;
   3093 pub const FILE_RENAME_FORCE_RESIZE_SR = 0x00000180;
   3094 
   3095 pub const FILE_RENAME_INFORMATION = extern struct {
   3096     Flags: BOOLEAN,
   3097     RootDirectory: ?HANDLE,
   3098     FileNameLength: ULONG,
   3099     FileName: [1]WCHAR,
   3100 };
   3101 
   3102 // FileRenameInformationEx (since .win10_rs1)
   3103 pub const FILE_RENAME_INFORMATION_EX = extern struct {
   3104     Flags: ULONG,
   3105     RootDirectory: ?HANDLE,
   3106     FileNameLength: ULONG,
   3107     FileName: [1]WCHAR,
   3108 };
   3109 
   3110 pub const IO_STATUS_BLOCK = extern struct {
   3111     // "DUMMYUNIONNAME" expands to "u"
   3112     u: extern union {
   3113         Status: NTSTATUS,
   3114         Pointer: ?*anyopaque,
   3115     },
   3116     Information: ULONG_PTR,
   3117 };
   3118 
   3119 pub const FILE_INFORMATION_CLASS = enum(c_int) {
   3120     FileDirectoryInformation = 1,
   3121     FileFullDirectoryInformation,
   3122     FileBothDirectoryInformation,
   3123     FileBasicInformation,
   3124     FileStandardInformation,
   3125     FileInternalInformation,
   3126     FileEaInformation,
   3127     FileAccessInformation,
   3128     FileNameInformation,
   3129     FileRenameInformation,
   3130     FileLinkInformation,
   3131     FileNamesInformation,
   3132     FileDispositionInformation,
   3133     FilePositionInformation,
   3134     FileFullEaInformation,
   3135     FileModeInformation,
   3136     FileAlignmentInformation,
   3137     FileAllInformation,
   3138     FileAllocationInformation,
   3139     FileEndOfFileInformation,
   3140     FileAlternateNameInformation,
   3141     FileStreamInformation,
   3142     FilePipeInformation,
   3143     FilePipeLocalInformation,
   3144     FilePipeRemoteInformation,
   3145     FileMailslotQueryInformation,
   3146     FileMailslotSetInformation,
   3147     FileCompressionInformation,
   3148     FileObjectIdInformation,
   3149     FileCompletionInformation,
   3150     FileMoveClusterInformation,
   3151     FileQuotaInformation,
   3152     FileReparsePointInformation,
   3153     FileNetworkOpenInformation,
   3154     FileAttributeTagInformation,
   3155     FileTrackingInformation,
   3156     FileIdBothDirectoryInformation,
   3157     FileIdFullDirectoryInformation,
   3158     FileValidDataLengthInformation,
   3159     FileShortNameInformation,
   3160     FileIoCompletionNotificationInformation,
   3161     FileIoStatusBlockRangeInformation,
   3162     FileIoPriorityHintInformation,
   3163     FileSfioReserveInformation,
   3164     FileSfioVolumeInformation,
   3165     FileHardLinkInformation,
   3166     FileProcessIdsUsingFileInformation,
   3167     FileNormalizedNameInformation,
   3168     FileNetworkPhysicalNameInformation,
   3169     FileIdGlobalTxDirectoryInformation,
   3170     FileIsRemoteDeviceInformation,
   3171     FileUnusedInformation,
   3172     FileNumaNodeInformation,
   3173     FileStandardLinkInformation,
   3174     FileRemoteProtocolInformation,
   3175     FileRenameInformationBypassAccessCheck,
   3176     FileLinkInformationBypassAccessCheck,
   3177     FileVolumeNameInformation,
   3178     FileIdInformation,
   3179     FileIdExtdDirectoryInformation,
   3180     FileReplaceCompletionInformation,
   3181     FileHardLinkFullIdInformation,
   3182     FileIdExtdBothDirectoryInformation,
   3183     FileDispositionInformationEx,
   3184     FileRenameInformationEx,
   3185     FileRenameInformationExBypassAccessCheck,
   3186     FileDesiredStorageClassInformation,
   3187     FileStatInformation,
   3188     FileMemoryPartitionInformation,
   3189     FileStatLxInformation,
   3190     FileCaseSensitiveInformation,
   3191     FileLinkInformationEx,
   3192     FileLinkInformationExBypassAccessCheck,
   3193     FileStorageReserveIdInformation,
   3194     FileCaseSensitiveInformationForceAccessCheck,
   3195     FileMaximumInformation,
   3196 };
   3197 
   3198 pub const FILE_ATTRIBUTE_TAG_INFO = extern struct {
   3199     FileAttributes: DWORD,
   3200     ReparseTag: DWORD,
   3201 };
   3202 
   3203 /// "If this bit is set, the file or directory represents another named entity in the system."
   3204 /// https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags
   3205 pub const reparse_tag_name_surrogate_bit = 0x20000000;
   3206 
   3207 pub const FILE_DISPOSITION_INFORMATION = extern struct {
   3208     DeleteFile: BOOLEAN,
   3209 };
   3210 
   3211 pub const FILE_FS_DEVICE_INFORMATION = extern struct {
   3212     DeviceType: DEVICE_TYPE,
   3213     Characteristics: ULONG,
   3214 };
   3215 
   3216 pub const FILE_FS_VOLUME_INFORMATION = extern struct {
   3217     VolumeCreationTime: LARGE_INTEGER,
   3218     VolumeSerialNumber: ULONG,
   3219     VolumeLabelLength: ULONG,
   3220     SupportsObjects: BOOLEAN,
   3221     // Flexible array member
   3222     VolumeLabel: [1]WCHAR,
   3223 };
   3224 
   3225 pub const FS_INFORMATION_CLASS = enum(c_int) {
   3226     FileFsVolumeInformation = 1,
   3227     FileFsLabelInformation,
   3228     FileFsSizeInformation,
   3229     FileFsDeviceInformation,
   3230     FileFsAttributeInformation,
   3231     FileFsControlInformation,
   3232     FileFsFullSizeInformation,
   3233     FileFsObjectIdInformation,
   3234     FileFsDriverPathInformation,
   3235     FileFsVolumeFlagsInformation,
   3236     FileFsSectorSizeInformation,
   3237     FileFsDataCopyInformation,
   3238     FileFsMetadataSizeInformation,
   3239     FileFsFullSizeInformationEx,
   3240     FileFsMaximumInformation,
   3241 };
   3242 
   3243 pub const OVERLAPPED = extern struct {
   3244     Internal: ULONG_PTR,
   3245     InternalHigh: ULONG_PTR,
   3246     DUMMYUNIONNAME: extern union {
   3247         DUMMYSTRUCTNAME: extern struct {
   3248             Offset: DWORD,
   3249             OffsetHigh: DWORD,
   3250         },
   3251         Pointer: ?PVOID,
   3252     },
   3253     hEvent: ?HANDLE,
   3254 };
   3255 
   3256 pub const OVERLAPPED_ENTRY = extern struct {
   3257     lpCompletionKey: ULONG_PTR,
   3258     lpOverlapped: *OVERLAPPED,
   3259     Internal: ULONG_PTR,
   3260     dwNumberOfBytesTransferred: DWORD,
   3261 };
   3262 
   3263 pub const MAX_PATH = 260;
   3264 
   3265 pub const FILE_INFO_BY_HANDLE_CLASS = enum(u32) {
   3266     FileBasicInfo = 0,
   3267     FileStandardInfo = 1,
   3268     FileNameInfo = 2,
   3269     FileRenameInfo = 3,
   3270     FileDispositionInfo = 4,
   3271     FileAllocationInfo = 5,
   3272     FileEndOfFileInfo = 6,
   3273     FileStreamInfo = 7,
   3274     FileCompressionInfo = 8,
   3275     FileAttributeTagInfo = 9,
   3276     FileIdBothDirectoryInfo = 10,
   3277     FileIdBothDirectoryRestartInfo = 11,
   3278     FileIoPriorityHintInfo = 12,
   3279     FileRemoteProtocolInfo = 13,
   3280     FileFullDirectoryInfo = 14,
   3281     FileFullDirectoryRestartInfo = 15,
   3282     FileStorageInfo = 16,
   3283     FileAlignmentInfo = 17,
   3284     FileIdInfo = 18,
   3285     FileIdExtdDirectoryInfo = 19,
   3286     FileIdExtdDirectoryRestartInfo = 20,
   3287 };
   3288 
   3289 pub const BY_HANDLE_FILE_INFORMATION = extern struct {
   3290     dwFileAttributes: DWORD,
   3291     ftCreationTime: FILETIME,
   3292     ftLastAccessTime: FILETIME,
   3293     ftLastWriteTime: FILETIME,
   3294     dwVolumeSerialNumber: DWORD,
   3295     nFileSizeHigh: DWORD,
   3296     nFileSizeLow: DWORD,
   3297     nNumberOfLinks: DWORD,
   3298     nFileIndexHigh: DWORD,
   3299     nFileIndexLow: DWORD,
   3300 };
   3301 
   3302 pub const FILE_NAME_INFO = extern struct {
   3303     FileNameLength: DWORD,
   3304     FileName: [1]WCHAR,
   3305 };
   3306 
   3307 /// Return the normalized drive name. This is the default.
   3308 pub const FILE_NAME_NORMALIZED = 0x0;
   3309 
   3310 /// Return the opened file name (not normalized).
   3311 pub const FILE_NAME_OPENED = 0x8;
   3312 
   3313 /// Return the path with the drive letter. This is the default.
   3314 pub const VOLUME_NAME_DOS = 0x0;
   3315 
   3316 /// Return the path with a volume GUID path instead of the drive name.
   3317 pub const VOLUME_NAME_GUID = 0x1;
   3318 
   3319 /// Return the path with no drive information.
   3320 pub const VOLUME_NAME_NONE = 0x4;
   3321 
   3322 /// Return the path with the volume device path.
   3323 pub const VOLUME_NAME_NT = 0x2;
   3324 
   3325 pub const SECURITY_ATTRIBUTES = extern struct {
   3326     nLength: DWORD,
   3327     lpSecurityDescriptor: ?*anyopaque,
   3328     bInheritHandle: BOOL,
   3329 };
   3330 
   3331 pub const PIPE_ACCESS_INBOUND = 0x00000001;
   3332 pub const PIPE_ACCESS_OUTBOUND = 0x00000002;
   3333 pub const PIPE_ACCESS_DUPLEX = 0x00000003;
   3334 
   3335 pub const PIPE_TYPE_BYTE = 0x00000000;
   3336 pub const PIPE_TYPE_MESSAGE = 0x00000004;
   3337 
   3338 pub const PIPE_READMODE_BYTE = 0x00000000;
   3339 pub const PIPE_READMODE_MESSAGE = 0x00000002;
   3340 
   3341 pub const PIPE_WAIT = 0x00000000;
   3342 pub const PIPE_NOWAIT = 0x00000001;
   3343 
   3344 pub const GENERIC_READ = 0x80000000;
   3345 pub const GENERIC_WRITE = 0x40000000;
   3346 pub const GENERIC_EXECUTE = 0x20000000;
   3347 pub const GENERIC_ALL = 0x10000000;
   3348 
   3349 pub const FILE_SHARE_DELETE = 0x00000004;
   3350 pub const FILE_SHARE_READ = 0x00000001;
   3351 pub const FILE_SHARE_WRITE = 0x00000002;
   3352 
   3353 pub const DELETE = 0x00010000;
   3354 pub const READ_CONTROL = 0x00020000;
   3355 pub const WRITE_DAC = 0x00040000;
   3356 pub const WRITE_OWNER = 0x00080000;
   3357 pub const SYNCHRONIZE = 0x00100000;
   3358 pub const STANDARD_RIGHTS_READ = READ_CONTROL;
   3359 pub const STANDARD_RIGHTS_WRITE = READ_CONTROL;
   3360 pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
   3361 pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;
   3362 pub const MAXIMUM_ALLOWED = 0x02000000;
   3363 
   3364 // disposition for NtCreateFile
   3365 pub const FILE_SUPERSEDE = 0;
   3366 pub const FILE_OPEN = 1;
   3367 pub const FILE_CREATE = 2;
   3368 pub const FILE_OPEN_IF = 3;
   3369 pub const FILE_OVERWRITE = 4;
   3370 pub const FILE_OVERWRITE_IF = 5;
   3371 pub const FILE_MAXIMUM_DISPOSITION = 5;
   3372 
   3373 // flags for NtCreateFile and NtOpenFile
   3374 pub const FILE_READ_DATA = 0x00000001;
   3375 pub const FILE_LIST_DIRECTORY = 0x00000001;
   3376 pub const FILE_WRITE_DATA = 0x00000002;
   3377 pub const FILE_ADD_FILE = 0x00000002;
   3378 pub const FILE_APPEND_DATA = 0x00000004;
   3379 pub const FILE_ADD_SUBDIRECTORY = 0x00000004;
   3380 pub const FILE_CREATE_PIPE_INSTANCE = 0x00000004;
   3381 pub const FILE_READ_EA = 0x00000008;
   3382 pub const FILE_WRITE_EA = 0x00000010;
   3383 pub const FILE_EXECUTE = 0x00000020;
   3384 pub const FILE_TRAVERSE = 0x00000020;
   3385 pub const FILE_DELETE_CHILD = 0x00000040;
   3386 pub const FILE_READ_ATTRIBUTES = 0x00000080;
   3387 pub const FILE_WRITE_ATTRIBUTES = 0x00000100;
   3388 
   3389 pub const FILE_DIRECTORY_FILE = 0x00000001;
   3390 pub const FILE_WRITE_THROUGH = 0x00000002;
   3391 pub const FILE_SEQUENTIAL_ONLY = 0x00000004;
   3392 pub const FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008;
   3393 pub const FILE_SYNCHRONOUS_IO_ALERT = 0x00000010;
   3394 pub const FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;
   3395 pub const FILE_NON_DIRECTORY_FILE = 0x00000040;
   3396 pub const FILE_CREATE_TREE_CONNECTION = 0x00000080;
   3397 pub const FILE_COMPLETE_IF_OPLOCKED = 0x00000100;
   3398 pub const FILE_NO_EA_KNOWLEDGE = 0x00000200;
   3399 pub const FILE_OPEN_FOR_RECOVERY = 0x00000400;
   3400 pub const FILE_RANDOM_ACCESS = 0x00000800;
   3401 pub const FILE_DELETE_ON_CLOSE = 0x00001000;
   3402 pub const FILE_OPEN_BY_FILE_ID = 0x00002000;
   3403 pub const FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
   3404 pub const FILE_NO_COMPRESSION = 0x00008000;
   3405 pub const FILE_RESERVE_OPFILTER = 0x00100000;
   3406 pub const FILE_OPEN_REPARSE_POINT = 0x00200000;
   3407 pub const FILE_OPEN_OFFLINE_FILE = 0x00400000;
   3408 pub const FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000;
   3409 
   3410 pub const CREATE_ALWAYS = 2;
   3411 pub const CREATE_NEW = 1;
   3412 pub const OPEN_ALWAYS = 4;
   3413 pub const OPEN_EXISTING = 3;
   3414 pub const TRUNCATE_EXISTING = 5;
   3415 
   3416 pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
   3417 pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
   3418 pub const FILE_ATTRIBUTE_DEVICE = 0x40;
   3419 pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
   3420 pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
   3421 pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
   3422 pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
   3423 pub const FILE_ATTRIBUTE_NORMAL = 0x80;
   3424 pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
   3425 pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
   3426 pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
   3427 pub const FILE_ATTRIBUTE_READONLY = 0x1;
   3428 pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
   3429 pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
   3430 pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
   3431 pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
   3432 pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
   3433 pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
   3434 pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
   3435 
   3436 pub const FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1ff;
   3437 pub const FILE_GENERIC_READ = STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE;
   3438 pub const FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE;
   3439 pub const FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE;
   3440 
   3441 // Flags for NtCreateNamedPipeFile
   3442 // NamedPipeType
   3443 pub const FILE_PIPE_BYTE_STREAM_TYPE = 0x0;
   3444 pub const FILE_PIPE_MESSAGE_TYPE = 0x1;
   3445 pub const FILE_PIPE_ACCEPT_REMOTE_CLIENTS = 0x0;
   3446 pub const FILE_PIPE_REJECT_REMOTE_CLIENTS = 0x2;
   3447 pub const FILE_PIPE_TYPE_VALID_MASK = 0x3;
   3448 // CompletionMode
   3449 pub const FILE_PIPE_QUEUE_OPERATION = 0x0;
   3450 pub const FILE_PIPE_COMPLETE_OPERATION = 0x1;
   3451 // ReadMode
   3452 pub const FILE_PIPE_BYTE_STREAM_MODE = 0x0;
   3453 pub const FILE_PIPE_MESSAGE_MODE = 0x1;
   3454 
   3455 // flags for CreateEvent
   3456 pub const CREATE_EVENT_INITIAL_SET = 0x00000002;
   3457 pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
   3458 
   3459 pub const EVENT_ALL_ACCESS = 0x1F0003;
   3460 pub const EVENT_MODIFY_STATE = 0x0002;
   3461 
   3462 // MEMORY_BASIC_INFORMATION.Type flags for VirtualQuery
   3463 pub const MEM_IMAGE = 0x1000000;
   3464 pub const MEM_MAPPED = 0x40000;
   3465 pub const MEM_PRIVATE = 0x20000;
   3466 
   3467 pub const PROCESS_INFORMATION = extern struct {
   3468     hProcess: HANDLE,
   3469     hThread: HANDLE,
   3470     dwProcessId: DWORD,
   3471     dwThreadId: DWORD,
   3472 };
   3473 
   3474 pub const STARTUPINFOW = extern struct {
   3475     cb: DWORD,
   3476     lpReserved: ?LPWSTR,
   3477     lpDesktop: ?LPWSTR,
   3478     lpTitle: ?LPWSTR,
   3479     dwX: DWORD,
   3480     dwY: DWORD,
   3481     dwXSize: DWORD,
   3482     dwYSize: DWORD,
   3483     dwXCountChars: DWORD,
   3484     dwYCountChars: DWORD,
   3485     dwFillAttribute: DWORD,
   3486     dwFlags: DWORD,
   3487     wShowWindow: WORD,
   3488     cbReserved2: WORD,
   3489     lpReserved2: ?*BYTE,
   3490     hStdInput: ?HANDLE,
   3491     hStdOutput: ?HANDLE,
   3492     hStdError: ?HANDLE,
   3493 };
   3494 
   3495 pub const STARTF_FORCEONFEEDBACK = 0x00000040;
   3496 pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
   3497 pub const STARTF_PREVENTPINNING = 0x00002000;
   3498 pub const STARTF_RUNFULLSCREEN = 0x00000020;
   3499 pub const STARTF_TITLEISAPPID = 0x00001000;
   3500 pub const STARTF_TITLEISLINKNAME = 0x00000800;
   3501 pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
   3502 pub const STARTF_USECOUNTCHARS = 0x00000008;
   3503 pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
   3504 pub const STARTF_USEHOTKEY = 0x00000200;
   3505 pub const STARTF_USEPOSITION = 0x00000004;
   3506 pub const STARTF_USESHOWWINDOW = 0x00000001;
   3507 pub const STARTF_USESIZE = 0x00000002;
   3508 pub const STARTF_USESTDHANDLES = 0x00000100;
   3509 
   3510 pub const INFINITE = 4294967295;
   3511 
   3512 pub const MAXIMUM_WAIT_OBJECTS = 64;
   3513 
   3514 pub const WAIT_ABANDONED = 0x00000080;
   3515 pub const WAIT_ABANDONED_0 = WAIT_ABANDONED + 0;
   3516 pub const WAIT_OBJECT_0 = 0x00000000;
   3517 pub const WAIT_TIMEOUT = 0x00000102;
   3518 pub const WAIT_FAILED = 0xFFFFFFFF;
   3519 
   3520 pub const HANDLE_FLAG_INHERIT = 0x00000001;
   3521 pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
   3522 
   3523 pub const MOVEFILE_COPY_ALLOWED = 2;
   3524 pub const MOVEFILE_CREATE_HARDLINK = 16;
   3525 pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
   3526 pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
   3527 pub const MOVEFILE_REPLACE_EXISTING = 1;
   3528 pub const MOVEFILE_WRITE_THROUGH = 8;
   3529 
   3530 pub const FILE_BEGIN = 0;
   3531 pub const FILE_CURRENT = 1;
   3532 pub const FILE_END = 2;
   3533 
   3534 pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
   3535 pub const HEAP_REALLOC_IN_PLACE_ONLY = 0x00000010;
   3536 pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
   3537 pub const HEAP_NO_SERIALIZE = 0x00000001;
   3538 
   3539 // AllocationType values
   3540 pub const MEM_COMMIT = 0x1000;
   3541 pub const MEM_RESERVE = 0x2000;
   3542 pub const MEM_FREE = 0x10000;
   3543 pub const MEM_RESET = 0x80000;
   3544 pub const MEM_RESET_UNDO = 0x1000000;
   3545 pub const MEM_LARGE_PAGES = 0x20000000;
   3546 pub const MEM_PHYSICAL = 0x400000;
   3547 pub const MEM_TOP_DOWN = 0x100000;
   3548 pub const MEM_WRITE_WATCH = 0x200000;
   3549 
   3550 // Protect values
   3551 pub const PAGE_EXECUTE = 0x10;
   3552 pub const PAGE_EXECUTE_READ = 0x20;
   3553 pub const PAGE_EXECUTE_READWRITE = 0x40;
   3554 pub const PAGE_EXECUTE_WRITECOPY = 0x80;
   3555 pub const PAGE_NOACCESS = 0x01;
   3556 pub const PAGE_READONLY = 0x02;
   3557 pub const PAGE_READWRITE = 0x04;
   3558 pub const PAGE_WRITECOPY = 0x08;
   3559 pub const PAGE_TARGETS_INVALID = 0x40000000;
   3560 pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID
   3561 pub const PAGE_GUARD = 0x100;
   3562 pub const PAGE_NOCACHE = 0x200;
   3563 pub const PAGE_WRITECOMBINE = 0x400;
   3564 
   3565 // FreeType values
   3566 pub const MEM_COALESCE_PLACEHOLDERS = 0x1;
   3567 pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
   3568 pub const MEM_DECOMMIT = 0x4000;
   3569 pub const MEM_RELEASE = 0x8000;
   3570 
   3571 pub const PTHREAD_START_ROUTINE = *const fn (LPVOID) callconv(.winapi) DWORD;
   3572 pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
   3573 
   3574 pub const WIN32_FIND_DATAW = extern struct {
   3575     dwFileAttributes: DWORD,
   3576     ftCreationTime: FILETIME,
   3577     ftLastAccessTime: FILETIME,
   3578     ftLastWriteTime: FILETIME,
   3579     nFileSizeHigh: DWORD,
   3580     nFileSizeLow: DWORD,
   3581     dwReserved0: DWORD,
   3582     dwReserved1: DWORD,
   3583     cFileName: [260]u16,
   3584     cAlternateFileName: [14]u16,
   3585 };
   3586 
   3587 pub const FILETIME = extern struct {
   3588     dwLowDateTime: DWORD,
   3589     dwHighDateTime: DWORD,
   3590 };
   3591 
   3592 pub const SYSTEM_INFO = extern struct {
   3593     anon1: extern union {
   3594         dwOemId: DWORD,
   3595         anon2: extern struct {
   3596             wProcessorArchitecture: WORD,
   3597             wReserved: WORD,
   3598         },
   3599     },
   3600     dwPageSize: DWORD,
   3601     lpMinimumApplicationAddress: LPVOID,
   3602     lpMaximumApplicationAddress: LPVOID,
   3603     dwActiveProcessorMask: DWORD_PTR,
   3604     dwNumberOfProcessors: DWORD,
   3605     dwProcessorType: DWORD,
   3606     dwAllocationGranularity: DWORD,
   3607     wProcessorLevel: WORD,
   3608     wProcessorRevision: WORD,
   3609 };
   3610 
   3611 pub const HRESULT = c_long;
   3612 
   3613 pub const KNOWNFOLDERID = GUID;
   3614 pub const GUID = extern struct {
   3615     Data1: u32,
   3616     Data2: u16,
   3617     Data3: u16,
   3618     Data4: [8]u8,
   3619 
   3620     const hex_offsets = switch (builtin.target.cpu.arch.endian()) {
   3621         .big => [16]u6{
   3622             0,  2,  4,  6,
   3623             9,  11, 14, 16,
   3624             19, 21, 24, 26,
   3625             28, 30, 32, 34,
   3626         },
   3627         .little => [16]u6{
   3628             6,  4,  2,  0,
   3629             11, 9,  16, 14,
   3630             19, 21, 24, 26,
   3631             28, 30, 32, 34,
   3632         },
   3633     };
   3634 
   3635     pub fn parse(s: []const u8) GUID {
   3636         assert(s[0] == '{');
   3637         assert(s[37] == '}');
   3638         return parseNoBraces(s[1 .. s.len - 1]) catch @panic("invalid GUID string");
   3639     }
   3640 
   3641     pub fn parseNoBraces(s: []const u8) !GUID {
   3642         assert(s.len == 36);
   3643         assert(s[8] == '-');
   3644         assert(s[13] == '-');
   3645         assert(s[18] == '-');
   3646         assert(s[23] == '-');
   3647         var bytes: [16]u8 = undefined;
   3648         for (hex_offsets, 0..) |hex_offset, i| {
   3649             bytes[i] = (try std.fmt.charToDigit(s[hex_offset], 16)) << 4 |
   3650                 try std.fmt.charToDigit(s[hex_offset + 1], 16);
   3651         }
   3652         return @as(GUID, @bitCast(bytes));
   3653     }
   3654 };
   3655 
   3656 test GUID {
   3657     try std.testing.expectEqual(
   3658         GUID{
   3659             .Data1 = 0x01234567,
   3660             .Data2 = 0x89ab,
   3661             .Data3 = 0xef10,
   3662             .Data4 = "\x32\x54\x76\x98\xba\xdc\xfe\x91".*,
   3663         },
   3664         GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}"),
   3665     );
   3666 }
   3667 
   3668 pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
   3669 
   3670 pub const KF_FLAG_DEFAULT = 0;
   3671 pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
   3672 pub const KF_FLAG_CREATE = 32768;
   3673 pub const KF_FLAG_DONT_VERIFY = 16384;
   3674 pub const KF_FLAG_DONT_UNEXPAND = 8192;
   3675 pub const KF_FLAG_NO_ALIAS = 4096;
   3676 pub const KF_FLAG_INIT = 2048;
   3677 pub const KF_FLAG_DEFAULT_PATH = 1024;
   3678 pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
   3679 pub const KF_FLAG_SIMPLE_IDLIST = 256;
   3680 pub const KF_FLAG_ALIAS_ONLY = -2147483648;
   3681 
   3682 pub const S_OK = 0;
   3683 pub const S_FALSE = 0x00000001;
   3684 pub const E_NOTIMPL = @as(c_long, @bitCast(@as(c_ulong, 0x80004001)));
   3685 pub const E_NOINTERFACE = @as(c_long, @bitCast(@as(c_ulong, 0x80004002)));
   3686 pub const E_POINTER = @as(c_long, @bitCast(@as(c_ulong, 0x80004003)));
   3687 pub const E_ABORT = @as(c_long, @bitCast(@as(c_ulong, 0x80004004)));
   3688 pub const E_FAIL = @as(c_long, @bitCast(@as(c_ulong, 0x80004005)));
   3689 pub const E_UNEXPECTED = @as(c_long, @bitCast(@as(c_ulong, 0x8000FFFF)));
   3690 pub const E_ACCESSDENIED = @as(c_long, @bitCast(@as(c_ulong, 0x80070005)));
   3691 pub const E_HANDLE = @as(c_long, @bitCast(@as(c_ulong, 0x80070006)));
   3692 pub const E_OUTOFMEMORY = @as(c_long, @bitCast(@as(c_ulong, 0x8007000E)));
   3693 pub const E_INVALIDARG = @as(c_long, @bitCast(@as(c_ulong, 0x80070057)));
   3694 
   3695 pub fn HRESULT_CODE(hr: HRESULT) Win32Error {
   3696     return @enumFromInt(hr & 0xFFFF);
   3697 }
   3698 
   3699 pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
   3700 pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
   3701 pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
   3702 pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
   3703 pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
   3704 pub const FILE_FLAG_OVERLAPPED = 0x40000000;
   3705 pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
   3706 pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
   3707 pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
   3708 pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
   3709 pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
   3710 
   3711 pub const RECT = extern struct {
   3712     left: LONG,
   3713     top: LONG,
   3714     right: LONG,
   3715     bottom: LONG,
   3716 };
   3717 
   3718 pub const SMALL_RECT = extern struct {
   3719     Left: SHORT,
   3720     Top: SHORT,
   3721     Right: SHORT,
   3722     Bottom: SHORT,
   3723 };
   3724 
   3725 pub const POINT = extern struct {
   3726     x: LONG,
   3727     y: LONG,
   3728 };
   3729 
   3730 pub const COORD = extern struct {
   3731     X: SHORT,
   3732     Y: SHORT,
   3733 };
   3734 
   3735 pub const CREATE_UNICODE_ENVIRONMENT = 1024;
   3736 
   3737 pub const TLS_OUT_OF_INDEXES = 4294967295;
   3738 pub const IMAGE_TLS_DIRECTORY = extern struct {
   3739     StartAddressOfRawData: usize,
   3740     EndAddressOfRawData: usize,
   3741     AddressOfIndex: usize,
   3742     AddressOfCallBacks: usize,
   3743     SizeOfZeroFill: u32,
   3744     Characteristics: u32,
   3745 };
   3746 pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
   3747 pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
   3748 
   3749 pub const PIMAGE_TLS_CALLBACK = ?*const fn (PVOID, DWORD, PVOID) callconv(.winapi) void;
   3750 
   3751 pub const PROV_RSA_FULL = 1;
   3752 
   3753 pub const REGSAM = ACCESS_MASK;
   3754 pub const ACCESS_MASK = DWORD;
   3755 pub const LSTATUS = LONG;
   3756 
   3757 pub const SECTION_INHERIT = enum(c_int) {
   3758     ViewShare = 0,
   3759     ViewUnmap = 1,
   3760 };
   3761 
   3762 pub const SECTION_QUERY = 0x0001;
   3763 pub const SECTION_MAP_WRITE = 0x0002;
   3764 pub const SECTION_MAP_READ = 0x0004;
   3765 pub const SECTION_MAP_EXECUTE = 0x0008;
   3766 pub const SECTION_EXTEND_SIZE = 0x0010;
   3767 pub const SECTION_ALL_ACCESS =
   3768     STANDARD_RIGHTS_REQUIRED |
   3769     SECTION_QUERY |
   3770     SECTION_MAP_WRITE |
   3771     SECTION_MAP_READ |
   3772     SECTION_MAP_EXECUTE |
   3773     SECTION_EXTEND_SIZE;
   3774 
   3775 pub const SEC_64K_PAGES = 0x80000;
   3776 pub const SEC_FILE = 0x800000;
   3777 pub const SEC_IMAGE = 0x1000000;
   3778 pub const SEC_PROTECTED_IMAGE = 0x2000000;
   3779 pub const SEC_RESERVE = 0x4000000;
   3780 pub const SEC_COMMIT = 0x8000000;
   3781 pub const SEC_IMAGE_NO_EXECUTE = SEC_IMAGE | SEC_NOCACHE;
   3782 pub const SEC_NOCACHE = 0x10000000;
   3783 pub const SEC_WRITECOMBINE = 0x40000000;
   3784 pub const SEC_LARGE_PAGES = 0x80000000;
   3785 
   3786 pub const HKEY = *opaque {};
   3787 
   3788 pub const HKEY_CLASSES_ROOT: HKEY = @ptrFromInt(0x80000000);
   3789 pub const HKEY_CURRENT_USER: HKEY = @ptrFromInt(0x80000001);
   3790 pub const HKEY_LOCAL_MACHINE: HKEY = @ptrFromInt(0x80000002);
   3791 pub const HKEY_USERS: HKEY = @ptrFromInt(0x80000003);
   3792 pub const HKEY_PERFORMANCE_DATA: HKEY = @ptrFromInt(0x80000004);
   3793 pub const HKEY_PERFORMANCE_TEXT: HKEY = @ptrFromInt(0x80000050);
   3794 pub const HKEY_PERFORMANCE_NLSTEXT: HKEY = @ptrFromInt(0x80000060);
   3795 pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005);
   3796 pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006);
   3797 pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = @ptrFromInt(0x80000007);
   3798 
   3799 /// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY,
   3800 /// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights.
   3801 pub const KEY_ALL_ACCESS = 0xF003F;
   3802 /// Reserved for system use.
   3803 pub const KEY_CREATE_LINK = 0x0020;
   3804 /// Required to create a subkey of a registry key.
   3805 pub const KEY_CREATE_SUB_KEY = 0x0004;
   3806 /// Required to enumerate the subkeys of a registry key.
   3807 pub const KEY_ENUMERATE_SUB_KEYS = 0x0008;
   3808 /// Equivalent to KEY_READ.
   3809 pub const KEY_EXECUTE = 0x20019;
   3810 /// Required to request change notifications for a registry key or for subkeys of a registry key.
   3811 pub const KEY_NOTIFY = 0x0010;
   3812 /// Required to query the values of a registry key.
   3813 pub const KEY_QUERY_VALUE = 0x0001;
   3814 /// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
   3815 pub const KEY_READ = 0x20019;
   3816 /// Required to create, delete, or set a registry value.
   3817 pub const KEY_SET_VALUE = 0x0002;
   3818 /// Indicates that an application on 64-bit Windows should operate on the 32-bit registry view.
   3819 /// This flag is ignored by 32-bit Windows.
   3820 pub const KEY_WOW64_32KEY = 0x0200;
   3821 /// Indicates that an application on 64-bit Windows should operate on the 64-bit registry view.
   3822 /// This flag is ignored by 32-bit Windows.
   3823 pub const KEY_WOW64_64KEY = 0x0100;
   3824 /// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.
   3825 pub const KEY_WRITE = 0x20006;
   3826 
   3827 /// Open symbolic link.
   3828 pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
   3829 
   3830 pub const RTL_QUERY_REGISTRY_TABLE = extern struct {
   3831     QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,
   3832     Flags: ULONG,
   3833     Name: ?PWSTR,
   3834     EntryContext: ?*anyopaque,
   3835     DefaultType: ULONG,
   3836     DefaultData: ?*anyopaque,
   3837     DefaultLength: ULONG,
   3838 };
   3839 
   3840 pub const RTL_QUERY_REGISTRY_ROUTINE = ?*const fn (
   3841     PWSTR,
   3842     ULONG,
   3843     ?*anyopaque,
   3844     ULONG,
   3845     ?*anyopaque,
   3846     ?*anyopaque,
   3847 ) callconv(.winapi) NTSTATUS;
   3848 
   3849 /// Path is a full path
   3850 pub const RTL_REGISTRY_ABSOLUTE = 0;
   3851 /// \Registry\Machine\System\CurrentControlSet\Services
   3852 pub const RTL_REGISTRY_SERVICES = 1;
   3853 /// \Registry\Machine\System\CurrentControlSet\Control
   3854 pub const RTL_REGISTRY_CONTROL = 2;
   3855 /// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
   3856 pub const RTL_REGISTRY_WINDOWS_NT = 3;
   3857 /// \Registry\Machine\Hardware\DeviceMap
   3858 pub const RTL_REGISTRY_DEVICEMAP = 4;
   3859 /// \Registry\User\CurrentUser
   3860 pub const RTL_REGISTRY_USER = 5;
   3861 pub const RTL_REGISTRY_MAXIMUM = 6;
   3862 
   3863 /// Low order bits are registry handle
   3864 pub const RTL_REGISTRY_HANDLE = 0x40000000;
   3865 /// Indicates the key node is optional
   3866 pub const RTL_REGISTRY_OPTIONAL = 0x80000000;
   3867 
   3868 /// Name is a subkey and remainder of table or until next subkey are value
   3869 /// names for that subkey to look at.
   3870 pub const RTL_QUERY_REGISTRY_SUBKEY = 0x00000001;
   3871 
   3872 /// Reset current key to original key for this and all following table entries.
   3873 pub const RTL_QUERY_REGISTRY_TOPKEY = 0x00000002;
   3874 
   3875 /// Fail if no match found for this table entry.
   3876 pub const RTL_QUERY_REGISTRY_REQUIRED = 0x00000004;
   3877 
   3878 /// Used to mark a table entry that has no value name, just wants a call out, not
   3879 /// an enumeration of all values.
   3880 pub const RTL_QUERY_REGISTRY_NOVALUE = 0x00000008;
   3881 
   3882 /// Used to suppress the expansion of REG_MULTI_SZ into multiple callouts or
   3883 /// to prevent the expansion of environment variable values in REG_EXPAND_SZ.
   3884 pub const RTL_QUERY_REGISTRY_NOEXPAND = 0x00000010;
   3885 
   3886 /// QueryRoutine field ignored.  EntryContext field points to location to store value.
   3887 /// For null terminated strings, EntryContext points to UNICODE_STRING structure that
   3888 /// that describes maximum size of buffer. If .Buffer field is NULL then a buffer is
   3889 /// allocated.
   3890 pub const RTL_QUERY_REGISTRY_DIRECT = 0x00000020;
   3891 
   3892 /// Used to delete value keys after they are queried.
   3893 pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040;
   3894 
   3895 /// Use this flag with the RTL_QUERY_REGISTRY_DIRECT flag to verify that the REG_XXX type
   3896 /// of the stored registry value matches the type expected by the caller.
   3897 /// If the types do not match, the call fails.
   3898 pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100;
   3899 
   3900 pub const REG = struct {
   3901     /// No value type
   3902     pub const NONE: ULONG = 0;
   3903     /// Unicode nul terminated string
   3904     pub const SZ: ULONG = 1;
   3905     /// Unicode nul terminated string (with environment variable references)
   3906     pub const EXPAND_SZ: ULONG = 2;
   3907     /// Free form binary
   3908     pub const BINARY: ULONG = 3;
   3909     /// 32-bit number
   3910     pub const DWORD: ULONG = 4;
   3911     /// 32-bit number (same as REG_DWORD)
   3912     pub const DWORD_LITTLE_ENDIAN: ULONG = 4;
   3913     /// 32-bit number
   3914     pub const DWORD_BIG_ENDIAN: ULONG = 5;
   3915     /// Symbolic Link (unicode)
   3916     pub const LINK: ULONG = 6;
   3917     /// Multiple Unicode strings
   3918     pub const MULTI_SZ: ULONG = 7;
   3919     /// Resource list in the resource map
   3920     pub const RESOURCE_LIST: ULONG = 8;
   3921     /// Resource list in the hardware description
   3922     pub const FULL_RESOURCE_DESCRIPTOR: ULONG = 9;
   3923     pub const RESOURCE_REQUIREMENTS_LIST: ULONG = 10;
   3924     /// 64-bit number
   3925     pub const QWORD: ULONG = 11;
   3926     /// 64-bit number (same as REG_QWORD)
   3927     pub const QWORD_LITTLE_ENDIAN: ULONG = 11;
   3928 };
   3929 
   3930 pub const FILE_NOTIFY_INFORMATION = extern struct {
   3931     NextEntryOffset: DWORD,
   3932     Action: DWORD,
   3933     FileNameLength: DWORD,
   3934     // Flexible array member
   3935     // FileName: [1]WCHAR,
   3936 };
   3937 
   3938 pub const FILE_ACTION_ADDED = 0x00000001;
   3939 pub const FILE_ACTION_REMOVED = 0x00000002;
   3940 pub const FILE_ACTION_MODIFIED = 0x00000003;
   3941 pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
   3942 pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
   3943 
   3944 pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?*const fn (DWORD, DWORD, *OVERLAPPED) callconv(.winapi) void;
   3945 
   3946 pub const FileNotifyChangeFilter = packed struct(DWORD) {
   3947     file_name: bool = false,
   3948     dir_name: bool = false,
   3949     attributes: bool = false,
   3950     size: bool = false,
   3951     last_write: bool = false,
   3952     last_access: bool = false,
   3953     creation: bool = false,
   3954     ea: bool = false,
   3955     security: bool = false,
   3956     stream_name: bool = false,
   3957     stream_size: bool = false,
   3958     stream_write: bool = false,
   3959     _pad: u20 = 0,
   3960 };
   3961 
   3962 pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
   3963     dwSize: COORD,
   3964     dwCursorPosition: COORD,
   3965     wAttributes: WORD,
   3966     srWindow: SMALL_RECT,
   3967     dwMaximumWindowSize: COORD,
   3968 };
   3969 
   3970 pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;
   3971 pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8;
   3972 
   3973 pub const FOREGROUND_BLUE = 1;
   3974 pub const FOREGROUND_GREEN = 2;
   3975 pub const FOREGROUND_RED = 4;
   3976 pub const FOREGROUND_INTENSITY = 8;
   3977 
   3978 pub const LIST_ENTRY = extern struct {
   3979     Flink: *LIST_ENTRY,
   3980     Blink: *LIST_ENTRY,
   3981 };
   3982 
   3983 pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
   3984     Type: WORD,
   3985     CreatorBackTraceIndex: WORD,
   3986     CriticalSection: *RTL_CRITICAL_SECTION,
   3987     ProcessLocksList: LIST_ENTRY,
   3988     EntryCount: DWORD,
   3989     ContentionCount: DWORD,
   3990     Flags: DWORD,
   3991     CreatorBackTraceIndexHigh: WORD,
   3992     SpareWORD: WORD,
   3993 };
   3994 
   3995 pub const RTL_CRITICAL_SECTION = extern struct {
   3996     DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
   3997     LockCount: LONG,
   3998     RecursionCount: LONG,
   3999     OwningThread: HANDLE,
   4000     LockSemaphore: HANDLE,
   4001     SpinCount: ULONG_PTR,
   4002 };
   4003 
   4004 pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
   4005 pub const INIT_ONCE = RTL_RUN_ONCE;
   4006 pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
   4007 pub const INIT_ONCE_FN = *const fn (InitOnce: *INIT_ONCE, Parameter: ?*anyopaque, Context: ?*anyopaque) callconv(.winapi) BOOL;
   4008 
   4009 pub const RTL_RUN_ONCE = extern struct {
   4010     Ptr: ?*anyopaque,
   4011 };
   4012 
   4013 pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
   4014 
   4015 pub const COINIT = struct {
   4016     pub const APARTMENTTHREADED = 2;
   4017     pub const MULTITHREADED = 0;
   4018     pub const DISABLE_OLE1DDE = 4;
   4019     pub const SPEED_OVER_MEMORY = 8;
   4020 };
   4021 
   4022 pub const MEMORY_BASIC_INFORMATION = extern struct {
   4023     BaseAddress: PVOID,
   4024     AllocationBase: PVOID,
   4025     AllocationProtect: DWORD,
   4026     PartitionId: WORD,
   4027     RegionSize: SIZE_T,
   4028     State: DWORD,
   4029     Protect: DWORD,
   4030     Type: DWORD,
   4031 };
   4032 
   4033 pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION;
   4034 
   4035 /// > The maximum path of 32,767 characters is approximate, because the "\\?\"
   4036 /// > prefix may be expanded to a longer string by the system at run time, and
   4037 /// > this expansion applies to the total length.
   4038 /// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
   4039 pub const PATH_MAX_WIDE = 32767;
   4040 
   4041 /// > [Each file name component can be] up to the value returned in the
   4042 /// > lpMaximumComponentLength parameter of the GetVolumeInformation function
   4043 /// > (this value is commonly 255 characters)
   4044 /// from https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
   4045 ///
   4046 /// > The value that is stored in the variable that *lpMaximumComponentLength points to is
   4047 /// > used to indicate that a specified file system supports long names. For example, for
   4048 /// > a FAT file system that supports long names, the function stores the value 255, rather
   4049 /// > than the previous 8.3 indicator. Long names can also be supported on systems that use
   4050 /// > the NTFS file system.
   4051 /// from https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw
   4052 ///
   4053 /// The assumption being made here is that while lpMaximumComponentLength may vary, it will never
   4054 /// be larger than 255.
   4055 ///
   4056 /// TODO: More verification of this assumption.
   4057 pub const NAME_MAX = 255;
   4058 
   4059 pub const FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
   4060 pub const FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
   4061 pub const FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
   4062 pub const FORMAT_MESSAGE_FROM_STRING = 0x00000400;
   4063 pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
   4064 pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
   4065 pub const FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF;
   4066 
   4067 pub const EXCEPTION_DATATYPE_MISALIGNMENT = 0x80000002;
   4068 pub const EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
   4069 pub const EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d;
   4070 pub const EXCEPTION_STACK_OVERFLOW = 0xc00000fd;
   4071 pub const EXCEPTION_CONTINUE_SEARCH = 0;
   4072 
   4073 pub const EXCEPTION_RECORD = extern struct {
   4074     ExceptionCode: u32,
   4075     ExceptionFlags: u32,
   4076     ExceptionRecord: *EXCEPTION_RECORD,
   4077     ExceptionAddress: *anyopaque,
   4078     NumberParameters: u32,
   4079     ExceptionInformation: [15]usize,
   4080 };
   4081 
   4082 pub const FLOATING_SAVE_AREA = switch (native_arch) {
   4083     .x86 => extern struct {
   4084         ControlWord: DWORD,
   4085         StatusWord: DWORD,
   4086         TagWord: DWORD,
   4087         ErrorOffset: DWORD,
   4088         ErrorSelector: DWORD,
   4089         DataOffset: DWORD,
   4090         DataSelector: DWORD,
   4091         RegisterArea: [80]BYTE,
   4092         Cr0NpxState: DWORD,
   4093     },
   4094     else => @compileError("FLOATING_SAVE_AREA only defined on x86"),
   4095 };
   4096 
   4097 pub const M128A = switch (native_arch) {
   4098     .x86_64 => extern struct {
   4099         Low: ULONGLONG,
   4100         High: LONGLONG,
   4101     },
   4102     else => @compileError("M128A only defined on x86_64"),
   4103 };
   4104 
   4105 pub const XMM_SAVE_AREA32 = switch (native_arch) {
   4106     .x86_64 => extern struct {
   4107         ControlWord: WORD,
   4108         StatusWord: WORD,
   4109         TagWord: BYTE,
   4110         Reserved1: BYTE,
   4111         ErrorOpcode: WORD,
   4112         ErrorOffset: DWORD,
   4113         ErrorSelector: WORD,
   4114         Reserved2: WORD,
   4115         DataOffset: DWORD,
   4116         DataSelector: WORD,
   4117         Reserved3: WORD,
   4118         MxCsr: DWORD,
   4119         MxCsr_Mask: DWORD,
   4120         FloatRegisters: [8]M128A,
   4121         XmmRegisters: [16]M128A,
   4122         Reserved4: [96]BYTE,
   4123     },
   4124     else => @compileError("XMM_SAVE_AREA32 only defined on x86_64"),
   4125 };
   4126 
   4127 pub const NEON128 = switch (native_arch) {
   4128     .thumb => extern struct {
   4129         Low: ULONGLONG,
   4130         High: LONGLONG,
   4131     },
   4132     .aarch64 => extern union {
   4133         DUMMYSTRUCTNAME: extern struct {
   4134             Low: ULONGLONG,
   4135             High: LONGLONG,
   4136         },
   4137         D: [2]f64,
   4138         S: [4]f32,
   4139         H: [8]WORD,
   4140         B: [16]BYTE,
   4141     },
   4142     else => @compileError("NEON128 only defined on aarch64"),
   4143 };
   4144 
   4145 pub const CONTEXT = switch (native_arch) {
   4146     .x86 => extern struct {
   4147         ContextFlags: DWORD,
   4148         Dr0: DWORD,
   4149         Dr1: DWORD,
   4150         Dr2: DWORD,
   4151         Dr3: DWORD,
   4152         Dr6: DWORD,
   4153         Dr7: DWORD,
   4154         FloatSave: FLOATING_SAVE_AREA,
   4155         SegGs: DWORD,
   4156         SegFs: DWORD,
   4157         SegEs: DWORD,
   4158         SegDs: DWORD,
   4159         Edi: DWORD,
   4160         Esi: DWORD,
   4161         Ebx: DWORD,
   4162         Edx: DWORD,
   4163         Ecx: DWORD,
   4164         Eax: DWORD,
   4165         Ebp: DWORD,
   4166         Eip: DWORD,
   4167         SegCs: DWORD,
   4168         EFlags: DWORD,
   4169         Esp: DWORD,
   4170         SegSs: DWORD,
   4171         ExtendedRegisters: [512]BYTE,
   4172 
   4173         pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize } {
   4174             return .{ .bp = ctx.Ebp, .ip = ctx.Eip };
   4175         }
   4176     },
   4177     .x86_64 => extern struct {
   4178         P1Home: DWORD64 align(16),
   4179         P2Home: DWORD64,
   4180         P3Home: DWORD64,
   4181         P4Home: DWORD64,
   4182         P5Home: DWORD64,
   4183         P6Home: DWORD64,
   4184         ContextFlags: DWORD,
   4185         MxCsr: DWORD,
   4186         SegCs: WORD,
   4187         SegDs: WORD,
   4188         SegEs: WORD,
   4189         SegFs: WORD,
   4190         SegGs: WORD,
   4191         SegSs: WORD,
   4192         EFlags: DWORD,
   4193         Dr0: DWORD64,
   4194         Dr1: DWORD64,
   4195         Dr2: DWORD64,
   4196         Dr3: DWORD64,
   4197         Dr6: DWORD64,
   4198         Dr7: DWORD64,
   4199         Rax: DWORD64,
   4200         Rcx: DWORD64,
   4201         Rdx: DWORD64,
   4202         Rbx: DWORD64,
   4203         Rsp: DWORD64,
   4204         Rbp: DWORD64,
   4205         Rsi: DWORD64,
   4206         Rdi: DWORD64,
   4207         R8: DWORD64,
   4208         R9: DWORD64,
   4209         R10: DWORD64,
   4210         R11: DWORD64,
   4211         R12: DWORD64,
   4212         R13: DWORD64,
   4213         R14: DWORD64,
   4214         R15: DWORD64,
   4215         Rip: DWORD64,
   4216         DUMMYUNIONNAME: extern union {
   4217             FltSave: XMM_SAVE_AREA32,
   4218             FloatSave: XMM_SAVE_AREA32,
   4219             DUMMYSTRUCTNAME: extern struct {
   4220                 Header: [2]M128A,
   4221                 Legacy: [8]M128A,
   4222                 Xmm0: M128A,
   4223                 Xmm1: M128A,
   4224                 Xmm2: M128A,
   4225                 Xmm3: M128A,
   4226                 Xmm4: M128A,
   4227                 Xmm5: M128A,
   4228                 Xmm6: M128A,
   4229                 Xmm7: M128A,
   4230                 Xmm8: M128A,
   4231                 Xmm9: M128A,
   4232                 Xmm10: M128A,
   4233                 Xmm11: M128A,
   4234                 Xmm12: M128A,
   4235                 Xmm13: M128A,
   4236                 Xmm14: M128A,
   4237                 Xmm15: M128A,
   4238             },
   4239         },
   4240         VectorRegister: [26]M128A,
   4241         VectorControl: DWORD64,
   4242         DebugControl: DWORD64,
   4243         LastBranchToRip: DWORD64,
   4244         LastBranchFromRip: DWORD64,
   4245         LastExceptionToRip: DWORD64,
   4246         LastExceptionFromRip: DWORD64,
   4247 
   4248         pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize, sp: usize } {
   4249             return .{ .bp = ctx.Rbp, .ip = ctx.Rip, .sp = ctx.Rsp };
   4250         }
   4251 
   4252         pub fn setIp(ctx: *CONTEXT, ip: usize) void {
   4253             ctx.Rip = ip;
   4254         }
   4255 
   4256         pub fn setSp(ctx: *CONTEXT, sp: usize) void {
   4257             ctx.Rsp = sp;
   4258         }
   4259     },
   4260     .thumb => extern struct {
   4261         ContextFlags: ULONG,
   4262         R0: ULONG,
   4263         R1: ULONG,
   4264         R2: ULONG,
   4265         R3: ULONG,
   4266         R4: ULONG,
   4267         R5: ULONG,
   4268         R6: ULONG,
   4269         R7: ULONG,
   4270         R8: ULONG,
   4271         R9: ULONG,
   4272         R10: ULONG,
   4273         R11: ULONG,
   4274         R12: ULONG,
   4275         Sp: ULONG,
   4276         Lr: ULONG,
   4277         Pc: ULONG,
   4278         Cpsr: ULONG,
   4279         Fpcsr: ULONG,
   4280         Padding: ULONG,
   4281         DUMMYUNIONNAME: extern union {
   4282             Q: [16]NEON128,
   4283             D: [32]ULONGLONG,
   4284             S: [32]ULONG,
   4285         },
   4286         Bvr: [8]ULONG,
   4287         Bcr: [8]ULONG,
   4288         Wvr: [1]ULONG,
   4289         Wcr: [1]ULONG,
   4290         Padding2: [2]ULONG,
   4291 
   4292         pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize, sp: usize } {
   4293             return .{
   4294                 .bp = ctx.DUMMYUNIONNAME.S[11],
   4295                 .ip = ctx.Pc,
   4296                 .sp = ctx.Sp,
   4297             };
   4298         }
   4299 
   4300         pub fn setIp(ctx: *CONTEXT, ip: usize) void {
   4301             ctx.Pc = ip;
   4302         }
   4303 
   4304         pub fn setSp(ctx: *CONTEXT, sp: usize) void {
   4305             ctx.Sp = sp;
   4306         }
   4307     },
   4308     .aarch64 => extern struct {
   4309         ContextFlags: ULONG align(16),
   4310         Cpsr: ULONG,
   4311         DUMMYUNIONNAME: extern union {
   4312             DUMMYSTRUCTNAME: extern struct {
   4313                 X0: DWORD64,
   4314                 X1: DWORD64,
   4315                 X2: DWORD64,
   4316                 X3: DWORD64,
   4317                 X4: DWORD64,
   4318                 X5: DWORD64,
   4319                 X6: DWORD64,
   4320                 X7: DWORD64,
   4321                 X8: DWORD64,
   4322                 X9: DWORD64,
   4323                 X10: DWORD64,
   4324                 X11: DWORD64,
   4325                 X12: DWORD64,
   4326                 X13: DWORD64,
   4327                 X14: DWORD64,
   4328                 X15: DWORD64,
   4329                 X16: DWORD64,
   4330                 X17: DWORD64,
   4331                 X18: DWORD64,
   4332                 X19: DWORD64,
   4333                 X20: DWORD64,
   4334                 X21: DWORD64,
   4335                 X22: DWORD64,
   4336                 X23: DWORD64,
   4337                 X24: DWORD64,
   4338                 X25: DWORD64,
   4339                 X26: DWORD64,
   4340                 X27: DWORD64,
   4341                 X28: DWORD64,
   4342                 Fp: DWORD64,
   4343                 Lr: DWORD64,
   4344             },
   4345             X: [31]DWORD64,
   4346         },
   4347         Sp: DWORD64,
   4348         Pc: DWORD64,
   4349         V: [32]NEON128,
   4350         Fpcr: DWORD,
   4351         Fpsr: DWORD,
   4352         Bcr: [8]DWORD,
   4353         Bvr: [8]DWORD64,
   4354         Wcr: [2]DWORD,
   4355         Wvr: [2]DWORD64,
   4356 
   4357         pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize, sp: usize } {
   4358             return .{
   4359                 .bp = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp,
   4360                 .ip = ctx.Pc,
   4361                 .sp = ctx.Sp,
   4362             };
   4363         }
   4364 
   4365         pub fn setIp(ctx: *CONTEXT, ip: usize) void {
   4366             ctx.Pc = ip;
   4367         }
   4368 
   4369         pub fn setSp(ctx: *CONTEXT, sp: usize) void {
   4370             ctx.Sp = sp;
   4371         }
   4372     },
   4373     else => @compileError("CONTEXT is not defined for this architecture"),
   4374 };
   4375 
   4376 pub const RUNTIME_FUNCTION = switch (native_arch) {
   4377     .x86_64 => extern struct {
   4378         BeginAddress: DWORD,
   4379         EndAddress: DWORD,
   4380         UnwindData: DWORD,
   4381     },
   4382     .thumb => extern struct {
   4383         BeginAddress: DWORD,
   4384         DUMMYUNIONNAME: extern union {
   4385             UnwindData: DWORD,
   4386             DUMMYSTRUCTNAME: packed struct {
   4387                 Flag: u2,
   4388                 FunctionLength: u11,
   4389                 Ret: u2,
   4390                 H: u1,
   4391                 Reg: u3,
   4392                 R: u1,
   4393                 L: u1,
   4394                 C: u1,
   4395                 StackAdjust: u10,
   4396             },
   4397         },
   4398     },
   4399     .aarch64 => extern struct {
   4400         BeginAddress: DWORD,
   4401         DUMMYUNIONNAME: extern union {
   4402             UnwindData: DWORD,
   4403             DUMMYSTRUCTNAME: packed struct {
   4404                 Flag: u2,
   4405                 FunctionLength: u11,
   4406                 RegF: u3,
   4407                 RegI: u4,
   4408                 H: u1,
   4409                 CR: u2,
   4410                 FrameSize: u9,
   4411             },
   4412         },
   4413     },
   4414     else => @compileError("RUNTIME_FUNCTION is not defined for this architecture"),
   4415 };
   4416 
   4417 pub const KNONVOLATILE_CONTEXT_POINTERS = switch (native_arch) {
   4418     .x86_64 => extern struct {
   4419         FloatingContext: [16]?*M128A,
   4420         IntegerContext: [16]?*ULONG64,
   4421     },
   4422     .thumb => extern struct {
   4423         R4: ?*DWORD,
   4424         R5: ?*DWORD,
   4425         R6: ?*DWORD,
   4426         R7: ?*DWORD,
   4427         R8: ?*DWORD,
   4428         R9: ?*DWORD,
   4429         R10: ?*DWORD,
   4430         R11: ?*DWORD,
   4431         Lr: ?*DWORD,
   4432         D8: ?*ULONGLONG,
   4433         D9: ?*ULONGLONG,
   4434         D10: ?*ULONGLONG,
   4435         D11: ?*ULONGLONG,
   4436         D12: ?*ULONGLONG,
   4437         D13: ?*ULONGLONG,
   4438         D14: ?*ULONGLONG,
   4439         D15: ?*ULONGLONG,
   4440     },
   4441     .aarch64 => extern struct {
   4442         X19: ?*DWORD64,
   4443         X20: ?*DWORD64,
   4444         X21: ?*DWORD64,
   4445         X22: ?*DWORD64,
   4446         X23: ?*DWORD64,
   4447         X24: ?*DWORD64,
   4448         X25: ?*DWORD64,
   4449         X26: ?*DWORD64,
   4450         X27: ?*DWORD64,
   4451         X28: ?*DWORD64,
   4452         Fp: ?*DWORD64,
   4453         Lr: ?*DWORD64,
   4454         D8: ?*DWORD64,
   4455         D9: ?*DWORD64,
   4456         D10: ?*DWORD64,
   4457         D11: ?*DWORD64,
   4458         D12: ?*DWORD64,
   4459         D13: ?*DWORD64,
   4460         D14: ?*DWORD64,
   4461         D15: ?*DWORD64,
   4462     },
   4463     else => @compileError("KNONVOLATILE_CONTEXT_POINTERS is not defined for this architecture"),
   4464 };
   4465 
   4466 pub const EXCEPTION_POINTERS = extern struct {
   4467     ExceptionRecord: *EXCEPTION_RECORD,
   4468     ContextRecord: *CONTEXT,
   4469 };
   4470 
   4471 pub const VECTORED_EXCEPTION_HANDLER = *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(.winapi) c_long;
   4472 
   4473 pub const EXCEPTION_DISPOSITION = i32;
   4474 pub const EXCEPTION_ROUTINE = *const fn (
   4475     ExceptionRecord: ?*EXCEPTION_RECORD,
   4476     EstablisherFrame: PVOID,
   4477     ContextRecord: *(Self.CONTEXT),
   4478     DispatcherContext: PVOID,
   4479 ) callconv(.winapi) EXCEPTION_DISPOSITION;
   4480 
   4481 pub const UNWIND_HISTORY_TABLE_SIZE = 12;
   4482 pub const UNWIND_HISTORY_TABLE_ENTRY = extern struct {
   4483     ImageBase: ULONG64,
   4484     FunctionEntry: *Self.RUNTIME_FUNCTION,
   4485 };
   4486 
   4487 pub const UNWIND_HISTORY_TABLE = extern struct {
   4488     Count: ULONG,
   4489     LocalHint: BYTE,
   4490     GlobalHint: BYTE,
   4491     Search: BYTE,
   4492     Once: BYTE,
   4493     LowAddress: ULONG64,
   4494     HighAddress: ULONG64,
   4495     Entry: [UNWIND_HISTORY_TABLE_SIZE]UNWIND_HISTORY_TABLE_ENTRY,
   4496 };
   4497 
   4498 pub const UNW_FLAG_NHANDLER = 0x0;
   4499 pub const UNW_FLAG_EHANDLER = 0x1;
   4500 pub const UNW_FLAG_UHANDLER = 0x2;
   4501 pub const UNW_FLAG_CHAININFO = 0x4;
   4502 
   4503 pub const OBJECT_ATTRIBUTES = extern struct {
   4504     Length: ULONG,
   4505     RootDirectory: ?HANDLE,
   4506     ObjectName: *UNICODE_STRING,
   4507     Attributes: ULONG,
   4508     SecurityDescriptor: ?*anyopaque,
   4509     SecurityQualityOfService: ?*anyopaque,
   4510 };
   4511 
   4512 pub const OBJ_INHERIT = 0x00000002;
   4513 pub const OBJ_PERMANENT = 0x00000010;
   4514 pub const OBJ_EXCLUSIVE = 0x00000020;
   4515 pub const OBJ_CASE_INSENSITIVE = 0x00000040;
   4516 pub const OBJ_OPENIF = 0x00000080;
   4517 pub const OBJ_OPENLINK = 0x00000100;
   4518 pub const OBJ_KERNEL_HANDLE = 0x00000200;
   4519 pub const OBJ_VALID_ATTRIBUTES = 0x000003F2;
   4520 
   4521 pub const UNICODE_STRING = extern struct {
   4522     Length: c_ushort,
   4523     MaximumLength: c_ushort,
   4524     Buffer: ?[*]WCHAR,
   4525 };
   4526 
   4527 pub const ACTIVATION_CONTEXT_DATA = opaque {};
   4528 pub const ASSEMBLY_STORAGE_MAP = opaque {};
   4529 pub const FLS_CALLBACK_INFO = opaque {};
   4530 pub const RTL_BITMAP = opaque {};
   4531 pub const KAFFINITY = usize;
   4532 pub const KPRIORITY = i32;
   4533 
   4534 pub const CLIENT_ID = extern struct {
   4535     UniqueProcess: HANDLE,
   4536     UniqueThread: HANDLE,
   4537 };
   4538 
   4539 pub const THREAD_BASIC_INFORMATION = extern struct {
   4540     ExitStatus: NTSTATUS,
   4541     TebBaseAddress: PVOID,
   4542     ClientId: CLIENT_ID,
   4543     AffinityMask: KAFFINITY,
   4544     Priority: KPRIORITY,
   4545     BasePriority: KPRIORITY,
   4546 };
   4547 
   4548 pub const TEB = extern struct {
   4549     NtTib: NT_TIB,
   4550     EnvironmentPointer: PVOID,
   4551     ClientId: CLIENT_ID,
   4552     ActiveRpcHandle: PVOID,
   4553     ThreadLocalStoragePointer: PVOID,
   4554     ProcessEnvironmentBlock: *PEB,
   4555     LastErrorValue: ULONG,
   4556     Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8,
   4557     Reserved3: [1952]u8,
   4558     TlsSlots: [64]PVOID,
   4559     Reserved4: [8]u8,
   4560     Reserved5: [26]PVOID,
   4561     ReservedForOle: PVOID,
   4562     Reserved6: [4]PVOID,
   4563     TlsExpansionSlots: PVOID,
   4564 };
   4565 
   4566 comptime {
   4567     // Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
   4568     // [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
   4569     assert(@offsetOf(TEB, "NtTib") == 0x00);
   4570     if (@sizeOf(usize) == 4) {
   4571         assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
   4572         assert(@offsetOf(TEB, "ClientId") == 0x20);
   4573         assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
   4574         assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
   4575         assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
   4576         assert(@offsetOf(TEB, "LastErrorValue") == 0x34);
   4577         assert(@offsetOf(TEB, "TlsSlots") == 0xe10);
   4578     } else if (@sizeOf(usize) == 8) {
   4579         assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
   4580         assert(@offsetOf(TEB, "ClientId") == 0x40);
   4581         assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
   4582         assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
   4583         assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
   4584         assert(@offsetOf(TEB, "LastErrorValue") == 0x68);
   4585         assert(@offsetOf(TEB, "TlsSlots") == 0x1480);
   4586     }
   4587 }
   4588 
   4589 pub const EXCEPTION_REGISTRATION_RECORD = extern struct {
   4590     Next: ?*EXCEPTION_REGISTRATION_RECORD,
   4591     Handler: ?*EXCEPTION_DISPOSITION,
   4592 };
   4593 
   4594 pub const NT_TIB = extern struct {
   4595     ExceptionList: ?*EXCEPTION_REGISTRATION_RECORD,
   4596     StackBase: PVOID,
   4597     StackLimit: PVOID,
   4598     SubSystemTib: PVOID,
   4599     DUMMYUNIONNAME: extern union { FiberData: PVOID, Version: DWORD },
   4600     ArbitraryUserPointer: PVOID,
   4601     Self: ?*@This(),
   4602 };
   4603 
   4604 /// Process Environment Block
   4605 /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
   4606 ///  - https://github.com/wine-mirror/wine/blob/1aff1e6a370ee8c0213a0fd4b220d121da8527aa/include/winternl.h#L269
   4607 ///  - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/index.htm
   4608 pub const PEB = extern struct {
   4609     // Versions: All
   4610     InheritedAddressSpace: BOOLEAN,
   4611 
   4612     // Versions: 3.51+
   4613     ReadImageFileExecOptions: BOOLEAN,
   4614     BeingDebugged: BOOLEAN,
   4615 
   4616     // Versions: 5.2+ (previously was padding)
   4617     BitField: UCHAR,
   4618 
   4619     // Versions: all
   4620     Mutant: HANDLE,
   4621     ImageBaseAddress: HMODULE,
   4622     Ldr: *PEB_LDR_DATA,
   4623     ProcessParameters: *RTL_USER_PROCESS_PARAMETERS,
   4624     SubSystemData: PVOID,
   4625     ProcessHeap: HANDLE,
   4626 
   4627     // Versions: 5.1+
   4628     FastPebLock: *RTL_CRITICAL_SECTION,
   4629 
   4630     // Versions: 5.2+
   4631     AtlThunkSListPtr: PVOID,
   4632     IFEOKey: PVOID,
   4633 
   4634     // Versions: 6.0+
   4635 
   4636     /// https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/crossprocessflags.htm
   4637     CrossProcessFlags: ULONG,
   4638 
   4639     // Versions: 6.0+
   4640     union1: extern union {
   4641         KernelCallbackTable: PVOID,
   4642         UserSharedInfoPtr: PVOID,
   4643     },
   4644 
   4645     // Versions: 5.1+
   4646     SystemReserved: ULONG,
   4647 
   4648     // Versions: 5.1, (not 5.2, not 6.0), 6.1+
   4649     AtlThunkSListPtr32: ULONG,
   4650 
   4651     // Versions: 6.1+
   4652     ApiSetMap: PVOID,
   4653 
   4654     // Versions: all
   4655     TlsExpansionCounter: ULONG,
   4656     // note: there is padding here on 64 bit
   4657     TlsBitmap: *RTL_BITMAP,
   4658     TlsBitmapBits: [2]ULONG,
   4659     ReadOnlySharedMemoryBase: PVOID,
   4660 
   4661     // Versions: 1703+
   4662     SharedData: PVOID,
   4663 
   4664     // Versions: all
   4665     ReadOnlyStaticServerData: *PVOID,
   4666     AnsiCodePageData: PVOID,
   4667     OemCodePageData: PVOID,
   4668     UnicodeCaseTableData: PVOID,
   4669 
   4670     // Versions: 3.51+
   4671     NumberOfProcessors: ULONG,
   4672     NtGlobalFlag: ULONG,
   4673 
   4674     // Versions: all
   4675     CriticalSectionTimeout: LARGE_INTEGER,
   4676 
   4677     // End of Original PEB size
   4678 
   4679     // Fields appended in 3.51:
   4680     HeapSegmentReserve: ULONG_PTR,
   4681     HeapSegmentCommit: ULONG_PTR,
   4682     HeapDeCommitTotalFreeThreshold: ULONG_PTR,
   4683     HeapDeCommitFreeBlockThreshold: ULONG_PTR,
   4684     NumberOfHeaps: ULONG,
   4685     MaximumNumberOfHeaps: ULONG,
   4686     ProcessHeaps: *PVOID,
   4687 
   4688     // Fields appended in 4.0:
   4689     GdiSharedHandleTable: PVOID,
   4690     ProcessStarterHelper: PVOID,
   4691     GdiDCAttributeList: ULONG,
   4692     // note: there is padding here on 64 bit
   4693     LoaderLock: *RTL_CRITICAL_SECTION,
   4694     OSMajorVersion: ULONG,
   4695     OSMinorVersion: ULONG,
   4696     OSBuildNumber: USHORT,
   4697     OSCSDVersion: USHORT,
   4698     OSPlatformId: ULONG,
   4699     ImageSubSystem: ULONG,
   4700     ImageSubSystemMajorVersion: ULONG,
   4701     ImageSubSystemMinorVersion: ULONG,
   4702     // note: there is padding here on 64 bit
   4703     ActiveProcessAffinityMask: KAFFINITY,
   4704     GdiHandleBuffer: [
   4705         switch (@sizeOf(usize)) {
   4706             4 => 0x22,
   4707             8 => 0x3C,
   4708             else => unreachable,
   4709         }
   4710     ]ULONG,
   4711 
   4712     // Fields appended in 5.0 (Windows 2000):
   4713     PostProcessInitRoutine: PVOID,
   4714     TlsExpansionBitmap: *RTL_BITMAP,
   4715     TlsExpansionBitmapBits: [32]ULONG,
   4716     SessionId: ULONG,
   4717     // note: there is padding here on 64 bit
   4718     // Versions: 5.1+
   4719     AppCompatFlags: ULARGE_INTEGER,
   4720     AppCompatFlagsUser: ULARGE_INTEGER,
   4721     ShimData: PVOID,
   4722     // Versions: 5.0+
   4723     AppCompatInfo: PVOID,
   4724     CSDVersion: UNICODE_STRING,
   4725 
   4726     // Fields appended in 5.1 (Windows XP):
   4727     ActivationContextData: *const ACTIVATION_CONTEXT_DATA,
   4728     ProcessAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
   4729     SystemDefaultActivationData: *const ACTIVATION_CONTEXT_DATA,
   4730     SystemAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
   4731     MinimumStackCommit: ULONG_PTR,
   4732 
   4733     // Fields appended in 5.2 (Windows Server 2003):
   4734     FlsCallback: *FLS_CALLBACK_INFO,
   4735     FlsListHead: LIST_ENTRY,
   4736     FlsBitmap: *RTL_BITMAP,
   4737     FlsBitmapBits: [4]ULONG,
   4738     FlsHighIndex: ULONG,
   4739 
   4740     // Fields appended in 6.0 (Windows Vista):
   4741     WerRegistrationData: PVOID,
   4742     WerShipAssertPtr: PVOID,
   4743 
   4744     // Fields appended in 6.1 (Windows 7):
   4745     pUnused: PVOID, // previously pContextData
   4746     pImageHeaderHash: PVOID,
   4747 
   4748     /// TODO: https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/tracingflags.htm
   4749     TracingFlags: ULONG,
   4750 
   4751     // Fields appended in 6.2 (Windows 8):
   4752     CsrServerReadOnlySharedMemoryBase: ULONGLONG,
   4753 
   4754     // Fields appended in 1511:
   4755     TppWorkerpListLock: ULONG,
   4756     TppWorkerpList: LIST_ENTRY,
   4757     WaitOnAddressHashTable: [0x80]PVOID,
   4758 
   4759     // Fields appended in 1709:
   4760     TelemetryCoverageHeader: PVOID,
   4761     CloudFileFlags: ULONG,
   4762 };
   4763 
   4764 /// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.
   4765 /// It is essentially the head of three double-linked lists of `LDR_DATA_TABLE_ENTRY` structures which each represent one loaded module.
   4766 ///
   4767 /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
   4768 ///  - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm
   4769 pub const PEB_LDR_DATA = extern struct {
   4770     // Versions: 3.51 and higher
   4771     /// The size in bytes of the structure
   4772     Length: ULONG,
   4773 
   4774     /// TRUE if the structure is prepared.
   4775     Initialized: BOOLEAN,
   4776 
   4777     SsHandle: PVOID,
   4778     InLoadOrderModuleList: LIST_ENTRY,
   4779     InMemoryOrderModuleList: LIST_ENTRY,
   4780     InInitializationOrderModuleList: LIST_ENTRY,
   4781 
   4782     // Versions: 5.1 and higher
   4783 
   4784     /// No known use of this field is known in Windows 8 and higher.
   4785     EntryInProgress: PVOID,
   4786 
   4787     // Versions: 6.0 from Windows Vista SP1, and higher
   4788     ShutdownInProgress: BOOLEAN,
   4789 
   4790     /// Though ShutdownThreadId is declared as a HANDLE,
   4791     /// it is indeed the thread ID as suggested by its name.
   4792     /// It is picked up from the UniqueThread member of the CLIENT_ID in the
   4793     /// TEB of the thread that asks to terminate the process.
   4794     ShutdownThreadId: HANDLE,
   4795 };
   4796 
   4797 /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
   4798 ///  - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data
   4799 ///  - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm
   4800 pub const LDR_DATA_TABLE_ENTRY = extern struct {
   4801     Reserved1: [2]PVOID,
   4802     InMemoryOrderLinks: LIST_ENTRY,
   4803     Reserved2: [2]PVOID,
   4804     DllBase: PVOID,
   4805     EntryPoint: PVOID,
   4806     SizeOfImage: ULONG,
   4807     FullDllName: UNICODE_STRING,
   4808     Reserved4: [8]BYTE,
   4809     Reserved5: [3]PVOID,
   4810     DUMMYUNIONNAME: extern union {
   4811         CheckSum: ULONG,
   4812         Reserved6: PVOID,
   4813     },
   4814     TimeDateStamp: ULONG,
   4815 };
   4816 
   4817 pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
   4818     AllocationSize: ULONG,
   4819     Size: ULONG,
   4820     Flags: ULONG,
   4821     DebugFlags: ULONG,
   4822     ConsoleHandle: HANDLE,
   4823     ConsoleFlags: ULONG,
   4824     hStdInput: HANDLE,
   4825     hStdOutput: HANDLE,
   4826     hStdError: HANDLE,
   4827     CurrentDirectory: CURDIR,
   4828     DllPath: UNICODE_STRING,
   4829     ImagePathName: UNICODE_STRING,
   4830     CommandLine: UNICODE_STRING,
   4831     Environment: [*:0]WCHAR,
   4832     dwX: ULONG,
   4833     dwY: ULONG,
   4834     dwXSize: ULONG,
   4835     dwYSize: ULONG,
   4836     dwXCountChars: ULONG,
   4837     dwYCountChars: ULONG,
   4838     dwFillAttribute: ULONG,
   4839     dwFlags: ULONG,
   4840     dwShowWindow: ULONG,
   4841     WindowTitle: UNICODE_STRING,
   4842     Desktop: UNICODE_STRING,
   4843     ShellInfo: UNICODE_STRING,
   4844     RuntimeInfo: UNICODE_STRING,
   4845     DLCurrentDirectory: [0x20]RTL_DRIVE_LETTER_CURDIR,
   4846 };
   4847 
   4848 pub const RTL_DRIVE_LETTER_CURDIR = extern struct {
   4849     Flags: c_ushort,
   4850     Length: c_ushort,
   4851     TimeStamp: ULONG,
   4852     DosPath: UNICODE_STRING,
   4853 };
   4854 
   4855 pub const PPS_POST_PROCESS_INIT_ROUTINE = ?*const fn () callconv(.winapi) void;
   4856 
   4857 pub const FILE_DIRECTORY_INFORMATION = extern struct {
   4858     NextEntryOffset: ULONG,
   4859     FileIndex: ULONG,
   4860     CreationTime: LARGE_INTEGER,
   4861     LastAccessTime: LARGE_INTEGER,
   4862     LastWriteTime: LARGE_INTEGER,
   4863     ChangeTime: LARGE_INTEGER,
   4864     EndOfFile: LARGE_INTEGER,
   4865     AllocationSize: LARGE_INTEGER,
   4866     FileAttributes: ULONG,
   4867     FileNameLength: ULONG,
   4868     FileName: [1]WCHAR,
   4869 };
   4870 
   4871 pub const FILE_BOTH_DIR_INFORMATION = extern struct {
   4872     NextEntryOffset: ULONG,
   4873     FileIndex: ULONG,
   4874     CreationTime: LARGE_INTEGER,
   4875     LastAccessTime: LARGE_INTEGER,
   4876     LastWriteTime: LARGE_INTEGER,
   4877     ChangeTime: LARGE_INTEGER,
   4878     EndOfFile: LARGE_INTEGER,
   4879     AllocationSize: LARGE_INTEGER,
   4880     FileAttributes: ULONG,
   4881     FileNameLength: ULONG,
   4882     EaSize: ULONG,
   4883     ShortNameLength: CHAR,
   4884     ShortName: [12]WCHAR,
   4885     FileName: [1]WCHAR,
   4886 };
   4887 pub const FILE_BOTH_DIRECTORY_INFORMATION = FILE_BOTH_DIR_INFORMATION;
   4888 
   4889 /// Helper for iterating a byte buffer of FILE_*_INFORMATION structures (from
   4890 /// things like NtQueryDirectoryFile calls).
   4891 pub fn FileInformationIterator(comptime FileInformationType: type) type {
   4892     return struct {
   4893         byte_offset: usize = 0,
   4894         buf: []u8 align(@alignOf(FileInformationType)),
   4895 
   4896         pub fn next(self: *@This()) ?*FileInformationType {
   4897             if (self.byte_offset >= self.buf.len) return null;
   4898             const cur: *FileInformationType = @ptrCast(@alignCast(&self.buf[self.byte_offset]));
   4899             if (cur.NextEntryOffset == 0) {
   4900                 self.byte_offset = self.buf.len;
   4901             } else {
   4902                 self.byte_offset += cur.NextEntryOffset;
   4903             }
   4904             return cur;
   4905         }
   4906     };
   4907 }
   4908 
   4909 pub const IO_APC_ROUTINE = *const fn (PVOID, *IO_STATUS_BLOCK, ULONG) callconv(.winapi) void;
   4910 
   4911 pub const CURDIR = extern struct {
   4912     DosPath: UNICODE_STRING,
   4913     Handle: HANDLE,
   4914 };
   4915 
   4916 pub const DUPLICATE_SAME_ACCESS = 2;
   4917 
   4918 pub const MODULEINFO = extern struct {
   4919     lpBaseOfDll: LPVOID,
   4920     SizeOfImage: DWORD,
   4921     EntryPoint: LPVOID,
   4922 };
   4923 
   4924 pub const PSAPI_WS_WATCH_INFORMATION = extern struct {
   4925     FaultingPc: LPVOID,
   4926     FaultingVa: LPVOID,
   4927 };
   4928 
   4929 pub const VM_COUNTERS = extern struct {
   4930     PeakVirtualSize: SIZE_T,
   4931     VirtualSize: SIZE_T,
   4932     PageFaultCount: ULONG,
   4933     PeakWorkingSetSize: SIZE_T,
   4934     WorkingSetSize: SIZE_T,
   4935     QuotaPeakPagedPoolUsage: SIZE_T,
   4936     QuotaPagedPoolUsage: SIZE_T,
   4937     QuotaPeakNonPagedPoolUsage: SIZE_T,
   4938     QuotaNonPagedPoolUsage: SIZE_T,
   4939     PagefileUsage: SIZE_T,
   4940     PeakPagefileUsage: SIZE_T,
   4941 };
   4942 
   4943 pub const PROCESS_MEMORY_COUNTERS = extern struct {
   4944     cb: DWORD,
   4945     PageFaultCount: DWORD,
   4946     PeakWorkingSetSize: SIZE_T,
   4947     WorkingSetSize: SIZE_T,
   4948     QuotaPeakPagedPoolUsage: SIZE_T,
   4949     QuotaPagedPoolUsage: SIZE_T,
   4950     QuotaPeakNonPagedPoolUsage: SIZE_T,
   4951     QuotaNonPagedPoolUsage: SIZE_T,
   4952     PagefileUsage: SIZE_T,
   4953     PeakPagefileUsage: SIZE_T,
   4954 };
   4955 
   4956 pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {
   4957     cb: DWORD,
   4958     PageFaultCount: DWORD,
   4959     PeakWorkingSetSize: SIZE_T,
   4960     WorkingSetSize: SIZE_T,
   4961     QuotaPeakPagedPoolUsage: SIZE_T,
   4962     QuotaPagedPoolUsage: SIZE_T,
   4963     QuotaPeakNonPagedPoolUsage: SIZE_T,
   4964     QuotaNonPagedPoolUsage: SIZE_T,
   4965     PagefileUsage: SIZE_T,
   4966     PeakPagefileUsage: SIZE_T,
   4967     PrivateUsage: SIZE_T,
   4968 };
   4969 
   4970 pub const GetProcessMemoryInfoError = error{
   4971     AccessDenied,
   4972     InvalidHandle,
   4973     Unexpected,
   4974 };
   4975 
   4976 pub fn GetProcessMemoryInfo(hProcess: HANDLE) GetProcessMemoryInfoError!VM_COUNTERS {
   4977     var vmc: VM_COUNTERS = undefined;
   4978     const rc = ntdll.NtQueryInformationProcess(hProcess, .ProcessVmCounters, &vmc, @sizeOf(VM_COUNTERS), null);
   4979     switch (rc) {
   4980         .SUCCESS => return vmc,
   4981         .ACCESS_DENIED => return error.AccessDenied,
   4982         .INVALID_HANDLE => return error.InvalidHandle,
   4983         .INVALID_PARAMETER => unreachable,
   4984         else => return unexpectedStatus(rc),
   4985     }
   4986 }
   4987 
   4988 pub const PERFORMANCE_INFORMATION = extern struct {
   4989     cb: DWORD,
   4990     CommitTotal: SIZE_T,
   4991     CommitLimit: SIZE_T,
   4992     CommitPeak: SIZE_T,
   4993     PhysicalTotal: SIZE_T,
   4994     PhysicalAvailable: SIZE_T,
   4995     SystemCache: SIZE_T,
   4996     KernelTotal: SIZE_T,
   4997     KernelPaged: SIZE_T,
   4998     KernelNonpaged: SIZE_T,
   4999     PageSize: SIZE_T,
   5000     HandleCount: DWORD,
   5001     ProcessCount: DWORD,
   5002     ThreadCount: DWORD,
   5003 };
   5004 
   5005 pub const ENUM_PAGE_FILE_INFORMATION = extern struct {
   5006     cb: DWORD,
   5007     Reserved: DWORD,
   5008     TotalSize: SIZE_T,
   5009     TotalInUse: SIZE_T,
   5010     PeakUsage: SIZE_T,
   5011 };
   5012 
   5013 pub const PENUM_PAGE_FILE_CALLBACKW = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.winapi) BOOL;
   5014 pub const PENUM_PAGE_FILE_CALLBACKA = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.winapi) BOOL;
   5015 
   5016 pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {
   5017     BasicInfo: PSAPI_WS_WATCH_INFORMATION,
   5018     FaultingThreadId: ULONG_PTR,
   5019     Flags: ULONG_PTR,
   5020 };
   5021 
   5022 pub const OSVERSIONINFOW = extern struct {
   5023     dwOSVersionInfoSize: ULONG,
   5024     dwMajorVersion: ULONG,
   5025     dwMinorVersion: ULONG,
   5026     dwBuildNumber: ULONG,
   5027     dwPlatformId: ULONG,
   5028     szCSDVersion: [128]WCHAR,
   5029 };
   5030 pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW;
   5031 
   5032 pub const REPARSE_DATA_BUFFER = extern struct {
   5033     ReparseTag: ULONG,
   5034     ReparseDataLength: USHORT,
   5035     Reserved: USHORT,
   5036     DataBuffer: [1]UCHAR,
   5037 };
   5038 pub const SYMBOLIC_LINK_REPARSE_BUFFER = extern struct {
   5039     SubstituteNameOffset: USHORT,
   5040     SubstituteNameLength: USHORT,
   5041     PrintNameOffset: USHORT,
   5042     PrintNameLength: USHORT,
   5043     Flags: ULONG,
   5044     PathBuffer: [1]WCHAR,
   5045 };
   5046 pub const MOUNT_POINT_REPARSE_BUFFER = extern struct {
   5047     SubstituteNameOffset: USHORT,
   5048     SubstituteNameLength: USHORT,
   5049     PrintNameOffset: USHORT,
   5050     PrintNameLength: USHORT,
   5051     PathBuffer: [1]WCHAR,
   5052 };
   5053 pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: ULONG = 16 * 1024;
   5054 pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
   5055 pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8;
   5056 pub const IO_REPARSE_TAG_SYMLINK: ULONG = 0xa000000c;
   5057 pub const IO_REPARSE_TAG_MOUNT_POINT: ULONG = 0xa0000003;
   5058 pub const SYMLINK_FLAG_RELATIVE: ULONG = 0x1;
   5059 
   5060 pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
   5061 pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
   5062 
   5063 pub const MOUNTMGRCONTROLTYPE = 0x0000006D;
   5064 
   5065 pub const MOUNTMGR_MOUNT_POINT = extern struct {
   5066     SymbolicLinkNameOffset: ULONG,
   5067     SymbolicLinkNameLength: USHORT,
   5068     Reserved1: USHORT,
   5069     UniqueIdOffset: ULONG,
   5070     UniqueIdLength: USHORT,
   5071     Reserved2: USHORT,
   5072     DeviceNameOffset: ULONG,
   5073     DeviceNameLength: USHORT,
   5074     Reserved3: USHORT,
   5075 };
   5076 pub const MOUNTMGR_MOUNT_POINTS = extern struct {
   5077     Size: ULONG,
   5078     NumberOfMountPoints: ULONG,
   5079     MountPoints: [1]MOUNTMGR_MOUNT_POINT,
   5080 };
   5081 pub const IOCTL_MOUNTMGR_QUERY_POINTS = CTL_CODE(MOUNTMGRCONTROLTYPE, 2, .METHOD_BUFFERED, FILE_ANY_ACCESS);
   5082 
   5083 pub const MOUNTMGR_TARGET_NAME = extern struct {
   5084     DeviceNameLength: USHORT,
   5085     DeviceName: [1]WCHAR,
   5086 };
   5087 pub const MOUNTMGR_VOLUME_PATHS = extern struct {
   5088     MultiSzLength: ULONG,
   5089     MultiSz: [1]WCHAR,
   5090 };
   5091 pub const IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH = CTL_CODE(MOUNTMGRCONTROLTYPE, 12, .METHOD_BUFFERED, FILE_ANY_ACCESS);
   5092 
   5093 pub const OBJECT_INFORMATION_CLASS = enum(c_int) {
   5094     ObjectBasicInformation = 0,
   5095     ObjectNameInformation = 1,
   5096     ObjectTypeInformation = 2,
   5097     ObjectTypesInformation = 3,
   5098     ObjectHandleFlagInformation = 4,
   5099     ObjectSessionInformation = 5,
   5100     MaxObjectInfoClass,
   5101 };
   5102 
   5103 pub const OBJECT_NAME_INFORMATION = extern struct {
   5104     Name: UNICODE_STRING,
   5105 };
   5106 
   5107 pub const SRWLOCK_INIT = SRWLOCK{};
   5108 pub const SRWLOCK = extern struct {
   5109     Ptr: ?PVOID = null,
   5110 };
   5111 
   5112 pub const CONDITION_VARIABLE_INIT = CONDITION_VARIABLE{};
   5113 pub const CONDITION_VARIABLE = extern struct {
   5114     Ptr: ?PVOID = null,
   5115 };
   5116 
   5117 pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1;
   5118 pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2;
   5119 
   5120 pub const CTRL_C_EVENT: DWORD = 0;
   5121 pub const CTRL_BREAK_EVENT: DWORD = 1;
   5122 pub const CTRL_CLOSE_EVENT: DWORD = 2;
   5123 pub const CTRL_LOGOFF_EVENT: DWORD = 5;
   5124 pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
   5125 
   5126 pub const HANDLER_ROUTINE = *const fn (dwCtrlType: DWORD) callconv(.winapi) BOOL;
   5127 
   5128 /// Processor feature enumeration.
   5129 pub const PF = enum(DWORD) {
   5130     /// On a Pentium, a floating-point precision error can occur in rare circumstances.
   5131     FLOATING_POINT_PRECISION_ERRATA = 0,
   5132 
   5133     /// Floating-point operations are emulated using software emulator.
   5134     /// This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero.
   5135     FLOATING_POINT_EMULATED = 1,
   5136 
   5137     /// The atomic compare and exchange operation (cmpxchg) is available.
   5138     COMPARE_EXCHANGE_DOUBLE = 2,
   5139 
   5140     /// The MMX instruction set is available.
   5141     MMX_INSTRUCTIONS_AVAILABLE = 3,
   5142 
   5143     PPC_MOVEMEM_64BIT_OK = 4,
   5144     ALPHA_BYTE_INSTRUCTIONS = 5,
   5145 
   5146     /// The SSE instruction set is available.
   5147     XMMI_INSTRUCTIONS_AVAILABLE = 6,
   5148 
   5149     /// The 3D-Now instruction is available.
   5150     @"3DNOW_INSTRUCTIONS_AVAILABLE" = 7,
   5151 
   5152     /// The RDTSC instruction is available.
   5153     RDTSC_INSTRUCTION_AVAILABLE = 8,
   5154 
   5155     /// The processor is PAE-enabled.
   5156     PAE_ENABLED = 9,
   5157 
   5158     /// The SSE2 instruction set is available.
   5159     XMMI64_INSTRUCTIONS_AVAILABLE = 10,
   5160 
   5161     SSE_DAZ_MODE_AVAILABLE = 11,
   5162 
   5163     /// Data execution prevention is enabled.
   5164     NX_ENABLED = 12,
   5165 
   5166     /// The SSE3 instruction set is available.
   5167     SSE3_INSTRUCTIONS_AVAILABLE = 13,
   5168 
   5169     /// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available.
   5170     COMPARE_EXCHANGE128 = 14,
   5171 
   5172     /// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available.
   5173     COMPARE64_EXCHANGE128 = 15,
   5174 
   5175     /// The processor channels are enabled.
   5176     CHANNELS_ENABLED = 16,
   5177 
   5178     /// The processor implements the XSAVI and XRSTOR instructions.
   5179     XSAVE_ENABLED = 17,
   5180 
   5181     /// The VFP/Neon: 32 x 64bit register bank is present.
   5182     /// This flag has the same meaning as PF_ARM_VFP_EXTENDED_REGISTERS.
   5183     ARM_VFP_32_REGISTERS_AVAILABLE = 18,
   5184 
   5185     /// This ARM processor implements the ARM v8 NEON instruction set.
   5186     ARM_NEON_INSTRUCTIONS_AVAILABLE = 19,
   5187 
   5188     /// Second Level Address Translation is supported by the hardware.
   5189     SECOND_LEVEL_ADDRESS_TRANSLATION = 20,
   5190 
   5191     /// Virtualization is enabled in the firmware and made available by the operating system.
   5192     VIRT_FIRMWARE_ENABLED = 21,
   5193 
   5194     /// RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions are available.
   5195     RDWRFSGBASE_AVAILABLE = 22,
   5196 
   5197     /// _fastfail() is available.
   5198     FASTFAIL_AVAILABLE = 23,
   5199 
   5200     /// The divide instruction_available.
   5201     ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24,
   5202 
   5203     /// The 64-bit load/store atomic instructions are available.
   5204     ARM_64BIT_LOADSTORE_ATOMIC = 25,
   5205 
   5206     /// The external cache is available.
   5207     ARM_EXTERNAL_CACHE_AVAILABLE = 26,
   5208 
   5209     /// The floating-point multiply-accumulate instruction is available.
   5210     ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27,
   5211 
   5212     RDRAND_INSTRUCTION_AVAILABLE = 28,
   5213 
   5214     /// This ARM processor implements the ARM v8 instructions set.
   5215     ARM_V8_INSTRUCTIONS_AVAILABLE = 29,
   5216 
   5217     /// This ARM processor implements the ARM v8 extra cryptographic instructions (i.e., AES, SHA1 and SHA2).
   5218     ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30,
   5219 
   5220     /// This ARM processor implements the ARM v8 extra CRC32 instructions.
   5221     ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31,
   5222 
   5223     RDTSCP_INSTRUCTION_AVAILABLE = 32,
   5224     RDPID_INSTRUCTION_AVAILABLE = 33,
   5225 
   5226     /// This ARM processor implements the ARM v8.1 atomic instructions (e.g., CAS, SWP).
   5227     ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34,
   5228 
   5229     MONITORX_INSTRUCTION_AVAILABLE = 35,
   5230 
   5231     /// The SSSE3 instruction set is available.
   5232     SSSE3_INSTRUCTIONS_AVAILABLE = 36,
   5233 
   5234     /// The SSE4_1 instruction set is available.
   5235     SSE4_1_INSTRUCTIONS_AVAILABLE = 37,
   5236 
   5237     /// The SSE4_2 instruction set is available.
   5238     SSE4_2_INSTRUCTIONS_AVAILABLE = 38,
   5239 
   5240     /// The AVX instruction set is available.
   5241     AVX_INSTRUCTIONS_AVAILABLE = 39,
   5242 
   5243     /// The AVX2 instruction set is available.
   5244     AVX2_INSTRUCTIONS_AVAILABLE = 40,
   5245 
   5246     /// The AVX512F instruction set is available.
   5247     AVX512F_INSTRUCTIONS_AVAILABLE = 41,
   5248 
   5249     ERMS_AVAILABLE = 42,
   5250 
   5251     /// This ARM processor implements the ARM v8.2 Dot Product (DP) instructions.
   5252     ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43,
   5253 
   5254     /// This ARM processor implements the ARM v8.3 JavaScript conversion (JSCVT) instructions.
   5255     ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44,
   5256 };
   5257 
   5258 pub const MAX_WOW64_SHARED_ENTRIES = 16;
   5259 pub const PROCESSOR_FEATURE_MAX = 64;
   5260 pub const MAXIMUM_XSTATE_FEATURES = 64;
   5261 
   5262 pub const KSYSTEM_TIME = extern struct {
   5263     LowPart: ULONG,
   5264     High1Time: LONG,
   5265     High2Time: LONG,
   5266 };
   5267 
   5268 pub const NT_PRODUCT_TYPE = enum(INT) {
   5269     NtProductWinNt = 1,
   5270     NtProductLanManNt,
   5271     NtProductServer,
   5272 };
   5273 
   5274 pub const ALTERNATIVE_ARCHITECTURE_TYPE = enum(INT) {
   5275     StandardDesign,
   5276     NEC98x86,
   5277     EndAlternatives,
   5278 };
   5279 
   5280 pub const XSTATE_FEATURE = extern struct {
   5281     Offset: ULONG,
   5282     Size: ULONG,
   5283 };
   5284 
   5285 pub const XSTATE_CONFIGURATION = extern struct {
   5286     EnabledFeatures: ULONG64,
   5287     Size: ULONG,
   5288     OptimizedSave: ULONG,
   5289     Features: [MAXIMUM_XSTATE_FEATURES]XSTATE_FEATURE,
   5290 };
   5291 
   5292 /// Shared Kernel User Data
   5293 pub const KUSER_SHARED_DATA = extern struct {
   5294     TickCountLowDeprecated: ULONG,
   5295     TickCountMultiplier: ULONG,
   5296     InterruptTime: KSYSTEM_TIME,
   5297     SystemTime: KSYSTEM_TIME,
   5298     TimeZoneBias: KSYSTEM_TIME,
   5299     ImageNumberLow: USHORT,
   5300     ImageNumberHigh: USHORT,
   5301     NtSystemRoot: [260]WCHAR,
   5302     MaxStackTraceDepth: ULONG,
   5303     CryptoExponent: ULONG,
   5304     TimeZoneId: ULONG,
   5305     LargePageMinimum: ULONG,
   5306     AitSamplingValue: ULONG,
   5307     AppCompatFlag: ULONG,
   5308     RNGSeedVersion: ULONGLONG,
   5309     GlobalValidationRunlevel: ULONG,
   5310     TimeZoneBiasStamp: LONG,
   5311     NtBuildNumber: ULONG,
   5312     NtProductType: NT_PRODUCT_TYPE,
   5313     ProductTypeIsValid: BOOLEAN,
   5314     Reserved0: [1]BOOLEAN,
   5315     NativeProcessorArchitecture: USHORT,
   5316     NtMajorVersion: ULONG,
   5317     NtMinorVersion: ULONG,
   5318     ProcessorFeatures: [PROCESSOR_FEATURE_MAX]BOOLEAN,
   5319     Reserved1: ULONG,
   5320     Reserved3: ULONG,
   5321     TimeSlip: ULONG,
   5322     AlternativeArchitecture: ALTERNATIVE_ARCHITECTURE_TYPE,
   5323     BootId: ULONG,
   5324     SystemExpirationDate: LARGE_INTEGER,
   5325     SuiteMaskY: ULONG,
   5326     KdDebuggerEnabled: BOOLEAN,
   5327     DummyUnion1: extern union {
   5328         MitigationPolicies: UCHAR,
   5329         Alt: packed struct {
   5330             NXSupportPolicy: u2,
   5331             SEHValidationPolicy: u2,
   5332             CurDirDevicesSkippedForDlls: u2,
   5333             Reserved: u2,
   5334         },
   5335     },
   5336     CyclesPerYield: USHORT,
   5337     ActiveConsoleId: ULONG,
   5338     DismountCount: ULONG,
   5339     ComPlusPackage: ULONG,
   5340     LastSystemRITEventTickCount: ULONG,
   5341     NumberOfPhysicalPages: ULONG,
   5342     SafeBootMode: BOOLEAN,
   5343     DummyUnion2: extern union {
   5344         VirtualizationFlags: UCHAR,
   5345         Alt: packed struct {
   5346             ArchStartedInEl2: u1,
   5347             QcSlIsSupported: u1,
   5348             SpareBits: u6,
   5349         },
   5350     },
   5351     Reserved12: [2]UCHAR,
   5352     DummyUnion3: extern union {
   5353         SharedDataFlags: ULONG,
   5354         Alt: packed struct {
   5355             DbgErrorPortPresent: u1,
   5356             DbgElevationEnabled: u1,
   5357             DbgVirtEnabled: u1,
   5358             DbgInstallerDetectEnabled: u1,
   5359             DbgLkgEnabled: u1,
   5360             DbgDynProcessorEnabled: u1,
   5361             DbgConsoleBrokerEnabled: u1,
   5362             DbgSecureBootEnabled: u1,
   5363             DbgMultiSessionSku: u1,
   5364             DbgMultiUsersInSessionSku: u1,
   5365             DbgStateSeparationEnabled: u1,
   5366             SpareBits: u21,
   5367         },
   5368     },
   5369     DataFlagsPad: [1]ULONG,
   5370     TestRetInstruction: ULONGLONG,
   5371     QpcFrequency: LONGLONG,
   5372     SystemCall: ULONG,
   5373     Reserved2: ULONG,
   5374     SystemCallPad: [2]ULONGLONG,
   5375     DummyUnion4: extern union {
   5376         TickCount: KSYSTEM_TIME,
   5377         TickCountQuad: ULONG64,
   5378         Alt: extern struct {
   5379             ReservedTickCountOverlay: [3]ULONG,
   5380             TickCountPad: [1]ULONG,
   5381         },
   5382     },
   5383     Cookie: ULONG,
   5384     CookiePad: [1]ULONG,
   5385     ConsoleSessionForegroundProcessId: LONGLONG,
   5386     TimeUpdateLock: ULONGLONG,
   5387     BaselineSystemTimeQpc: ULONGLONG,
   5388     BaselineInterruptTimeQpc: ULONGLONG,
   5389     QpcSystemTimeIncrement: ULONGLONG,
   5390     QpcInterruptTimeIncrement: ULONGLONG,
   5391     QpcSystemTimeIncrementShift: UCHAR,
   5392     QpcInterruptTimeIncrementShift: UCHAR,
   5393     UnparkedProcessorCount: USHORT,
   5394     EnclaveFeatureMask: [4]ULONG,
   5395     TelemetryCoverageRound: ULONG,
   5396     UserModeGlobalLogger: [16]USHORT,
   5397     ImageFileExecutionOptions: ULONG,
   5398     LangGenerationCount: ULONG,
   5399     Reserved4: ULONGLONG,
   5400     InterruptTimeBias: ULONGLONG,
   5401     QpcBias: ULONGLONG,
   5402     ActiveProcessorCount: ULONG,
   5403     ActiveGroupCount: UCHAR,
   5404     Reserved9: UCHAR,
   5405     DummyUnion5: extern union {
   5406         QpcData: USHORT,
   5407         Alt: extern struct {
   5408             QpcBypassEnabled: UCHAR,
   5409             QpcShift: UCHAR,
   5410         },
   5411     },
   5412     TimeZoneBiasEffectiveStart: LARGE_INTEGER,
   5413     TimeZoneBiasEffectiveEnd: LARGE_INTEGER,
   5414     XState: XSTATE_CONFIGURATION,
   5415     FeatureConfigurationChangeStamp: KSYSTEM_TIME,
   5416     Spare: ULONG,
   5417     UserPointerAuthMask: ULONG64,
   5418 };
   5419 
   5420 /// Read-only user-mode address for the shared data.
   5421 /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
   5422 /// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/
   5423 pub const SharedUserData: *const KUSER_SHARED_DATA = @as(*const KUSER_SHARED_DATA, @ptrFromInt(0x7FFE0000));
   5424 
   5425 pub fn IsProcessorFeaturePresent(feature: PF) bool {
   5426     if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false;
   5427     return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1;
   5428 }
   5429 
   5430 pub const TH32CS_SNAPHEAPLIST = 0x00000001;
   5431 pub const TH32CS_SNAPPROCESS = 0x00000002;
   5432 pub const TH32CS_SNAPTHREAD = 0x00000004;
   5433 pub const TH32CS_SNAPMODULE = 0x00000008;
   5434 pub const TH32CS_SNAPMODULE32 = 0x00000010;
   5435 pub const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE;
   5436 pub const TH32CS_INHERIT = 0x80000000;
   5437 
   5438 pub const MAX_MODULE_NAME32 = 255;
   5439 pub const MODULEENTRY32 = extern struct {
   5440     dwSize: DWORD,
   5441     th32ModuleID: DWORD,
   5442     th32ProcessID: DWORD,
   5443     GlblcntUsage: DWORD,
   5444     ProccntUsage: DWORD,
   5445     modBaseAddr: *BYTE,
   5446     modBaseSize: DWORD,
   5447     hModule: HMODULE,
   5448     szModule: [MAX_MODULE_NAME32 + 1]CHAR,
   5449     szExePath: [MAX_PATH]CHAR,
   5450 };
   5451 
   5452 pub const SYSTEM_INFORMATION_CLASS = enum(c_int) {
   5453     SystemBasicInformation = 0,
   5454     SystemPerformanceInformation = 2,
   5455     SystemTimeOfDayInformation = 3,
   5456     SystemProcessInformation = 5,
   5457     SystemProcessorPerformanceInformation = 8,
   5458     SystemInterruptInformation = 23,
   5459     SystemExceptionInformation = 33,
   5460     SystemRegistryQuotaInformation = 37,
   5461     SystemLookasideInformation = 45,
   5462     SystemCodeIntegrityInformation = 103,
   5463     SystemPolicyInformation = 134,
   5464 };
   5465 
   5466 pub const SYSTEM_BASIC_INFORMATION = extern struct {
   5467     Reserved: ULONG,
   5468     TimerResolution: ULONG,
   5469     PageSize: ULONG,
   5470     NumberOfPhysicalPages: ULONG,
   5471     LowestPhysicalPageNumber: ULONG,
   5472     HighestPhysicalPageNumber: ULONG,
   5473     AllocationGranularity: ULONG,
   5474     MinimumUserModeAddress: ULONG_PTR,
   5475     MaximumUserModeAddress: ULONG_PTR,
   5476     ActiveProcessorsAffinityMask: KAFFINITY,
   5477     NumberOfProcessors: UCHAR,
   5478 };
   5479 
   5480 pub const THREADINFOCLASS = enum(c_int) {
   5481     ThreadBasicInformation,
   5482     ThreadTimes,
   5483     ThreadPriority,
   5484     ThreadBasePriority,
   5485     ThreadAffinityMask,
   5486     ThreadImpersonationToken,
   5487     ThreadDescriptorTableEntry,
   5488     ThreadEnableAlignmentFaultFixup,
   5489     ThreadEventPair_Reusable,
   5490     ThreadQuerySetWin32StartAddress,
   5491     ThreadZeroTlsCell,
   5492     ThreadPerformanceCount,
   5493     ThreadAmILastThread,
   5494     ThreadIdealProcessor,
   5495     ThreadPriorityBoost,
   5496     ThreadSetTlsArrayAddress,
   5497     ThreadIsIoPending,
   5498     // Windows 2000+ from here
   5499     ThreadHideFromDebugger,
   5500     // Windows XP+ from here
   5501     ThreadBreakOnTermination,
   5502     ThreadSwitchLegacyState,
   5503     ThreadIsTerminated,
   5504     // Windows Vista+ from here
   5505     ThreadLastSystemCall,
   5506     ThreadIoPriority,
   5507     ThreadCycleTime,
   5508     ThreadPagePriority,
   5509     ThreadActualBasePriority,
   5510     ThreadTebInformation,
   5511     ThreadCSwitchMon,
   5512     // Windows 7+ from here
   5513     ThreadCSwitchPmu,
   5514     ThreadWow64Context,
   5515     ThreadGroupInformation,
   5516     ThreadUmsInformation,
   5517     ThreadCounterProfiling,
   5518     ThreadIdealProcessorEx,
   5519     // Windows 8+ from here
   5520     ThreadCpuAccountingInformation,
   5521     // Windows 8.1+ from here
   5522     ThreadSuspendCount,
   5523     // Windows 10+ from here
   5524     ThreadHeterogeneousCpuPolicy,
   5525     ThreadContainerId,
   5526     ThreadNameInformation,
   5527     ThreadSelectedCpuSets,
   5528     ThreadSystemThreadInformation,
   5529     ThreadActualGroupAffinity,
   5530 };
   5531 
   5532 pub const PROCESSINFOCLASS = enum(c_int) {
   5533     ProcessBasicInformation,
   5534     ProcessQuotaLimits,
   5535     ProcessIoCounters,
   5536     ProcessVmCounters,
   5537     ProcessTimes,
   5538     ProcessBasePriority,
   5539     ProcessRaisePriority,
   5540     ProcessDebugPort,
   5541     ProcessExceptionPort,
   5542     ProcessAccessToken,
   5543     ProcessLdtInformation,
   5544     ProcessLdtSize,
   5545     ProcessDefaultHardErrorMode,
   5546     ProcessIoPortHandlers,
   5547     ProcessPooledUsageAndLimits,
   5548     ProcessWorkingSetWatch,
   5549     ProcessUserModeIOPL,
   5550     ProcessEnableAlignmentFaultFixup,
   5551     ProcessPriorityClass,
   5552     ProcessWx86Information,
   5553     ProcessHandleCount,
   5554     ProcessAffinityMask,
   5555     ProcessPriorityBoost,
   5556     ProcessDeviceMap,
   5557     ProcessSessionInformation,
   5558     ProcessForegroundInformation,
   5559     ProcessWow64Information,
   5560     ProcessImageFileName,
   5561     ProcessLUIDDeviceMapsEnabled,
   5562     ProcessBreakOnTermination,
   5563     ProcessDebugObjectHandle,
   5564     ProcessDebugFlags,
   5565     ProcessHandleTracing,
   5566     ProcessIoPriority,
   5567     ProcessExecuteFlags,
   5568     ProcessTlsInformation,
   5569     ProcessCookie,
   5570     ProcessImageInformation,
   5571     ProcessCycleTime,
   5572     ProcessPagePriority,
   5573     ProcessInstrumentationCallback,
   5574     ProcessThreadStackAllocation,
   5575     ProcessWorkingSetWatchEx,
   5576     ProcessImageFileNameWin32,
   5577     ProcessImageFileMapping,
   5578     ProcessAffinityUpdateMode,
   5579     ProcessMemoryAllocationMode,
   5580     ProcessGroupInformation,
   5581     ProcessTokenVirtualizationEnabled,
   5582     ProcessConsoleHostProcess,
   5583     ProcessWindowInformation,
   5584     MaxProcessInfoClass,
   5585 };
   5586 
   5587 pub const PROCESS_BASIC_INFORMATION = extern struct {
   5588     ExitStatus: NTSTATUS,
   5589     PebBaseAddress: *PEB,
   5590     AffinityMask: ULONG_PTR,
   5591     BasePriority: KPRIORITY,
   5592     UniqueProcessId: ULONG_PTR,
   5593     InheritedFromUniqueProcessId: ULONG_PTR,
   5594 };
   5595 
   5596 pub const ReadMemoryError = error{
   5597     Unexpected,
   5598 };
   5599 
   5600 pub fn ReadProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []u8) ReadMemoryError![]u8 {
   5601     var nread: usize = 0;
   5602     switch (ntdll.NtReadVirtualMemory(
   5603         handle,
   5604         addr,
   5605         buffer.ptr,
   5606         buffer.len,
   5607         &nread,
   5608     )) {
   5609         .SUCCESS => return buffer[0..nread],
   5610         // TODO: map errors
   5611         else => |rc| return unexpectedStatus(rc),
   5612     }
   5613 }
   5614 
   5615 pub const WriteMemoryError = error{
   5616     Unexpected,
   5617 };
   5618 
   5619 pub fn WriteProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []const u8) WriteMemoryError!usize {
   5620     var nwritten: usize = 0;
   5621     switch (ntdll.NtWriteVirtualMemory(
   5622         handle,
   5623         addr,
   5624         buffer.ptr,
   5625         buffer.len,
   5626         &nwritten,
   5627     )) {
   5628         .SUCCESS => return nwritten,
   5629         // TODO: map errors
   5630         else => |rc| return unexpectedStatus(rc),
   5631     }
   5632 }
   5633 
   5634 pub const ProcessBaseAddressError = GetProcessMemoryInfoError || ReadMemoryError;
   5635 
   5636 /// Returns the base address of the process loaded into memory.
   5637 pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
   5638     var info: PROCESS_BASIC_INFORMATION = undefined;
   5639     var nread: DWORD = 0;
   5640     const rc = ntdll.NtQueryInformationProcess(
   5641         handle,
   5642         .ProcessBasicInformation,
   5643         &info,
   5644         @sizeOf(PROCESS_BASIC_INFORMATION),
   5645         &nread,
   5646     );
   5647     switch (rc) {
   5648         .SUCCESS => {},
   5649         .ACCESS_DENIED => return error.AccessDenied,
   5650         .INVALID_HANDLE => return error.InvalidHandle,
   5651         .INVALID_PARAMETER => unreachable,
   5652         else => return unexpectedStatus(rc),
   5653     }
   5654 
   5655     var peb_buf: [@sizeOf(PEB)]u8 align(@alignOf(PEB)) = undefined;
   5656     const peb_out = try ReadProcessMemory(handle, info.PebBaseAddress, &peb_buf);
   5657     const ppeb: *const PEB = @ptrCast(@alignCast(peb_out.ptr));
   5658     return ppeb.ImageBaseAddress;
   5659 }