Commit | Line | Data |
---|---|---|
2fab2ef1 AJ |
1 | /* |
2 | * Registry management | |
3 | * | |
4 | * Copyright (C) 1999 Alexandre Julliard | |
5 | * | |
6 | * Based on misc/registry.c code | |
7 | * Copyright (C) 1996 Marcus Meissner | |
8 | * Copyright (C) 1998 Matthew Becker | |
9 | * Copyright (C) 1999 Sylvain St-Germain | |
10 | * | |
0799c1a7 AJ |
11 | * This library is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
360a3f91 | 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
2fab2ef1 AJ |
24 | */ |
25 | ||
26 | #include <stdlib.h> | |
e37c6e18 | 27 | #include <stdarg.h> |
383da68c | 28 | #include <stdio.h> |
2fab2ef1 | 29 | |
1a1583a3 GG |
30 | #include "ntstatus.h" |
31 | #define WIN32_NO_STATUS | |
e37c6e18 | 32 | #include "windef.h" |
2fab2ef1 AJ |
33 | #include "winbase.h" |
34 | #include "winreg.h" | |
35 | #include "winerror.h" | |
efbea2e2 | 36 | #include "winternl.h" |
ac615ce5 | 37 | #include "winuser.h" |
efbea2e2 | 38 | |
c7e7df8b | 39 | #include "wine/unicode.h" |
0799c1a7 | 40 | #include "wine/debug.h" |
2fab2ef1 | 41 | |
0799c1a7 | 42 | WINE_DEFAULT_DEBUG_CHANNEL(reg); |
2fab2ef1 | 43 | |
f2ef2c2b AJ |
44 | #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT |
45 | #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA | |
b88554d2 | 46 | #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1) |
f2ef2c2b AJ |
47 | |
48 | static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS]; | |
52aaddcd | 49 | static BOOL hkcu_cache_disabled; |
f2ef2c2b AJ |
50 | |
51 | static const WCHAR name_CLASSES_ROOT[] = | |
52 | {'M','a','c','h','i','n','e','\\', | |
53 | 'S','o','f','t','w','a','r','e','\\', | |
54 | 'C','l','a','s','s','e','s',0}; | |
55 | static const WCHAR name_LOCAL_MACHINE[] = | |
56 | {'M','a','c','h','i','n','e',0}; | |
57 | static const WCHAR name_USERS[] = | |
58 | {'U','s','e','r',0}; | |
59 | static const WCHAR name_PERFORMANCE_DATA[] = | |
60 | {'P','e','r','f','D','a','t','a',0}; | |
61 | static const WCHAR name_CURRENT_CONFIG[] = | |
62 | {'M','a','c','h','i','n','e','\\', | |
63 | 'S','y','s','t','e','m','\\', | |
64 | 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', | |
8e9d88c1 | 65 | 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\', |
f2ef2c2b AJ |
66 | 'C','u','r','r','e','n','t',0}; |
67 | static const WCHAR name_DYN_DATA[] = | |
68 | {'D','y','n','D','a','t','a',0}; | |
69 | ||
e5b4b47c | 70 | static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] = |
f2ef2c2b | 71 | { |
e852f195 AJ |
72 | name_CLASSES_ROOT, |
73 | NULL, /* HKEY_CURRENT_USER is determined dynamically */ | |
74 | name_LOCAL_MACHINE, | |
75 | name_USERS, | |
76 | name_PERFORMANCE_DATA, | |
77 | name_CURRENT_CONFIG, | |
78 | name_DYN_DATA | |
f2ef2c2b | 79 | }; |
f2ef2c2b | 80 | |
68a5c347 | 81 | static const int is_win64 = (sizeof(void *) > sizeof(int)); |
2fab2ef1 | 82 | |
2fab2ef1 | 83 | /* check if value type needs string conversion (Ansi<->Unicode) */ |
a2e7c325 | 84 | static inline int is_string( DWORD type ) |
2fab2ef1 AJ |
85 | { |
86 | return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); | |
87 | } | |
88 | ||
7dbce65b | 89 | /* check if current version is NT or Win95 */ |
a2e7c325 | 90 | static inline int is_version_nt(void) |
7dbce65b MC |
91 | { |
92 | return !(GetVersion() & 0x80000000); | |
93 | } | |
2fab2ef1 | 94 | |
68a5c347 AJ |
95 | static BOOL is_wow6432node( const UNICODE_STRING *name ) |
96 | { | |
97 | static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'}; | |
98 | ||
99 | return (name->Length == sizeof(wow6432nodeW) && | |
100 | !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) )); | |
101 | } | |
102 | ||
103 | /* open the Wow6432Node subkey of the specified key */ | |
104 | static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name ) | |
105 | { | |
106 | static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0}; | |
107 | OBJECT_ATTRIBUTES attr; | |
108 | UNICODE_STRING nameW; | |
109 | HANDLE ret; | |
110 | ||
111 | attr.Length = sizeof(attr); | |
112 | attr.RootDirectory = key; | |
113 | attr.ObjectName = &nameW; | |
114 | attr.Attributes = 0; | |
115 | attr.SecurityDescriptor = NULL; | |
116 | attr.SecurityQualityOfService = NULL; | |
117 | RtlInitUnicodeString( &nameW, wow6432nodeW ); | |
118 | if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0; | |
119 | return ret; | |
120 | } | |
121 | ||
972f96d6 AJ |
122 | /* wrapper for NtCreateKey that creates the key recursively if necessary */ |
123 | static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, | |
124 | const UNICODE_STRING *class, ULONG options, PULONG dispos ) | |
125 | { | |
68a5c347 AJ |
126 | BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); |
127 | NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; | |
128 | ||
129 | if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos ); | |
972f96d6 AJ |
130 | |
131 | if (status == STATUS_OBJECT_NAME_NOT_FOUND) | |
132 | { | |
68a5c347 AJ |
133 | HANDLE subkey, root = attr->RootDirectory; |
134 | WCHAR *buffer = attr->ObjectName->Buffer; | |
135 | DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); | |
136 | UNICODE_STRING str; | |
137 | ||
138 | while (i < len && buffer[i] != '\\') i++; | |
139 | if (i == len && !force_wow32) return status; | |
972f96d6 | 140 | |
972f96d6 AJ |
141 | attrs = attr->Attributes; |
142 | attr->Attributes &= ~OBJ_OPENLINK; | |
68a5c347 | 143 | attr->ObjectName = &str; |
972f96d6 AJ |
144 | |
145 | while (i < len) | |
146 | { | |
68a5c347 AJ |
147 | str.Buffer = buffer + pos; |
148 | str.Length = (i - pos) * sizeof(WCHAR); | |
149 | if (force_wow32 && pos) | |
150 | { | |
151 | if (is_wow6432node( &str )) force_wow32 = FALSE; | |
152 | else if ((subkey = open_wow6432node( attr->RootDirectory, &str ))) | |
153 | { | |
154 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); | |
155 | attr->RootDirectory = subkey; | |
156 | force_wow32 = FALSE; | |
157 | } | |
158 | } | |
159 | status = NtCreateKey( &subkey, access, attr, 0, class, | |
972f96d6 | 160 | options & ~REG_OPTION_CREATE_LINK, dispos ); |
68a5c347 | 161 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); |
972f96d6 | 162 | if (status) return status; |
68a5c347 AJ |
163 | attr->RootDirectory = subkey; |
164 | while (i < len && buffer[i] == '\\') i++; | |
165 | pos = i; | |
166 | while (i < len && buffer[i] != '\\') i++; | |
972f96d6 | 167 | } |
68a5c347 AJ |
168 | str.Buffer = buffer + pos; |
169 | str.Length = (i - pos) * sizeof(WCHAR); | |
972f96d6 | 170 | attr->Attributes = attrs; |
972f96d6 | 171 | status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos ); |
68a5c347 | 172 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); |
972f96d6 AJ |
173 | } |
174 | return status; | |
175 | } | |
176 | ||
21da080d AJ |
177 | /* wrapper for NtOpenKey to handle Wow6432 nodes */ |
178 | static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) | |
179 | { | |
180 | NTSTATUS status; | |
181 | BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); | |
182 | HANDLE subkey, root = attr->RootDirectory; | |
183 | WCHAR *buffer = attr->ObjectName->Buffer; | |
184 | DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); | |
185 | UNICODE_STRING str; | |
186 | ||
187 | if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr ); | |
188 | ||
189 | if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID; | |
190 | while (i < len && buffer[i] != '\\') i++; | |
191 | attrs = attr->Attributes; | |
192 | attr->Attributes &= ~OBJ_OPENLINK; | |
193 | attr->ObjectName = &str; | |
194 | ||
195 | while (i < len) | |
196 | { | |
197 | str.Buffer = buffer + pos; | |
198 | str.Length = (i - pos) * sizeof(WCHAR); | |
199 | if (force_wow32 && pos) | |
200 | { | |
201 | if (is_wow6432node( &str )) force_wow32 = FALSE; | |
202 | else if ((subkey = open_wow6432node( attr->RootDirectory, &str ))) | |
203 | { | |
204 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); | |
205 | attr->RootDirectory = subkey; | |
206 | force_wow32 = FALSE; | |
207 | } | |
208 | } | |
209 | status = NtOpenKey( &subkey, access, attr ); | |
210 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); | |
211 | if (status) return status; | |
212 | attr->RootDirectory = subkey; | |
213 | while (i < len && buffer[i] == '\\') i++; | |
214 | pos = i; | |
215 | while (i < len && buffer[i] != '\\') i++; | |
216 | } | |
217 | str.Buffer = buffer + pos; | |
218 | str.Length = (i - pos) * sizeof(WCHAR); | |
219 | attr->Attributes = attrs; | |
220 | status = NtOpenKey( (PHANDLE)retkey, access, attr ); | |
221 | if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); | |
222 | return status; | |
223 | ||
224 | } | |
225 | ||
f2ef2c2b | 226 | /* create one of the HKEY_* special root keys */ |
972f96d6 | 227 | static HKEY create_special_root_hkey( HKEY hkey, DWORD access ) |
f2ef2c2b AJ |
228 | { |
229 | HKEY ret = 0; | |
261e3764 | 230 | int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST; |
f2ef2c2b AJ |
231 | |
232 | if (hkey == HKEY_CURRENT_USER) | |
233 | { | |
972f96d6 | 234 | if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0; |
cbacde52 | 235 | TRACE( "HKEY_CURRENT_USER -> %p\n", hkey ); |
52aaddcd RS |
236 | |
237 | /* don't cache the key in the table if caching is disabled */ | |
238 | if (hkcu_cache_disabled) | |
239 | return hkey; | |
f2ef2c2b AJ |
240 | } |
241 | else | |
242 | { | |
243 | OBJECT_ATTRIBUTES attr; | |
e852f195 | 244 | UNICODE_STRING name; |
f2ef2c2b AJ |
245 | |
246 | attr.Length = sizeof(attr); | |
247 | attr.RootDirectory = 0; | |
e852f195 | 248 | attr.ObjectName = &name; |
f2ef2c2b AJ |
249 | attr.Attributes = 0; |
250 | attr.SecurityDescriptor = NULL; | |
251 | attr.SecurityQualityOfService = NULL; | |
e852f195 | 252 | RtlInitUnicodeString( &name, root_key_names[idx] ); |
972f96d6 | 253 | if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0; |
cbacde52 | 254 | TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); |
f2ef2c2b AJ |
255 | } |
256 | ||
cbacde52 | 257 | if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 ))) |
f2ef2c2b AJ |
258 | ret = hkey; |
259 | else | |
260 | NtClose( hkey ); /* somebody beat us to it */ | |
261 | return ret; | |
262 | } | |
263 | ||
264 | /* map the hkey from special root to normal key if necessary */ | |
a2e7c325 | 265 | static inline HKEY get_special_root_hkey( HKEY hkey ) |
f2ef2c2b AJ |
266 | { |
267 | HKEY ret = hkey; | |
268 | ||
269 | if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST)) | |
270 | { | |
261e3764 | 271 | if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST])) |
7fea0e33 | 272 | ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED ); |
f2ef2c2b AJ |
273 | } |
274 | return ret; | |
275 | } | |
276 | ||
a44e0b0f | 277 | |
df0f42fe AJ |
278 | /****************************************************************************** |
279 | * RegOverridePredefKey [ADVAPI32.@] | |
280 | */ | |
281 | LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override ) | |
282 | { | |
283 | HKEY old_key; | |
284 | int idx; | |
285 | ||
286 | if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST)) | |
287 | return ERROR_INVALID_PARAMETER; | |
288 | idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST; | |
289 | ||
290 | if (override) | |
291 | { | |
292 | NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override, | |
293 | GetCurrentProcess(), (HANDLE *)&override, | |
294 | 0, 0, DUPLICATE_SAME_ACCESS ); | |
295 | if (status) return RtlNtStatusToDosError( status ); | |
296 | } | |
297 | ||
298 | old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override ); | |
299 | if (old_key) NtClose( old_key ); | |
300 | return ERROR_SUCCESS; | |
301 | } | |
302 | ||
303 | ||
2fab2ef1 | 304 | /****************************************************************************** |
6a358c40 | 305 | * RegCreateKeyExW [ADVAPI32.@] |
2fab2ef1 | 306 | * |
50ce0844 | 307 | * See RegCreateKeyExA. |
2fab2ef1 | 308 | */ |
af183df6 | 309 | LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class, |
0542e835 BJY |
310 | DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, |
311 | PHKEY retkey, LPDWORD dispos ) | |
2fab2ef1 | 312 | { |
bcf393a5 AJ |
313 | OBJECT_ATTRIBUTES attr; |
314 | UNICODE_STRING nameW, classW; | |
2fab2ef1 AJ |
315 | |
316 | if (reserved) return ERROR_INVALID_PARAMETER; | |
f2ef2c2b | 317 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 318 | |
bcf393a5 AJ |
319 | attr.Length = sizeof(attr); |
320 | attr.RootDirectory = hkey; | |
321 | attr.ObjectName = &nameW; | |
322 | attr.Attributes = 0; | |
323 | attr.SecurityDescriptor = NULL; | |
324 | attr.SecurityQualityOfService = NULL; | |
6c078502 | 325 | if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; |
bcf393a5 AJ |
326 | RtlInitUnicodeString( &nameW, name ); |
327 | RtlInitUnicodeString( &classW, class ); | |
328 | ||
972f96d6 | 329 | return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) ); |
2fab2ef1 AJ |
330 | } |
331 | ||
332 | ||
333 | /****************************************************************************** | |
6a358c40 | 334 | * RegCreateKeyExA [ADVAPI32.@] |
a44e0b0f | 335 | * |
50ce0844 JG |
336 | * Open a registry key, creating it if it doesn't exist. |
337 | * | |
338 | * PARAMS | |
6a358c40 JH |
339 | * hkey [I] Handle of the parent registry key |
340 | * name [I] Name of the new key to open or create | |
341 | * reserved [I] Reserved, pass 0 | |
342 | * class [I] The object type of the new key | |
343 | * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h") | |
344 | * access [I] Access level desired | |
345 | * sa [I] Security attributes for the key | |
346 | * retkey [O] Destination for the resulting handle | |
347 | * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY | |
50ce0844 JG |
348 | * |
349 | * RETURNS | |
6a358c40 JH |
350 | * Success: ERROR_SUCCESS. |
351 | * Failure: A standard Win32 error code. retkey remains untouched. | |
50ce0844 JG |
352 | * |
353 | * FIXME | |
6a358c40 | 354 | * MAXIMUM_ALLOWED in access mask not supported by server |
2fab2ef1 | 355 | */ |
af183df6 | 356 | LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class, |
0542e835 BJY |
357 | DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, |
358 | PHKEY retkey, LPDWORD dispos ) | |
2fab2ef1 | 359 | { |
bcf393a5 | 360 | OBJECT_ATTRIBUTES attr; |
ab5e9759 | 361 | UNICODE_STRING classW; |
bcf393a5 AJ |
362 | ANSI_STRING nameA, classA; |
363 | NTSTATUS status; | |
2fab2ef1 AJ |
364 | |
365 | if (reserved) return ERROR_INVALID_PARAMETER; | |
62b69d64 RK |
366 | if (!is_version_nt()) |
367 | { | |
7fea0e33 | 368 | access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ |
62b69d64 RK |
369 | if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */ |
370 | } | |
f2ef2c2b | 371 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 372 | |
bcf393a5 AJ |
373 | attr.Length = sizeof(attr); |
374 | attr.RootDirectory = hkey; | |
ab5e9759 | 375 | attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; |
bcf393a5 AJ |
376 | attr.Attributes = 0; |
377 | attr.SecurityDescriptor = NULL; | |
378 | attr.SecurityQualityOfService = NULL; | |
6c078502 | 379 | if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; |
bcf393a5 AJ |
380 | RtlInitAnsiString( &nameA, name ); |
381 | RtlInitAnsiString( &classA, class ); | |
382 | ||
ab5e9759 AJ |
383 | if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, |
384 | &nameA, FALSE ))) | |
2fab2ef1 | 385 | { |
bcf393a5 AJ |
386 | if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE ))) |
387 | { | |
972f96d6 | 388 | status = create_key( retkey, access, &attr, &classW, options, dispos ); |
bcf393a5 AJ |
389 | RtlFreeUnicodeString( &classW ); |
390 | } | |
2fab2ef1 | 391 | } |
bcf393a5 | 392 | return RtlNtStatusToDosError( status ); |
2fab2ef1 AJ |
393 | } |
394 | ||
395 | ||
396 | /****************************************************************************** | |
6a358c40 JH |
397 | * RegCreateKeyW [ADVAPI32.@] |
398 | * | |
399 | * Creates the specified reg key. | |
400 | * | |
401 | * PARAMS | |
402 | * hKey [I] Handle to an open key. | |
403 | * lpSubKey [I] Name of a key that will be opened or created. | |
404 | * phkResult [O] Receives a handle to the opened or created key. | |
405 | * | |
406 | * RETURNS | |
407 | * Success: ERROR_SUCCESS | |
408 | * Failure: nonzero error code defined in Winerror.h | |
2fab2ef1 | 409 | */ |
af183df6 | 410 | LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult ) |
2fab2ef1 AJ |
411 | { |
412 | /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */ | |
413 | /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */ | |
6a358c40 | 414 | return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, |
7fea0e33 | 415 | MAXIMUM_ALLOWED, NULL, phkResult, NULL ); |
2fab2ef1 AJ |
416 | } |
417 | ||
418 | ||
419 | /****************************************************************************** | |
6a358c40 JH |
420 | * RegCreateKeyA [ADVAPI32.@] |
421 | * | |
d45811ce | 422 | * See RegCreateKeyW. |
2fab2ef1 | 423 | */ |
af183df6 | 424 | LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult ) |
2fab2ef1 | 425 | { |
6a358c40 | 426 | return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, |
7fea0e33 | 427 | MAXIMUM_ALLOWED, NULL, phkResult, NULL ); |
2fab2ef1 AJ |
428 | } |
429 | ||
430 | ||
431 | ||
432 | /****************************************************************************** | |
6a358c40 JH |
433 | * RegOpenKeyExW [ADVAPI32.@] |
434 | * | |
50ce0844 | 435 | * See RegOpenKeyExA. |
2fab2ef1 | 436 | */ |
6c078502 | 437 | LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey ) |
2fab2ef1 | 438 | { |
bcf393a5 AJ |
439 | OBJECT_ATTRIBUTES attr; |
440 | UNICODE_STRING nameW; | |
441 | ||
aacb511d LZ |
442 | /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ |
443 | if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++; | |
444 | ||
0e98500e | 445 | if (!retkey) return ERROR_INVALID_PARAMETER; |
f2ef2c2b AJ |
446 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
447 | ||
bcf393a5 AJ |
448 | attr.Length = sizeof(attr); |
449 | attr.RootDirectory = hkey; | |
450 | attr.ObjectName = &nameW; | |
451 | attr.Attributes = 0; | |
452 | attr.SecurityDescriptor = NULL; | |
453 | attr.SecurityQualityOfService = NULL; | |
6c078502 | 454 | if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; |
bcf393a5 | 455 | RtlInitUnicodeString( &nameW, name ); |
21da080d | 456 | return RtlNtStatusToDosError( open_key( retkey, access, &attr ) ); |
2fab2ef1 AJ |
457 | } |
458 | ||
459 | ||
460 | /****************************************************************************** | |
6a358c40 | 461 | * RegOpenKeyExA [ADVAPI32.@] |
50ce0844 JG |
462 | * |
463 | * Open a registry key. | |
464 | * | |
465 | * PARAMS | |
6a358c40 JH |
466 | * hkey [I] Handle of open key |
467 | * name [I] Name of subkey to open | |
6c078502 | 468 | * options [I] Open options (can be set to REG_OPTION_OPEN_LINK) |
6a358c40 JH |
469 | * access [I] Security access mask |
470 | * retkey [O] Handle to open key | |
50ce0844 JG |
471 | * |
472 | * RETURNS | |
6a358c40 JH |
473 | * Success: ERROR_SUCCESS |
474 | * Failure: A standard Win32 error code. retkey is set to 0. | |
50ce0844 JG |
475 | * |
476 | * NOTES | |
6a358c40 JH |
477 | * Unlike RegCreateKeyExA(), this function will not create the key if it |
478 | * does not exist. | |
2fab2ef1 | 479 | */ |
6c078502 | 480 | LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey ) |
2fab2ef1 | 481 | { |
bcf393a5 | 482 | OBJECT_ATTRIBUTES attr; |
bcf393a5 AJ |
483 | STRING nameA; |
484 | NTSTATUS status; | |
485 | ||
7fea0e33 | 486 | if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */ |
aacb511d LZ |
487 | else |
488 | { | |
489 | /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */ | |
490 | if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++; | |
491 | } | |
7dbce65b | 492 | |
f2ef2c2b AJ |
493 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
494 | ||
bcf393a5 AJ |
495 | attr.Length = sizeof(attr); |
496 | attr.RootDirectory = hkey; | |
ab5e9759 | 497 | attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString; |
bcf393a5 AJ |
498 | attr.Attributes = 0; |
499 | attr.SecurityDescriptor = NULL; | |
500 | attr.SecurityQualityOfService = NULL; | |
6c078502 | 501 | if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; |
bcf393a5 AJ |
502 | |
503 | RtlInitAnsiString( &nameA, name ); | |
ab5e9759 AJ |
504 | if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, |
505 | &nameA, FALSE ))) | |
bcf393a5 | 506 | { |
21da080d | 507 | status = open_key( retkey, access, &attr ); |
bcf393a5 AJ |
508 | } |
509 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
510 | } |
511 | ||
512 | ||
513 | /****************************************************************************** | |
6a358c40 | 514 | * RegOpenKeyW [ADVAPI32.@] |
2fab2ef1 | 515 | * |
50ce0844 | 516 | * See RegOpenKeyA. |
2fab2ef1 | 517 | */ |
af183df6 | 518 | LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey ) |
2fab2ef1 | 519 | { |
0ca3b3b4 DR |
520 | if (!retkey) |
521 | return ERROR_INVALID_PARAMETER; | |
522 | ||
e8d1e2f7 JH |
523 | if (!name || !*name) |
524 | { | |
525 | *retkey = hkey; | |
526 | return ERROR_SUCCESS; | |
527 | } | |
7fea0e33 | 528 | return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey ); |
2fab2ef1 AJ |
529 | } |
530 | ||
531 | ||
532 | /****************************************************************************** | |
6a358c40 | 533 | * RegOpenKeyA [ADVAPI32.@] |
50ce0844 JG |
534 | * |
535 | * Open a registry key. | |
536 | * | |
537 | * PARAMS | |
6a358c40 JH |
538 | * hkey [I] Handle of parent key to open the new key under |
539 | * name [I] Name of the key under hkey to open | |
540 | * retkey [O] Destination for the resulting Handle | |
50ce0844 JG |
541 | * |
542 | * RETURNS | |
6a358c40 | 543 | * Success: ERROR_SUCCESS |
0ca3b3b4 | 544 | * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0. |
2fab2ef1 | 545 | */ |
af183df6 | 546 | LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey ) |
2fab2ef1 | 547 | { |
0ca3b3b4 DR |
548 | if (!retkey) |
549 | return ERROR_INVALID_PARAMETER; | |
550 | ||
e8d1e2f7 JH |
551 | if (!name || !*name) |
552 | { | |
553 | *retkey = hkey; | |
554 | return ERROR_SUCCESS; | |
555 | } | |
7fea0e33 | 556 | return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey ); |
2fab2ef1 AJ |
557 | } |
558 | ||
559 | ||
44f84b55 | 560 | /****************************************************************************** |
6a358c40 | 561 | * RegOpenCurrentUser [ADVAPI32.@] |
ec350525 MA |
562 | * |
563 | * Get a handle to the HKEY_CURRENT_USER key for the user | |
564 | * the current thread is impersonating. | |
565 | * | |
566 | * PARAMS | |
567 | * access [I] Desired access rights to the key | |
568 | * retkey [O] Handle to the opened key | |
569 | * | |
570 | * RETURNS | |
571 | * Success: ERROR_SUCCESS | |
572 | * Failure: nonzero error code from Winerror.h | |
573 | * | |
574 | * FIXME | |
575 | * This function is supposed to retrieve a handle to the | |
576 | * HKEY_CURRENT_USER for the user the current thread is impersonating. | |
577 | * Since Wine does not currently allow threads to impersonate other users, | |
578 | * this stub should work fine. | |
44f84b55 | 579 | */ |
af183df6 | 580 | LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey ) |
44f84b55 DE |
581 | { |
582 | return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey ); | |
583 | } | |
584 | ||
585 | ||
2fab2ef1 AJ |
586 | |
587 | /****************************************************************************** | |
6a358c40 | 588 | * RegEnumKeyExW [ADVAPI32.@] |
2fab2ef1 | 589 | * |
ec350525 MA |
590 | * Enumerate subkeys of the specified open registry key. |
591 | * | |
2fab2ef1 | 592 | * PARAMS |
6a358c40 JH |
593 | * hkey [I] Handle to key to enumerate |
594 | * index [I] Index of subkey to enumerate | |
595 | * name [O] Buffer for subkey name | |
596 | * name_len [O] Size of subkey buffer | |
597 | * reserved [I] Reserved | |
598 | * class [O] Buffer for class string | |
599 | * class_len [O] Size of class buffer | |
600 | * ft [O] Time key last written to | |
601 | * | |
602 | * RETURNS | |
603 | * Success: ERROR_SUCCESS | |
604 | * Failure: System error code. If there are no more subkeys available, the | |
605 | * function returns ERROR_NO_MORE_ITEMS. | |
2fab2ef1 | 606 | */ |
af183df6 | 607 | LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len, |
0542e835 | 608 | LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft ) |
2fab2ef1 | 609 | { |
454355ec AJ |
610 | NTSTATUS status; |
611 | char buffer[256], *buf_ptr = buffer; | |
612 | KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; | |
613 | DWORD total_size; | |
2fab2ef1 | 614 | |
414cdc04 AT |
615 | TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len, |
616 | name_len ? *name_len : 0, reserved, class, class_len, ft ); | |
2fab2ef1 AJ |
617 | |
618 | if (reserved) return ERROR_INVALID_PARAMETER; | |
f2ef2c2b | 619 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
0bb6fdda | 620 | |
454355ec AJ |
621 | status = NtEnumerateKey( hkey, index, KeyNodeInformation, |
622 | buffer, sizeof(buffer), &total_size ); | |
2fab2ef1 | 623 | |
454355ec AJ |
624 | while (status == STATUS_BUFFER_OVERFLOW) |
625 | { | |
626 | /* retry with a dynamically allocated buffer */ | |
627 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
628 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
629 | return ERROR_NOT_ENOUGH_MEMORY; | |
630 | info = (KEY_NODE_INFORMATION *)buf_ptr; | |
631 | status = NtEnumerateKey( hkey, index, KeyNodeInformation, | |
632 | buf_ptr, total_size, &total_size ); | |
633 | } | |
2fab2ef1 | 634 | |
454355ec | 635 | if (!status) |
2fab2ef1 | 636 | { |
454355ec AJ |
637 | DWORD len = info->NameLength / sizeof(WCHAR); |
638 | DWORD cls_len = info->ClassLength / sizeof(WCHAR); | |
639 | ||
6b6596a1 | 640 | if (ft) *ft = *(FILETIME *)&info->LastWriteTime; |
454355ec | 641 | |
20a4cc31 | 642 | if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) |
454355ec AJ |
643 | status = STATUS_BUFFER_OVERFLOW; |
644 | else | |
645 | { | |
646 | *name_len = len; | |
647 | memcpy( name, info->Name, info->NameLength ); | |
648 | name[len] = 0; | |
649 | if (class_len) | |
650 | { | |
651 | *class_len = cls_len; | |
652 | if (class) | |
653 | { | |
654 | memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); | |
655 | class[cls_len] = 0; | |
656 | } | |
657 | } | |
658 | } | |
2fab2ef1 | 659 | } |
454355ec AJ |
660 | |
661 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
662 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
663 | } |
664 | ||
665 | ||
666 | /****************************************************************************** | |
6a358c40 JH |
667 | * RegEnumKeyExA [ADVAPI32.@] |
668 | * | |
d45811ce | 669 | * See RegEnumKeyExW. |
2fab2ef1 | 670 | */ |
af183df6 | 671 | LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len, |
0542e835 | 672 | LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft ) |
2fab2ef1 | 673 | { |
454355ec AJ |
674 | NTSTATUS status; |
675 | char buffer[256], *buf_ptr = buffer; | |
676 | KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; | |
677 | DWORD total_size; | |
2fab2ef1 | 678 | |
414cdc04 AT |
679 | TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len, |
680 | name_len ? *name_len : 0, reserved, class, class_len, ft ); | |
2fab2ef1 AJ |
681 | |
682 | if (reserved) return ERROR_INVALID_PARAMETER; | |
f2ef2c2b | 683 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
0bb6fdda | 684 | |
454355ec AJ |
685 | status = NtEnumerateKey( hkey, index, KeyNodeInformation, |
686 | buffer, sizeof(buffer), &total_size ); | |
2fab2ef1 | 687 | |
454355ec AJ |
688 | while (status == STATUS_BUFFER_OVERFLOW) |
689 | { | |
690 | /* retry with a dynamically allocated buffer */ | |
691 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
692 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
693 | return ERROR_NOT_ENOUGH_MEMORY; | |
694 | info = (KEY_NODE_INFORMATION *)buf_ptr; | |
695 | status = NtEnumerateKey( hkey, index, KeyNodeInformation, | |
696 | buf_ptr, total_size, &total_size ); | |
697 | } | |
2fab2ef1 | 698 | |
454355ec | 699 | if (!status) |
2fab2ef1 | 700 | { |
60fd03d2 | 701 | DWORD len, cls_len; |
454355ec | 702 | |
60fd03d2 AJ |
703 | RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); |
704 | RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset), | |
705 | info->ClassLength ); | |
6b6596a1 | 706 | if (ft) *ft = *(FILETIME *)&info->LastWriteTime; |
454355ec | 707 | |
20a4cc31 | 708 | if (len >= *name_len || (class && class_len && (cls_len >= *class_len))) |
454355ec AJ |
709 | status = STATUS_BUFFER_OVERFLOW; |
710 | else | |
711 | { | |
712 | *name_len = len; | |
60fd03d2 | 713 | RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength ); |
454355ec AJ |
714 | name[len] = 0; |
715 | if (class_len) | |
716 | { | |
717 | *class_len = cls_len; | |
718 | if (class) | |
719 | { | |
60fd03d2 AJ |
720 | RtlUnicodeToMultiByteN( class, cls_len, NULL, |
721 | (WCHAR *)(buf_ptr + info->ClassOffset), | |
722 | info->ClassLength ); | |
454355ec AJ |
723 | class[cls_len] = 0; |
724 | } | |
725 | } | |
726 | } | |
2fab2ef1 | 727 | } |
454355ec AJ |
728 | |
729 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
730 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
731 | } |
732 | ||
733 | ||
734 | /****************************************************************************** | |
6a358c40 JH |
735 | * RegEnumKeyW [ADVAPI32.@] |
736 | * | |
d347ebe1 | 737 | * Enumerates subkeys of the specified open reg key. |
6a358c40 JH |
738 | * |
739 | * PARAMS | |
740 | * hKey [I] Handle to an open key. | |
741 | * dwIndex [I] Index of the subkey of hKey to retrieve. | |
742 | * lpName [O] Name of the subkey. | |
743 | * cchName [I] Size of lpName in TCHARS. | |
744 | * | |
745 | * RETURNS | |
746 | * Success: ERROR_SUCCESS | |
747 | * Failure: system error code. If there are no more subkeys available, the | |
748 | * function returns ERROR_NO_MORE_ITEMS. | |
2fab2ef1 | 749 | */ |
af183df6 | 750 | LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len ) |
2fab2ef1 AJ |
751 | { |
752 | return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL ); | |
753 | } | |
754 | ||
755 | ||
756 | /****************************************************************************** | |
6a358c40 JH |
757 | * RegEnumKeyA [ADVAPI32.@] |
758 | * | |
d45811ce | 759 | * See RegEnumKeyW. |
2fab2ef1 | 760 | */ |
af183df6 | 761 | LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len ) |
2fab2ef1 AJ |
762 | { |
763 | return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL ); | |
764 | } | |
765 | ||
766 | ||
767 | /****************************************************************************** | |
6a358c40 | 768 | * RegQueryInfoKeyW [ADVAPI32.@] |
2fab2ef1 | 769 | * |
d45811ce MA |
770 | * Retrieves information about the specified registry key. |
771 | * | |
2fab2ef1 AJ |
772 | * PARAMS |
773 | * hkey [I] Handle to key to query | |
774 | * class [O] Buffer for class string | |
775 | * class_len [O] Size of class string buffer | |
776 | * reserved [I] Reserved | |
777 | * subkeys [O] Buffer for number of subkeys | |
778 | * max_subkey [O] Buffer for longest subkey name length | |
779 | * max_class [O] Buffer for longest class string length | |
780 | * values [O] Buffer for number of value entries | |
781 | * max_value [O] Buffer for longest value name length | |
782 | * max_data [O] Buffer for longest value data length | |
783 | * security [O] Buffer for security descriptor length | |
784 | * modif [O] Modification time | |
785 | * | |
d45811ce MA |
786 | * RETURNS |
787 | * Success: ERROR_SUCCESS | |
788 | * Failure: system error code. | |
789 | * | |
790 | * NOTES | |
791 | * - win95 allows class to be valid and class_len to be NULL | |
792 | * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL | |
793 | * - both allow class to be NULL and class_len to be NULL | |
794 | * (it's hard to test validity, so test !NULL instead) | |
2fab2ef1 | 795 | */ |
af183df6 | 796 | LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved, |
0542e835 BJY |
797 | LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class, |
798 | LPDWORD values, LPDWORD max_value, LPDWORD max_data, | |
799 | LPDWORD security, FILETIME *modif ) | |
2fab2ef1 | 800 | { |
454355ec AJ |
801 | NTSTATUS status; |
802 | char buffer[256], *buf_ptr = buffer; | |
803 | KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; | |
804 | DWORD total_size; | |
2fab2ef1 | 805 | |
4301816d | 806 | TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, |
2fab2ef1 AJ |
807 | reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); |
808 | ||
7dbce65b | 809 | if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 810 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 811 | |
454355ec | 812 | status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); |
c6615832 | 813 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; |
2fab2ef1 AJ |
814 | |
815 | if (class) | |
816 | { | |
454355ec AJ |
817 | /* retry with a dynamically allocated buffer */ |
818 | while (status == STATUS_BUFFER_OVERFLOW) | |
2fab2ef1 | 819 | { |
454355ec AJ |
820 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
821 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
822 | return ERROR_NOT_ENOUGH_MEMORY; | |
823 | info = (KEY_FULL_INFORMATION *)buf_ptr; | |
824 | status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); | |
825 | } | |
826 | ||
c6615832 AJ |
827 | if (status) goto done; |
828 | ||
829 | if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len)) | |
454355ec | 830 | { |
c6615832 AJ |
831 | status = STATUS_BUFFER_OVERFLOW; |
832 | } | |
833 | else | |
834 | { | |
835 | memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); | |
836 | class[info->ClassLength/sizeof(WCHAR)] = 0; | |
2fab2ef1 | 837 | } |
2fab2ef1 | 838 | } |
c6615832 | 839 | else status = STATUS_SUCCESS; |
454355ec | 840 | |
c6615832 AJ |
841 | if (class_len) *class_len = info->ClassLength / sizeof(WCHAR); |
842 | if (subkeys) *subkeys = info->SubKeys; | |
843 | if (max_subkey) *max_subkey = info->MaxNameLen; | |
844 | if (max_class) *max_class = info->MaxClassLen; | |
845 | if (values) *values = info->Values; | |
846 | if (max_value) *max_value = info->MaxValueNameLen; | |
847 | if (max_data) *max_data = info->MaxValueDataLen; | |
6b6596a1 | 848 | if (modif) *modif = *(FILETIME *)&info->LastWriteTime; |
454355ec | 849 | |
c6615832 | 850 | done: |
454355ec AJ |
851 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
852 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
853 | } |
854 | ||
855 | ||
751c4544 | 856 | /****************************************************************************** |
6a358c40 JH |
857 | * RegQueryMultipleValuesA [ADVAPI32.@] |
858 | * | |
859 | * Retrieves the type and data for a list of value names associated with a key. | |
860 | * | |
861 | * PARAMS | |
862 | * hKey [I] Handle to an open key. | |
863 | * val_list [O] Array of VALENT structures that describes the entries. | |
864 | * num_vals [I] Number of elements in val_list. | |
865 | * lpValueBuf [O] Pointer to a buffer that receives the data for each value. | |
866 | * ldwTotsize [I/O] Size of lpValueBuf. | |
867 | * | |
868 | * RETURNS | |
869 | * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied. | |
870 | * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed | |
871 | * bytes. | |
751c4544 | 872 | */ |
af183df6 | 873 | LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals, |
0542e835 | 874 | LPSTR lpValueBuf, LPDWORD ldwTotsize ) |
751c4544 | 875 | { |
411fc5f1 | 876 | unsigned int i; |
751c4544 DS |
877 | DWORD maxBytes = *ldwTotsize; |
878 | HRESULT status; | |
879 | LPSTR bufptr = lpValueBuf; | |
880 | *ldwTotsize = 0; | |
881 | ||
4301816d | 882 | TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); |
751c4544 DS |
883 | |
884 | for(i=0; i < num_vals; ++i) | |
885 | { | |
886 | ||
887 | val_list[i].ve_valuelen=0; | |
888 | status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen); | |
889 | if(status != ERROR_SUCCESS) | |
890 | { | |
891 | return status; | |
892 | } | |
893 | ||
894 | if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) | |
895 | { | |
896 | status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type, | |
257c337c | 897 | (LPBYTE)bufptr, &val_list[i].ve_valuelen); |
751c4544 DS |
898 | if(status != ERROR_SUCCESS) |
899 | { | |
900 | return status; | |
901 | } | |
902 | ||
903 | val_list[i].ve_valueptr = (DWORD_PTR)bufptr; | |
904 | ||
905 | bufptr += val_list[i].ve_valuelen; | |
906 | } | |
907 | ||
908 | *ldwTotsize += val_list[i].ve_valuelen; | |
909 | } | |
910 | return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA; | |
911 | } | |
912 | ||
913 | ||
914 | /****************************************************************************** | |
6a358c40 JH |
915 | * RegQueryMultipleValuesW [ADVAPI32.@] |
916 | * | |
d45811ce | 917 | * See RegQueryMultipleValuesA. |
751c4544 | 918 | */ |
af183df6 | 919 | LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals, |
0542e835 | 920 | LPWSTR lpValueBuf, LPDWORD ldwTotsize ) |
751c4544 | 921 | { |
411fc5f1 | 922 | unsigned int i; |
751c4544 DS |
923 | DWORD maxBytes = *ldwTotsize; |
924 | HRESULT status; | |
925 | LPSTR bufptr = (LPSTR)lpValueBuf; | |
926 | *ldwTotsize = 0; | |
927 | ||
4301816d | 928 | TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); |
751c4544 DS |
929 | |
930 | for(i=0; i < num_vals; ++i) | |
931 | { | |
932 | val_list[i].ve_valuelen=0; | |
933 | status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen); | |
934 | if(status != ERROR_SUCCESS) | |
935 | { | |
936 | return status; | |
937 | } | |
938 | ||
939 | if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) | |
940 | { | |
941 | status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type, | |
257c337c | 942 | (LPBYTE)bufptr, &val_list[i].ve_valuelen); |
751c4544 DS |
943 | if(status != ERROR_SUCCESS) |
944 | { | |
945 | return status; | |
946 | } | |
947 | ||
948 | val_list[i].ve_valueptr = (DWORD_PTR)bufptr; | |
949 | ||
950 | bufptr += val_list[i].ve_valuelen; | |
951 | } | |
952 | ||
953 | *ldwTotsize += val_list[i].ve_valuelen; | |
954 | } | |
955 | return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA; | |
956 | } | |
957 | ||
2fab2ef1 | 958 | /****************************************************************************** |
6a358c40 JH |
959 | * RegQueryInfoKeyA [ADVAPI32.@] |
960 | * | |
961 | * Retrieves information about a registry key. | |
962 | * | |
963 | * PARAMS | |
964 | * hKey [I] Handle to an open key. | |
965 | * lpClass [O] Class string of the key. | |
966 | * lpcClass [I/O] size of lpClass. | |
967 | * lpReserved [I] Reserved; must be NULL. | |
968 | * lpcSubKeys [O] Number of subkeys contained by the key. | |
969 | * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name. | |
970 | * lpcMaxClassLen [O] Size of the longest string specifying a subkey | |
971 | * class in TCHARS. | |
972 | * lpcValues [O] Number of values associated with the key. | |
973 | * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS. | |
974 | * lpcMaxValueLen [O] Longest data component among the key's values | |
975 | * lpcbSecurityDescriptor [O] Size of the key's security descriptor. | |
d347ebe1 | 976 | * lpftLastWriteTime [O] FILETIME structure that is the last write time. |
6a358c40 JH |
977 | * |
978 | * RETURNS | |
979 | * Success: ERROR_SUCCESS | |
980 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 | 981 | */ |
af183df6 | 982 | LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved, |
0542e835 BJY |
983 | LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class, |
984 | LPDWORD values, LPDWORD max_value, LPDWORD max_data, | |
985 | LPDWORD security, FILETIME *modif ) | |
2fab2ef1 | 986 | { |
454355ec AJ |
987 | NTSTATUS status; |
988 | char buffer[256], *buf_ptr = buffer; | |
989 | KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; | |
c6615832 | 990 | DWORD total_size, len; |
2fab2ef1 | 991 | |
4301816d | 992 | TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, |
2fab2ef1 AJ |
993 | reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); |
994 | ||
7dbce65b | 995 | if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 996 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 997 | |
454355ec | 998 | status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); |
c6615832 | 999 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; |
2fab2ef1 | 1000 | |
454355ec | 1001 | if (class || class_len) |
2fab2ef1 | 1002 | { |
454355ec AJ |
1003 | /* retry with a dynamically allocated buffer */ |
1004 | while (status == STATUS_BUFFER_OVERFLOW) | |
1005 | { | |
1006 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
1007 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
1008 | return ERROR_NOT_ENOUGH_MEMORY; | |
1009 | info = (KEY_FULL_INFORMATION *)buf_ptr; | |
1010 | status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); | |
1011 | } | |
1012 | ||
c6615832 AJ |
1013 | if (status) goto done; |
1014 | ||
60fd03d2 | 1015 | RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength); |
c6615832 | 1016 | if (class_len) |
2fab2ef1 | 1017 | { |
c6615832 AJ |
1018 | if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW; |
1019 | *class_len = len; | |
1020 | } | |
1021 | if (class && !status) | |
1022 | { | |
60fd03d2 AJ |
1023 | RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset), |
1024 | info->ClassLength ); | |
c6615832 | 1025 | class[len] = 0; |
2fab2ef1 | 1026 | } |
2fab2ef1 | 1027 | } |
c6615832 | 1028 | else status = STATUS_SUCCESS; |
454355ec | 1029 | |
c6615832 AJ |
1030 | if (subkeys) *subkeys = info->SubKeys; |
1031 | if (max_subkey) *max_subkey = info->MaxNameLen; | |
1032 | if (max_class) *max_class = info->MaxClassLen; | |
1033 | if (values) *values = info->Values; | |
1034 | if (max_value) *max_value = info->MaxValueNameLen; | |
1035 | if (max_data) *max_data = info->MaxValueDataLen; | |
6b6596a1 | 1036 | if (modif) *modif = *(FILETIME *)&info->LastWriteTime; |
454355ec | 1037 | |
c6615832 | 1038 | done: |
454355ec AJ |
1039 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
1040 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
1041 | } |
1042 | ||
1043 | ||
1044 | /****************************************************************************** | |
6a358c40 | 1045 | * RegCloseKey [ADVAPI32.@] |
2fab2ef1 | 1046 | * |
50ce0844 | 1047 | * Close an open registry key. |
2fab2ef1 AJ |
1048 | * |
1049 | * PARAMS | |
6a358c40 | 1050 | * hkey [I] Handle of key to close |
2fab2ef1 AJ |
1051 | * |
1052 | * RETURNS | |
6a358c40 JH |
1053 | * Success: ERROR_SUCCESS |
1054 | * Failure: Error code | |
2fab2ef1 | 1055 | */ |
af183df6 | 1056 | LSTATUS WINAPI RegCloseKey( HKEY hkey ) |
2fab2ef1 | 1057 | { |
e8d1e2f7 | 1058 | if (!hkey) return ERROR_INVALID_HANDLE; |
d5e2b7c8 | 1059 | if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS; |
bcf393a5 | 1060 | return RtlNtStatusToDosError( NtClose( hkey ) ); |
2fab2ef1 AJ |
1061 | } |
1062 | ||
1063 | ||
1064 | /****************************************************************************** | |
9b7d1041 | 1065 | * RegDeleteKeyExW [ADVAPI32.@] |
2fab2ef1 | 1066 | */ |
9b7d1041 | 1067 | LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved ) |
2fab2ef1 AJ |
1068 | { |
1069 | DWORD ret; | |
bcf393a5 | 1070 | HKEY tmp; |
2fab2ef1 | 1071 | |
a9d5de84 JH |
1072 | if (!name) return ERROR_INVALID_PARAMETER; |
1073 | ||
f2ef2c2b AJ |
1074 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
1075 | ||
9b7d1041 AJ |
1076 | access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; |
1077 | if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp ))) | |
da00742a | 1078 | { |
bcf393a5 AJ |
1079 | ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); |
1080 | RegCloseKey( tmp ); | |
1081 | } | |
4301816d | 1082 | TRACE("%s ret=%08x\n", debugstr_w(name), ret); |
bcf393a5 | 1083 | return ret; |
2fab2ef1 AJ |
1084 | } |
1085 | ||
1086 | ||
1087 | /****************************************************************************** | |
9b7d1041 | 1088 | * RegDeleteKeyW [ADVAPI32.@] |
45d47c42 | 1089 | * |
9b7d1041 | 1090 | * See RegDeleteKeyA. |
2fab2ef1 | 1091 | */ |
9b7d1041 AJ |
1092 | LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name ) |
1093 | { | |
1094 | return RegDeleteKeyExW( hkey, name, 0, 0 ); | |
1095 | } | |
1096 | ||
1097 | ||
1098 | /****************************************************************************** | |
1099 | * RegDeleteKeyExA [ADVAPI32.@] | |
1100 | */ | |
1101 | LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved ) | |
2fab2ef1 AJ |
1102 | { |
1103 | DWORD ret; | |
bcf393a5 | 1104 | HKEY tmp; |
2fab2ef1 | 1105 | |
a9d5de84 JH |
1106 | if (!name) return ERROR_INVALID_PARAMETER; |
1107 | ||
f2ef2c2b AJ |
1108 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
1109 | ||
9b7d1041 AJ |
1110 | access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY; |
1111 | if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp ))) | |
da00742a MM |
1112 | { |
1113 | if (!is_version_nt()) /* win95 does recursive key deletes */ | |
1114 | { | |
1115 | CHAR name[MAX_PATH]; | |
1116 | ||
9591836f | 1117 | while(!RegEnumKeyA(tmp, 0, name, sizeof(name))) |
da00742a | 1118 | { |
9b7d1041 | 1119 | if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */ |
da00742a MM |
1120 | break; |
1121 | } | |
1122 | } | |
bcf393a5 AJ |
1123 | ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) ); |
1124 | RegCloseKey( tmp ); | |
1125 | } | |
4301816d | 1126 | TRACE("%s ret=%08x\n", debugstr_a(name), ret); |
bcf393a5 | 1127 | return ret; |
2fab2ef1 AJ |
1128 | } |
1129 | ||
1130 | ||
9b7d1041 AJ |
1131 | /****************************************************************************** |
1132 | * RegDeleteKeyA [ADVAPI32.@] | |
1133 | * | |
1134 | * Delete a registry key. | |
1135 | * | |
1136 | * PARAMS | |
1137 | * hkey [I] Handle to parent key containing the key to delete | |
1138 | * name [I] Name of the key user hkey to delete | |
1139 | * | |
1140 | * NOTES | |
1141 | * | |
1142 | * MSDN is wrong when it says that hkey must be opened with the DELETE access | |
1143 | * right. In reality, it opens a new handle with DELETE access. | |
1144 | * | |
1145 | * RETURNS | |
1146 | * Success: ERROR_SUCCESS | |
1147 | * Failure: Error code | |
1148 | */ | |
1149 | LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name ) | |
1150 | { | |
1151 | return RegDeleteKeyExA( hkey, name, 0, 0 ); | |
1152 | } | |
1153 | ||
1154 | ||
2fab2ef1 AJ |
1155 | |
1156 | /****************************************************************************** | |
6a358c40 | 1157 | * RegSetValueExW [ADVAPI32.@] |
2fab2ef1 | 1158 | * |
50ce0844 | 1159 | * Set the data and contents of a registry value. |
2fab2ef1 AJ |
1160 | * |
1161 | * PARAMS | |
6a358c40 JH |
1162 | * hkey [I] Handle of key to set value for |
1163 | * name [I] Name of value to set | |
1164 | * reserved [I] Reserved, must be zero | |
1165 | * type [I] Type of the value being set | |
1166 | * data [I] The new contents of the value to set | |
1167 | * count [I] Size of data | |
2fab2ef1 AJ |
1168 | * |
1169 | * RETURNS | |
6a358c40 JH |
1170 | * Success: ERROR_SUCCESS |
1171 | * Failure: Error code | |
2fab2ef1 | 1172 | */ |
af183df6 | 1173 | LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved, |
0542e835 | 1174 | DWORD type, CONST BYTE *data, DWORD count ) |
2fab2ef1 | 1175 | { |
bcf393a5 | 1176 | UNICODE_STRING nameW; |
2fab2ef1 | 1177 | |
bba76fca AJ |
1178 | /* no need for version check, not implemented on win9x anyway */ |
1179 | if (count && is_string(type)) | |
2fab2ef1 AJ |
1180 | { |
1181 | LPCWSTR str = (LPCWSTR)data; | |
1182 | /* if user forgot to count terminating null, add it (yes NT does this) */ | |
1183 | if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)]) | |
1184 | count += sizeof(WCHAR); | |
1185 | } | |
f2ef2c2b | 1186 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
a01004d8 | 1187 | |
bcf393a5 AJ |
1188 | RtlInitUnicodeString( &nameW, name ); |
1189 | return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) ); | |
2fab2ef1 AJ |
1190 | } |
1191 | ||
1192 | ||
1193 | /****************************************************************************** | |
6a358c40 JH |
1194 | * RegSetValueExA [ADVAPI32.@] |
1195 | * | |
d45811ce | 1196 | * See RegSetValueExW. |
bba76fca AJ |
1197 | * |
1198 | * NOTES | |
1199 | * win95 does not care about count for REG_SZ and finds out the len by itself (js) | |
1200 | * NT does definitely care (aj) | |
2fab2ef1 | 1201 | */ |
af183df6 | 1202 | LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type, |
0542e835 | 1203 | CONST BYTE *data, DWORD count ) |
2fab2ef1 | 1204 | { |
bcf393a5 | 1205 | ANSI_STRING nameA; |
acc41b50 | 1206 | UNICODE_STRING nameW; |
bcf393a5 AJ |
1207 | WCHAR *dataW = NULL; |
1208 | NTSTATUS status; | |
2fab2ef1 | 1209 | |
7dbce65b | 1210 | if (!is_version_nt()) /* win95 */ |
918da64a | 1211 | { |
bba76fca AJ |
1212 | if (type == REG_SZ) |
1213 | { | |
1214 | if (!data) return ERROR_INVALID_PARAMETER; | |
280bcf6e | 1215 | count = strlen((const char *)data) + 1; |
bba76fca | 1216 | } |
918da64a AJ |
1217 | } |
1218 | else if (count && is_string(type)) | |
2fab2ef1 AJ |
1219 | { |
1220 | /* if user forgot to count terminating null, add it (yes NT does this) */ | |
1221 | if (data[count-1] && !data[count]) count++; | |
1222 | } | |
a01004d8 | 1223 | |
f2ef2c2b AJ |
1224 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
1225 | ||
bcf393a5 | 1226 | if (is_string( type )) /* need to convert to Unicode */ |
a01004d8 | 1227 | { |
60fd03d2 | 1228 | DWORD lenW; |
280bcf6e | 1229 | RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count ); |
60fd03d2 | 1230 | if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY; |
280bcf6e | 1231 | RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count ); |
60fd03d2 | 1232 | count = lenW; |
bcf393a5 AJ |
1233 | data = (BYTE *)dataW; |
1234 | } | |
a01004d8 | 1235 | |
bcf393a5 | 1236 | RtlInitAnsiString( &nameA, name ); |
acc41b50 | 1237 | if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) |
bcf393a5 | 1238 | { |
acc41b50 AJ |
1239 | status = NtSetValueKey( hkey, &nameW, 0, type, data, count ); |
1240 | RtlFreeUnicodeString( &nameW ); | |
a01004d8 | 1241 | } |
5ad7d858 | 1242 | HeapFree( GetProcessHeap(), 0, dataW ); |
bcf393a5 | 1243 | return RtlNtStatusToDosError( status ); |
2fab2ef1 AJ |
1244 | } |
1245 | ||
1246 | ||
1247 | /****************************************************************************** | |
6a358c40 JH |
1248 | * RegSetValueW [ADVAPI32.@] |
1249 | * | |
1250 | * Sets the data for the default or unnamed value of a reg key. | |
1251 | * | |
1252 | * PARAMS | |
1253 | * hKey [I] Handle to an open key. | |
1254 | * lpSubKey [I] Name of a subkey of hKey. | |
1255 | * dwType [I] Type of information to store. | |
1256 | * lpData [I] String that contains the data to set for the default value. | |
628183c2 | 1257 | * cbData [I] Ignored. |
6a358c40 JH |
1258 | * |
1259 | * RETURNS | |
1260 | * Success: ERROR_SUCCESS | |
1261 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 | 1262 | */ |
af183df6 | 1263 | LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count ) |
2fab2ef1 AJ |
1264 | { |
1265 | HKEY subkey = hkey; | |
1266 | DWORD ret; | |
1267 | ||
4301816d | 1268 | TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count ); |
2fab2ef1 | 1269 | |
121be51f | 1270 | if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER; |
2fab2ef1 AJ |
1271 | |
1272 | if (name && name[0]) /* need to create the subkey */ | |
1273 | { | |
1274 | if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; | |
1275 | } | |
1276 | ||
0a258964 | 1277 | ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data, |
c7e7df8b | 1278 | (strlenW( data ) + 1) * sizeof(WCHAR) ); |
2fab2ef1 AJ |
1279 | if (subkey != hkey) RegCloseKey( subkey ); |
1280 | return ret; | |
1281 | } | |
1282 | ||
1283 | ||
1284 | /****************************************************************************** | |
6a358c40 JH |
1285 | * RegSetValueA [ADVAPI32.@] |
1286 | * | |
d45811ce | 1287 | * See RegSetValueW. |
2fab2ef1 | 1288 | */ |
af183df6 | 1289 | LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count ) |
2fab2ef1 AJ |
1290 | { |
1291 | HKEY subkey = hkey; | |
1292 | DWORD ret; | |
1293 | ||
4301816d | 1294 | TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count ); |
2fab2ef1 | 1295 | |
121be51f | 1296 | if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER; |
2fab2ef1 AJ |
1297 | |
1298 | if (name && name[0]) /* need to create the subkey */ | |
1299 | { | |
1300 | if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; | |
1301 | } | |
0a258964 | 1302 | ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 ); |
2fab2ef1 AJ |
1303 | if (subkey != hkey) RegCloseKey( subkey ); |
1304 | return ret; | |
1305 | } | |
1306 | ||
1307 | ||
1308 | ||
1309 | /****************************************************************************** | |
6a358c40 | 1310 | * RegQueryValueExW [ADVAPI32.@] |
2fab2ef1 | 1311 | * |
50ce0844 | 1312 | * See RegQueryValueExA. |
2fab2ef1 | 1313 | */ |
af183df6 | 1314 | LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type, |
0542e835 | 1315 | LPBYTE data, LPDWORD count ) |
2fab2ef1 | 1316 | { |
bcf393a5 AJ |
1317 | NTSTATUS status; |
1318 | UNICODE_STRING name_str; | |
1319 | DWORD total_size; | |
454355ec | 1320 | char buffer[256], *buf_ptr = buffer; |
bcf393a5 | 1321 | KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; |
a010932a | 1322 | static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); |
2fab2ef1 | 1323 | |
4301816d | 1324 | TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", |
8f63a714 FG |
1325 | hkey, debugstr_w(name), reserved, type, data, count, |
1326 | (count && data) ? *count : 0 ); | |
2fab2ef1 | 1327 | |
2c655f5e | 1328 | if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 1329 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 1330 | |
bcf393a5 AJ |
1331 | RtlInitUnicodeString( &name_str, name ); |
1332 | ||
1333 | if (data) total_size = min( sizeof(buffer), *count + info_size ); | |
bc590e87 RS |
1334 | else |
1335 | { | |
1336 | total_size = info_size; | |
1337 | if (count) *count = 0; | |
1338 | } | |
bcf393a5 AJ |
1339 | |
1340 | status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, | |
1341 | buffer, total_size, &total_size ); | |
1342 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; | |
a01004d8 AJ |
1343 | |
1344 | if (data) | |
2fab2ef1 | 1345 | { |
bcf393a5 AJ |
1346 | /* retry with a dynamically allocated buffer */ |
1347 | while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) | |
a01004d8 | 1348 | { |
bcf393a5 AJ |
1349 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
1350 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
454355ec AJ |
1351 | return ERROR_NOT_ENOUGH_MEMORY; |
1352 | info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; | |
1353 | status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, | |
1354 | buf_ptr, total_size, &total_size ); | |
bcf393a5 AJ |
1355 | } |
1356 | ||
1357 | if (!status) | |
1358 | { | |
1359 | memcpy( data, buf_ptr + info_size, total_size - info_size ); | |
1360 | /* if the type is REG_SZ and data is not 0-terminated | |
1361 | * and there is enough space in the buffer NT appends a \0 */ | |
1362 | if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type)) | |
a01004d8 | 1363 | { |
bcf393a5 AJ |
1364 | WCHAR *ptr = (WCHAR *)(data + total_size - info_size); |
1365 | if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; | |
a01004d8 AJ |
1366 | } |
1367 | } | |
454355ec | 1368 | else if (status != STATUS_BUFFER_OVERFLOW) goto done; |
2fab2ef1 | 1369 | } |
c6615832 | 1370 | else status = STATUS_SUCCESS; |
bcf393a5 AJ |
1371 | |
1372 | if (type) *type = info->Type; | |
1373 | if (count) *count = total_size - info_size; | |
1374 | ||
1375 | done: | |
454355ec | 1376 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
bcf393a5 | 1377 | return RtlNtStatusToDosError(status); |
2fab2ef1 AJ |
1378 | } |
1379 | ||
1380 | ||
1381 | /****************************************************************************** | |
6a358c40 | 1382 | * RegQueryValueExA [ADVAPI32.@] |
2fab2ef1 | 1383 | * |
50ce0844 JG |
1384 | * Get the type and contents of a specified value under with a key. |
1385 | * | |
1386 | * PARAMS | |
6a358c40 JH |
1387 | * hkey [I] Handle of the key to query |
1388 | * name [I] Name of value under hkey to query | |
1389 | * reserved [I] Reserved - must be NULL | |
1390 | * type [O] Destination for the value type, or NULL if not required | |
1391 | * data [O] Destination for the values contents, or NULL if not required | |
1392 | * count [I/O] Size of data, updated with the number of bytes returned | |
50ce0844 JG |
1393 | * |
1394 | * RETURNS | |
1395 | * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. | |
1396 | * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. | |
1397 | * ERROR_INVALID_PARAMETER, if any other parameter is invalid. | |
1398 | * ERROR_MORE_DATA, if on input *count is too small to hold the contents. | |
1399 | * | |
1400 | * NOTES | |
1401 | * MSDN states that if data is too small it is partially filled. In reality | |
1402 | * it remains untouched. | |
2fab2ef1 | 1403 | */ |
af183df6 | 1404 | LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type, |
0542e835 | 1405 | LPBYTE data, LPDWORD count ) |
2fab2ef1 | 1406 | { |
bcf393a5 AJ |
1407 | NTSTATUS status; |
1408 | ANSI_STRING nameA; | |
acc41b50 | 1409 | UNICODE_STRING nameW; |
1590b1f7 | 1410 | DWORD total_size, datalen = 0; |
454355ec | 1411 | char buffer[256], *buf_ptr = buffer; |
bcf393a5 | 1412 | KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; |
a010932a | 1413 | static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); |
2fab2ef1 | 1414 | |
4301816d | 1415 | TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", |
2fab2ef1 AJ |
1416 | hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); |
1417 | ||
2c655f5e | 1418 | if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 1419 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 1420 | |
1590b1f7 | 1421 | if (count) datalen = *count; |
bc590e87 RS |
1422 | if (!data && count) *count = 0; |
1423 | ||
1424 | /* this matches Win9x behaviour - NT sets *type to a random value */ | |
1425 | if (type) *type = REG_NONE; | |
1426 | ||
bcf393a5 | 1427 | RtlInitAnsiString( &nameA, name ); |
acc41b50 | 1428 | if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) |
454355ec | 1429 | return RtlNtStatusToDosError(status); |
a01004d8 | 1430 | |
acc41b50 AJ |
1431 | status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, |
1432 | buffer, sizeof(buffer), &total_size ); | |
bcf393a5 | 1433 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; |
a01004d8 | 1434 | |
bcf393a5 AJ |
1435 | /* we need to fetch the contents for a string type even if not requested, |
1436 | * because we need to compute the length of the ASCII string. */ | |
1437 | if (data || is_string(info->Type)) | |
2fab2ef1 | 1438 | { |
bcf393a5 AJ |
1439 | /* retry with a dynamically allocated buffer */ |
1440 | while (status == STATUS_BUFFER_OVERFLOW) | |
a01004d8 | 1441 | { |
bcf393a5 AJ |
1442 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
1443 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
454355ec | 1444 | { |
bcf393a5 | 1445 | status = STATUS_NO_MEMORY; |
454355ec AJ |
1446 | goto done; |
1447 | } | |
1448 | info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; | |
acc41b50 AJ |
1449 | status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, |
1450 | buf_ptr, total_size, &total_size ); | |
bcf393a5 AJ |
1451 | } |
1452 | ||
c6615832 AJ |
1453 | if (status) goto done; |
1454 | ||
1455 | if (is_string(info->Type)) | |
bcf393a5 | 1456 | { |
60fd03d2 AJ |
1457 | DWORD len; |
1458 | ||
1459 | RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size), | |
1460 | total_size - info_size ); | |
c6615832 | 1461 | if (data && len) |
a01004d8 | 1462 | { |
1590b1f7 | 1463 | if (len > datalen) status = STATUS_BUFFER_OVERFLOW; |
c6615832 | 1464 | else |
bcf393a5 | 1465 | { |
280bcf6e | 1466 | RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size), |
60fd03d2 | 1467 | total_size - info_size ); |
c6615832 AJ |
1468 | /* if the type is REG_SZ and data is not 0-terminated |
1469 | * and there is enough space in the buffer NT appends a \0 */ | |
1590b1f7 | 1470 | if (len < datalen && data[len-1]) data[len] = 0; |
bcf393a5 | 1471 | } |
57f05e19 | 1472 | } |
c6615832 AJ |
1473 | total_size = len + info_size; |
1474 | } | |
1475 | else if (data) | |
1476 | { | |
1590b1f7 | 1477 | if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; |
c6615832 | 1478 | else memcpy( data, buf_ptr + info_size, total_size - info_size ); |
a01004d8 | 1479 | } |
2fab2ef1 | 1480 | } |
c6615832 | 1481 | else status = STATUS_SUCCESS; |
a01004d8 | 1482 | |
bcf393a5 AJ |
1483 | if (type) *type = info->Type; |
1484 | if (count) *count = total_size - info_size; | |
bcf393a5 AJ |
1485 | |
1486 | done: | |
454355ec | 1487 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
acc41b50 | 1488 | RtlFreeUnicodeString( &nameW ); |
bcf393a5 | 1489 | return RtlNtStatusToDosError(status); |
2fab2ef1 AJ |
1490 | } |
1491 | ||
1492 | ||
1493 | /****************************************************************************** | |
6a358c40 JH |
1494 | * RegQueryValueW [ADVAPI32.@] |
1495 | * | |
1496 | * Retrieves the data associated with the default or unnamed value of a key. | |
1497 | * | |
1498 | * PARAMS | |
bbde53fb AJ |
1499 | * hkey [I] Handle to an open key. |
1500 | * name [I] Name of the subkey of hKey. | |
1501 | * data [O] Receives the string associated with the default value | |
6a358c40 | 1502 | * of the key. |
bbde53fb | 1503 | * count [I/O] Size of lpValue in bytes. |
6a358c40 JH |
1504 | * |
1505 | * RETURNS | |
1506 | * Success: ERROR_SUCCESS | |
1507 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 | 1508 | */ |
af183df6 | 1509 | LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) |
2fab2ef1 AJ |
1510 | { |
1511 | DWORD ret; | |
1512 | HKEY subkey = hkey; | |
1513 | ||
4301816d | 1514 | TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); |
2fab2ef1 AJ |
1515 | |
1516 | if (name && name[0]) | |
1517 | { | |
1518 | if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; | |
1519 | } | |
280bcf6e | 1520 | ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); |
2fab2ef1 AJ |
1521 | if (subkey != hkey) RegCloseKey( subkey ); |
1522 | if (ret == ERROR_FILE_NOT_FOUND) | |
1523 | { | |
1524 | /* return empty string if default value not found */ | |
1525 | if (data) *data = 0; | |
bbde53fb | 1526 | if (count) *count = sizeof(WCHAR); |
2fab2ef1 AJ |
1527 | ret = ERROR_SUCCESS; |
1528 | } | |
1529 | return ret; | |
1530 | } | |
1531 | ||
1532 | ||
1533 | /****************************************************************************** | |
6a358c40 JH |
1534 | * RegQueryValueA [ADVAPI32.@] |
1535 | * | |
d45811ce | 1536 | * See RegQueryValueW. |
2fab2ef1 | 1537 | */ |
af183df6 | 1538 | LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) |
2fab2ef1 AJ |
1539 | { |
1540 | DWORD ret; | |
1541 | HKEY subkey = hkey; | |
1542 | ||
4301816d | 1543 | TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); |
2fab2ef1 AJ |
1544 | |
1545 | if (name && name[0]) | |
1546 | { | |
1547 | if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; | |
1548 | } | |
280bcf6e | 1549 | ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); |
2fab2ef1 AJ |
1550 | if (subkey != hkey) RegCloseKey( subkey ); |
1551 | if (ret == ERROR_FILE_NOT_FOUND) | |
1552 | { | |
1553 | /* return empty string if default value not found */ | |
1554 | if (data) *data = 0; | |
1555 | if (count) *count = 1; | |
1556 | ret = ERROR_SUCCESS; | |
1557 | } | |
1558 | return ret; | |
1559 | } | |
1560 | ||
1561 | ||
48533ae9 FN |
1562 | /****************************************************************************** |
1563 | * ADVAPI_ApplyRestrictions [internal] | |
1564 | * | |
1565 | * Helper function for RegGetValueA/W. | |
1566 | */ | |
2730fe6d JH |
1567 | static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType, |
1568 | DWORD cbData, PLONG ret ) | |
48533ae9 FN |
1569 | { |
1570 | /* Check if the type is restricted by the passed flags */ | |
1571 | if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA) | |
1572 | { | |
1573 | DWORD dwMask = 0; | |
1574 | ||
1575 | switch (dwType) | |
1576 | { | |
1577 | case REG_NONE: dwMask = RRF_RT_REG_NONE; break; | |
1578 | case REG_SZ: dwMask = RRF_RT_REG_SZ; break; | |
1579 | case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break; | |
1580 | case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break; | |
1581 | case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break; | |
1582 | case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break; | |
1583 | case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break; | |
1584 | } | |
1585 | ||
1586 | if (dwFlags & dwMask) | |
1587 | { | |
1588 | /* Type is not restricted, check for size mismatch */ | |
1589 | if (dwType == REG_BINARY) | |
1590 | { | |
1591 | DWORD cbExpect = 0; | |
1592 | ||
96ca7087 | 1593 | if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) |
48533ae9 | 1594 | cbExpect = 4; |
96ca7087 | 1595 | else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) |
48533ae9 FN |
1596 | cbExpect = 8; |
1597 | ||
1598 | if (cbExpect && cbData != cbExpect) | |
1599 | *ret = ERROR_DATATYPE_MISMATCH; | |
1600 | } | |
1601 | } | |
1602 | else *ret = ERROR_UNSUPPORTED_TYPE; | |
1603 | } | |
1604 | } | |
1605 | ||
1606 | ||
1607 | /****************************************************************************** | |
1608 | * RegGetValueW [ADVAPI32.@] | |
1609 | * | |
c47c6483 FG |
1610 | * Retrieves the type and data for a value name associated with a key, |
1611 | * optionally expanding its content and restricting its type. | |
48533ae9 FN |
1612 | * |
1613 | * PARAMS | |
1614 | * hKey [I] Handle to an open key. | |
1615 | * pszSubKey [I] Name of the subkey of hKey. | |
1616 | * pszValue [I] Name of value under hKey/szSubKey to query. | |
1617 | * dwFlags [I] Flags restricting the value type to retrieve. | |
1618 | * pdwType [O] Destination for the values type, may be NULL. | |
1619 | * pvData [O] Destination for the values content, may be NULL. | |
c47c6483 FG |
1620 | * pcbData [I/O] Size of pvData, updated with the size in bytes required to |
1621 | * retrieve the whole content, including the trailing '\0' | |
1622 | * for strings. | |
48533ae9 FN |
1623 | * |
1624 | * RETURNS | |
1625 | * Success: ERROR_SUCCESS | |
1626 | * Failure: nonzero error code from Winerror.h | |
1627 | * | |
1628 | * NOTES | |
c47c6483 FG |
1629 | * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically |
1630 | * expanded and pdwType is set to REG_SZ instead. | |
48533ae9 FN |
1631 | * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ |
1632 | * without RRF_NOEXPAND is thus not allowed. | |
9a7dc159 MK |
1633 | * An exception is the case where RRF_RT_ANY is specified, because then |
1634 | * RRF_NOEXPAND is allowed. | |
48533ae9 | 1635 | */ |
af183df6 | 1636 | LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, |
48533ae9 FN |
1637 | DWORD dwFlags, LPDWORD pdwType, PVOID pvData, |
1638 | LPDWORD pcbData ) | |
1639 | { | |
1640 | DWORD dwType, cbData = pcbData ? *pcbData : 0; | |
1641 | PVOID pvBuf = NULL; | |
1642 | LONG ret; | |
1643 | ||
4301816d | 1644 | TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", |
48533ae9 FN |
1645 | hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, |
1646 | pvData, pcbData, cbData); | |
1647 | ||
1da7a32b FG |
1648 | if (pvData && !pcbData) |
1649 | return ERROR_INVALID_PARAMETER; | |
9a7dc159 MK |
1650 | if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && |
1651 | ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) | |
48533ae9 FN |
1652 | return ERROR_INVALID_PARAMETER; |
1653 | ||
1654 | if (pszSubKey && pszSubKey[0]) | |
1655 | { | |
1656 | ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); | |
1657 | if (ret != ERROR_SUCCESS) return ret; | |
1658 | } | |
1659 | ||
1660 | ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData); | |
1661 | ||
1662 | /* If we are going to expand we need to read in the whole the value even | |
1663 | * if the passed buffer was too small as the expanded string might be | |
1664 | * smaller than the unexpanded one and could fit into cbData bytes. */ | |
1665 | if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && | |
1da7a32b | 1666 | dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) |
48533ae9 FN |
1667 | { |
1668 | do { | |
a8752003 | 1669 | HeapFree(GetProcessHeap(), 0, pvBuf); |
48533ae9 FN |
1670 | |
1671 | pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); | |
1672 | if (!pvBuf) | |
1673 | { | |
1674 | ret = ERROR_NOT_ENOUGH_MEMORY; | |
1675 | break; | |
1676 | } | |
1677 | ||
1da7a32b | 1678 | if (ret == ERROR_MORE_DATA || !pvData) |
48533ae9 FN |
1679 | ret = RegQueryValueExW(hKey, pszValue, NULL, |
1680 | &dwType, pvBuf, &cbData); | |
1681 | else | |
1682 | { | |
1683 | /* Even if cbData was large enough we have to copy the | |
1684 | * string since ExpandEnvironmentStrings can't handle | |
1685 | * overlapping buffers. */ | |
1686 | CopyMemory(pvBuf, pvData, cbData); | |
1687 | } | |
1688 | ||
1689 | /* Both the type or the value itself could have been modified in | |
1690 | * between so we have to keep retrying until the buffer is large | |
1691 | * enough or we no longer have to expand the value. */ | |
1692 | } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); | |
1693 | ||
1694 | if (ret == ERROR_SUCCESS) | |
1695 | { | |
1da7a32b | 1696 | /* Recheck dwType in case it changed since the first call */ |
48533ae9 FN |
1697 | if (dwType == REG_EXPAND_SZ) |
1698 | { | |
1699 | cbData = ExpandEnvironmentStringsW(pvBuf, pvData, | |
d9a06b23 | 1700 | pcbData ? *pcbData : 0) * sizeof(WCHAR); |
48533ae9 | 1701 | dwType = REG_SZ; |
c47c6483 | 1702 | if(pvData && pcbData && cbData > *pcbData) |
48533ae9 FN |
1703 | ret = ERROR_MORE_DATA; |
1704 | } | |
1da7a32b | 1705 | else if (pvData) |
48533ae9 FN |
1706 | CopyMemory(pvData, pvBuf, *pcbData); |
1707 | } | |
1708 | ||
a8752003 | 1709 | HeapFree(GetProcessHeap(), 0, pvBuf); |
48533ae9 FN |
1710 | } |
1711 | ||
1712 | if (pszSubKey && pszSubKey[0]) | |
1713 | RegCloseKey(hKey); | |
1714 | ||
1715 | ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret); | |
1716 | ||
1da7a32b | 1717 | if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) |
48533ae9 FN |
1718 | ZeroMemory(pvData, *pcbData); |
1719 | ||
1720 | if (pdwType) *pdwType = dwType; | |
1721 | if (pcbData) *pcbData = cbData; | |
1722 | ||
1723 | return ret; | |
1724 | } | |
1725 | ||
1726 | ||
1727 | /****************************************************************************** | |
1728 | * RegGetValueA [ADVAPI32.@] | |
1729 | * | |
1730 | * See RegGetValueW. | |
1731 | */ | |
af183df6 | 1732 | LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, |
48533ae9 FN |
1733 | DWORD dwFlags, LPDWORD pdwType, PVOID pvData, |
1734 | LPDWORD pcbData ) | |
1735 | { | |
1736 | DWORD dwType, cbData = pcbData ? *pcbData : 0; | |
1737 | PVOID pvBuf = NULL; | |
1738 | LONG ret; | |
1739 | ||
4301816d | 1740 | TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", |
48533ae9 FN |
1741 | hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData, |
1742 | cbData); | |
1743 | ||
1da7a32b FG |
1744 | if (pvData && !pcbData) |
1745 | return ERROR_INVALID_PARAMETER; | |
9a7dc159 MK |
1746 | if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && |
1747 | ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) | |
48533ae9 FN |
1748 | return ERROR_INVALID_PARAMETER; |
1749 | ||
1750 | if (pszSubKey && pszSubKey[0]) | |
1751 | { | |
1752 | ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); | |
1753 | if (ret != ERROR_SUCCESS) return ret; | |
1754 | } | |
1755 | ||
1756 | ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData); | |
1757 | ||
1758 | /* If we are going to expand we need to read in the whole the value even | |
1759 | * if the passed buffer was too small as the expanded string might be | |
1760 | * smaller than the unexpanded one and could fit into cbData bytes. */ | |
1761 | if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && | |
1da7a32b | 1762 | dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) |
48533ae9 FN |
1763 | { |
1764 | do { | |
a8752003 | 1765 | HeapFree(GetProcessHeap(), 0, pvBuf); |
48533ae9 FN |
1766 | |
1767 | pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); | |
1768 | if (!pvBuf) | |
1769 | { | |
1770 | ret = ERROR_NOT_ENOUGH_MEMORY; | |
1771 | break; | |
1772 | } | |
1773 | ||
1da7a32b | 1774 | if (ret == ERROR_MORE_DATA || !pvData) |
48533ae9 FN |
1775 | ret = RegQueryValueExA(hKey, pszValue, NULL, |
1776 | &dwType, pvBuf, &cbData); | |
1777 | else | |
1778 | { | |
1779 | /* Even if cbData was large enough we have to copy the | |
1780 | * string since ExpandEnvironmentStrings can't handle | |
1781 | * overlapping buffers. */ | |
1782 | CopyMemory(pvBuf, pvData, cbData); | |
1783 | } | |
1784 | ||
1785 | /* Both the type or the value itself could have been modified in | |
1786 | * between so we have to keep retrying until the buffer is large | |
1787 | * enough or we no longer have to expand the value. */ | |
1788 | } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); | |
1789 | ||
1790 | if (ret == ERROR_SUCCESS) | |
1791 | { | |
1da7a32b | 1792 | /* Recheck dwType in case it changed since the first call */ |
48533ae9 FN |
1793 | if (dwType == REG_EXPAND_SZ) |
1794 | { | |
1795 | cbData = ExpandEnvironmentStringsA(pvBuf, pvData, | |
1796 | pcbData ? *pcbData : 0); | |
1797 | dwType = REG_SZ; | |
c47c6483 | 1798 | if(pvData && pcbData && cbData > *pcbData) |
48533ae9 FN |
1799 | ret = ERROR_MORE_DATA; |
1800 | } | |
1da7a32b | 1801 | else if (pvData) |
48533ae9 FN |
1802 | CopyMemory(pvData, pvBuf, *pcbData); |
1803 | } | |
1804 | ||
a8752003 | 1805 | HeapFree(GetProcessHeap(), 0, pvBuf); |
48533ae9 FN |
1806 | } |
1807 | ||
1808 | if (pszSubKey && pszSubKey[0]) | |
1809 | RegCloseKey(hKey); | |
1810 | ||
1811 | ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret); | |
1812 | ||
1da7a32b | 1813 | if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) |
48533ae9 FN |
1814 | ZeroMemory(pvData, *pcbData); |
1815 | ||
1816 | if (pdwType) *pdwType = dwType; | |
1817 | if (pcbData) *pcbData = cbData; | |
1818 | ||
1819 | return ret; | |
1820 | } | |
1821 | ||
1822 | ||
2fab2ef1 | 1823 | /****************************************************************************** |
6a358c40 | 1824 | * RegEnumValueW [ADVAPI32.@] |
2fab2ef1 | 1825 | * |
d45811ce MA |
1826 | * Enumerates the values for the specified open registry key. |
1827 | * | |
2fab2ef1 | 1828 | * PARAMS |
6a358c40 JH |
1829 | * hkey [I] Handle to key to query |
1830 | * index [I] Index of value to query | |
1831 | * value [O] Value string | |
1832 | * val_count [I/O] Size of value buffer (in wchars) | |
1833 | * reserved [I] Reserved | |
1834 | * type [O] Type code | |
1835 | * data [O] Value data | |
1836 | * count [I/O] Size of data buffer (in bytes) | |
1837 | * | |
1838 | * RETURNS | |
1839 | * Success: ERROR_SUCCESS | |
1840 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 AJ |
1841 | */ |
1842 | ||
af183df6 | 1843 | LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count, |
0542e835 | 1844 | LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) |
2fab2ef1 | 1845 | { |
0b6a79c9 AJ |
1846 | NTSTATUS status; |
1847 | DWORD total_size; | |
1848 | char buffer[256], *buf_ptr = buffer; | |
1849 | KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; | |
a010932a | 1850 | static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); |
2fab2ef1 | 1851 | |
4301816d | 1852 | TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", |
2fab2ef1 AJ |
1853 | hkey, index, value, val_count, reserved, type, data, count ); |
1854 | ||
1855 | /* NT only checks count, not val_count */ | |
2c655f5e | 1856 | if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 1857 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 1858 | |
0b6a79c9 AJ |
1859 | total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); |
1860 | if (data) total_size += *count; | |
1861 | total_size = min( sizeof(buffer), total_size ); | |
2fab2ef1 | 1862 | |
0b6a79c9 AJ |
1863 | status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, |
1864 | buffer, total_size, &total_size ); | |
1865 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; | |
2fab2ef1 | 1866 | |
0b6a79c9 | 1867 | if (value || data) |
a01004d8 | 1868 | { |
0b6a79c9 AJ |
1869 | /* retry with a dynamically allocated buffer */ |
1870 | while (status == STATUS_BUFFER_OVERFLOW) | |
1871 | { | |
1872 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
1873 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
1874 | return ERROR_NOT_ENOUGH_MEMORY; | |
1875 | info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr; | |
1876 | status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, | |
1877 | buf_ptr, total_size, &total_size ); | |
1878 | } | |
1879 | ||
1880 | if (status) goto done; | |
1881 | ||
1882 | if (value) | |
1883 | { | |
1884 | if (info->NameLength/sizeof(WCHAR) >= *val_count) | |
1885 | { | |
1886 | status = STATUS_BUFFER_OVERFLOW; | |
c1dddbea | 1887 | goto overflow; |
0b6a79c9 AJ |
1888 | } |
1889 | memcpy( value, info->Name, info->NameLength ); | |
1890 | *val_count = info->NameLength / sizeof(WCHAR); | |
1891 | value[*val_count] = 0; | |
1892 | } | |
1893 | ||
1894 | if (data) | |
a01004d8 | 1895 | { |
0b6a79c9 | 1896 | if (total_size - info->DataOffset > *count) |
a01004d8 | 1897 | { |
0b6a79c9 | 1898 | status = STATUS_BUFFER_OVERFLOW; |
c1dddbea | 1899 | goto overflow; |
0b6a79c9 AJ |
1900 | } |
1901 | memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset ); | |
1902 | if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type)) | |
1903 | { | |
1904 | /* if the type is REG_SZ and data is not 0-terminated | |
1905 | * and there is enough space in the buffer NT appends a \0 */ | |
1906 | WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset); | |
1907 | if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; | |
a01004d8 AJ |
1908 | } |
1909 | } | |
a01004d8 | 1910 | } |
c6615832 | 1911 | else status = STATUS_SUCCESS; |
0b6a79c9 | 1912 | |
c1dddbea | 1913 | overflow: |
0b6a79c9 AJ |
1914 | if (type) *type = info->Type; |
1915 | if (count) *count = info->DataLength; | |
1916 | ||
1917 | done: | |
1918 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
1919 | return RtlNtStatusToDosError(status); | |
2fab2ef1 AJ |
1920 | } |
1921 | ||
1922 | ||
1923 | /****************************************************************************** | |
6a358c40 JH |
1924 | * RegEnumValueA [ADVAPI32.@] |
1925 | * | |
d45811ce | 1926 | * See RegEnumValueW. |
2fab2ef1 | 1927 | */ |
af183df6 | 1928 | LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, |
0542e835 | 1929 | LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count ) |
2fab2ef1 | 1930 | { |
0b6a79c9 AJ |
1931 | NTSTATUS status; |
1932 | DWORD total_size; | |
1933 | char buffer[256], *buf_ptr = buffer; | |
1934 | KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; | |
a010932a | 1935 | static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name ); |
2fab2ef1 | 1936 | |
4301816d | 1937 | TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n", |
2fab2ef1 AJ |
1938 | hkey, index, value, val_count, reserved, type, data, count ); |
1939 | ||
1940 | /* NT only checks count, not val_count */ | |
2c655f5e | 1941 | if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; |
f2ef2c2b | 1942 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 | 1943 | |
0b6a79c9 AJ |
1944 | total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); |
1945 | if (data) total_size += *count; | |
1946 | total_size = min( sizeof(buffer), total_size ); | |
2fab2ef1 | 1947 | |
0b6a79c9 AJ |
1948 | status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, |
1949 | buffer, total_size, &total_size ); | |
1950 | if (status && status != STATUS_BUFFER_OVERFLOW) goto done; | |
a01004d8 | 1951 | |
0b6a79c9 AJ |
1952 | /* we need to fetch the contents for a string type even if not requested, |
1953 | * because we need to compute the length of the ASCII string. */ | |
1954 | if (value || data || is_string(info->Type)) | |
a01004d8 | 1955 | { |
0b6a79c9 AJ |
1956 | /* retry with a dynamically allocated buffer */ |
1957 | while (status == STATUS_BUFFER_OVERFLOW) | |
a01004d8 | 1958 | { |
0b6a79c9 AJ |
1959 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); |
1960 | if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) | |
1961 | return ERROR_NOT_ENOUGH_MEMORY; | |
1962 | info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr; | |
1963 | status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation, | |
1964 | buf_ptr, total_size, &total_size ); | |
1965 | } | |
1966 | ||
1967 | if (status) goto done; | |
1968 | ||
0b6a79c9 AJ |
1969 | if (is_string(info->Type)) |
1970 | { | |
60fd03d2 AJ |
1971 | DWORD len; |
1972 | RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset), | |
1973 | total_size - info->DataOffset ); | |
0b6a79c9 AJ |
1974 | if (data && len) |
1975 | { | |
c1dddbea AJ |
1976 | if (len > *count) status = STATUS_BUFFER_OVERFLOW; |
1977 | else | |
0b6a79c9 | 1978 | { |
280bcf6e | 1979 | RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset), |
c1dddbea AJ |
1980 | total_size - info->DataOffset ); |
1981 | /* if the type is REG_SZ and data is not 0-terminated | |
1982 | * and there is enough space in the buffer NT appends a \0 */ | |
1983 | if (len < *count && data[len-1]) data[len] = 0; | |
0b6a79c9 | 1984 | } |
a01004d8 | 1985 | } |
0b6a79c9 AJ |
1986 | info->DataLength = len; |
1987 | } | |
1988 | else if (data) | |
1989 | { | |
1990 | if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW; | |
1991 | else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset ); | |
a01004d8 | 1992 | } |
c1dddbea AJ |
1993 | |
1994 | if (value && !status) | |
1995 | { | |
1996 | DWORD len; | |
1997 | ||
1998 | RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); | |
1999 | if (len >= *val_count) | |
2000 | { | |
2001 | status = STATUS_BUFFER_OVERFLOW; | |
2002 | if (*val_count) | |
2003 | { | |
2004 | len = *val_count - 1; | |
2005 | RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength ); | |
2006 | value[len] = 0; | |
2007 | } | |
2008 | } | |
2009 | else | |
2010 | { | |
2011 | RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength ); | |
2012 | value[len] = 0; | |
2013 | *val_count = len; | |
2014 | } | |
2015 | } | |
a01004d8 | 2016 | } |
c6615832 | 2017 | else status = STATUS_SUCCESS; |
a01004d8 | 2018 | |
0b6a79c9 AJ |
2019 | if (type) *type = info->Type; |
2020 | if (count) *count = info->DataLength; | |
2021 | ||
2022 | done: | |
2023 | if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); | |
2024 | return RtlNtStatusToDosError(status); | |
2fab2ef1 AJ |
2025 | } |
2026 | ||
2027 | ||
2028 | ||
2029 | /****************************************************************************** | |
6a358c40 | 2030 | * RegDeleteValueW [ADVAPI32.@] |
2fab2ef1 | 2031 | * |
cd4234aa | 2032 | * See RegDeleteValueA. |
2fab2ef1 | 2033 | */ |
af183df6 | 2034 | LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name ) |
2fab2ef1 | 2035 | { |
bcf393a5 | 2036 | UNICODE_STRING nameW; |
f2ef2c2b AJ |
2037 | |
2038 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; | |
2039 | ||
bcf393a5 AJ |
2040 | RtlInitUnicodeString( &nameW, name ); |
2041 | return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) ); | |
2fab2ef1 AJ |
2042 | } |
2043 | ||
2044 | ||
2045 | /****************************************************************************** | |
6a358c40 | 2046 | * RegDeleteValueA [ADVAPI32.@] |
cd4234aa JG |
2047 | * |
2048 | * Delete a value from the registry. | |
2049 | * | |
2050 | * PARAMS | |
2051 | * hkey [I] Registry handle of the key holding the value | |
2052 | * name [I] Name of the value under hkey to delete | |
2053 | * | |
2054 | * RETURNS | |
6a358c40 JH |
2055 | * Success: ERROR_SUCCESS |
2056 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 | 2057 | */ |
af183df6 | 2058 | LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name ) |
2fab2ef1 | 2059 | { |
acc41b50 AJ |
2060 | ANSI_STRING nameA; |
2061 | UNICODE_STRING nameW; | |
bcf393a5 | 2062 | NTSTATUS status; |
2fab2ef1 | 2063 | |
f2ef2c2b AJ |
2064 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2065 | ||
bcf393a5 | 2066 | RtlInitAnsiString( &nameA, name ); |
acc41b50 AJ |
2067 | if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) |
2068 | { | |
2069 | status = NtDeleteValueKey( hkey, &nameW ); | |
2070 | RtlFreeUnicodeString( &nameW ); | |
2071 | } | |
bcf393a5 | 2072 | return RtlNtStatusToDosError( status ); |
2fab2ef1 AJ |
2073 | } |
2074 | ||
2075 | ||
2076 | /****************************************************************************** | |
6a358c40 | 2077 | * RegLoadKeyW [ADVAPI32.@] |
2fab2ef1 | 2078 | * |
ec350525 MA |
2079 | * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store |
2080 | * registration information from a specified file into that subkey. | |
2081 | * | |
2fab2ef1 | 2082 | * PARAMS |
6a358c40 JH |
2083 | * hkey [I] Handle of open key |
2084 | * subkey [I] Address of name of subkey | |
2085 | * filename [I] Address of filename for registry information | |
2086 | * | |
2087 | * RETURNS | |
30e44c85 | 2088 | * Success: ERROR_SUCCESS |
6a358c40 | 2089 | * Failure: nonzero error code from Winerror.h |
2fab2ef1 | 2090 | */ |
af183df6 | 2091 | LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename ) |
2fab2ef1 | 2092 | { |
580ded65 JH |
2093 | OBJECT_ATTRIBUTES destkey, file; |
2094 | UNICODE_STRING subkeyW, filenameW; | |
4dfd319d | 2095 | NTSTATUS status; |
580ded65 JH |
2096 | |
2097 | if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE; | |
2098 | ||
2099 | destkey.Length = sizeof(destkey); | |
2100 | destkey.RootDirectory = hkey; /* root key: HKLM or HKU */ | |
2101 | destkey.ObjectName = &subkeyW; /* name of the key */ | |
2102 | destkey.Attributes = 0; | |
2103 | destkey.SecurityDescriptor = NULL; | |
2104 | destkey.SecurityQualityOfService = NULL; | |
2105 | RtlInitUnicodeString(&subkeyW, subkey); | |
2106 | ||
2107 | file.Length = sizeof(file); | |
2108 | file.RootDirectory = NULL; | |
2109 | file.ObjectName = &filenameW; /* file containing the hive */ | |
2110 | file.Attributes = OBJ_CASE_INSENSITIVE; | |
2111 | file.SecurityDescriptor = NULL; | |
2112 | file.SecurityQualityOfService = NULL; | |
2113 | RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL); | |
2114 | ||
4dfd319d EP |
2115 | status = NtLoadKey(&destkey, &file); |
2116 | RtlFreeUnicodeString(&filenameW); | |
2117 | return RtlNtStatusToDosError( status ); | |
2fab2ef1 AJ |
2118 | } |
2119 | ||
2120 | ||
2121 | /****************************************************************************** | |
6a358c40 JH |
2122 | * RegLoadKeyA [ADVAPI32.@] |
2123 | * | |
d45811ce | 2124 | * See RegLoadKeyW. |
2fab2ef1 | 2125 | */ |
af183df6 | 2126 | LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename ) |
2fab2ef1 | 2127 | { |
580ded65 JH |
2128 | UNICODE_STRING subkeyW, filenameW; |
2129 | STRING subkeyA, filenameA; | |
2130 | NTSTATUS status; | |
4dfd319d | 2131 | LONG ret; |
57f05e19 | 2132 | |
580ded65 JH |
2133 | RtlInitAnsiString(&subkeyA, subkey); |
2134 | RtlInitAnsiString(&filenameA, filename); | |
57f05e19 | 2135 | |
4dfd319d EP |
2136 | RtlInitUnicodeString(&subkeyW, NULL); |
2137 | RtlInitUnicodeString(&filenameW, NULL); | |
2138 | if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) && | |
2139 | !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE))) | |
2140 | { | |
2141 | ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer); | |
2142 | } | |
2143 | else ret = RtlNtStatusToDosError(status); | |
2144 | RtlFreeUnicodeString(&subkeyW); | |
2145 | RtlFreeUnicodeString(&filenameW); | |
2146 | return ret; | |
2fab2ef1 AJ |
2147 | } |
2148 | ||
2149 | ||
2150 | /****************************************************************************** | |
6a358c40 | 2151 | * RegSaveKeyW [ADVAPI32.@] |
2fab2ef1 | 2152 | * |
ec350525 MA |
2153 | * Save a key and all of its subkeys and values to a new file in the standard format. |
2154 | * | |
2fab2ef1 | 2155 | * PARAMS |
6a358c40 JH |
2156 | * hkey [I] Handle of key where save begins |
2157 | * lpFile [I] Address of filename to save to | |
2158 | * sa [I] Address of security structure | |
2159 | * | |
2160 | * RETURNS | |
2161 | * Success: ERROR_SUCCESS | |
2162 | * Failure: nonzero error code from Winerror.h | |
2fab2ef1 | 2163 | */ |
af183df6 | 2164 | LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa ) |
2fab2ef1 | 2165 | { |
4550b8b7 TL |
2166 | static const WCHAR format[] = |
2167 | {'r','e','g','%','0','4','x','.','t','m','p',0}; | |
2168 | WCHAR buffer[MAX_PATH]; | |
2fab2ef1 | 2169 | int count = 0; |
4550b8b7 | 2170 | LPWSTR nameW; |
2fab2ef1 | 2171 | DWORD ret, err; |
7375597f | 2172 | HANDLE handle; |
2fab2ef1 | 2173 | |
4550b8b7 | 2174 | TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa ); |
2fab2ef1 AJ |
2175 | |
2176 | if (!file || !*file) return ERROR_INVALID_PARAMETER; | |
f2ef2c2b | 2177 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
2fab2ef1 AJ |
2178 | |
2179 | err = GetLastError(); | |
4550b8b7 TL |
2180 | GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW ); |
2181 | ||
2fab2ef1 AJ |
2182 | for (;;) |
2183 | { | |
4550b8b7 TL |
2184 | snprintfW( nameW, 16, format, count++ ); |
2185 | handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, | |
da2b6a9f | 2186 | CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); |
2fab2ef1 | 2187 | if (handle != INVALID_HANDLE_VALUE) break; |
3d73173f | 2188 | if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done; |
6297451d AM |
2189 | |
2190 | /* Something gone haywire ? Please report if this happens abnormally */ | |
2191 | if (count >= 100) | |
4550b8b7 | 2192 | MESSAGE("Wow, we are already fiddling with a temp file %s with an ordinal as high as %d !\nYou might want to delete all corresponding temp files in that directory.\n", debugstr_w(buffer), count); |
2fab2ef1 AJ |
2193 | } |
2194 | ||
f74b0adb | 2195 | ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle)); |
57f05e19 | 2196 | |
2fab2ef1 AJ |
2197 | CloseHandle( handle ); |
2198 | if (!ret) | |
2199 | { | |
4550b8b7 | 2200 | if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING )) |
2fab2ef1 | 2201 | { |
4550b8b7 TL |
2202 | ERR( "Failed to move %s to %s\n", debugstr_w(buffer), |
2203 | debugstr_w(file) ); | |
2fab2ef1 AJ |
2204 | ret = GetLastError(); |
2205 | } | |
2206 | } | |
4550b8b7 | 2207 | if (ret) DeleteFileW( buffer ); |
2fab2ef1 AJ |
2208 | |
2209 | done: | |
2210 | SetLastError( err ); /* restore last error code */ | |
2211 | return ret; | |
2212 | } | |
2213 | ||
2214 | ||
2215 | /****************************************************************************** | |
6a358c40 JH |
2216 | * RegSaveKeyA [ADVAPI32.@] |
2217 | * | |
d45811ce | 2218 | * See RegSaveKeyW. |
2fab2ef1 | 2219 | */ |
af183df6 | 2220 | LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa ) |
2fab2ef1 | 2221 | { |
4550b8b7 TL |
2222 | UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString; |
2223 | NTSTATUS status; | |
2224 | STRING fileA; | |
2225 | ||
2226 | RtlInitAnsiString(&fileA, file); | |
2227 | if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE))) | |
2228 | return RtlNtStatusToDosError( status ); | |
2229 | return RegSaveKeyW(hkey, fileW->Buffer, sa); | |
2fab2ef1 | 2230 | } |
5ce2329a AJ |
2231 | |
2232 | ||
2233 | /****************************************************************************** | |
d0a41774 | 2234 | * RegRestoreKeyW [ADVAPI32.@] |
5ce2329a | 2235 | * |
ec350525 MA |
2236 | * Read the registry information from a file and copy it over a key. |
2237 | * | |
5ce2329a | 2238 | * PARAMS |
6a358c40 JH |
2239 | * hkey [I] Handle of key where restore begins |
2240 | * lpFile [I] Address of filename containing saved tree | |
2241 | * dwFlags [I] Optional flags | |
2242 | * | |
2243 | * RETURNS | |
2244 | * Success: ERROR_SUCCESS | |
2245 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2246 | */ |
af183df6 | 2247 | LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags ) |
5ce2329a | 2248 | { |
4301816d | 2249 | TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags); |
5ce2329a AJ |
2250 | |
2251 | /* It seems to do this check before the hkey check */ | |
2252 | if (!lpFile || !*lpFile) | |
2253 | return ERROR_INVALID_PARAMETER; | |
2254 | ||
4301816d | 2255 | FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags); |
5ce2329a AJ |
2256 | |
2257 | /* Check for file existence */ | |
2258 | ||
2259 | return ERROR_SUCCESS; | |
2260 | } | |
2261 | ||
2262 | ||
2263 | /****************************************************************************** | |
d0a41774 | 2264 | * RegRestoreKeyA [ADVAPI32.@] |
6a358c40 | 2265 | * |
d45811ce | 2266 | * See RegRestoreKeyW. |
5ce2329a | 2267 | */ |
af183df6 | 2268 | LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags ) |
5ce2329a | 2269 | { |
6f2a071d MD |
2270 | UNICODE_STRING lpFileW; |
2271 | LONG ret; | |
2272 | ||
2273 | RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile ); | |
2274 | ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags ); | |
2275 | RtlFreeUnicodeString( &lpFileW ); | |
5ce2329a AJ |
2276 | return ret; |
2277 | } | |
2278 | ||
2279 | ||
2280 | /****************************************************************************** | |
d0a41774 | 2281 | * RegUnLoadKeyW [ADVAPI32.@] |
5ce2329a | 2282 | * |
ec350525 MA |
2283 | * Unload a registry key and its subkeys from the registry. |
2284 | * | |
5ce2329a | 2285 | * PARAMS |
6a358c40 JH |
2286 | * hkey [I] Handle of open key |
2287 | * lpSubKey [I] Address of name of subkey to unload | |
2288 | * | |
2289 | * RETURNS | |
2290 | * Success: ERROR_SUCCESS | |
2291 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2292 | */ |
af183df6 | 2293 | LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey ) |
5ce2329a | 2294 | { |
5ac945c0 MM |
2295 | DWORD ret; |
2296 | HKEY shkey; | |
fdff5c3a BJY |
2297 | OBJECT_ATTRIBUTES attr; |
2298 | UNICODE_STRING subkey; | |
5ac945c0 MM |
2299 | |
2300 | TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey)); | |
2301 | ||
2302 | ret = RegOpenKeyW(hkey,lpSubKey,&shkey); | |
2303 | if( ret ) | |
2304 | return ERROR_INVALID_PARAMETER; | |
2305 | ||
fdff5c3a BJY |
2306 | RtlInitUnicodeString(&subkey, lpSubKey); |
2307 | InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL); | |
2308 | ret = RtlNtStatusToDosError(NtUnloadKey(&attr)); | |
f74b0adb | 2309 | |
5ac945c0 MM |
2310 | RegCloseKey(shkey); |
2311 | ||
2312 | return ret; | |
5ce2329a AJ |
2313 | } |
2314 | ||
2315 | ||
2316 | /****************************************************************************** | |
d0a41774 | 2317 | * RegUnLoadKeyA [ADVAPI32.@] |
6a358c40 | 2318 | * |
d45811ce | 2319 | * See RegUnLoadKeyW. |
5ce2329a | 2320 | */ |
af183df6 | 2321 | LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) |
5ce2329a | 2322 | { |
6f2a071d MD |
2323 | UNICODE_STRING lpSubKeyW; |
2324 | LONG ret; | |
2325 | ||
2326 | RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey ); | |
2327 | ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer ); | |
2328 | RtlFreeUnicodeString( &lpSubKeyW ); | |
5ce2329a AJ |
2329 | return ret; |
2330 | } | |
2331 | ||
2332 | ||
2333 | /****************************************************************************** | |
d0a41774 | 2334 | * RegReplaceKeyW [ADVAPI32.@] |
5ce2329a | 2335 | * |
ec350525 MA |
2336 | * Replace the file backing a registry key and all its subkeys with another file. |
2337 | * | |
5ce2329a | 2338 | * PARAMS |
6a358c40 JH |
2339 | * hkey [I] Handle of open key |
2340 | * lpSubKey [I] Address of name of subkey | |
2341 | * lpNewFile [I] Address of filename for file with new data | |
2342 | * lpOldFile [I] Address of filename for backup file | |
2343 | * | |
2344 | * RETURNS | |
2345 | * Success: ERROR_SUCCESS | |
2346 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2347 | */ |
af183df6 | 2348 | LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile, |
5ce2329a AJ |
2349 | LPCWSTR lpOldFile ) |
2350 | { | |
cbacde52 | 2351 | FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), |
5ce2329a AJ |
2352 | debugstr_w(lpNewFile),debugstr_w(lpOldFile)); |
2353 | return ERROR_SUCCESS; | |
2354 | } | |
2355 | ||
2356 | ||
2357 | /****************************************************************************** | |
d0a41774 | 2358 | * RegReplaceKeyA [ADVAPI32.@] |
6a358c40 | 2359 | * |
d45811ce | 2360 | * See RegReplaceKeyW. |
5ce2329a | 2361 | */ |
af183df6 | 2362 | LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, |
5ce2329a AJ |
2363 | LPCSTR lpOldFile ) |
2364 | { | |
6f2a071d MD |
2365 | UNICODE_STRING lpSubKeyW; |
2366 | UNICODE_STRING lpNewFileW; | |
2367 | UNICODE_STRING lpOldFileW; | |
2368 | LONG ret; | |
2369 | ||
2370 | RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey ); | |
2371 | RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile ); | |
2372 | RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile ); | |
2373 | ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer ); | |
2374 | RtlFreeUnicodeString( &lpOldFileW ); | |
2375 | RtlFreeUnicodeString( &lpNewFileW ); | |
2376 | RtlFreeUnicodeString( &lpSubKeyW ); | |
5ce2329a AJ |
2377 | return ret; |
2378 | } | |
2379 | ||
2380 | ||
2381 | /****************************************************************************** | |
d0a41774 | 2382 | * RegSetKeySecurity [ADVAPI32.@] |
5ce2329a | 2383 | * |
ec350525 MA |
2384 | * Set the security of an open registry key. |
2385 | * | |
5ce2329a | 2386 | * PARAMS |
6a358c40 JH |
2387 | * hkey [I] Open handle of key to set |
2388 | * SecurityInfo [I] Descriptor contents | |
2389 | * pSecurityDesc [I] Address of descriptor for key | |
2390 | * | |
2391 | * RETURNS | |
2392 | * Success: ERROR_SUCCESS | |
2393 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2394 | */ |
af183df6 | 2395 | LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo, |
5ce2329a AJ |
2396 | PSECURITY_DESCRIPTOR pSecurityDesc ) |
2397 | { | |
4301816d | 2398 | TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc); |
5ce2329a AJ |
2399 | |
2400 | /* It seems to perform this check before the hkey check */ | |
2401 | if ((SecurityInfo & OWNER_SECURITY_INFORMATION) || | |
2402 | (SecurityInfo & GROUP_SECURITY_INFORMATION) || | |
2403 | (SecurityInfo & DACL_SECURITY_INFORMATION) || | |
2404 | (SecurityInfo & SACL_SECURITY_INFORMATION)) { | |
2405 | /* Param OK */ | |
2406 | } else | |
2407 | return ERROR_INVALID_PARAMETER; | |
2408 | ||
2409 | if (!pSecurityDesc) | |
2410 | return ERROR_INVALID_PARAMETER; | |
2411 | ||
4301816d | 2412 | FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc); |
5ce2329a AJ |
2413 | |
2414 | return ERROR_SUCCESS; | |
2415 | } | |
2416 | ||
2417 | ||
2418 | /****************************************************************************** | |
d0a41774 | 2419 | * RegGetKeySecurity [ADVAPI32.@] |
50ce0844 JG |
2420 | * |
2421 | * Get a copy of the security descriptor for a given registry key. | |
5ce2329a AJ |
2422 | * |
2423 | * PARAMS | |
6a358c40 JH |
2424 | * hkey [I] Open handle of key to set |
2425 | * SecurityInformation [I] Descriptor contents | |
2426 | * pSecurityDescriptor [O] Address of descriptor for key | |
2427 | * lpcbSecurityDescriptor [I/O] Address of size of buffer and description | |
5ce2329a AJ |
2428 | * |
2429 | * RETURNS | |
6a358c40 JH |
2430 | * Success: ERROR_SUCCESS |
2431 | * Failure: Error code | |
5ce2329a | 2432 | */ |
af183df6 | 2433 | LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation, |
5ce2329a AJ |
2434 | PSECURITY_DESCRIPTOR pSecurityDescriptor, |
2435 | LPDWORD lpcbSecurityDescriptor ) | |
2436 | { | |
4301816d | 2437 | TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor, |
7579145a | 2438 | *lpcbSecurityDescriptor); |
5ce2329a | 2439 | |
81e7d69d | 2440 | if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE; |
79313d37 | 2441 | |
81e7d69d JL |
2442 | return RtlNtStatusToDosError( NtQuerySecurityObject( hkey, |
2443 | SecurityInformation, pSecurityDescriptor, | |
2444 | *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) ); | |
5ce2329a AJ |
2445 | } |
2446 | ||
2447 | ||
2448 | /****************************************************************************** | |
d0a41774 | 2449 | * RegFlushKey [ADVAPI32.@] |
50ce0844 JG |
2450 | * |
2451 | * Immediately write a registry key to registry. | |
5ce2329a AJ |
2452 | * |
2453 | * PARAMS | |
6a358c40 | 2454 | * hkey [I] Handle of key to write |
5ce2329a AJ |
2455 | * |
2456 | * RETURNS | |
6a358c40 JH |
2457 | * Success: ERROR_SUCCESS |
2458 | * Failure: Error code | |
5ce2329a | 2459 | */ |
af183df6 | 2460 | LSTATUS WINAPI RegFlushKey( HKEY hkey ) |
5ce2329a | 2461 | { |
43cb03be MH |
2462 | hkey = get_special_root_hkey( hkey ); |
2463 | if (!hkey) return ERROR_INVALID_HANDLE; | |
2464 | ||
2465 | return RtlNtStatusToDosError( NtFlushKey( hkey ) ); | |
5ce2329a AJ |
2466 | } |
2467 | ||
2468 | ||
2469 | /****************************************************************************** | |
d0a41774 | 2470 | * RegConnectRegistryW [ADVAPI32.@] |
5ce2329a | 2471 | * |
d347ebe1 | 2472 | * Establish a connection to a predefined registry key on another computer. |
ec350525 | 2473 | * |
5ce2329a | 2474 | * PARAMS |
6a358c40 JH |
2475 | * lpMachineName [I] Address of name of remote computer |
2476 | * hHey [I] Predefined registry handle | |
2477 | * phkResult [I] Address of buffer for remote registry handle | |
2478 | * | |
2479 | * RETURNS | |
2480 | * Success: ERROR_SUCCESS | |
2481 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2482 | */ |
af183df6 | 2483 | LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, |
5cf56a3a | 2484 | PHKEY phkResult ) |
5ce2329a | 2485 | { |
ae176d16 JL |
2486 | LONG ret; |
2487 | ||
cbacde52 | 2488 | TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult); |
5ce2329a AJ |
2489 | |
2490 | if (!lpMachineName || !*lpMachineName) { | |
2491 | /* Use the local machine name */ | |
ae176d16 | 2492 | ret = RegOpenKeyW( hKey, NULL, phkResult ); |
5ce2329a | 2493 | } |
c16e7058 | 2494 | else { |
ae176d16 JL |
2495 | WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1]; |
2496 | DWORD len = sizeof(compName) / sizeof(WCHAR); | |
5ce2329a | 2497 | |
c16e7058 RK |
2498 | /* MSDN says lpMachineName must start with \\ : not so */ |
2499 | if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\') | |
2500 | lpMachineName += 2; | |
ae176d16 JL |
2501 | if (GetComputerNameW(compName, &len)) |
2502 | { | |
c16e7058 | 2503 | if (!strcmpiW(lpMachineName, compName)) |
ae176d16 JL |
2504 | ret = RegOpenKeyW(hKey, NULL, phkResult); |
2505 | else | |
2506 | { | |
c16e7058 | 2507 | FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName)); |
ae176d16 JL |
2508 | ret = ERROR_BAD_NETPATH; |
2509 | } | |
2510 | } | |
2511 | else | |
2512 | ret = GetLastError(); | |
2513 | } | |
2514 | return ret; | |
5ce2329a AJ |
2515 | } |
2516 | ||
2517 | ||
2518 | /****************************************************************************** | |
d0a41774 | 2519 | * RegConnectRegistryA [ADVAPI32.@] |
6a358c40 | 2520 | * |
d45811ce | 2521 | * See RegConnectRegistryW. |
5ce2329a | 2522 | */ |
af183df6 | 2523 | LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey ) |
5ce2329a | 2524 | { |
6f2a071d MD |
2525 | UNICODE_STRING machineW; |
2526 | LONG ret; | |
2527 | ||
2528 | RtlCreateUnicodeStringFromAsciiz( &machineW, machine ); | |
2529 | ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey ); | |
2530 | RtlFreeUnicodeString( &machineW ); | |
5ce2329a AJ |
2531 | return ret; |
2532 | } | |
2533 | ||
2534 | ||
2535 | /****************************************************************************** | |
d0a41774 | 2536 | * RegNotifyChangeKeyValue [ADVAPI32.@] |
5ce2329a | 2537 | * |
ec350525 MA |
2538 | * Notify the caller about changes to the attributes or contents of a registry key. |
2539 | * | |
5ce2329a | 2540 | * PARAMS |
6a358c40 JH |
2541 | * hkey [I] Handle of key to watch |
2542 | * fWatchSubTree [I] Flag for subkey notification | |
2543 | * fdwNotifyFilter [I] Changes to be reported | |
2544 | * hEvent [I] Handle of signaled event | |
2545 | * fAsync [I] Flag for asynchronous reporting | |
2546 | * | |
2547 | * RETURNS | |
2548 | * Success: ERROR_SUCCESS | |
2549 | * Failure: nonzero error code from Winerror.h | |
5ce2329a | 2550 | */ |
af183df6 | 2551 | LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, |
5ce2329a AJ |
2552 | DWORD fdwNotifyFilter, HANDLE hEvent, |
2553 | BOOL fAsync ) | |
2554 | { | |
efbea2e2 RS |
2555 | NTSTATUS status; |
2556 | IO_STATUS_BLOCK iosb; | |
11f4b444 | 2557 | |
efbea2e2 RS |
2558 | hkey = get_special_root_hkey( hkey ); |
2559 | if (!hkey) return ERROR_INVALID_HANDLE; | |
11f4b444 | 2560 | |
4301816d | 2561 | TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter, |
efbea2e2 | 2562 | hEvent, fAsync); |
11f4b444 | 2563 | |
efbea2e2 | 2564 | status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb, |
91080639 AS |
2565 | fdwNotifyFilter, fAsync, NULL, 0, |
2566 | fWatchSubTree); | |
11f4b444 | 2567 | |
efbea2e2 RS |
2568 | if (status && status != STATUS_TIMEOUT) |
2569 | return RtlNtStatusToDosError( status ); | |
2570 | ||
2571 | return ERROR_SUCCESS; | |
5ce2329a | 2572 | } |
65e81827 RS |
2573 | |
2574 | /****************************************************************************** | |
2575 | * RegOpenUserClassesRoot [ADVAPI32.@] | |
50ce0844 JG |
2576 | * |
2577 | * Open the HKEY_CLASSES_ROOT key for a user. | |
65e81827 RS |
2578 | * |
2579 | * PARAMS | |
6a358c40 | 2580 | * hToken [I] Handle of token representing the user |
d347ebe1 | 2581 | * dwOptions [I] Reserved, must be 0 |
6a358c40 JH |
2582 | * samDesired [I] Desired access rights |
2583 | * phkResult [O] Destination for the resulting key handle | |
65e81827 | 2584 | * |
6a358c40 JH |
2585 | * RETURNS |
2586 | * Success: ERROR_SUCCESS | |
2587 | * Failure: nonzero error code from Winerror.h | |
2588 | * | |
50ce0844 | 2589 | * NOTES |
6a358c40 JH |
2590 | * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the |
2591 | * "HKEY_LOCAL_MACHINE\Software\Classes" and the | |
2592 | * "HKEY_CURRENT_USER\Software\Classes" keys merged together. | |
65e81827 | 2593 | */ |
af183df6 | 2594 | LSTATUS WINAPI RegOpenUserClassesRoot( |
65e81827 RS |
2595 | HANDLE hToken, |
2596 | DWORD dwOptions, | |
2597 | REGSAM samDesired, | |
2598 | PHKEY phkResult | |
2599 | ) | |
2600 | { | |
4301816d | 2601 | FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult); |
65e81827 RS |
2602 | |
2603 | *phkResult = HKEY_CLASSES_ROOT; | |
2604 | return ERROR_SUCCESS; | |
2605 | } | |
ac615ce5 MJ |
2606 | |
2607 | /****************************************************************************** | |
2608 | * load_string [Internal] | |
2609 | * | |
2610 | * This is basically a copy of user32/resource.c's LoadStringW. Necessary to | |
2611 | * avoid importing user32, which is higher level than advapi32. Helper for | |
2612 | * RegLoadMUIString. | |
2613 | */ | |
2614 | static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) | |
2615 | { | |
2616 | HGLOBAL hMemory; | |
2617 | HRSRC hResource; | |
2618 | WCHAR *pString; | |
2619 | int idxString; | |
2620 | ||
2621 | /* Negative values have to be inverted. */ | |
2622 | if (HIWORD(resId) == 0xffff) | |
2623 | resId = (UINT)(-((INT)resId)); | |
2624 | ||
2625 | /* Load the resource into memory and get a pointer to it. */ | |
2626 | hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); | |
2627 | if (!hResource) return 0; | |
2628 | hMemory = LoadResource(hModule, hResource); | |
2629 | if (!hMemory) return 0; | |
2630 | pString = LockResource(hMemory); | |
2631 | ||
2632 | /* Strings are length-prefixed. Lowest nibble of resId is an index. */ | |
2633 | idxString = resId & 0xf; | |
2634 | while (idxString--) pString += *pString + 1; | |
2635 | ||
2636 | /* If no buffer is given, return length of the string. */ | |
2637 | if (!pwszBuffer) return *pString; | |
2638 | ||
2639 | /* Else copy over the string, respecting the buffer size. */ | |
2640 | cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); | |
2641 | if (cMaxChars >= 0) { | |
2642 | memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); | |
2643 | pwszBuffer[cMaxChars] = '\0'; | |
2644 | } | |
2645 | ||
2646 | return cMaxChars; | |
2647 | } | |
2648 | ||
2649 | /****************************************************************************** | |
2650 | * RegLoadMUIStringW [ADVAPI32.@] | |
2651 | * | |
2652 | * Load the localized version of a string resource from some PE, respective | |
2653 | * id and path of which are given in the registry value in the format | |
2654 | * @[path]\dllname,-resourceId | |
2655 | * | |
2656 | * PARAMS | |
2657 | * hKey [I] Key, of which to load the string value from. | |
2658 | * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type). | |
2659 | * pszBuffer [O] Buffer to store the localized string in. | |
2660 | * cbBuffer [I] Size of the destination buffer in bytes. | |
2661 | * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL). | |
2662 | * dwFlags [I] None supported yet. | |
2663 | * pszBaseDir [I] Not supported yet. | |
2664 | * | |
2665 | * RETURNS | |
2666 | * Success: ERROR_SUCCESS, | |
2667 | * Failure: nonzero error code from winerror.h | |
2668 | * | |
2669 | * NOTES | |
2670 | * This is an API of Windows Vista, which wasn't available at the time this code | |
2671 | * was written. We have to check for the correct behaviour once it's available. | |
2672 | */ | |
af183df6 | 2673 | LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer, |
ac615ce5 MJ |
2674 | LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir) |
2675 | { | |
2676 | DWORD dwValueType, cbData; | |
2677 | LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; | |
2678 | LONG result; | |
2679 | ||
4301816d HL |
2680 | TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, " |
2681 | "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer, | |
ac615ce5 MJ |
2682 | cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir)); |
2683 | ||
2684 | /* Parameter sanity checks. */ | |
2685 | if (!hKey || !pwszBuffer) | |
2686 | return ERROR_INVALID_PARAMETER; | |
2687 | ||
2688 | if (pwszBaseDir && *pwszBaseDir) { | |
2689 | FIXME("BaseDir parameter not yet supported!\n"); | |
2690 | return ERROR_INVALID_PARAMETER; | |
2691 | } | |
2692 | ||
2693 | /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ | |
2694 | result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData); | |
2695 | if (result != ERROR_SUCCESS) goto cleanup; | |
2696 | if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) { | |
2697 | result = ERROR_FILE_NOT_FOUND; | |
2698 | goto cleanup; | |
2699 | } | |
2700 | pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); | |
2701 | if (!pwszTempBuffer) { | |
2702 | result = ERROR_NOT_ENOUGH_MEMORY; | |
2703 | goto cleanup; | |
2704 | } | |
2705 | result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); | |
2706 | if (result != ERROR_SUCCESS) goto cleanup; | |
2707 | ||
2708 | /* Expand environment variables, if appropriate, or copy the original string over. */ | |
2709 | if (dwValueType == REG_EXPAND_SZ) { | |
2710 | cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); | |
2711 | if (!cbData) goto cleanup; | |
2712 | pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); | |
2713 | if (!pwszExpandedBuffer) { | |
2714 | result = ERROR_NOT_ENOUGH_MEMORY; | |
2715 | goto cleanup; | |
2716 | } | |
2717 | ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); | |
2718 | } else { | |
2719 | pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); | |
2720 | memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); | |
2721 | } | |
2722 | ||
2723 | /* If the value references a resource based string, parse the value and load the string. | |
2724 | * Else just copy over the original value. */ | |
2725 | result = ERROR_SUCCESS; | |
2726 | if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */ | |
2727 | lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR)); | |
2728 | } else { | |
2729 | WCHAR *pComma = strrchrW(pwszExpandedBuffer, ','); | |
2730 | UINT uiStringId; | |
2731 | HMODULE hModule; | |
2732 | ||
2733 | /* Format of the expanded value is 'path_to_dll,-resId' */ | |
2734 | if (!pComma || pComma[1] != '-') { | |
2735 | result = ERROR_BADKEY; | |
2736 | goto cleanup; | |
2737 | } | |
2738 | ||
2739 | uiStringId = atoiW(pComma+2); | |
2740 | *pComma = '\0'; | |
2741 | ||
2742 | hModule = LoadLibraryW(pwszExpandedBuffer + 1); | |
2743 | if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR))) | |
2744 | result = ERROR_BADKEY; | |
2745 | FreeLibrary(hModule); | |
2746 | } | |
2747 | ||
2748 | cleanup: | |
2749 | HeapFree(GetProcessHeap(), 0, pwszTempBuffer); | |
2750 | HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); | |
2751 | return result; | |
2752 | } | |
2753 | ||
2754 | /****************************************************************************** | |
2755 | * RegLoadMUIStringA [ADVAPI32.@] | |
2756 | * | |
2757 | * See RegLoadMUIStringW | |
2758 | */ | |
af183df6 | 2759 | LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer, |
ac615ce5 MJ |
2760 | LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir) |
2761 | { | |
2762 | UNICODE_STRING valueW, baseDirW; | |
2763 | WCHAR *pwszBuffer; | |
2764 | DWORD cbData = cbBuffer * sizeof(WCHAR); | |
2765 | LONG result; | |
2766 | ||
2767 | valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL; | |
2768 | if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) || | |
2769 | !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) || | |
2770 | !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData))) | |
2771 | { | |
2772 | result = ERROR_NOT_ENOUGH_MEMORY; | |
2773 | goto cleanup; | |
2774 | } | |
2775 | ||
2776 | result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags, | |
2777 | baseDirW.Buffer); | |
2778 | ||
2779 | if (result == ERROR_SUCCESS) { | |
2780 | cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL); | |
2781 | if (pcbData) | |
2782 | *pcbData = cbData; | |
2783 | } | |
2784 | ||
2785 | cleanup: | |
2786 | HeapFree(GetProcessHeap(), 0, pwszBuffer); | |
2787 | RtlFreeUnicodeString(&baseDirW); | |
2788 | RtlFreeUnicodeString(&valueW); | |
2789 | ||
2790 | return result; | |
2791 | } | |
52aaddcd RS |
2792 | |
2793 | /****************************************************************************** | |
2794 | * RegDisablePredefinedCache [ADVAPI32.@] | |
2795 | * | |
2796 | * Disables the caching of the HKEY_CLASSES_ROOT key for the process. | |
2797 | * | |
2798 | * PARAMS | |
2799 | * None. | |
2800 | * | |
2801 | * RETURNS | |
2802 | * Success: ERROR_SUCCESS | |
2803 | * Failure: nonzero error code from Winerror.h | |
2804 | * | |
2805 | * NOTES | |
2806 | * This is useful for services that use impersonation. | |
2807 | */ | |
af183df6 | 2808 | LSTATUS WINAPI RegDisablePredefinedCache(void) |
52aaddcd RS |
2809 | { |
2810 | HKEY hkey_current_user; | |
2811 | int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST; | |
2812 | ||
2813 | /* prevent caching of future requests */ | |
2814 | hkcu_cache_disabled = TRUE; | |
2815 | ||
2816 | hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL ); | |
2817 | ||
2818 | if (hkey_current_user) | |
2819 | NtClose( hkey_current_user ); | |
2820 | ||
2821 | return ERROR_SUCCESS; | |
2822 | } | |
88b6bc4f SL |
2823 | |
2824 | /****************************************************************************** | |
2825 | * RegDeleteTreeW [ADVAPI32.@] | |
2826 | * | |
2827 | */ | |
af183df6 | 2828 | LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) |
88b6bc4f SL |
2829 | { |
2830 | LONG ret; | |
2831 | DWORD dwMaxSubkeyLen, dwMaxValueLen; | |
2832 | DWORD dwMaxLen, dwSize; | |
2833 | WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; | |
2834 | HKEY hSubKey = hKey; | |
2835 | ||
2836 | TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey)); | |
2837 | ||
2838 | if(lpszSubKey) | |
2839 | { | |
2840 | ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); | |
2841 | if (ret) return ret; | |
2842 | } | |
2843 | ||
2844 | /* Get highest length for keys, values */ | |
2845 | ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, | |
2846 | &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); | |
2847 | if (ret) goto cleanup; | |
2848 | ||
2849 | dwMaxSubkeyLen++; | |
2850 | dwMaxValueLen++; | |
2851 | dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); | |
2852 | if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR)) | |
2853 | { | |
2854 | /* Name too big: alloc a buffer for it */ | |
2855 | if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR)))) | |
2856 | { | |
2857 | ret = ERROR_NOT_ENOUGH_MEMORY; | |
2858 | goto cleanup; | |
2859 | } | |
2860 | } | |
2861 | ||
2862 | ||
2863 | /* Recursively delete all the subkeys */ | |
2864 | while (TRUE) | |
2865 | { | |
2866 | dwSize = dwMaxLen; | |
2867 | if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, | |
2868 | NULL, NULL, NULL)) break; | |
2869 | ||
2870 | ret = RegDeleteTreeW(hSubKey, lpszName); | |
2871 | if (ret) goto cleanup; | |
2872 | } | |
2873 | ||
2874 | if (lpszSubKey) | |
2875 | ret = RegDeleteKeyW(hKey, lpszSubKey); | |
2876 | else | |
2877 | while (TRUE) | |
2878 | { | |
2879 | dwSize = dwMaxLen; | |
2880 | if (RegEnumValueW(hKey, 0, lpszName, &dwSize, | |
2881 | NULL, NULL, NULL, NULL)) break; | |
2882 | ||
2883 | ret = RegDeleteValueW(hKey, lpszName); | |
2884 | if (ret) goto cleanup; | |
2885 | } | |
2886 | ||
2887 | cleanup: | |
2888 | /* Free buffer if allocated */ | |
2889 | if (lpszName != szNameBuf) | |
2890 | HeapFree( GetProcessHeap(), 0, lpszName); | |
2891 | if(lpszSubKey) | |
2892 | RegCloseKey(hSubKey); | |
2893 | return ret; | |
2894 | } | |
2895 | ||
2896 | /****************************************************************************** | |
2897 | * RegDeleteTreeA [ADVAPI32.@] | |
2898 | * | |
2899 | */ | |
af183df6 | 2900 | LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) |
88b6bc4f SL |
2901 | { |
2902 | LONG ret; | |
2903 | UNICODE_STRING lpszSubKeyW; | |
2904 | ||
2905 | if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey); | |
2906 | else lpszSubKeyW.Buffer = NULL; | |
2907 | ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer); | |
2908 | RtlFreeUnicodeString( &lpszSubKeyW ); | |
2909 | return ret; | |
2910 | } |