| ... | ... | @@ -2088,6 +2088,7 @@ pub const LPWSTR = [*:0]WCHAR; |
| 2088 | 2088 | pub const LPCWSTR = [*:0]const WCHAR; |
| 2089 | 2089 | pub const PVOID = *anyopaque; |
| 2090 | 2090 | pub const PWSTR = [*:0]WCHAR; |
| 2091 | pub const PCWSTR = [*:0]const WCHAR; |
| 2091 | 2092 | pub const SIZE_T = usize; |
| 2092 | 2093 | pub const UINT = c_uint; |
| 2093 | 2094 | pub const ULONG_PTR = usize; |
| ... | ... | @@ -2876,8 +2877,134 @@ pub const ACCESS_MASK = DWORD; |
| 2876 | 2877 | pub const LSTATUS = LONG; |
| 2877 | 2878 | |
| 2878 | 2879 | pub const HKEY = HANDLE; |
| 2880 | |
| 2879 | 2881 | pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002); |
| 2880 | 2882 | |
| 2883 | /// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, |
| 2884 | /// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights. |
| 2885 | pub const KEY_ALL_ACCESS = 0xF003F; |
| 2886 | /// Reserved for system use. |
| 2887 | pub const KEY_CREATE_LINK = 0x0020; |
| 2888 | /// Required to create a subkey of a registry key. |
| 2889 | pub const KEY_CREATE_SUB_KEY = 0x0004; |
| 2890 | /// Required to enumerate the subkeys of a registry key. |
| 2891 | pub const KEY_ENUMERATE_SUB_KEYS = 0x0008; |
| 2892 | /// Equivalent to KEY_READ. |
| 2893 | pub const KEY_EXECUTE = 0x20019; |
| 2894 | /// Required to request change notifications for a registry key or for subkeys of a registry key. |
| 2895 | pub const KEY_NOTIFY = 0x0010; |
| 2896 | /// Required to query the values of a registry key. |
| 2897 | pub const KEY_QUERY_VALUE = 0x0001; |
| 2898 | /// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values. |
| 2899 | pub const KEY_READ = 0x20019; |
| 2900 | /// Required to create, delete, or set a registry value. |
| 2901 | pub const KEY_SET_VALUE = 0x0002; |
| 2902 | /// Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. |
| 2903 | /// This flag is ignored by 32-bit Windows. |
| 2904 | pub const KEY_WOW64_32KEY = 0x0200; |
| 2905 | /// Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. |
| 2906 | /// This flag is ignored by 32-bit Windows. |
| 2907 | pub const KEY_WOW64_64KEY = 0x0100; |
| 2908 | /// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights. |
| 2909 | pub const KEY_WRITE = 0x20006; |
| 2910 | |
| 2911 | /// Open symbolic link. |
| 2912 | pub const REG_OPTION_OPEN_LINK: DWORD = 0x8; |
| 2913 | |
| 2914 | pub const RTL_QUERY_REGISTRY_TABLE = extern struct { |
| 2915 | QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE, |
| 2916 | Flags: ULONG, |
| 2917 | Name: ?PWSTR, |
| 2918 | EntryContext: ?*anyopaque, |
| 2919 | DefaultType: ULONG, |
| 2920 | DefaultData: ?*anyopaque, |
| 2921 | DefaultLength: ULONG, |
| 2922 | }; |
| 2923 | |
| 2924 | pub const RTL_QUERY_REGISTRY_ROUTINE = ?std.meta.FnPtr(fn ( |
| 2925 | PWSTR, |
| 2926 | ULONG, |
| 2927 | ?*anyopaque, |
| 2928 | ULONG, |
| 2929 | ?*anyopaque, |
| 2930 | ?*anyopaque, |
| 2931 | ) callconv(WINAPI) NTSTATUS); |
| 2932 | |
| 2933 | /// Path is a full path |
| 2934 | pub const RTL_REGISTRY_ABSOLUTE = 0; |
| 2935 | /// \Registry\Machine\System\CurrentControlSet\Services |
| 2936 | pub const RTL_REGISTRY_SERVICES = 1; |
| 2937 | /// \Registry\Machine\System\CurrentControlSet\Control |
| 2938 | pub const RTL_REGISTRY_CONTROL = 2; |
| 2939 | /// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion |
| 2940 | pub const RTL_REGISTRY_WINDOWS_NT = 3; |
| 2941 | /// \Registry\Machine\Hardware\DeviceMap |
| 2942 | pub const RTL_REGISTRY_DEVICEMAP = 4; |
| 2943 | /// \Registry\User\CurrentUser |
| 2944 | pub const RTL_REGISTRY_USER = 5; |
| 2945 | pub const RTL_REGISTRY_MAXIMUM = 6; |
| 2946 | |
| 2947 | /// Low order bits are registry handle |
| 2948 | pub const RTL_REGISTRY_HANDLE = 0x40000000; |
| 2949 | /// Indicates the key node is optional |
| 2950 | pub const RTL_REGISTRY_OPTIONAL = 0x80000000; |
| 2951 | |
| 2952 | /// Name is a subkey and remainder of table or until next subkey are value |
| 2953 | /// names for that subkey to look at. |
| 2954 | pub const RTL_QUERY_REGISTRY_SUBKEY = 0x00000001; |
| 2955 | |
| 2956 | /// Reset current key to original key for this and all following table entries. |
| 2957 | pub const RTL_QUERY_REGISTRY_TOPKEY = 0x00000002; |
| 2958 | |
| 2959 | /// Fail if no match found for this table entry. |
| 2960 | pub const RTL_QUERY_REGISTRY_REQUIRED = 0x00000004; |
| 2961 | |
| 2962 | /// Used to mark a table entry that has no value name, just wants a call out, not |
| 2963 | /// an enumeration of all values. |
| 2964 | pub const RTL_QUERY_REGISTRY_NOVALUE = 0x00000008; |
| 2965 | |
| 2966 | /// Used to suppress the expansion of REG_MULTI_SZ into multiple callouts or |
| 2967 | /// to prevent the expansion of environment variable values in REG_EXPAND_SZ. |
| 2968 | pub const RTL_QUERY_REGISTRY_NOEXPAND = 0x00000010; |
| 2969 | |
| 2970 | /// QueryRoutine field ignored. EntryContext field points to location to store value. |
| 2971 | /// For null terminated strings, EntryContext points to UNICODE_STRING structure that |
| 2972 | /// that describes maximum size of buffer. If .Buffer field is NULL then a buffer is |
| 2973 | /// allocated. |
| 2974 | pub const RTL_QUERY_REGISTRY_DIRECT = 0x00000020; |
| 2975 | |
| 2976 | /// Used to delete value keys after they are queried. |
| 2977 | pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040; |
| 2978 | |
| 2979 | /// Use this flag with the RTL_QUERY_REGISTRY_DIRECT flag to verify that the REG_XXX type |
| 2980 | /// of the stored registry value matches the type expected by the caller. |
| 2981 | /// If the types do not match, the call fails. |
| 2982 | pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100; |
| 2983 | |
| 2984 | /// No value type |
| 2985 | pub const REG_NONE = 0; |
| 2986 | /// Unicode nul terminated string |
| 2987 | pub const REG_SZ = 1; |
| 2988 | /// Unicode nul terminated string (with environment variable references) |
| 2989 | pub const REG_EXPAND_SZ = 2; |
| 2990 | /// Free form binary |
| 2991 | pub const REG_BINARY = 3; |
| 2992 | /// 32-bit number |
| 2993 | pub const REG_DWORD = 4; |
| 2994 | /// 32-bit number (same as REG_DWORD) |
| 2995 | pub const REG_DWORD_LITTLE_ENDIAN = 4; |
| 2996 | /// 32-bit number |
| 2997 | pub const REG_DWORD_BIG_ENDIAN = 5; |
| 2998 | /// Symbolic Link (unicode) |
| 2999 | pub const REG_LINK = 6; |
| 3000 | /// Multiple Unicode strings |
| 3001 | pub const REG_MULTI_SZ = 7; |
| 3002 | /// Resource list in the resource map |
| 3003 | pub const REG_RESOURCE_LIST = 8; |
| 3004 | /// Resource list in the hardware description |
| 3005 | pub const REG_FULL_RESOURCE_DESCRIPTOR = 9; |
| 3006 | pub const REG_RESOURCE_REQUIREMENTS_LIST = 10; |
| 3007 | |
| 2881 | 3008 | pub const FILE_NOTIFY_INFORMATION = extern struct { |
| 2882 | 3009 | NextEntryOffset: DWORD, |
| 2883 | 3010 | Action: DWORD, |
| ... | ... | @@ -4020,187 +4147,3 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool { |
| 4020 | 4147 | if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false; |
| 4021 | 4148 | return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1; |
| 4022 | 4149 | } |
| 4023 | | |
| 4024 | | pub const KEY_QUERY_VALUE = 0x0001; |
| 4025 | | |
| 4026 | | /// Open symbolic link. |
| 4027 | | pub const REG_OPTION_OPEN_LINK: DWORD = 0x8; |
| 4028 | | |
| 4029 | | inline fn IsPredefKey(hkey: HKEY) bool { |
| 4030 | | return @ptrToInt(hkey) & 0xF0000000 == 0x80000000; |
| 4031 | | } |
| 4032 | | |
| 4033 | | inline fn GetPredefKeyIndex(hkey: HKEY) usize { |
| 4034 | | return @ptrToInt(hkey) & 0x0FFFFFFF; |
| 4035 | | } |
| 4036 | | |
| 4037 | | inline fn ClosePredefKey(hkey: HKEY) void { |
| 4038 | | if (@ptrToInt(hkey) & 0x1 != 0) { |
| 4039 | | assert(ntdll.NtClose(hkey) == .SUCCESS); |
| 4040 | | } |
| 4041 | | } |
| 4042 | | |
| 4043 | | const MAX_DEFAULT_HANDLES = 6; |
| 4044 | | pub const REG_MAX_NAME_SIZE = 256; |
| 4045 | | |
| 4046 | | pub const RegOpenKeyOpts = struct { |
| 4047 | | ulOptions: DWORD = 0, |
| 4048 | | samDesired: ACCESS_MASK = KEY_QUERY_VALUE, |
| 4049 | | }; |
| 4050 | | |
| 4051 | | /// Pulls existing key from the registry. |
| 4052 | | pub fn RegOpenKey(hkey: HKEY, lpSubKey: []const u16, opts: RegOpenKeyOpts) !HKEY { |
| 4053 | | if (IsPredefKey(hkey) and lpSubKey.len == 0) { |
| 4054 | | return hkey; |
| 4055 | | } |
| 4056 | | |
| 4057 | | const key_handle = try MapDefaultKey(hkey); |
| 4058 | | defer ClosePredefKey(key_handle); |
| 4059 | | |
| 4060 | | var subkey_string: UNICODE_STRING = undefined; |
| 4061 | | if (lpSubKey.len == 0 or mem.eql(u16, &[_]u16{'\\'}, lpSubKey)) { |
| 4062 | | subkey_string = .{ |
| 4063 | | .Length = 0, |
| 4064 | | .MaximumLength = 0, |
| 4065 | | .Buffer = @intToPtr([*]u16, @ptrToInt(&[0]u16{})), |
| 4066 | | }; |
| 4067 | | } else { |
| 4068 | | const len_bytes = math.cast(u16, lpSubKey.len * 2) orelse return error.NameTooLong; |
| 4069 | | subkey_string = .{ |
| 4070 | | .Length = len_bytes, |
| 4071 | | .MaximumLength = len_bytes, |
| 4072 | | .Buffer = @intToPtr([*]u16, @ptrToInt(lpSubKey.ptr)), |
| 4073 | | }; |
| 4074 | | } |
| 4075 | | |
| 4076 | | var attributes: ULONG = OBJ_CASE_INSENSITIVE; |
| 4077 | | if (opts.ulOptions & REG_OPTION_OPEN_LINK != 0) { |
| 4078 | | attributes |= OBJ_OPENLINK; |
| 4079 | | } |
| 4080 | | |
| 4081 | | var attr = OBJECT_ATTRIBUTES{ |
| 4082 | | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| 4083 | | .RootDirectory = key_handle, |
| 4084 | | .Attributes = attributes, |
| 4085 | | .ObjectName = &subkey_string, |
| 4086 | | .SecurityDescriptor = null, |
| 4087 | | .SecurityQualityOfService = null, |
| 4088 | | }; |
| 4089 | | |
| 4090 | | var result: HKEY = undefined; |
| 4091 | | const rc = ntdll.NtOpenKey( |
| 4092 | | &result, |
| 4093 | | opts.samDesired, |
| 4094 | | attr, |
| 4095 | | ); |
| 4096 | | switch (rc) { |
| 4097 | | .SUCCESS => return result, |
| 4098 | | else => return unexpectedStatus(rc), |
| 4099 | | } |
| 4100 | | } |
| 4101 | | |
| 4102 | | pub fn RegCloseKey(hkey: HKEY) void { |
| 4103 | | if (IsPredefKey(hkey)) return; |
| 4104 | | assert(ntdll.NtClose(hkey) == .SUCCESS); |
| 4105 | | } |
| 4106 | | |
| 4107 | | extern var DefaultHandleHKUDisabled: BOOLEAN; |
| 4108 | | extern var DefaultHandlesDisabled: BOOLEAN; |
| 4109 | | extern var DefaultHandleTable: [MAX_DEFAULT_HANDLES]?HANDLE; |
| 4110 | | |
| 4111 | | fn MapDefaultKey(key: HKEY) !HANDLE { |
| 4112 | | if (!IsPredefKey(key)) return @intToPtr(HANDLE, @ptrToInt(key) & ~@as(usize, 0x1)); |
| 4113 | | |
| 4114 | | const index = GetPredefKeyIndex(key); |
| 4115 | | if (index >= MAX_DEFAULT_HANDLES) { |
| 4116 | | return error.InvalidParameter; |
| 4117 | | } |
| 4118 | | |
| 4119 | | const def_disabled = if (key == HKEY_LOCAL_MACHINE) DefaultHandleHKUDisabled else DefaultHandlesDisabled; |
| 4120 | | |
| 4121 | | var handle: HANDLE = undefined; |
| 4122 | | var do_open: bool = true; |
| 4123 | | |
| 4124 | | if (def_disabled != 0) { |
| 4125 | | const tmp = DefaultHandleTable[index]; |
| 4126 | | if (tmp) |h| { |
| 4127 | | do_open = false; |
| 4128 | | handle = h; |
| 4129 | | } |
| 4130 | | } |
| 4131 | | |
| 4132 | | if (do_open) { |
| 4133 | | handle = try OpenPredefinedKey(index); |
| 4134 | | } |
| 4135 | | |
| 4136 | | if (def_disabled == 0) { |
| 4137 | | handle = @intToPtr(HANDLE, @ptrToInt(handle) | 0x1); |
| 4138 | | } |
| 4139 | | |
| 4140 | | return handle; |
| 4141 | | } |
| 4142 | | |
| 4143 | | fn OpenPredefinedKey(index: usize) !HANDLE { |
| 4144 | | switch (index) { |
| 4145 | | 0 => { |
| 4146 | | // HKEY_CLASSES_ROOT |
| 4147 | | return error.Unimplemented; |
| 4148 | | }, |
| 4149 | | 1 => { |
| 4150 | | // HKEY_CURRENT_USER |
| 4151 | | return error.Unimplemented; |
| 4152 | | }, |
| 4153 | | 2 => { |
| 4154 | | // HKEY_LOCAL_MACHINE |
| 4155 | | return OpenLocalMachineKey(); |
| 4156 | | }, |
| 4157 | | 3 => { |
| 4158 | | // HKEY_USERS |
| 4159 | | return error.Unimplemented; |
| 4160 | | }, |
| 4161 | | 5 => { |
| 4162 | | // HKEY_CURRENT_CONFIG |
| 4163 | | return error.Unimplemented; |
| 4164 | | }, |
| 4165 | | 6 => { |
| 4166 | | // HKEY_DYN_DATA |
| 4167 | | return error.Unimplemented; |
| 4168 | | }, |
| 4169 | | else => { |
| 4170 | | return error.InvalidParameter; |
| 4171 | | }, |
| 4172 | | } |
| 4173 | | } |
| 4174 | | |
| 4175 | | fn OpenLocalMachineKey() !HANDLE { |
| 4176 | | const path = "\\Registry\\Machine"; |
| 4177 | | var path_u16: [REG_MAX_NAME_SIZE]u16 = undefined; |
| 4178 | | const path_len_u16 = try std.unicode.utf8ToUtf16Le(&path_u16, path); |
| 4179 | | const path_len_bytes = @intCast(u16, path_len_u16 * 2); |
| 4180 | | |
| 4181 | | var key_name = UNICODE_STRING{ |
| 4182 | | .Length = path_len_bytes, |
| 4183 | | .MaximumLength = path_len_bytes, |
| 4184 | | .Buffer = @intToPtr([*]u16, @ptrToInt(&path_u16)), |
| 4185 | | }; |
| 4186 | | |
| 4187 | | var attr = OBJECT_ATTRIBUTES{ |
| 4188 | | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| 4189 | | .RootDirectory = null, |
| 4190 | | .Attributes = OBJ_CASE_INSENSITIVE, |
| 4191 | | .ObjectName = &key_name, |
| 4192 | | .SecurityDescriptor = null, |
| 4193 | | .SecurityQualityOfService = null, |
| 4194 | | }; |
| 4195 | | |
| 4196 | | var result: HKEY = undefined; |
| 4197 | | const rc = ntdll.NtOpenKey( |
| 4198 | | &result, |
| 4199 | | MAXIMUM_ALLOWED, |
| 4200 | | attr, |
| 4201 | | ); |
| 4202 | | switch (rc) { |
| 4203 | | .SUCCESS => return result, |
| 4204 | | else => return unexpectedStatus(rc), |
| 4205 | | } |
| 4206 | | } |