| ... | @@ -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 | } |
| 2908 | | 2908 | |
| 2909 | pub 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 | | | |
| 2922 | pub const DeleteFileOptions = struct { | | |
| 2923 | dir: ?HANDLE, | | |
| 2924 | remove_dir: bool = false, | | |
| 2925 | }; | | |
| 2926 | | | |
| 2927 | pub 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 | | | |
| 3055 | pub 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 | | | |
| 3071 | pub 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 | | | |
| 3178 | pub const GetStdHandleError = error{ | 2909 | pub 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 | } |
| 3510 | | 3241 | |
| 3511 | pub const GetFileSizeError = error{Unexpected}; | | |
| 3512 | | | |
| 3513 | pub 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 | | | |
| 3523 | pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 { | 3242 | pub 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 | }; |
| 3716 | | 3435 | |
| 3717 | pub 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 | | | |
| 3780 | pub const LoadLibraryError = error{ | 3436 | pub 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 | } |
| 3845 | | 3501 | |
| 3846 | pub 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 put | 3502 | /// 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. |
| 3852 | extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque; | 3504 | extern 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 | }; |
| 6074 | | 5726 | |
| 6075 | pub const GetProcessMemoryInfoError = error{ | | |
| 6076 | AccessDenied, | | |
| 6077 | InvalidHandle, | | |
| 6078 | Unexpected, | | |
| 6079 | }; | | |
| 6080 | | | |
| 6081 | pub 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 | | | |
| 6093 | pub const PERFORMANCE_INFORMATION = extern struct { | 5727 | pub 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 | } |
| 6625 | | 6259 | |
| 6626 | pub const ProcessBaseAddressError = GetProcessMemoryInfoError || ReadMemoryError; | 6260 | pub const ProcessBaseAddressError = error{ |
| | 6261 | AccessDenied, |
| | 6262 | InvalidHandle, |
| | 6263 | Unexpected, |
| | 6264 | } || ReadMemoryError; |
| 6627 | | 6265 | |
| 6628 | /// Returns the base address of the process loaded into memory. | 6266 | /// Returns the base address of the process loaded into memory. |
| 6629 | pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE { | 6267 | pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE { |