- Migrate CRTDLL to MSVCRT.
[wine/hacks.git] / memory / registry.c
blob1245c3d1a2a84e76f719c7c59f3705f9915c7b72
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
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
11 * This file is concerned about handle management and interaction with the Wine server.
12 * Registry file I/O is in misc/registry.c.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
19 #include "winbase.h"
20 #include "winreg.h"
21 #include "winerror.h"
22 #include "wine/winbase16.h"
23 #include "wine/unicode.h"
24 #include "heap.h"
25 #include "server.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(reg);
31 /* check if value type needs string conversion (Ansi<->Unicode) */
32 static inline int is_string( DWORD type )
34 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
37 /* do a server call without setting the last error code */
38 static inline int reg_server_call( enum request req )
40 unsigned int res = server_call_noerr( req );
41 if (res) res = RtlNtStatusToDosError(res);
42 return res;
45 /******************************************************************************
46 * RegCreateKeyExA [ADVAPI32.130]
48 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
49 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
50 LPHKEY retkey, LPDWORD dispos )
52 OBJECT_ATTRIBUTES attr;
53 UNICODE_STRING nameW, classW;
54 ANSI_STRING nameA, classA;
55 NTSTATUS status;
57 if (reserved) return ERROR_INVALID_PARAMETER;
58 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
60 attr.Length = sizeof(attr);
61 attr.RootDirectory = hkey;
62 attr.ObjectName = &nameW;
63 attr.Attributes = 0;
64 attr.SecurityDescriptor = NULL;
65 attr.SecurityQualityOfService = NULL;
66 RtlInitAnsiString( &nameA, name );
67 RtlInitAnsiString( &classA, class );
69 /* FIXME: should use Unicode buffer in TEB */
70 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
72 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
74 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
75 RtlFreeUnicodeString( &classW );
77 RtlFreeUnicodeString( &nameW );
79 return RtlNtStatusToDosError( status );
83 /******************************************************************************
84 * RegCreateKeyA [ADVAPI32.129]
86 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
88 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
89 KEY_ALL_ACCESS, NULL, retkey, NULL );
94 /******************************************************************************
95 * RegOpenKeyExA [ADVAPI32.149]
97 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
99 OBJECT_ATTRIBUTES attr;
100 UNICODE_STRING nameW;
101 STRING nameA;
102 NTSTATUS status;
104 attr.Length = sizeof(attr);
105 attr.RootDirectory = hkey;
106 attr.ObjectName = &nameW;
107 attr.Attributes = 0;
108 attr.SecurityDescriptor = NULL;
109 attr.SecurityQualityOfService = NULL;
111 RtlInitAnsiString( &nameA, name );
112 /* FIXME: should use Unicode buffer in TEB */
113 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
115 status = NtOpenKey( retkey, access, &attr );
116 RtlFreeUnicodeString( &nameW );
118 return RtlNtStatusToDosError( status );
122 /******************************************************************************
123 * RegOpenKeyA [ADVAPI32.148]
125 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
127 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
131 /******************************************************************************
132 * RegEnumKeyExA [ADVAPI32.138]
134 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
135 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
137 NTSTATUS status;
138 char buffer[256], *buf_ptr = buffer;
139 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
140 DWORD total_size;
142 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
143 name_len ? *name_len : -1, reserved, class, class_len, ft );
145 if (reserved) return ERROR_INVALID_PARAMETER;
147 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
148 buffer, sizeof(buffer), &total_size );
150 while (status == STATUS_BUFFER_OVERFLOW)
152 /* retry with a dynamically allocated buffer */
153 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
154 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
155 return ERROR_NOT_ENOUGH_MEMORY;
156 info = (KEY_NODE_INFORMATION *)buf_ptr;
157 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
158 buf_ptr, total_size, &total_size );
161 if (!status)
163 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
164 NULL, 0, NULL, NULL );
165 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
166 info->ClassLength / sizeof(WCHAR),
167 NULL, 0, NULL, NULL );
169 if (ft) *ft = info->LastWriteTime;
171 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
172 status = STATUS_BUFFER_OVERFLOW;
173 else
175 *name_len = len;
176 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
177 name, len, NULL, NULL );
178 name[len] = 0;
179 if (class_len)
181 *class_len = cls_len;
182 if (class)
184 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
185 info->ClassLength / sizeof(WCHAR),
186 class, cls_len, NULL, NULL );
187 class[cls_len] = 0;
193 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
194 return RtlNtStatusToDosError( status );
198 /******************************************************************************
199 * RegEnumKeyA [ADVAPI32.137]
201 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
203 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
207 /******************************************************************************
208 * RegQueryInfoKeyA [ADVAPI32.152]
210 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
211 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
212 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
213 LPDWORD security, FILETIME *modif )
215 NTSTATUS status;
216 char buffer[256], *buf_ptr = buffer;
217 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
218 DWORD total_size;
220 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
221 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
223 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
224 return ERROR_INVALID_PARAMETER;
226 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
228 if (class || class_len)
230 /* retry with a dynamically allocated buffer */
231 while (status == STATUS_BUFFER_OVERFLOW)
233 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
234 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
235 return ERROR_NOT_ENOUGH_MEMORY;
236 info = (KEY_FULL_INFORMATION *)buf_ptr;
237 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
240 if (!status)
242 DWORD len = WideCharToMultiByte( CP_ACP, 0,
243 (WCHAR *)(buf_ptr + info->ClassOffset),
244 info->ClassLength/sizeof(WCHAR),
245 NULL, 0, NULL, NULL );
246 if (class_len)
248 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
249 *class_len = len;
251 if (class && !status)
253 WideCharToMultiByte( CP_ACP, 0,
254 (WCHAR *)(buf_ptr + info->ClassOffset),
255 info->ClassLength/sizeof(WCHAR),
256 class, len, NULL, NULL );
257 class[len] = 0;
262 if (!status || status == STATUS_BUFFER_OVERFLOW)
264 if (subkeys) *subkeys = info->SubKeys;
265 if (max_subkey) *max_subkey = info->MaxNameLen;
266 if (max_class) *max_class = info->MaxClassLen;
267 if (values) *values = info->Values;
268 if (max_value) *max_value = info->MaxValueNameLen;
269 if (max_data) *max_data = info->MaxValueDataLen;
270 if (modif) *modif = info->LastWriteTime;
273 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
274 return RtlNtStatusToDosError( status );
278 /******************************************************************************
279 * RegCloseKey [ADVAPI32.126]
281 * Releases the handle of the specified key
283 * PARAMS
284 * hkey [I] Handle of key to close
286 * RETURNS
287 * Success: ERROR_SUCCESS
288 * Failure: Error code
290 DWORD WINAPI RegCloseKey( HKEY hkey )
292 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
293 return RtlNtStatusToDosError( NtClose( hkey ) );
297 /******************************************************************************
298 * RegDeleteKeyA [ADVAPI32.133]
300 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
302 DWORD ret;
303 HKEY tmp;
305 if (!name || !*name) return NtDeleteKey( hkey );
306 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
308 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
309 RegCloseKey( tmp );
311 return ret;
316 /******************************************************************************
317 * RegSetValueExA [ADVAPI32.169]
319 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
320 CONST BYTE *data, DWORD count )
322 UNICODE_STRING nameW;
323 ANSI_STRING nameA;
324 WCHAR *dataW = NULL;
325 NTSTATUS status;
327 if (count && is_string(type))
329 /* if user forgot to count terminating null, add it (yes NT does this) */
330 if (data[count-1] && !data[count]) count++;
333 if (is_string( type )) /* need to convert to Unicode */
335 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
336 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
337 return ERROR_OUTOFMEMORY;
338 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
339 count = lenW * sizeof(WCHAR);
340 data = (BYTE *)dataW;
343 RtlInitAnsiString( &nameA, name );
344 /* FIXME: should use Unicode buffer in TEB */
345 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
347 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
348 RtlFreeUnicodeString( &nameW );
350 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
351 return RtlNtStatusToDosError( status );
355 /******************************************************************************
356 * RegSetValueA [ADVAPI32.168]
358 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
360 HKEY subkey = hkey;
361 DWORD ret;
363 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
365 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
367 if (name && name[0]) /* need to create the subkey */
369 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
371 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
372 if (subkey != hkey) RegCloseKey( subkey );
373 return ret;
378 /******************************************************************************
379 * RegQueryValueExA [ADVAPI32.157]
381 * NOTES:
382 * the documentation is wrong: if the buffer is too small it remains untouched
384 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
385 LPBYTE data, LPDWORD count )
387 NTSTATUS status;
388 ANSI_STRING nameA;
389 UNICODE_STRING nameW;
390 DWORD total_size;
391 char buffer[256], *buf_ptr = buffer;
392 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
393 static const int info_size = sizeof(*info) - sizeof(info->Data);
395 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
396 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
398 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
400 RtlInitAnsiString( &nameA, name );
401 /* FIXME: should use Unicode buffer in TEB */
402 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
403 return RtlNtStatusToDosError(status);
405 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
406 buffer, sizeof(buffer), &total_size );
407 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
409 /* we need to fetch the contents for a string type even if not requested,
410 * because we need to compute the length of the ASCII string. */
411 if (data || is_string(info->Type))
413 /* retry with a dynamically allocated buffer */
414 while (status == STATUS_BUFFER_OVERFLOW)
416 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
417 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
419 status = STATUS_NO_MEMORY;
420 goto done;
422 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
423 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
424 buf_ptr, total_size, &total_size );
427 if (!status)
429 if (is_string(info->Type))
431 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
432 (total_size - info_size) /sizeof(WCHAR),
433 NULL, 0, NULL, NULL );
434 if (data && len)
436 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
437 else
439 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
440 (total_size - info_size) /sizeof(WCHAR),
441 data, len, NULL, NULL );
442 /* if the type is REG_SZ and data is not 0-terminated
443 * and there is enough space in the buffer NT appends a \0 */
444 if (len < *count && data[len-1]) data[len] = 0;
447 total_size = len + info_size;
449 else if (data)
451 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
452 else memcpy( data, buf_ptr + info_size, total_size - info_size );
455 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
458 if (type) *type = info->Type;
459 if (count) *count = total_size - info_size;
461 done:
462 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
463 RtlFreeUnicodeString( &nameW );
464 return RtlNtStatusToDosError(status);
468 /******************************************************************************
469 * RegQueryValueA [ADVAPI32.156]
471 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
473 DWORD ret;
474 HKEY subkey = hkey;
476 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
478 if (name && name[0])
480 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
482 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
483 if (subkey != hkey) RegCloseKey( subkey );
484 if (ret == ERROR_FILE_NOT_FOUND)
486 /* return empty string if default value not found */
487 if (data) *data = 0;
488 if (count) *count = 1;
489 ret = ERROR_SUCCESS;
491 return ret;
495 /******************************************************************************
496 * RegEnumValueA [ADVAPI32.141]
498 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
499 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
501 NTSTATUS status;
502 DWORD total_size;
503 char buffer[256], *buf_ptr = buffer;
504 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
505 static const int info_size = sizeof(*info) - sizeof(info->Name);
507 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
508 hkey, index, value, val_count, reserved, type, data, count );
510 /* NT only checks count, not val_count */
511 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
513 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
514 if (data) total_size += *count;
515 total_size = min( sizeof(buffer), total_size );
517 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
518 buffer, total_size, &total_size );
519 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
521 /* we need to fetch the contents for a string type even if not requested,
522 * because we need to compute the length of the ASCII string. */
523 if (value || data || is_string(info->Type))
525 /* retry with a dynamically allocated buffer */
526 while (status == STATUS_BUFFER_OVERFLOW)
528 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
529 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
530 return ERROR_NOT_ENOUGH_MEMORY;
531 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
532 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
533 buf_ptr, total_size, &total_size );
536 if (status) goto done;
538 if (value)
540 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
541 NULL, 0, NULL, NULL );
542 if (len >= *val_count)
544 status = STATUS_BUFFER_OVERFLOW;
545 goto done;
547 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
548 value, len, NULL, NULL );
549 value[len] = 0;
550 *val_count = len;
553 if (is_string(info->Type))
555 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
556 (total_size - info->DataOffset) / sizeof(WCHAR),
557 NULL, 0, NULL, NULL );
558 if (data && len)
560 if (len > *count)
562 status = STATUS_BUFFER_OVERFLOW;
563 goto done;
565 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
566 (total_size - info->DataOffset) / sizeof(WCHAR),
567 data, len, NULL, NULL );
568 /* if the type is REG_SZ and data is not 0-terminated
569 * and there is enough space in the buffer NT appends a \0 */
570 if (len < *count && data[len-1]) data[len] = 0;
572 info->DataLength = len;
574 else if (data)
576 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
577 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
581 if (type) *type = info->Type;
582 if (count) *count = info->DataLength;
584 done:
585 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
586 return RtlNtStatusToDosError(status);
591 /******************************************************************************
592 * RegDeleteValueA [ADVAPI32.135]
594 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
596 UNICODE_STRING nameW;
597 STRING nameA;
598 NTSTATUS status;
600 RtlInitAnsiString( &nameA, name );
601 /* FIXME: should use Unicode buffer in TEB */
602 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
604 status = NtDeleteValueKey( hkey, &nameW );
605 RtlFreeUnicodeString( &nameW );
607 return RtlNtStatusToDosError( status );
611 /******************************************************************************
612 * RegLoadKeyA [ADVAPI32.184]
614 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
616 HANDLE file;
617 DWORD ret, len, err = GetLastError();
619 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
621 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
622 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
624 len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
625 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
627 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
628 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
630 ret = GetLastError();
631 goto done;
634 SERVER_START_REQ
636 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
637 req->hkey = hkey;
638 req->file = file;
639 MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey),
640 server_data_ptr(req), len/sizeof(WCHAR) );
641 ret = reg_server_call( REQ_LOAD_REGISTRY );
643 SERVER_END_REQ;
644 CloseHandle( file );
646 done:
647 SetLastError( err ); /* restore the last error code */
648 return ret;
652 /******************************************************************************
653 * RegSaveKeyA [ADVAPI32.165]
655 * PARAMS
656 * hkey [I] Handle of key where save begins
657 * lpFile [I] Address of filename to save to
658 * sa [I] Address of security structure
660 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
662 char buffer[1024];
663 int count = 0;
664 LPSTR name;
665 DWORD ret, err;
666 HANDLE handle;
668 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
670 if (!file || !*file) return ERROR_INVALID_PARAMETER;
672 err = GetLastError();
673 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
674 for (;;)
676 sprintf( name, "reg%04x.tmp", count++ );
677 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
678 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
679 if (handle != INVALID_HANDLE_VALUE) break;
680 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
682 /* Something gone haywire ? Please report if this happens abnormally */
683 if (count >= 100)
684 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);
687 SERVER_START_REQ
689 struct save_registry_request *req = server_alloc_req( sizeof(*req), 0 );
690 req->hkey = hkey;
691 req->file = handle;
692 ret = reg_server_call( REQ_SAVE_REGISTRY );
694 SERVER_END_REQ;
696 CloseHandle( handle );
697 if (!ret)
699 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
701 ERR( "Failed to move %s to %s\n", buffer, file );
702 ret = GetLastError();
705 if (ret) DeleteFileA( buffer );
707 done:
708 SetLastError( err ); /* restore last error code */
709 return ret;