Implemented SHCreateStdEnumFmtEtc.
[wine] / dlls / advapi32 / registry.c
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  *
11  * This file is concerned about handle management and interaction with the Wine server.
12  * Registry file I/O is in misc/registry.c.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31
32 #include "winbase.h"
33 #include "winreg.h"
34 #include "winerror.h"
35 #include "wine/unicode.h"
36 #include "heap.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(reg);
41
42
43 /* check if value type needs string conversion (Ansi<->Unicode) */
44 inline static int is_string( DWORD type )
45 {
46     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
47 }
48
49 /* check if current version is NT or Win95 */
50 inline static int is_version_nt(void)
51 {
52     return !(GetVersion() & 0x80000000);
53 }
54
55 /* allowed bits for access mask */
56 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
57
58 /******************************************************************************
59  *           RegCreateKeyExW   [ADVAPI32.@]
60  *
61  * PARAMS
62  *    hkey       [I] Handle of an open key
63  *    name       [I] Address of subkey name
64  *    reserved   [I] Reserved - must be 0
65  *    class      [I] Address of class string
66  *    options    [I] Special options flag
67  *    access     [I] Desired security access
68  *    sa         [I] Address of key security structure
69  *    retkey     [O] Address of buffer for opened handle
70  *    dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
71  *
72  * NOTES
73  *  in case of failing retkey remains untouched
74  *
75  * FIXME MAXIMUM_ALLOWED in access mask not supported by server
76  */
77 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
78                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
79                               LPHKEY retkey, LPDWORD dispos )
80 {
81     OBJECT_ATTRIBUTES attr;
82     UNICODE_STRING nameW, classW;
83
84     if (reserved) return ERROR_INVALID_PARAMETER;
85     if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
86
87     attr.Length = sizeof(attr);
88     attr.RootDirectory = hkey;
89     attr.ObjectName = &nameW;
90     attr.Attributes = 0;
91     attr.SecurityDescriptor = NULL;
92     attr.SecurityQualityOfService = NULL;
93     RtlInitUnicodeString( &nameW, name );
94     RtlInitUnicodeString( &classW, class );
95
96     return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
97                                                &classW, options, dispos ) );
98 }
99
100
101 /******************************************************************************
102  *           RegCreateKeyExA   [ADVAPI32.@]
103  *
104  * FIXME MAXIMUM_ALLOWED in access mask not supported by server
105  */
106 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
107                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
108                               LPHKEY retkey, LPDWORD dispos )
109 {
110     OBJECT_ATTRIBUTES attr;
111     UNICODE_STRING classW;
112     ANSI_STRING nameA, classA;
113     NTSTATUS status;
114
115     if (reserved) return ERROR_INVALID_PARAMETER;
116     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
117     else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
118
119     attr.Length = sizeof(attr);
120     attr.RootDirectory = hkey;
121     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
122     attr.Attributes = 0;
123     attr.SecurityDescriptor = NULL;
124     attr.SecurityQualityOfService = NULL;
125     RtlInitAnsiString( &nameA, name );
126     RtlInitAnsiString( &classA, class );
127
128     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
129                                                  &nameA, FALSE )))
130     {
131         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
132         {
133             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
134             RtlFreeUnicodeString( &classW );
135         }
136     }
137     return RtlNtStatusToDosError( status );
138 }
139
140
141 /******************************************************************************
142  *           RegCreateKeyW   [ADVAPI32.@]
143  */
144 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
145 {
146     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
147     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
148     return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
149                             KEY_ALL_ACCESS, NULL, retkey, NULL );
150 }
151
152
153 /******************************************************************************
154  *           RegCreateKeyA   [ADVAPI32.@]
155  */
156 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
157 {
158     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
159                             KEY_ALL_ACCESS, NULL, retkey, NULL );
160 }
161
162
163
164 /******************************************************************************
165  *           RegOpenKeyExW   [ADVAPI32.@]
166  *
167  * Opens the specified key
168  *
169  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
170  *
171  * PARAMS
172  *    hkey       [I] Handle of open key
173  *    name       [I] Name of subkey to open
174  *    reserved   [I] Reserved - must be zero
175  *    access     [I] Security access mask
176  *    retkey     [O] Handle to open key
177  *
178  * RETURNS
179  *    Success: ERROR_SUCCESS
180  *    Failure: Error code
181  *
182  * NOTES
183  *  in case of failing is retkey = 0
184  */
185 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
186 {
187     OBJECT_ATTRIBUTES attr;
188     UNICODE_STRING nameW;
189
190     attr.Length = sizeof(attr);
191     attr.RootDirectory = hkey;
192     attr.ObjectName = &nameW;
193     attr.Attributes = 0;
194     attr.SecurityDescriptor = NULL;
195     attr.SecurityQualityOfService = NULL;
196     RtlInitUnicodeString( &nameW, name );
197     return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
198 }
199
200
201 /******************************************************************************
202  *           RegOpenKeyExA   [ADVAPI32.@]
203  */
204 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
205 {
206     OBJECT_ATTRIBUTES attr;
207     STRING nameA;
208     NTSTATUS status;
209
210     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
211
212     attr.Length = sizeof(attr);
213     attr.RootDirectory = hkey;
214     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
215     attr.Attributes = 0;
216     attr.SecurityDescriptor = NULL;
217     attr.SecurityQualityOfService = NULL;
218
219     RtlInitAnsiString( &nameA, name );
220     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
221                                                  &nameA, FALSE )))
222     {
223         status = NtOpenKey( retkey, access, &attr );
224     }
225     return RtlNtStatusToDosError( status );
226 }
227
228
229 /******************************************************************************
230  *           RegOpenKeyW   [ADVAPI32.@]
231  *
232  * PARAMS
233  *    hkey    [I] Handle of open key
234  *    name    [I] Address of name of subkey to open
235  *    retkey  [O] Handle to open key
236  *
237  * RETURNS
238  *    Success: ERROR_SUCCESS
239  *    Failure: Error code
240  *
241  * NOTES
242  *  in case of failing is retkey = 0
243  */
244 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
245 {
246     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
247 }
248
249
250 /******************************************************************************
251  *           RegOpenKeyA   [ADVAPI32.@]
252  */
253 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
254 {
255     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
256 }
257
258
259 /******************************************************************************
260  *           RegOpenCurrentUser   [ADVAPI32.@]
261  * FIXME: This function is supposed to retrieve a handle to the
262  * HKEY_CURRENT_USER for the user the current thread is impersonating.
263  * Since Wine does not currently allow threads to impersonate other users,
264  * this stub should work fine.
265  */
266 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
267 {
268     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
269 }
270
271
272
273 /******************************************************************************
274  *           RegEnumKeyExW   [ADVAPI32.@]
275  *
276  * PARAMS
277  *    hkey         [I] Handle to key to enumerate
278  *    index        [I] Index of subkey to enumerate
279  *    name         [O] Buffer for subkey name
280  *    name_len     [O] Size of subkey buffer
281  *    reserved     [I] Reserved
282  *    class        [O] Buffer for class string
283  *    class_len    [O] Size of class buffer
284  *    ft           [O] Time key last written to
285  */
286 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
287                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
288 {
289     NTSTATUS status;
290     char buffer[256], *buf_ptr = buffer;
291     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
292     DWORD total_size;
293
294     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
295            name_len ? *name_len : -1, reserved, class, class_len, ft );
296
297     if (reserved) return ERROR_INVALID_PARAMETER;
298
299     if (!hkey) return ERROR_INVALID_HANDLE;
300
301     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
302                              buffer, sizeof(buffer), &total_size );
303
304     while (status == STATUS_BUFFER_OVERFLOW)
305     {
306         /* retry with a dynamically allocated buffer */
307         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
308         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
309             return ERROR_NOT_ENOUGH_MEMORY;
310         info = (KEY_NODE_INFORMATION *)buf_ptr;
311         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
312                                  buf_ptr, total_size, &total_size );
313     }
314
315     if (!status)
316     {
317         DWORD len = info->NameLength / sizeof(WCHAR);
318         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
319
320         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
321
322         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
323             status = STATUS_BUFFER_OVERFLOW;
324         else
325         {
326             *name_len = len;
327             memcpy( name, info->Name, info->NameLength );
328             name[len] = 0;
329             if (class_len)
330             {
331                 *class_len = cls_len;
332                 if (class)
333                 {
334                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
335                     class[cls_len] = 0;
336                 }
337             }
338         }
339     }
340
341     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
342     return RtlNtStatusToDosError( status );
343 }
344
345
346 /******************************************************************************
347  *           RegEnumKeyExA   [ADVAPI32.@]
348  */
349 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
350                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
351 {
352     NTSTATUS status;
353     char buffer[256], *buf_ptr = buffer;
354     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
355     DWORD total_size;
356
357     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
358            name_len ? *name_len : -1, reserved, class, class_len, ft );
359
360     if (reserved) return ERROR_INVALID_PARAMETER;
361
362     if (!hkey) return ERROR_INVALID_HANDLE;
363
364     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
365                              buffer, sizeof(buffer), &total_size );
366
367     while (status == STATUS_BUFFER_OVERFLOW)
368     {
369         /* retry with a dynamically allocated buffer */
370         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
371         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
372             return ERROR_NOT_ENOUGH_MEMORY;
373         info = (KEY_NODE_INFORMATION *)buf_ptr;
374         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
375                                  buf_ptr, total_size, &total_size );
376     }
377
378     if (!status)
379     {
380         DWORD len, cls_len;
381
382         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
383         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
384                                    info->ClassLength );
385         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
386
387         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
388             status = STATUS_BUFFER_OVERFLOW;
389         else
390         {
391             *name_len = len;
392             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
393             name[len] = 0;
394             if (class_len)
395             {
396                 *class_len = cls_len;
397                 if (class)
398                 {
399                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
400                                             (WCHAR *)(buf_ptr + info->ClassOffset),
401                                             info->ClassLength );
402                     class[cls_len] = 0;
403                 }
404             }
405         }
406     }
407
408     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
409     return RtlNtStatusToDosError( status );
410 }
411
412
413 /******************************************************************************
414  *           RegEnumKeyW   [ADVAPI32.@]
415  */
416 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
417 {
418     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
419 }
420
421
422 /******************************************************************************
423  *           RegEnumKeyA   [ADVAPI32.@]
424  */
425 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
426 {
427     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
428 }
429
430
431 /******************************************************************************
432  *           RegQueryInfoKeyW   [ADVAPI32.@]
433  *
434  * PARAMS
435  *    hkey       [I] Handle to key to query
436  *    class      [O] Buffer for class string
437  *    class_len  [O] Size of class string buffer
438  *    reserved   [I] Reserved
439  *    subkeys    [O] Buffer for number of subkeys
440  *    max_subkey [O] Buffer for longest subkey name length
441  *    max_class  [O] Buffer for longest class string length
442  *    values     [O] Buffer for number of value entries
443  *    max_value  [O] Buffer for longest value name length
444  *    max_data   [O] Buffer for longest value data length
445  *    security   [O] Buffer for security descriptor length
446  *    modif      [O] Modification time
447  *
448  * - win95 allows class to be valid and class_len to be NULL
449  * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
450  * - both allow class to be NULL and class_len to be NULL
451  * (it's hard to test validity, so test !NULL instead)
452  */
453 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
454                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
455                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
456                                LPDWORD security, FILETIME *modif )
457 {
458     NTSTATUS status;
459     char buffer[256], *buf_ptr = buffer;
460     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
461     DWORD total_size;
462
463     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
464            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
465
466     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
467
468     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
469     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
470
471     if (class)
472     {
473         /* retry with a dynamically allocated buffer */
474         while (status == STATUS_BUFFER_OVERFLOW)
475         {
476             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
477             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
478                 return ERROR_NOT_ENOUGH_MEMORY;
479             info = (KEY_FULL_INFORMATION *)buf_ptr;
480             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
481         }
482
483         if (status) goto done;
484
485         if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
486         {
487             status = STATUS_BUFFER_OVERFLOW;
488         }
489         else
490         {
491             memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
492             class[info->ClassLength/sizeof(WCHAR)] = 0;
493         }
494     }
495     else status = STATUS_SUCCESS;
496
497     if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
498     if (subkeys) *subkeys = info->SubKeys;
499     if (max_subkey) *max_subkey = info->MaxNameLen;
500     if (max_class) *max_class = info->MaxClassLen;
501     if (values) *values = info->Values;
502     if (max_value) *max_value = info->MaxValueNameLen;
503     if (max_data) *max_data = info->MaxValueDataLen;
504     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
505
506  done:
507     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
508     return RtlNtStatusToDosError( status );
509 }
510
511
512 /******************************************************************************
513  *           RegQueryMultipleValuesA   [ADVAPI32.@]
514  */
515 DWORD WINAPI RegQueryMultipleValuesA(HKEY hkey, PVALENTA val_list, DWORD num_vals,
516                                      LPSTR lpValueBuf, LPDWORD ldwTotsize)
517 {
518     int i;
519     DWORD maxBytes = *ldwTotsize;
520     HRESULT status;
521     LPSTR bufptr = lpValueBuf;
522     *ldwTotsize = 0;
523
524     TRACE("(%x,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
525
526     for(i=0; i < num_vals; ++i)
527     {
528
529         val_list[i].ve_valuelen=0;
530         status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
531         if(status != ERROR_SUCCESS)
532         {
533             return status;
534         }
535
536         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
537         {
538             status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
539                                       bufptr, &val_list[i].ve_valuelen);
540             if(status != ERROR_SUCCESS)
541             {
542                 return status;
543             }
544
545             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
546
547             bufptr += val_list[i].ve_valuelen;
548         }
549
550         *ldwTotsize += val_list[i].ve_valuelen;
551     }
552     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
553 }
554
555
556 /******************************************************************************
557  *           RegQueryMultipleValuesW   [ADVAPI32.@]
558  */
559 DWORD WINAPI RegQueryMultipleValuesW(HKEY hkey, PVALENTW val_list, DWORD num_vals,
560                                      LPWSTR lpValueBuf, LPDWORD ldwTotsize)
561 {
562     int i;
563     DWORD maxBytes = *ldwTotsize;
564     HRESULT status;
565     LPSTR bufptr = (LPSTR)lpValueBuf;
566     *ldwTotsize = 0;
567
568     TRACE("(%x,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
569
570     for(i=0; i < num_vals; ++i)
571     {
572         val_list[i].ve_valuelen=0;
573         status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
574         if(status != ERROR_SUCCESS)
575         {
576             return status;
577         }
578
579         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
580         {
581             status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
582                                       bufptr, &val_list[i].ve_valuelen);
583             if(status != ERROR_SUCCESS)
584             {
585                 return status;
586             }
587
588             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
589
590             bufptr += val_list[i].ve_valuelen;
591         }
592
593         *ldwTotsize += val_list[i].ve_valuelen;
594     }
595     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
596 }
597
598 /******************************************************************************
599  *           RegQueryInfoKeyA   [ADVAPI32.@]
600  */
601 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
602                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
603                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
604                                LPDWORD security, FILETIME *modif )
605 {
606     NTSTATUS status;
607     char buffer[256], *buf_ptr = buffer;
608     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
609     DWORD total_size, len;
610
611     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
612            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
613
614     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
615
616     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
617     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
618
619     if (class || class_len)
620     {
621         /* retry with a dynamically allocated buffer */
622         while (status == STATUS_BUFFER_OVERFLOW)
623         {
624             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
625             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
626                 return ERROR_NOT_ENOUGH_MEMORY;
627             info = (KEY_FULL_INFORMATION *)buf_ptr;
628             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
629         }
630
631         if (status) goto done;
632
633         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
634         if (class_len)
635         {
636             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
637             *class_len = len;
638         }
639         if (class && !status)
640         {
641             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
642                                     info->ClassLength );
643             class[len] = 0;
644         }
645     }
646     else status = STATUS_SUCCESS;
647
648     if (subkeys) *subkeys = info->SubKeys;
649     if (max_subkey) *max_subkey = info->MaxNameLen;
650     if (max_class) *max_class = info->MaxClassLen;
651     if (values) *values = info->Values;
652     if (max_value) *max_value = info->MaxValueNameLen;
653     if (max_data) *max_data = info->MaxValueDataLen;
654     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
655
656  done:
657     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
658     return RtlNtStatusToDosError( status );
659 }
660
661
662 /******************************************************************************
663  *           RegCloseKey   [ADVAPI32.@]
664  *
665  * Releases the handle of the specified key
666  *
667  * PARAMS
668  *    hkey [I] Handle of key to close
669  *
670  * RETURNS
671  *    Success: ERROR_SUCCESS
672  *    Failure: Error code
673  */
674 DWORD WINAPI RegCloseKey( HKEY hkey )
675 {
676     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
677     return RtlNtStatusToDosError( NtClose( hkey ) );
678 }
679
680
681 /******************************************************************************
682  *           RegDeleteKeyW   [ADVAPI32.@]
683  *
684  * PARAMS
685  *    hkey   [I] Handle to open key
686  *    name   [I] Name of subkey to delete
687  *
688  * RETURNS
689  *    Success: ERROR_SUCCESS
690  *    Failure: Error code
691  */
692 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
693 {
694     DWORD ret;
695     HKEY tmp;
696
697     if (!name || !*name)
698     {
699         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
700     }
701     else if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
702     {
703         if (!is_version_nt()) /* win95 does recursive key deletes */
704         {
705             WCHAR name[MAX_PATH];
706
707             while(!RegEnumKeyW(tmp, 0, name, sizeof name))
708             {
709                 if(RegDeleteKeyW(tmp, name))  /* recurse */
710                     break;
711             }
712         }
713         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
714         RegCloseKey( tmp );
715     }
716     TRACE("%s ret=%08lx\n", debugstr_w(name), ret);
717     return ret;
718 }
719
720
721 /******************************************************************************
722  *           RegDeleteKeyA   [ADVAPI32.@]
723  */
724 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
725 {
726     DWORD ret;
727     HKEY tmp;
728
729     if (!name || !*name)
730     {
731         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
732     }
733     else if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, &tmp )))
734     {
735         if (!is_version_nt()) /* win95 does recursive key deletes */
736         {
737             CHAR name[MAX_PATH];
738
739             while(!RegEnumKeyA(tmp, 0, name, sizeof name))
740             {
741                 if(RegDeleteKeyA(tmp, name))  /* recurse */
742                     break;
743             }
744         }
745         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
746         RegCloseKey( tmp );
747     }
748     TRACE("%s ret=%08lx\n", debugstr_a(name), ret);
749     return ret;
750 }
751
752
753
754 /******************************************************************************
755  *           RegSetValueExW   [ADVAPI32.@]
756  *
757  * Sets the data and type of a value under a register key
758  *
759  * PARAMS
760  *    hkey       [I] Handle of key to set value for
761  *    name       [I] Name of value to set
762  *    reserved   [I] Reserved - must be zero
763  *    type       [I] Flag for value type
764  *    data       [I] Address of value data
765  *    count      [I] Size of value data
766  *
767  * RETURNS
768  *    Success: ERROR_SUCCESS
769  *    Failure: Error code
770  *
771  * NOTES
772  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
773  *   NT does definitely care (aj)
774  */
775 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
776                              DWORD type, CONST BYTE *data, DWORD count )
777 {
778     UNICODE_STRING nameW;
779
780     if (!is_version_nt())  /* win95 */
781     {
782         if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR);
783     }
784     else if (count && is_string(type))
785     {
786         LPCWSTR str = (LPCWSTR)data;
787         /* if user forgot to count terminating null, add it (yes NT does this) */
788         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
789             count += sizeof(WCHAR);
790     }
791
792     RtlInitUnicodeString( &nameW, name );
793     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
794 }
795
796
797 /******************************************************************************
798  *           RegSetValueExA   [ADVAPI32.@]
799  */
800 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
801                              CONST BYTE *data, DWORD count )
802 {
803     ANSI_STRING nameA;
804     WCHAR *dataW = NULL;
805     NTSTATUS status;
806
807     if (!is_version_nt())  /* win95 */
808     {
809         if (type == REG_SZ) count = strlen(data) + 1;
810     }
811     else if (count && is_string(type))
812     {
813         /* if user forgot to count terminating null, add it (yes NT does this) */
814         if (data[count-1] && !data[count]) count++;
815     }
816
817     if (is_string( type )) /* need to convert to Unicode */
818     {
819         DWORD lenW;
820         RtlMultiByteToUnicodeSize( &lenW, data, count );
821         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
822         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
823         count = lenW;
824         data = (BYTE *)dataW;
825     }
826
827     RtlInitAnsiString( &nameA, name );
828     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
829                                                  &nameA, FALSE )))
830     {
831         status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
832     }
833     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
834     return RtlNtStatusToDosError( status );
835 }
836
837
838 /******************************************************************************
839  *           RegSetValueW   [ADVAPI32.@]
840  */
841 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
842 {
843     HKEY subkey = hkey;
844     DWORD ret;
845
846     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
847
848     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
849
850     if (name && name[0])  /* need to create the subkey */
851     {
852         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
853     }
854
855     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
856                           (strlenW( data ) + 1) * sizeof(WCHAR) );
857     if (subkey != hkey) RegCloseKey( subkey );
858     return ret;
859 }
860
861
862 /******************************************************************************
863  *           RegSetValueA   [ADVAPI32.@]
864  */
865 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
866 {
867     HKEY subkey = hkey;
868     DWORD ret;
869
870     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
871
872     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
873
874     if (name && name[0])  /* need to create the subkey */
875     {
876         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
877     }
878     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
879     if (subkey != hkey) RegCloseKey( subkey );
880     return ret;
881 }
882
883
884
885 /******************************************************************************
886  *           RegQueryValueExW   [ADVAPI32.@]
887  *
888  * Retrieves type and data for a specified name associated with an open key
889  *
890  * PARAMS
891  *    hkey      [I]   Handle of key to query
892  *    name      [I]   Name of value to query
893  *    reserved  [I]   Reserved - must be NULL
894  *    type      [O]   Address of buffer for value type.  If NULL, the type
895  *                        is not required.
896  *    data      [O]   Address of data buffer.  If NULL, the actual data is
897  *                        not required.
898  *    count     [I/O] Address of data buffer size
899  *
900  * RETURNS
901  *    ERROR_SUCCESS:   Success
902  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
903  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
904  */
905 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
906                                LPBYTE data, LPDWORD count )
907 {
908     NTSTATUS status;
909     UNICODE_STRING name_str;
910     DWORD total_size;
911     char buffer[256], *buf_ptr = buffer;
912     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
913     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
914
915     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
916           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
917
918     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
919
920     RtlInitUnicodeString( &name_str, name );
921
922     if (data) total_size = min( sizeof(buffer), *count + info_size );
923     else total_size = info_size;
924
925     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
926                               buffer, total_size, &total_size );
927     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
928
929     if (data)
930     {
931         /* retry with a dynamically allocated buffer */
932         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
933         {
934             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
935             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
936                 return ERROR_NOT_ENOUGH_MEMORY;
937             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
938             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
939                                       buf_ptr, total_size, &total_size );
940         }
941
942         if (!status)
943         {
944             memcpy( data, buf_ptr + info_size, total_size - info_size );
945             /* if the type is REG_SZ and data is not 0-terminated
946              * and there is enough space in the buffer NT appends a \0 */
947             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
948             {
949                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
950                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
951             }
952         }
953         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
954     }
955     else status = STATUS_SUCCESS;
956
957     if (type) *type = info->Type;
958     if (count) *count = total_size - info_size;
959
960  done:
961     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
962     return RtlNtStatusToDosError(status);
963 }
964
965
966 /******************************************************************************
967  *           RegQueryValueExA   [ADVAPI32.@]
968  *
969  * NOTES:
970  * the documentation is wrong: if the buffer is too small it remains untouched
971  */
972 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
973                                LPBYTE data, LPDWORD count )
974 {
975     NTSTATUS status;
976     ANSI_STRING nameA;
977     DWORD total_size;
978     char buffer[256], *buf_ptr = buffer;
979     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
980     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
981
982     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
983           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
984
985     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
986
987     RtlInitAnsiString( &nameA, name );
988     if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
989                                                 &nameA, FALSE )))
990         return RtlNtStatusToDosError(status);
991
992     status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
993                               KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
994     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
995
996     /* we need to fetch the contents for a string type even if not requested,
997      * because we need to compute the length of the ASCII string. */
998     if (data || is_string(info->Type))
999     {
1000         /* retry with a dynamically allocated buffer */
1001         while (status == STATUS_BUFFER_OVERFLOW)
1002         {
1003             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1004             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1005             {
1006                 status = STATUS_NO_MEMORY;
1007                 goto done;
1008             }
1009             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1010             status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1011                                     KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1012         }
1013
1014         if (status) goto done;
1015
1016         if (is_string(info->Type))
1017         {
1018             DWORD len;
1019
1020             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1021                                        total_size - info_size );
1022             if (data && len)
1023             {
1024                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1025                 else
1026                 {
1027                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1028                                             total_size - info_size );
1029                     /* if the type is REG_SZ and data is not 0-terminated
1030                      * and there is enough space in the buffer NT appends a \0 */
1031                     if (len < *count && data[len-1]) data[len] = 0;
1032                 }
1033             }
1034             total_size = len + info_size;
1035         }
1036         else if (data)
1037         {
1038             if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
1039             else memcpy( data, buf_ptr + info_size, total_size - info_size );
1040         }
1041     }
1042     else status = STATUS_SUCCESS;
1043
1044     if (type) *type = info->Type;
1045     if (count) *count = total_size - info_size;
1046
1047  done:
1048     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1049     return RtlNtStatusToDosError(status);
1050 }
1051
1052
1053 /******************************************************************************
1054  *           RegQueryValueW   [ADVAPI32.@]
1055  */
1056 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1057 {
1058     DWORD ret;
1059     HKEY subkey = hkey;
1060
1061     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1062
1063     if (name && name[0])
1064     {
1065         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1066     }
1067     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1068     if (subkey != hkey) RegCloseKey( subkey );
1069     if (ret == ERROR_FILE_NOT_FOUND)
1070     {
1071         /* return empty string if default value not found */
1072         if (data) *data = 0;
1073         if (count) *count = 1;
1074         ret = ERROR_SUCCESS;
1075     }
1076     return ret;
1077 }
1078
1079
1080 /******************************************************************************
1081  *           RegQueryValueA   [ADVAPI32.@]
1082  */
1083 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1084 {
1085     DWORD ret;
1086     HKEY subkey = hkey;
1087
1088     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1089
1090     if (name && name[0])
1091     {
1092         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1093     }
1094     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1095     if (subkey != hkey) RegCloseKey( subkey );
1096     if (ret == ERROR_FILE_NOT_FOUND)
1097     {
1098         /* return empty string if default value not found */
1099         if (data) *data = 0;
1100         if (count) *count = 1;
1101         ret = ERROR_SUCCESS;
1102     }
1103     return ret;
1104 }
1105
1106
1107 /******************************************************************************
1108  *           RegEnumValueW   [ADVAPI32.@]
1109  *
1110  * PARAMS
1111  *    hkey       [I] Handle to key to query
1112  *    index      [I] Index of value to query
1113  *    value      [O] Value string
1114  *    val_count  [I/O] Size of value buffer (in wchars)
1115  *    reserved   [I] Reserved
1116  *    type       [O] Type code
1117  *    data       [O] Value data
1118  *    count      [I/O] Size of data buffer (in bytes)
1119  */
1120
1121 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1122                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1123 {
1124     NTSTATUS status;
1125     DWORD total_size;
1126     char buffer[256], *buf_ptr = buffer;
1127     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1128     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1129
1130     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1131           hkey, index, value, val_count, reserved, type, data, count );
1132
1133     /* NT only checks count, not val_count */
1134     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1135
1136     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1137     if (data) total_size += *count;
1138     total_size = min( sizeof(buffer), total_size );
1139
1140     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1141                                   buffer, total_size, &total_size );
1142     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1143
1144     if (value || data)
1145     {
1146         /* retry with a dynamically allocated buffer */
1147         while (status == STATUS_BUFFER_OVERFLOW)
1148         {
1149             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1150             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1151                 return ERROR_NOT_ENOUGH_MEMORY;
1152             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1153             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1154                                           buf_ptr, total_size, &total_size );
1155         }
1156
1157         if (status) goto done;
1158
1159         if (value)
1160         {
1161             if (info->NameLength/sizeof(WCHAR) >= *val_count)
1162             {
1163                 status = STATUS_BUFFER_OVERFLOW;
1164                 goto overflow;
1165             }
1166             memcpy( value, info->Name, info->NameLength );
1167             *val_count = info->NameLength / sizeof(WCHAR);
1168             value[*val_count] = 0;
1169         }
1170
1171         if (data)
1172         {
1173             if (total_size - info->DataOffset > *count)
1174             {
1175                 status = STATUS_BUFFER_OVERFLOW;
1176                 goto overflow;
1177             }
1178             memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1179             if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1180             {
1181                 /* if the type is REG_SZ and data is not 0-terminated
1182                  * and there is enough space in the buffer NT appends a \0 */
1183                 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1184                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1185             }
1186         }
1187     }
1188     else status = STATUS_SUCCESS;
1189
1190  overflow:
1191     if (type) *type = info->Type;
1192     if (count) *count = info->DataLength;
1193
1194  done:
1195     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1196     return RtlNtStatusToDosError(status);
1197 }
1198
1199
1200 /******************************************************************************
1201  *           RegEnumValueA   [ADVAPI32.@]
1202  */
1203 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1204                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1205 {
1206     NTSTATUS status;
1207     DWORD total_size;
1208     char buffer[256], *buf_ptr = buffer;
1209     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1210     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1211
1212     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1213           hkey, index, value, val_count, reserved, type, data, count );
1214
1215     /* NT only checks count, not val_count */
1216     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1217
1218     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1219     if (data) total_size += *count;
1220     total_size = min( sizeof(buffer), total_size );
1221
1222     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1223                                   buffer, total_size, &total_size );
1224     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1225
1226     /* we need to fetch the contents for a string type even if not requested,
1227      * because we need to compute the length of the ASCII string. */
1228     if (value || data || is_string(info->Type))
1229     {
1230         /* retry with a dynamically allocated buffer */
1231         while (status == STATUS_BUFFER_OVERFLOW)
1232         {
1233             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1234             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1235                 return ERROR_NOT_ENOUGH_MEMORY;
1236             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1237             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1238                                           buf_ptr, total_size, &total_size );
1239         }
1240
1241         if (status) goto done;
1242
1243         if (is_string(info->Type))
1244         {
1245             DWORD len;
1246             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1247                                        total_size - info->DataOffset );
1248             if (data && len)
1249             {
1250                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1251                 else
1252                 {
1253                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1254                                             total_size - info->DataOffset );
1255                     /* if the type is REG_SZ and data is not 0-terminated
1256                      * and there is enough space in the buffer NT appends a \0 */
1257                     if (len < *count && data[len-1]) data[len] = 0;
1258                 }
1259             }
1260             info->DataLength = len;
1261         }
1262         else if (data)
1263         {
1264             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1265             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1266         }
1267
1268         if (value && !status)
1269         {
1270             DWORD len;
1271
1272             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1273             if (len >= *val_count)
1274             {
1275                 status = STATUS_BUFFER_OVERFLOW;
1276                 if (*val_count)
1277                 {
1278                     len = *val_count - 1;
1279                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1280                     value[len] = 0;
1281                 }
1282             }
1283             else
1284             {
1285                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1286                 value[len] = 0;
1287                 *val_count = len;
1288             }
1289         }
1290     }
1291     else status = STATUS_SUCCESS;
1292
1293     if (type) *type = info->Type;
1294     if (count) *count = info->DataLength;
1295
1296  done:
1297     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1298     return RtlNtStatusToDosError(status);
1299 }
1300
1301
1302
1303 /******************************************************************************
1304  *           RegDeleteValueW   [ADVAPI32.@]
1305  *
1306  * PARAMS
1307  *    hkey   [I] handle to key
1308  *    name   [I] name of value to delete
1309  *
1310  * RETURNS
1311  *    error status
1312  */
1313 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1314 {
1315     UNICODE_STRING nameW;
1316     RtlInitUnicodeString( &nameW, name );
1317     return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1318 }
1319
1320
1321 /******************************************************************************
1322  *           RegDeleteValueA   [ADVAPI32.@]
1323  */
1324 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1325 {
1326     STRING nameA;
1327     NTSTATUS status;
1328
1329     RtlInitAnsiString( &nameA, name );
1330     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1331                                                  &nameA, FALSE )))
1332     {
1333         status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1334     }
1335     return RtlNtStatusToDosError( status );
1336 }
1337
1338
1339 /******************************************************************************
1340  *           RegLoadKeyW   [ADVAPI32.@]
1341  *
1342  * PARAMS
1343  *    hkey      [I] Handle of open key
1344  *    subkey    [I] Address of name of subkey
1345  *    filename  [I] Address of filename for registry information
1346  */
1347 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1348 {
1349     HANDLE file;
1350     DWORD ret, len, err = GetLastError();
1351
1352     TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1353
1354     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1355     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1356
1357     len = strlenW( subkey ) * sizeof(WCHAR);
1358     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1359
1360     if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1361                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1362     {
1363         ret = GetLastError();
1364         goto done;
1365     }
1366
1367     SERVER_START_REQ( load_registry )
1368     {
1369         req->hkey  = hkey;
1370         req->file  = file;
1371         wine_server_add_data( req, subkey, len );
1372         ret = RtlNtStatusToDosError( wine_server_call(req) );
1373     }
1374     SERVER_END_REQ;
1375     CloseHandle( file );
1376
1377  done:
1378     SetLastError( err );  /* restore the last error code */
1379     return ret;
1380 }
1381
1382
1383 /******************************************************************************
1384  *           RegLoadKeyA   [ADVAPI32.@]
1385  */
1386 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1387 {
1388     WCHAR buffer[MAX_PATH];
1389     HANDLE file;
1390     DWORD ret, len, err = GetLastError();
1391
1392     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1393
1394     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1395     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1396
1397     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
1398         return ERROR_INVALID_PARAMETER;
1399
1400     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1401                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1402     {
1403         ret = GetLastError();
1404         goto done;
1405     }
1406
1407     SERVER_START_REQ( load_registry )
1408     {
1409         req->hkey  = hkey;
1410         req->file  = file;
1411         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
1412         ret = RtlNtStatusToDosError( wine_server_call(req) );
1413     }
1414     SERVER_END_REQ;
1415     CloseHandle( file );
1416
1417  done:
1418     SetLastError( err );  /* restore the last error code */
1419     return ret;
1420 }
1421
1422
1423 /******************************************************************************
1424  *           RegSaveKeyA   [ADVAPI32.@]
1425  *
1426  * PARAMS
1427  *    hkey   [I] Handle of key where save begins
1428  *    lpFile [I] Address of filename to save to
1429  *    sa     [I] Address of security structure
1430  */
1431 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1432 {
1433     char buffer[1024];
1434     int count = 0;
1435     LPSTR name;
1436     DWORD ret, err;
1437     HANDLE handle;
1438
1439     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1440
1441     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1442
1443     err = GetLastError();
1444     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1445     for (;;)
1446     {
1447         sprintf( name, "reg%04x.tmp", count++ );
1448         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1449                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1450         if (handle != INVALID_HANDLE_VALUE) break;
1451         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1452
1453         /* Something gone haywire ? Please report if this happens abnormally */
1454         if (count >= 100)
1455             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", buffer, count);
1456     }
1457
1458     SERVER_START_REQ( save_registry )
1459     {
1460         req->hkey = hkey;
1461         req->file = handle;
1462         ret = RtlNtStatusToDosError( wine_server_call( req ) );
1463     }
1464     SERVER_END_REQ;
1465
1466     CloseHandle( handle );
1467     if (!ret)
1468     {
1469         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1470         {
1471             ERR( "Failed to move %s to %s\n", buffer, file );
1472             ret = GetLastError();
1473         }
1474     }
1475     if (ret) DeleteFileA( buffer );
1476
1477 done:
1478     SetLastError( err );  /* restore last error code */
1479     return ret;
1480 }
1481
1482
1483 /******************************************************************************
1484  *           RegSaveKeyW   [ADVAPI32.@]
1485  */
1486 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1487 {
1488     LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1489     DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1490     if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1491     return ret;
1492 }
1493
1494
1495 /******************************************************************************
1496  * RegRestoreKeyW [ADVAPI32.@]
1497  *
1498  * PARAMS
1499  *    hkey    [I] Handle of key where restore begins
1500  *    lpFile  [I] Address of filename containing saved tree
1501  *    dwFlags [I] Optional flags
1502  */
1503 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1504 {
1505     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1506
1507     /* It seems to do this check before the hkey check */
1508     if (!lpFile || !*lpFile)
1509         return ERROR_INVALID_PARAMETER;
1510
1511     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1512
1513     /* Check for file existence */
1514
1515     return ERROR_SUCCESS;
1516 }
1517
1518
1519 /******************************************************************************
1520  * RegRestoreKeyA [ADVAPI32.@]
1521  */
1522 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1523 {
1524     LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1525     LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1526     HeapFree( GetProcessHeap(), 0, lpFileW );
1527     return ret;
1528 }
1529
1530
1531 /******************************************************************************
1532  * RegUnLoadKeyW [ADVAPI32.@]
1533  *
1534  * PARAMS
1535  *    hkey     [I] Handle of open key
1536  *    lpSubKey [I] Address of name of subkey to unload
1537  */
1538 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1539 {
1540     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1541     return ERROR_SUCCESS;
1542 }
1543
1544
1545 /******************************************************************************
1546  * RegUnLoadKeyA [ADVAPI32.@]
1547  */
1548 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1549 {
1550     LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1551     LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1552     if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1553     return ret;
1554 }
1555
1556
1557 /******************************************************************************
1558  * RegReplaceKeyW [ADVAPI32.@]
1559  *
1560  * PARAMS
1561  *    hkey      [I] Handle of open key
1562  *    lpSubKey  [I] Address of name of subkey
1563  *    lpNewFile [I] Address of filename for file with new data
1564  *    lpOldFile [I] Address of filename for backup file
1565  */
1566 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1567                               LPCWSTR lpOldFile )
1568 {
1569     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1570           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1571     return ERROR_SUCCESS;
1572 }
1573
1574
1575 /******************************************************************************
1576  * RegReplaceKeyA [ADVAPI32.@]
1577  */
1578 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1579                               LPCSTR lpOldFile )
1580 {
1581     LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1582     LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1583     LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1584     LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1585     HeapFree( GetProcessHeap(), 0, lpOldFileW );
1586     HeapFree( GetProcessHeap(), 0, lpNewFileW );
1587     HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1588     return ret;
1589 }
1590
1591
1592 /******************************************************************************
1593  * RegSetKeySecurity [ADVAPI32.@]
1594  *
1595  * PARAMS
1596  *    hkey          [I] Open handle of key to set
1597  *    SecurityInfo  [I] Descriptor contents
1598  *    pSecurityDesc [I] Address of descriptor for key
1599  */
1600 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1601                                PSECURITY_DESCRIPTOR pSecurityDesc )
1602 {
1603     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1604
1605     /* It seems to perform this check before the hkey check */
1606     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1607         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1608         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1609         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1610         /* Param OK */
1611     } else
1612         return ERROR_INVALID_PARAMETER;
1613
1614     if (!pSecurityDesc)
1615         return ERROR_INVALID_PARAMETER;
1616
1617     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1618
1619     return ERROR_SUCCESS;
1620 }
1621
1622
1623 /******************************************************************************
1624  * RegGetKeySecurity [ADVAPI32.@]
1625  * Retrieves a copy of security descriptor protecting the registry key
1626  *
1627  * PARAMS
1628  *    hkey                   [I]   Open handle of key to set
1629  *    SecurityInformation    [I]   Descriptor contents
1630  *    pSecurityDescriptor    [O]   Address of descriptor for key
1631  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1632  *
1633  * RETURNS
1634  *    Success: ERROR_SUCCESS
1635  *    Failure: Error code
1636  */
1637 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1638                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1639                                LPDWORD lpcbSecurityDescriptor )
1640 {
1641     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1642           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1643
1644     /* FIXME: Check for valid SecurityInformation values */
1645
1646     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1647         return ERROR_INSUFFICIENT_BUFFER;
1648
1649     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1650           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1651
1652     /* Do not leave security descriptor filled with garbage */
1653     RtlCreateSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1654
1655     return ERROR_SUCCESS;
1656 }
1657
1658
1659 /******************************************************************************
1660  * RegFlushKey [ADVAPI32.@]
1661  * Immediately writes key to registry.
1662  * Only returns after data has been written to disk.
1663  *
1664  * FIXME: does it really wait until data is written ?
1665  *
1666  * PARAMS
1667  *    hkey [I] Handle of key to write
1668  *
1669  * RETURNS
1670  *    Success: ERROR_SUCCESS
1671  *    Failure: Error code
1672  */
1673 DWORD WINAPI RegFlushKey( HKEY hkey )
1674 {
1675     FIXME( "(%x): stub\n", hkey );
1676     return ERROR_SUCCESS;
1677 }
1678
1679
1680 /******************************************************************************
1681  * RegConnectRegistryW [ADVAPI32.@]
1682  *
1683  * PARAMS
1684  *    lpMachineName [I] Address of name of remote computer
1685  *    hHey          [I] Predefined registry handle
1686  *    phkResult     [I] Address of buffer for remote registry handle
1687  */
1688 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1689                                    LPHKEY phkResult )
1690 {
1691     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1692
1693     if (!lpMachineName || !*lpMachineName) {
1694         /* Use the local machine name */
1695         return RegOpenKeyA( hKey, "", phkResult );
1696     }
1697
1698     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1699     return ERROR_BAD_NETPATH;
1700 }
1701
1702
1703 /******************************************************************************
1704  * RegConnectRegistryA [ADVAPI32.@]
1705  */
1706 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1707 {
1708     LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1709     DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1710     HeapFree( GetProcessHeap(), 0, machineW );
1711     return ret;
1712 }
1713
1714
1715 /******************************************************************************
1716  * RegNotifyChangeKeyValue [ADVAPI32.@]
1717  *
1718  * PARAMS
1719  *    hkey            [I] Handle of key to watch
1720  *    fWatchSubTree   [I] Flag for subkey notification
1721  *    fdwNotifyFilter [I] Changes to be reported
1722  *    hEvent          [I] Handle of signaled event
1723  *    fAsync          [I] Flag for asynchronous reporting
1724  */
1725 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1726                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1727                                      BOOL fAsync )
1728 {
1729     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1730           hEvent,fAsync);
1731     return ERROR_SUCCESS;
1732 }