authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-28 20:05:20-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 03:39:46+01:00
log9b415761dd66904aef363e387b4501f3ddd0bf76
tree353b7dc77df1458eb126722fd73cc8b8c81ccd2a
parent5571c08e6603173378db7cfe1436e33e902f9c0a

std.os.windows: delete unused APIs

Intention is to go through std.Io for these things.

6 files changed, 36 insertions(+), 398 deletions(-)

lib/std/Io/File/Reader.zig+1-1
...@@ -48,7 +48,7 @@ pub const Error = error{...@@ -48,7 +48,7 @@ pub const Error = error{
48 LockViolation,48 LockViolation,
49} || Io.Cancelable || Io.UnexpectedError;49} || Io.Cancelable || Io.UnexpectedError;
5050
51pub const SizeError = std.os.windows.GetFileSizeError || File.StatError || error{51pub const SizeError = File.StatError || error{
52 /// Occurs if, for example, the file handle is a network socket and therefore does not have a size.52 /// Occurs if, for example, the file handle is a network socket and therefore does not have a size.
53 Streaming,53 Streaming,
54};54};
lib/std/Io/Threaded.zig+13-2
...@@ -13960,8 +13960,19 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child...@@ -13960,8 +13960,19 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child
13960fn childCleanupWindows(child: *process.Child) void {13960fn childCleanupWindows(child: *process.Child) void {
13961 const handle = child.id orelse return;13961 const handle = child.id orelse return;
1396213962
13963 if (child.request_resource_usage_statistics)13963 if (child.request_resource_usage_statistics) {
13964 child.resource_usage_statistics.rusage = windows.GetProcessMemoryInfo(handle) catch null;13964 var vmc: windows.VM_COUNTERS = undefined;
13965 switch (windows.ntdll.NtQueryInformationProcess(
13966 handle,
13967 .VmCounters,
13968 &vmc,
13969 @sizeOf(windows.VM_COUNTERS),
13970 null,
13971 )) {
13972 .SUCCESS => child.resource_usage_statistics.rusage = vmc,
13973 else => child.resource_usage_statistics.rusage = null,
13974 }
13975 }
1396513976
13966 windows.CloseHandle(handle);13977 windows.CloseHandle(handle);
13967 child.id = null;13978 child.id = null;
lib/std/os/windows.zig+5-367
...@@ -2906,275 +2906,6 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {...@@ -2906,275 +2906,6 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
2906 return buffer[0..end_index];2906 return buffer[0..end_index];
2907}2907}
29082908
2909pub const DeleteFileError = error{
2910 FileNotFound,
2911 AccessDenied,
2912 NameTooLong,
2913 /// Also known as sharing violation.
2914 FileBusy,
2915 Unexpected,
2916 NotDir,
2917 IsDir,
2918 DirNotEmpty,
2919 NetworkNotFound,
2920};
2921
2922pub const DeleteFileOptions = struct {
2923 dir: ?HANDLE,
2924 remove_dir: bool = false,
2925};
2926
2927pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFileError!void {
2928 const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));
2929 var nt_name: UNICODE_STRING = .{
2930 .Length = path_len_bytes,
2931 .MaximumLength = path_len_bytes,
2932 // The Windows API makes this mutable, but it will not mutate here.
2933 .Buffer = @constCast(sub_path_w.ptr),
2934 };
2935
2936 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
2937 // Windows does not recognize this, but it does work with empty string.
2938 nt_name.Length = 0;
2939 }
2940 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
2941 // Can't remove the parent directory with an open handle.
2942 return error.FileBusy;
2943 }
2944
2945 var io: IO_STATUS_BLOCK = undefined;
2946 var tmp_handle: HANDLE = undefined;
2947 var rc = ntdll.NtCreateFile(
2948 &tmp_handle,
2949 .{ .STANDARD = .{
2950 .RIGHTS = .{ .DELETE = true },
2951 .SYNCHRONIZE = true,
2952 } },
2953 &.{
2954 .Length = @sizeOf(OBJECT_ATTRIBUTES),
2955 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir,
2956 .Attributes = .{},
2957 .ObjectName = &nt_name,
2958 .SecurityDescriptor = null,
2959 .SecurityQualityOfService = null,
2960 },
2961 &io,
2962 null,
2963 .{},
2964 .VALID_FLAGS,
2965 .OPEN,
2966 .{
2967 .DIRECTORY_FILE = options.remove_dir,
2968 .NON_DIRECTORY_FILE = !options.remove_dir,
2969 .OPEN_REPARSE_POINT = true, // would we ever want to delete the target instead?
2970 },
2971 null,
2972 0,
2973 );
2974 switch (rc) {
2975 .SUCCESS => {},
2976 .OBJECT_NAME_INVALID => unreachable,
2977 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2978 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2979 .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
2980 .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
2981 .INVALID_PARAMETER => unreachable,
2982 .FILE_IS_A_DIRECTORY => return error.IsDir,
2983 .NOT_A_DIRECTORY => return error.NotDir,
2984 .SHARING_VIOLATION => return error.FileBusy,
2985 .ACCESS_DENIED => return error.AccessDenied,
2986 .DELETE_PENDING => return,
2987 else => return unexpectedStatus(rc),
2988 }
2989 defer CloseHandle(tmp_handle);
2990
2991 // FileDispositionInformationEx has varying levels of support:
2992 // - FILE_DISPOSITION_INFORMATION_EX requires >= win10_rs1
2993 // (INVALID_INFO_CLASS is returned if not supported)
2994 // - Requires the NTFS filesystem
2995 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
2996 // - FILE_DISPOSITION_POSIX_SEMANTICS requires >= win10_rs1
2997 // - FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
2998 // (NOT_SUPPORTED is returned if a flag is unsupported)
2999 //
3000 // The strategy here is just to try using FileDispositionInformationEx and fall back to
3001 // FileDispositionInformation if the return value lets us know that some aspect of it is not supported.
3002 const need_fallback = need_fallback: {
3003 // Deletion with posix semantics if the filesystem supports it.
3004 var info: FILE.DISPOSITION.INFORMATION.EX = .{ .Flags = .{
3005 .DELETE = true,
3006 .POSIX_SEMANTICS = true,
3007 .IGNORE_READONLY_ATTRIBUTE = true,
3008 } };
3009 rc = ntdll.NtSetInformationFile(
3010 tmp_handle,
3011 &io,
3012 &info,
3013 @sizeOf(FILE.DISPOSITION.INFORMATION.EX),
3014 .DispositionEx,
3015 );
3016 switch (rc) {
3017 .SUCCESS => return,
3018 // The filesystem does not support FileDispositionInformationEx
3019 .INVALID_PARAMETER,
3020 // The operating system does not support FileDispositionInformationEx
3021 .INVALID_INFO_CLASS,
3022 // The operating system does not support one of the flags
3023 .NOT_SUPPORTED,
3024 => break :need_fallback true,
3025 // For all other statuses, fall down to the switch below to handle them.
3026 else => break :need_fallback false,
3027 }
3028 };
3029
3030 if (need_fallback) {
3031 // Deletion with file pending semantics, which requires waiting or moving
3032 // files to get them removed (from here).
3033 var file_dispo: FILE.DISPOSITION.INFORMATION = .{
3034 .DeleteFile = TRUE,
3035 };
3036 rc = ntdll.NtSetInformationFile(
3037 tmp_handle,
3038 &io,
3039 &file_dispo,
3040 @sizeOf(FILE.DISPOSITION.INFORMATION),
3041 .Disposition,
3042 );
3043 }
3044 switch (rc) {
3045 .SUCCESS => {},
3046 .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
3047 .INVALID_PARAMETER => unreachable,
3048 .CANNOT_DELETE => return error.AccessDenied,
3049 .MEDIA_WRITE_PROTECTED => return error.AccessDenied,
3050 .ACCESS_DENIED => return error.AccessDenied,
3051 else => return unexpectedStatus(rc),
3052 }
3053}
3054
3055pub const RenameError = error{
3056 IsDir,
3057 NotDir,
3058 FileNotFound,
3059 NoDevice,
3060 AccessDenied,
3061 PipeBusy,
3062 PathAlreadyExists,
3063 Unexpected,
3064 NameTooLong,
3065 NetworkNotFound,
3066 AntivirusInterference,
3067 BadPathName,
3068 CrossDevice,
3069} || UnexpectedError;
3070
3071pub fn RenameFile(
3072 /// May only be `null` if `old_path_w` is a fully-qualified absolute path.
3073 old_dir_fd: ?HANDLE,
3074 old_path_w: []const u16,
3075 /// May only be `null` if `new_path_w` is a fully-qualified absolute path,
3076 /// or if the file is not being moved to a different directory.
3077 new_dir_fd: ?HANDLE,
3078 new_path_w: []const u16,
3079 replace_if_exists: bool,
3080) RenameError!void {
3081 const src_fd = OpenFile(old_path_w, .{
3082 .dir = old_dir_fd,
3083 .access_mask = .{
3084 .STANDARD = .{
3085 .RIGHTS = .{ .DELETE = true },
3086 .SYNCHRONIZE = true,
3087 },
3088 .GENERIC = .{ .WRITE = true },
3089 },
3090 .creation = .OPEN,
3091 .filter = .any, // This function is supposed to rename both files and directories.
3092 .follow_symlinks = false,
3093 }) catch |err| switch (err) {
3094 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
3095 else => |e| return e,
3096 };
3097 defer CloseHandle(src_fd);
3098
3099 var rc: NTSTATUS = undefined;
3100 // FileRenameInformationEx has varying levels of support:
3101 // - FILE_RENAME_INFORMATION_EX requires >= win10_rs1
3102 // (INVALID_INFO_CLASS is returned if not supported)
3103 // - Requires the NTFS filesystem
3104 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
3105 // - FILE_RENAME_POSIX_SEMANTICS requires >= win10_rs1
3106 // - FILE_RENAME_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
3107 // (NOT_SUPPORTED is returned if a flag is unsupported)
3108 //
3109 // The strategy here is just to try using FileRenameInformationEx and fall back to
3110 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.
3111 const need_fallback = need_fallback: {
3112 var rename_info: FILE.RENAME_INFORMATION = .init(.{
3113 .Flags = .{
3114 .REPLACE_IF_EXISTS = replace_if_exists,
3115 .POSIX_SEMANTICS = true,
3116 .IGNORE_READONLY_ATTRIBUTE = true,
3117 },
3118 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
3119 .FileName = new_path_w,
3120 });
3121 var io_status_block: IO_STATUS_BLOCK = undefined;
3122 const rename_info_buf = rename_info.toBuffer();
3123 rc = ntdll.NtSetInformationFile(
3124 src_fd,
3125 &io_status_block,
3126 rename_info_buf.ptr,
3127 @intCast(rename_info_buf.len), // already checked for error.NameTooLong
3128 .RenameEx,
3129 );
3130 switch (rc) {
3131 .SUCCESS => return,
3132 // The filesystem does not support FileDispositionInformationEx
3133 .INVALID_PARAMETER,
3134 // The operating system does not support FileDispositionInformationEx
3135 .INVALID_INFO_CLASS,
3136 // The operating system does not support one of the flags
3137 .NOT_SUPPORTED,
3138 => break :need_fallback true,
3139 // For all other statuses, fall down to the switch below to handle them.
3140 else => break :need_fallback false,
3141 }
3142 };
3143
3144 if (need_fallback) {
3145 var rename_info: FILE.RENAME_INFORMATION = .init(.{
3146 .Flags = .{ .REPLACE_IF_EXISTS = replace_if_exists },
3147 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
3148 .FileName = new_path_w,
3149 });
3150 var io_status_block: IO_STATUS_BLOCK = undefined;
3151 const rename_info_buf = rename_info.toBuffer();
3152 rc = ntdll.NtSetInformationFile(
3153 src_fd,
3154 &io_status_block,
3155 rename_info_buf.ptr,
3156 @intCast(rename_info_buf.len), // already checked for error.NameTooLong
3157 .Rename,
3158 );
3159 }
3160
3161 switch (rc) {
3162 .SUCCESS => {},
3163 .INVALID_HANDLE => unreachable,
3164 .INVALID_PARAMETER => unreachable,
3165 .OBJECT_PATH_SYNTAX_BAD => unreachable,
3166 .ACCESS_DENIED => return error.AccessDenied,
3167 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
3168 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
3169 .NOT_SAME_DEVICE => return error.CrossDevice,
3170 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
3171 .DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
3172 .FILE_IS_A_DIRECTORY => return error.IsDir,
3173 .NOT_A_DIRECTORY => return error.NotDir,
3174 else => return unexpectedStatus(rc),
3175 }
3176}
3177
3178pub const GetStdHandleError = error{2909pub const GetStdHandleError = error{
3179 NoStandardHandleAttached,2910 NoStandardHandleAttached,
3180 Unexpected,2911 Unexpected,
...@@ -3508,18 +3239,6 @@ test GetFinalPathNameByHandle {...@@ -3508,18 +3239,6 @@ test GetFinalPathNameByHandle {
3508 _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0..required_len_in_u16]);3239 _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0..required_len_in_u16]);
3509}3240}
35103241
3511pub const GetFileSizeError = error{Unexpected};
3512
3513pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
3514 var file_size: LARGE_INTEGER = undefined;
3515 if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) {
3516 switch (GetLastError()) {
3517 else => |err| return unexpectedError(err),
3518 }
3519 }
3520 return @as(u64, @bitCast(file_size));
3521}
3522
3523pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {3242pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
3524 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));3243 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
3525}3244}
...@@ -3714,69 +3433,6 @@ pub const CreateProcessFlags = packed struct(u32) {...@@ -3714,69 +3433,6 @@ pub const CreateProcessFlags = packed struct(u32) {
3714 create_ignore_system_default: bool = false,3433 create_ignore_system_default: bool = false,
3715};3434};
37163435
3717pub fn CreateProcessW(
3718 lpApplicationName: ?LPCWSTR,
3719 lpCommandLine: ?LPWSTR,
3720 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
3721 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
3722 bInheritHandles: BOOL,
3723 dwCreationFlags: CreateProcessFlags,
3724 lpEnvironment: ?[*:0]u16,
3725 lpCurrentDirectory: ?LPCWSTR,
3726 lpStartupInfo: *STARTUPINFOW,
3727 lpProcessInformation: *PROCESS_INFORMATION,
3728) CreateProcessError!void {
3729 if (kernel32.CreateProcessW(
3730 lpApplicationName,
3731 lpCommandLine,
3732 lpProcessAttributes,
3733 lpThreadAttributes,
3734 bInheritHandles,
3735 dwCreationFlags,
3736 lpEnvironment,
3737 lpCurrentDirectory,
3738 lpStartupInfo,
3739 lpProcessInformation,
3740 ) == 0) {
3741 switch (GetLastError()) {
3742 .FILE_NOT_FOUND => return error.FileNotFound,
3743 .PATH_NOT_FOUND => return error.FileNotFound,
3744 .DIRECTORY => return error.FileNotFound,
3745 .ACCESS_DENIED => return error.AccessDenied,
3746 .INVALID_PARAMETER => unreachable,
3747 .INVALID_NAME => return error.InvalidName,
3748 .FILENAME_EXCED_RANGE => return error.NameTooLong,
3749 .SHARING_VIOLATION => return error.FileBusy,
3750 // These are all the system errors that are mapped to ENOEXEC by
3751 // the undocumented _dosmaperr (old CRT) or __acrt_errno_map_os_error
3752 // (newer CRT) functions. Their code can be found in crt/src/dosmap.c (old SDK)
3753 // or urt/misc/errno.cpp (newer SDK) in the Windows SDK.
3754 .BAD_FORMAT,
3755 .INVALID_STARTING_CODESEG, // MIN_EXEC_ERROR in errno.cpp
3756 .INVALID_STACKSEG,
3757 .INVALID_MODULETYPE,
3758 .INVALID_EXE_SIGNATURE,
3759 .EXE_MARKED_INVALID,
3760 .BAD_EXE_FORMAT,
3761 .ITERATED_DATA_EXCEEDS_64k,
3762 .INVALID_MINALLOCSIZE,
3763 .DYNLINK_FROM_INVALID_RING,
3764 .IOPL_NOT_ENABLED,
3765 .INVALID_SEGDPL,
3766 .AUTODATASEG_EXCEEDS_64k,
3767 .RING2SEG_MUST_BE_MOVABLE,
3768 .RELOC_CHAIN_XEEDS_SEGLIM,
3769 .INFLOOP_IN_RELOC_CHAIN, // MAX_EXEC_ERROR in errno.cpp
3770 // This one is not mapped to ENOEXEC but it is possible, for example
3771 // when calling CreateProcessW on a plain text file with a .exe extension
3772 .EXE_MACHINE_TYPE_MISMATCH,
3773 => return error.InvalidExe,
3774 .COMMITMENT_LIMIT => return error.SystemResources,
3775 else => |err| return unexpectedError(err),
3776 }
3777 }
3778}
3779
3780pub const LoadLibraryError = error{3436pub const LoadLibraryError = error{
3781 FileNotFound,3437 FileNotFound,
3782 Unexpected,3438 Unexpected,
...@@ -3843,10 +3499,6 @@ pub fn QueryPerformanceCounter() u64 {...@@ -3843,10 +3499,6 @@ pub fn QueryPerformanceCounter() u64 {
3843 return @as(u64, @bitCast(result));3499 return @as(u64, @bitCast(result));
3844}3500}
38453501
3846pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*anyopaque, Context: ?*anyopaque) void {
3847 assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
3848}
3849
3850/// This is a workaround for the C backend until zig has the ability to put3502/// This is a workaround for the C backend until zig has the ability to put
3851/// C code in inline assembly.3503/// C code in inline assembly.
3852extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque;3504extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque;
...@@ -6072,24 +5724,6 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {...@@ -6072,24 +5724,6 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {
6072 PrivateUsage: SIZE_T,5724 PrivateUsage: SIZE_T,
6073};5725};
60745726
6075pub const GetProcessMemoryInfoError = error{
6076 AccessDenied,
6077 InvalidHandle,
6078 Unexpected,
6079};
6080
6081pub fn GetProcessMemoryInfo(hProcess: HANDLE) GetProcessMemoryInfoError!VM_COUNTERS {
6082 var vmc: VM_COUNTERS = undefined;
6083 const rc = ntdll.NtQueryInformationProcess(hProcess, .VmCounters, &vmc, @sizeOf(VM_COUNTERS), null);
6084 switch (rc) {
6085 .SUCCESS => return vmc,
6086 .ACCESS_DENIED => return error.AccessDenied,
6087 .INVALID_HANDLE => return error.InvalidHandle,
6088 .INVALID_PARAMETER => unreachable,
6089 else => return unexpectedStatus(rc),
6090 }
6091}
6092
6093pub const PERFORMANCE_INFORMATION = extern struct {5727pub const PERFORMANCE_INFORMATION = extern struct {
6094 cb: DWORD,5728 cb: DWORD,
6095 CommitTotal: SIZE_T,5729 CommitTotal: SIZE_T,
...@@ -6623,7 +6257,11 @@ pub fn WriteProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []const u8) Wri...@@ -6623,7 +6257,11 @@ pub fn WriteProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []const u8) Wri
6623 }6257 }
6624}6258}
66256259
6626pub const ProcessBaseAddressError = GetProcessMemoryInfoError || ReadMemoryError;6260pub const ProcessBaseAddressError = error{
6261 AccessDenied,
6262 InvalidHandle,
6263 Unexpected,
6264} || ReadMemoryError;
66276265
6628/// Returns the base address of the process loaded into memory.6266/// Returns the base address of the process loaded into memory.
6629pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {6267pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
lib/std/os/windows/kernel32.zig-19
...@@ -117,12 +117,6 @@ pub extern "kernel32" fn WriteFile(...@@ -117,12 +117,6 @@ pub extern "kernel32" fn WriteFile(
117 in_out_lpOverlapped: ?*OVERLAPPED,117 in_out_lpOverlapped: ?*OVERLAPPED,
118) callconv(.winapi) BOOL;118) callconv(.winapi) BOOL;
119119
120// TODO: wrapper for NtQueryInformationFile + `FILE_STANDARD_INFORMATION`
121pub extern "kernel32" fn GetFileSizeEx(
122 hFile: HANDLE,
123 lpFileSize: *LARGE_INTEGER,
124) callconv(.winapi) BOOL;
125
126// TODO: Wrapper around GetStdHandle + NtFlushBuffersFile.120// TODO: Wrapper around GetStdHandle + NtFlushBuffersFile.
127pub extern "kernel32" fn FlushFileBuffers(121pub extern "kernel32" fn FlushFileBuffers(
128 hFile: HANDLE,122 hFile: HANDLE,
...@@ -283,12 +277,6 @@ pub extern "kernel32" fn GetExitCodeProcess(...@@ -283,12 +277,6 @@ pub extern "kernel32" fn GetExitCodeProcess(
283 lpExitCode: *DWORD,277 lpExitCode: *DWORD,
284) callconv(.winapi) BOOL;278) callconv(.winapi) BOOL;
285279
286// TODO: Wrapper around RtlSetEnvironmentVar.
287pub extern "kernel32" fn SetEnvironmentVariableW(
288 lpName: LPCWSTR,
289 lpValue: ?LPCWSTR,
290) callconv(.winapi) BOOL;
291
292pub extern "kernel32" fn CreateToolhelp32Snapshot(280pub extern "kernel32" fn CreateToolhelp32Snapshot(
293 dwFlags: DWORD,281 dwFlags: DWORD,
294 th32ProcessID: DWORD,282 th32ProcessID: DWORD,
...@@ -311,13 +299,6 @@ pub extern "kernel32" fn CreateThread(...@@ -311,13 +299,6 @@ pub extern "kernel32" fn CreateThread(
311299
312// Locks, critical sections, initializers300// Locks, critical sections, initializers
313301
314pub extern "kernel32" fn InitOnceExecuteOnce(
315 InitOnce: *INIT_ONCE,
316 InitFn: INIT_ONCE_FN,
317 Parameter: ?*anyopaque,
318 Context: ?*anyopaque,
319) callconv(.winapi) BOOL;
320
321// TODO:302// TODO:
322// - dwMilliseconds -> LARGE_INTEGER.303// - dwMilliseconds -> LARGE_INTEGER.
323// - RtlSleepConditionVariableSRW304// - RtlSleepConditionVariableSRW
test/standalone/windows_argv/fuzz.zig+5-2
...@@ -129,7 +129,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO...@@ -129,7 +129,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
129 };129 };
130 var proc_info: windows.PROCESS_INFORMATION = undefined;130 var proc_info: windows.PROCESS_INFORMATION = undefined;
131131
132 try windows.CreateProcessW(132 if (windows.kernel32.CreateProcessW(
133 @constCast(verify_path.ptr),133 @constCast(verify_path.ptr),
134 @constCast(cmd_line.ptr),134 @constCast(cmd_line.ptr),
135 null,135 null,
...@@ -140,7 +140,10 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO...@@ -140,7 +140,10 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
140 null,140 null,
141 &startup_info,141 &startup_info,
142 &proc_info,142 &proc_info,
143 );143 ) == 0) {
144 std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.kernel32.GetLastError()});
145 }
146
144 windows.CloseHandle(proc_info.hThread);147 windows.CloseHandle(proc_info.hThread);
145148
146 break :spawn proc_info.hProcess;149 break :spawn proc_info.hProcess;
test/standalone/windows_spawn/main.zig+12-7
...@@ -31,13 +31,13 @@ pub fn main(init: std.process.Init) !void {...@@ -31,13 +31,13 @@ pub fn main(init: std.process.Init) !void {
31 defer gpa.free(tmp_relative_path);31 defer gpa.free(tmp_relative_path);
3232
33 // Clear PATH33 // Clear PATH
34 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(34 std.debug.assert(SetEnvironmentVariableW(
35 utf16Literal("PATH"),35 utf16Literal("PATH"),
36 null,36 null,
37 ) == windows.TRUE);37 ) == windows.TRUE);
3838
39 // Set PATHEXT to something predictable39 // Set PATHEXT to something predictable
40 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(40 std.debug.assert(SetEnvironmentVariableW(
41 utf16Literal("PATHEXT"),41 utf16Literal("PATHEXT"),
42 utf16Literal(".COM;.EXE;.BAT;.CMD;.JS"),42 utf16Literal(".COM;.EXE;.BAT;.CMD;.JS"),
43 ) == windows.TRUE);43 ) == windows.TRUE);
...@@ -48,7 +48,7 @@ pub fn main(init: std.process.Init) !void {...@@ -48,7 +48,7 @@ pub fn main(init: std.process.Init) !void {
48 // make sure we don't get error.BadPath traversing out of cwd with a relative path48 // make sure we don't get error.BadPath traversing out of cwd with a relative path
49 try testExecError(error.FileNotFound, gpa, io, "..\\.\\.\\.\\\\..\\more_missing");49 try testExecError(error.FileNotFound, gpa, io, "..\\.\\.\\.\\\\..\\more_missing");
5050
51 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(51 std.debug.assert(SetEnvironmentVariableW(
52 utf16Literal("PATH"),52 utf16Literal("PATH"),
53 tmp_absolute_path_w,53 tmp_absolute_path_w,
54 ) == windows.TRUE);54 ) == windows.TRUE);
...@@ -131,7 +131,7 @@ pub fn main(init: std.process.Init) !void {...@@ -131,7 +131,7 @@ pub fn main(init: std.process.Init) !void {
131 const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);131 const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
132 defer gpa.free(something_subdir_abs_path);132 defer gpa.free(something_subdir_abs_path);
133133
134 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(134 std.debug.assert(SetEnvironmentVariableW(
135 utf16Literal("PATH"),135 utf16Literal("PATH"),
136 something_subdir_abs_path,136 something_subdir_abs_path,
137 ) == windows.TRUE);137 ) == windows.TRUE);
...@@ -171,7 +171,7 @@ pub fn main(init: std.process.Init) !void {...@@ -171,7 +171,7 @@ pub fn main(init: std.process.Init) !void {
171 defer gpa.free(denormed_something_subdir_wtf8);171 defer gpa.free(denormed_something_subdir_wtf8);
172172
173 // clear the path to ensure that the match comes from the cwd173 // clear the path to ensure that the match comes from the cwd
174 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(174 std.debug.assert(SetEnvironmentVariableW(
175 utf16Literal("PATH"),175 utf16Literal("PATH"),
176 null,176 null,
177 ) == windows.TRUE);177 ) == windows.TRUE);
...@@ -179,7 +179,7 @@ pub fn main(init: std.process.Init) !void {...@@ -179,7 +179,7 @@ pub fn main(init: std.process.Init) !void {
179 try testExecWithCwd(gpa, io, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");179 try testExecWithCwd(gpa, io, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
180180
181 // normalization should also work if the non-normalized path is found in the PATH var.181 // normalization should also work if the non-normalized path is found in the PATH var.
182 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(182 std.debug.assert(SetEnvironmentVariableW(
183 utf16Literal("PATH"),183 utf16Literal("PATH"),
184 denormed_something_subdir_abs_path,184 denormed_something_subdir_abs_path,
185 ) == windows.TRUE);185 ) == windows.TRUE);
...@@ -193,7 +193,7 @@ pub fn main(init: std.process.Init) !void {...@@ -193,7 +193,7 @@ pub fn main(init: std.process.Init) !void {
193 try std.process.setCurrentDir(io, subdir_cwd);193 try std.process.setCurrentDir(io, subdir_cwd);
194194
195 // clear the PATH again195 // clear the PATH again
196 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(196 std.debug.assert(SetEnvironmentVariableW(
197 utf16Literal("PATH"),197 utf16Literal("PATH"),
198 null,198 null,
199 ) == windows.TRUE);199 ) == windows.TRUE);
...@@ -235,3 +235,8 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons...@@ -235,3 +235,8 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons
235 else => |e| return e,235 else => |e| return e,
236 };236 };
237}237}
238
239pub extern "kernel32" fn SetEnvironmentVariableW(
240 lpName: windows.LPCWSTR,
241 lpValue: ?windows.LPCWSTR,
242) callconv(.winapi) windows.BOOL;