ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

reg.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS system libraries
00004  * FILE:            lib/advapi32/reg/reg.c
00005  * PURPOSE:         Registry functions
00006  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
00007  *                  Thomas Weidenmueller <w3seek@reactos.com>
00008  * UPDATE HISTORY:
00009  *                  Created 01/11/98
00010  *                  19990309 EA Stubs
00011  *                  20050502 Fireball imported some stuff from WINE
00012  */
00013 
00014 /* INCLUDES *****************************************************************/
00015 
00016 #include <advapi32.h>
00017 WINE_DEFAULT_DEBUG_CHANNEL(reg);
00018 
00019 /* DEFINES ******************************************************************/
00020 
00021 #define MAX_DEFAULT_HANDLES   6
00022 #define REG_MAX_NAME_SIZE     256
00023 #define REG_MAX_DATA_SIZE     2048
00024 
00025 /* GLOBALS ******************************************************************/
00026 
00027 static RTL_CRITICAL_SECTION HandleTableCS;
00028 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
00029 static HANDLE ProcessHeap;
00030 static BOOLEAN DefaultHandlesDisabled = FALSE;
00031 static BOOLEAN DefaultHandleHKUDisabled = FALSE;
00032 static BOOLEAN DllInitialized = FALSE; /* HACK */
00033 
00034 /* PROTOTYPES ***************************************************************/
00035 
00036 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key);
00037 static VOID CloseDefaultKeys(VOID);
00038 #define ClosePredefKey(Handle)                                                 \
00039     if ((ULONG_PTR)Handle & 0x1) {                                             \
00040         NtClose(Handle);                                                       \
00041     }
00042 #define IsPredefKey(HKey)                                                      \
00043     (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
00044 #define GetPredefKeyIndex(HKey)                                                \
00045     ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
00046 
00047 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
00048 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle);
00049 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle);
00050 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle);
00051 
00052 
00053 /* FUNCTIONS ****************************************************************/
00054 /* check if value type needs string conversion (Ansi<->Unicode) */
00055 __inline static int is_string( DWORD type )
00056 {
00057     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
00058 }
00059 
00060 /************************************************************************
00061  *  RegInitDefaultHandles
00062  */
00063 BOOL
00064 RegInitialize(VOID)
00065 {
00066     TRACE("RegInitialize()\n");
00067 
00068     /* Lazy init hack */
00069     if (!DllInitialized)
00070     {
00071         ProcessHeap = RtlGetProcessHeap();
00072         RtlZeroMemory(DefaultHandleTable,
00073                       MAX_DEFAULT_HANDLES * sizeof(HANDLE));
00074         RtlInitializeCriticalSection(&HandleTableCS);
00075 
00076         DllInitialized = TRUE;
00077     }
00078 
00079     return TRUE;
00080 }
00081 
00082 
00083 /************************************************************************
00084  *  RegInit
00085  */
00086 BOOL
00087 RegCleanup(VOID)
00088 {
00089     TRACE("RegCleanup()\n");
00090 
00091     CloseDefaultKeys();
00092     RtlDeleteCriticalSection(&HandleTableCS);
00093 
00094     return TRUE;
00095 }
00096 
00097 
00098 static NTSTATUS
00099 OpenPredefinedKey(IN ULONG Index,
00100                   OUT HANDLE Handle)
00101 {
00102     NTSTATUS Status;
00103 
00104     switch (Index)
00105     {
00106         case 0: /* HKEY_CLASSES_ROOT */
00107             Status = OpenClassesRootKey (Handle);
00108             break;
00109 
00110         case 1: /* HKEY_CURRENT_USER */
00111             Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED,
00112                                          Handle);
00113             break;
00114 
00115         case 2: /* HKEY_LOCAL_MACHINE */
00116             Status = OpenLocalMachineKey (Handle);
00117             break;
00118 
00119         case 3: /* HKEY_USERS */
00120             Status = OpenUsersKey (Handle);
00121             break;
00122 #if 0
00123         case 4: /* HKEY_PERFORMANCE_DATA */
00124             Status = OpenPerformanceDataKey (Handle);
00125             break;
00126 #endif
00127 
00128         case 5: /* HKEY_CURRENT_CONFIG */
00129             Status = OpenCurrentConfigKey (Handle);
00130             break;
00131 
00132         case 6: /* HKEY_DYN_DATA */
00133             Status = STATUS_NOT_IMPLEMENTED;
00134             break;
00135 
00136         default:
00137             WARN("MapDefaultHandle() no handle creator\n");
00138             Status = STATUS_INVALID_PARAMETER;
00139             break;
00140     }
00141 
00142     return Status;
00143 }
00144 
00145 
00146 static NTSTATUS
00147 MapDefaultKey(OUT PHANDLE RealKey,
00148               IN HKEY Key)
00149 {
00150     PHANDLE Handle;
00151     ULONG Index;
00152     BOOLEAN DoOpen, DefDisabled;
00153     NTSTATUS Status = STATUS_SUCCESS;
00154 
00155     TRACE("MapDefaultKey (Key %x)\n", Key);
00156 
00157     if (!IsPredefKey(Key))
00158     {
00159         *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
00160         return STATUS_SUCCESS;
00161     }
00162 
00163     /* Handle special cases here */
00164     Index = GetPredefKeyIndex(Key);
00165     if (Index >= MAX_DEFAULT_HANDLES)
00166     {
00167         return STATUS_INVALID_PARAMETER;
00168     }
00169     RegInitialize(); /* HACK until delay-loading is implemented */
00170     RtlEnterCriticalSection (&HandleTableCS);
00171 
00172     if (Key == HKEY_CURRENT_USER)
00173         DefDisabled = DefaultHandleHKUDisabled;
00174     else
00175         DefDisabled = DefaultHandlesDisabled;
00176 
00177     if (!DefDisabled)
00178     {
00179         Handle = &DefaultHandleTable[Index];
00180         DoOpen = (*Handle == NULL);
00181     }
00182     else
00183     {
00184         Handle = RealKey;
00185         DoOpen = TRUE;
00186     }
00187 
00188     if (DoOpen)
00189     {
00190         /* create/open the default handle */
00191         Status = OpenPredefinedKey(Index,
00192                                    Handle);
00193     }
00194 
00195     if (NT_SUCCESS(Status))
00196     {
00197         if (!DefDisabled)
00198             *RealKey = *Handle;
00199         else
00200             *(PULONG_PTR)Handle |= 0x1;
00201     }
00202 
00203     RtlLeaveCriticalSection (&HandleTableCS);
00204 
00205     return Status;
00206 }
00207 
00208 
00209 static VOID
00210 CloseDefaultKeys(VOID)
00211 {
00212     ULONG i;
00213     RegInitialize(); /* HACK until delay-loading is implemented */
00214     RtlEnterCriticalSection(&HandleTableCS);
00215 
00216     for (i = 0; i < MAX_DEFAULT_HANDLES; i++)
00217     {
00218         if (DefaultHandleTable[i] != NULL)
00219         {
00220             NtClose(DefaultHandleTable[i]);
00221             DefaultHandleTable[i] = NULL;
00222         }
00223     }
00224 
00225     RtlLeaveCriticalSection(&HandleTableCS);
00226 }
00227 
00228 
00229 static NTSTATUS
00230 OpenClassesRootKey(PHANDLE KeyHandle)
00231 {
00232     OBJECT_ATTRIBUTES Attributes;
00233     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
00234 
00235     TRACE("OpenClassesRootKey()\n");
00236 
00237     InitializeObjectAttributes(&Attributes,
00238                                &KeyName,
00239                                OBJ_CASE_INSENSITIVE,
00240                                NULL,
00241                                NULL);
00242     return NtOpenKey(KeyHandle,
00243                      MAXIMUM_ALLOWED,
00244                      &Attributes);
00245 }
00246 
00247 
00248 static NTSTATUS
00249 OpenLocalMachineKey(PHANDLE KeyHandle)
00250 {
00251     OBJECT_ATTRIBUTES Attributes;
00252     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
00253     NTSTATUS Status;
00254 
00255     TRACE("OpenLocalMachineKey()\n");
00256 
00257     InitializeObjectAttributes(&Attributes,
00258                                &KeyName,
00259                                OBJ_CASE_INSENSITIVE,
00260                                NULL,
00261                                NULL);
00262     Status = NtOpenKey(KeyHandle,
00263                        MAXIMUM_ALLOWED,
00264                        &Attributes);
00265 
00266     TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status);
00267 
00268     return Status;
00269 }
00270 
00271 
00272 static NTSTATUS
00273 OpenUsersKey(PHANDLE KeyHandle)
00274 {
00275     OBJECT_ATTRIBUTES Attributes;
00276     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User");
00277 
00278     TRACE("OpenUsersKey()\n");
00279 
00280     InitializeObjectAttributes(&Attributes,
00281                                &KeyName,
00282                                OBJ_CASE_INSENSITIVE,
00283                                NULL,
00284                                NULL);
00285     return NtOpenKey(KeyHandle,
00286                      MAXIMUM_ALLOWED,
00287                      &Attributes);
00288 }
00289 
00290 
00291 static NTSTATUS
00292 OpenCurrentConfigKey (PHANDLE KeyHandle)
00293 {
00294     OBJECT_ATTRIBUTES Attributes;
00295     UNICODE_STRING KeyName =
00296         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
00297 
00298     TRACE("OpenCurrentConfigKey()\n");
00299 
00300     InitializeObjectAttributes(&Attributes,
00301                                &KeyName,
00302                                OBJ_CASE_INSENSITIVE,
00303                                NULL,
00304                                NULL);
00305     return NtOpenKey(KeyHandle,
00306                      MAXIMUM_ALLOWED,
00307                      &Attributes);
00308 }
00309 
00310 
00311 /************************************************************************
00312  *  RegDisablePredefinedCache
00313  *
00314  * @implemented
00315  */
00316 LONG WINAPI
00317 RegDisablePredefinedCache(VOID)
00318 {
00319     RegInitialize(); /* HACK until delay-loading is implemented */
00320     RtlEnterCriticalSection(&HandleTableCS);
00321     DefaultHandleHKUDisabled = TRUE;
00322     RtlLeaveCriticalSection(&HandleTableCS);
00323     return ERROR_SUCCESS;
00324 }
00325 
00326 
00327 /************************************************************************
00328  *  RegDisablePredefinedCacheEx
00329  *
00330  * @implemented
00331  */
00332 LONG WINAPI
00333 RegDisablePredefinedCacheEx(VOID)
00334 {
00335     RegInitialize(); /* HACK until delay-loading is implemented */
00336     RtlEnterCriticalSection(&HandleTableCS);
00337     DefaultHandlesDisabled = TRUE;
00338     DefaultHandleHKUDisabled = TRUE;
00339     RtlLeaveCriticalSection(&HandleTableCS);
00340     return ERROR_SUCCESS;
00341 }
00342 
00343 
00344 /************************************************************************
00345  *  RegOverridePredefKey
00346  *
00347  * @implemented
00348  */
00349 LONG WINAPI
00350 RegOverridePredefKey(IN HKEY hKey,
00351                      IN HKEY hNewHKey  OPTIONAL)
00352 {
00353     LONG ErrorCode = ERROR_SUCCESS;
00354 
00355     if ((hKey == HKEY_CLASSES_ROOT ||
00356          hKey == HKEY_CURRENT_CONFIG ||
00357          hKey == HKEY_CURRENT_USER ||
00358          hKey == HKEY_LOCAL_MACHINE ||
00359          hKey == HKEY_PERFORMANCE_DATA ||
00360          hKey == HKEY_USERS) &&
00361         !IsPredefKey(hNewHKey))
00362     {
00363         PHANDLE Handle;
00364         ULONG Index;
00365 
00366         Index = GetPredefKeyIndex(hKey);
00367         Handle = &DefaultHandleTable[Index];
00368 
00369         if (hNewHKey == NULL)
00370         {
00371             /* restore the default mapping */
00372             NTSTATUS Status = OpenPredefinedKey(Index,
00373                                                 &hNewHKey);
00374             if (!NT_SUCCESS(Status))
00375             {
00376                 return RtlNtStatusToDosError(Status);
00377             }
00378 
00379             ASSERT(hNewHKey != NULL);
00380         }
00381         RegInitialize(); /* HACK until delay-loading is implemented */
00382         RtlEnterCriticalSection(&HandleTableCS);
00383 
00384         /* close the currently mapped handle if existing */
00385         if (*Handle != NULL)
00386         {
00387             NtClose(*Handle);
00388         }
00389 
00390         /* update the mapping */
00391         *Handle = hNewHKey;
00392 
00393         RtlLeaveCriticalSection(&HandleTableCS);
00394     }
00395     else
00396         ErrorCode = ERROR_INVALID_HANDLE;
00397 
00398     return ErrorCode;
00399 }
00400 
00401 
00402 /************************************************************************
00403  *  RegCloseKey
00404  *
00405  * @implemented
00406  */
00407 LONG WINAPI
00408 RegCloseKey(HKEY hKey)
00409 {
00410     NTSTATUS Status;
00411 
00412     /* don't close null handle or a pseudo handle */
00413     if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
00414     {
00415         return ERROR_INVALID_HANDLE;
00416     }
00417 
00418     Status = NtClose(hKey);
00419     if (!NT_SUCCESS(Status))
00420     {
00421         return RtlNtStatusToDosError(Status);
00422     }
00423 
00424   return ERROR_SUCCESS;
00425 }
00426 
00427 
00428 static NTSTATUS
00429 RegpCopyTree(IN HKEY hKeySrc,
00430              IN HKEY hKeyDest)
00431 {
00432     typedef struct
00433     {
00434         LIST_ENTRY ListEntry;
00435         HANDLE hKeySrc;
00436         HANDLE hKeyDest;
00437     } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
00438 
00439     LIST_ENTRY copyQueueHead;
00440     PREGP_COPY_KEYS copyKeys, newCopyKeys;
00441     union
00442     {
00443         KEY_VALUE_FULL_INFORMATION *KeyValue;
00444         KEY_NODE_INFORMATION *KeyNode;
00445         PVOID Buffer;
00446     } Info;
00447     ULONG Index, BufferSizeRequired, BufferSize = 0x200;
00448     NTSTATUS Status = STATUS_SUCCESS;
00449     NTSTATUS Status2 = STATUS_SUCCESS;
00450 
00451     InitializeListHead(&copyQueueHead);
00452 
00453     Info.Buffer = RtlAllocateHeap(ProcessHeap,
00454                                   0,
00455                                   BufferSize);
00456     if (Info.Buffer == NULL)
00457     {
00458         return STATUS_INSUFFICIENT_RESOURCES;
00459     }
00460 
00461     copyKeys = RtlAllocateHeap(ProcessHeap,
00462                                0,
00463                                sizeof(REGP_COPY_KEYS));
00464     if (copyKeys != NULL)
00465     {
00466         copyKeys->hKeySrc = hKeySrc;
00467         copyKeys->hKeyDest = hKeyDest;
00468         InsertHeadList(&copyQueueHead,
00469                        &copyKeys->ListEntry);
00470 
00471         /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
00472 
00473         do
00474         {
00475             copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
00476                                          REGP_COPY_KEYS,
00477                                          ListEntry);
00478 
00479             /* enumerate all values and copy them */
00480             Index = 0;
00481             for (;;)
00482             {
00483                 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
00484                                               Index,
00485                                               KeyValueFullInformation,
00486                                               Info.KeyValue,
00487                                               BufferSize,
00488                                               &BufferSizeRequired);
00489                 if (NT_SUCCESS(Status2))
00490                 {
00491                     UNICODE_STRING ValueName;
00492                     PVOID Data;
00493 
00494                     /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
00495                     ValueName.Length = Info.KeyValue->NameLength;
00496                     ValueName.MaximumLength = ValueName.Length;
00497                     ValueName.Buffer = Info.KeyValue->Name;
00498 
00499                     Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
00500 
00501                     Status2 = NtSetValueKey(copyKeys->hKeyDest,
00502                                             &ValueName,
00503                                             Info.KeyValue->TitleIndex,
00504                                             Info.KeyValue->Type,
00505                                             Data,
00506                                             Info.KeyValue->DataLength);
00507 
00508                     /* don't break, let's try to copy as many values as possible */
00509                     if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
00510                     {
00511                         Status = Status2;
00512                     }
00513 
00514                     Index++;
00515                 }
00516                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
00517                 {
00518                     PVOID Buffer;
00519 
00520                     ASSERT(BufferSize < BufferSizeRequired);
00521 
00522                     Buffer = RtlReAllocateHeap(ProcessHeap,
00523                                                0,
00524                                                Info.Buffer,
00525                                                BufferSizeRequired);
00526                     if (Buffer != NULL)
00527                     {
00528                         Info.Buffer = Buffer;
00529                         /* try again */
00530                     }
00531                     else
00532                     {
00533                         /* don't break, let's try to copy as many values as possible */
00534                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
00535                         Index++;
00536 
00537                         if (NT_SUCCESS(Status))
00538                         {
00539                             Status = Status2;
00540                         }
00541                     }
00542                 }
00543                 else
00544                 {
00545                     /* break to avoid an infinite loop in case of denied access or
00546                        other errors! */
00547                     if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
00548                     {
00549                         Status = Status2;
00550                     }
00551 
00552                     break;
00553                 }
00554             }
00555 
00556             /* enumerate all subkeys and open and enqueue them */
00557             Index = 0;
00558             for (;;)
00559             {
00560                 Status2 = NtEnumerateKey(copyKeys->hKeySrc,
00561                                          Index,
00562                                          KeyNodeInformation,
00563                                          Info.KeyNode,
00564                                          BufferSize,
00565                                          &BufferSizeRequired);
00566                 if (NT_SUCCESS(Status2))
00567                 {
00568                     HANDLE KeyHandle, NewKeyHandle;
00569                     OBJECT_ATTRIBUTES ObjectAttributes;
00570                     UNICODE_STRING SubKeyName, ClassName;
00571 
00572                     /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
00573                     SubKeyName.Length = Info.KeyNode->NameLength;
00574                     SubKeyName.MaximumLength = SubKeyName.Length;
00575                     SubKeyName.Buffer = Info.KeyNode->Name;
00576                     ClassName.Length = Info.KeyNode->ClassLength;
00577                     ClassName.MaximumLength = ClassName.Length;
00578                     ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
00579 
00580                     /* open the subkey with sufficient rights */
00581 
00582                     InitializeObjectAttributes(&ObjectAttributes,
00583                                                &SubKeyName,
00584                                                OBJ_CASE_INSENSITIVE,
00585                                                copyKeys->hKeySrc,
00586                                                NULL);
00587 
00588                     Status2 = NtOpenKey(&KeyHandle,
00589                                         KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
00590                                         &ObjectAttributes);
00591                     if (NT_SUCCESS(Status2))
00592                     {
00593                         /* FIXME - attempt to query the security information */
00594 
00595                         InitializeObjectAttributes(&ObjectAttributes,
00596                                                &SubKeyName,
00597                                                OBJ_CASE_INSENSITIVE,
00598                                                copyKeys->hKeyDest,
00599                                                NULL);
00600 
00601                         Status2 = NtCreateKey(&NewKeyHandle,
00602                                               KEY_ALL_ACCESS,
00603                                               &ObjectAttributes,
00604                                               Info.KeyNode->TitleIndex,
00605                                               &ClassName,
00606                                               0,
00607                                               NULL);
00608                         if (NT_SUCCESS(Status2))
00609                         {
00610                             newCopyKeys = RtlAllocateHeap(ProcessHeap,
00611                                                           0,
00612                                                           sizeof(REGP_COPY_KEYS));
00613                             if (newCopyKeys != NULL)
00614                             {
00615                                 /* save the handles and enqueue the subkey */
00616                                 newCopyKeys->hKeySrc = KeyHandle;
00617                                 newCopyKeys->hKeyDest = NewKeyHandle;
00618                                 InsertTailList(&copyQueueHead,
00619                                                &newCopyKeys->ListEntry);
00620                             }
00621                             else
00622                             {
00623                                 NtClose(KeyHandle);
00624                                 NtClose(NewKeyHandle);
00625 
00626                                 Status2 = STATUS_INSUFFICIENT_RESOURCES;
00627                             }
00628                         }
00629                         else
00630                         {
00631                             NtClose(KeyHandle);
00632                         }
00633                     }
00634 
00635                     if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
00636                     {
00637                         Status = Status2;
00638                     }
00639 
00640                     Index++;
00641                 }
00642                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
00643                 {
00644                     PVOID Buffer;
00645 
00646                     ASSERT(BufferSize < BufferSizeRequired);
00647 
00648                     Buffer = RtlReAllocateHeap(ProcessHeap,
00649                                                0,
00650                                                Info.Buffer,
00651                                                BufferSizeRequired);
00652                     if (Buffer != NULL)
00653                     {
00654                         Info.Buffer = Buffer;
00655                         /* try again */
00656                     }
00657                     else
00658                     {
00659                         /* don't break, let's try to copy as many keys as possible */
00660                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
00661                         Index++;
00662 
00663                         if (NT_SUCCESS(Status))
00664                         {
00665                             Status = Status2;
00666                         }
00667                     }
00668                 }
00669                 else
00670                 {
00671                     /* break to avoid an infinite loop in case of denied access or
00672                        other errors! */
00673                     if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
00674                     {
00675                         Status = Status2;
00676                     }
00677 
00678                     break;
00679                 }
00680             }
00681 
00682             /* close the handles and remove the entry from the list */
00683             if (copyKeys->hKeySrc != hKeySrc)
00684             {
00685                 NtClose(copyKeys->hKeySrc);
00686             }
00687             if (copyKeys->hKeyDest != hKeyDest)
00688             {
00689                 NtClose(copyKeys->hKeyDest);
00690             }
00691 
00692             RemoveEntryList(&copyKeys->ListEntry);
00693 
00694             RtlFreeHeap(ProcessHeap,
00695                         0,
00696                         copyKeys);
00697         } while (!IsListEmpty(&copyQueueHead));
00698     }
00699     else
00700         Status = STATUS_INSUFFICIENT_RESOURCES;
00701 
00702     RtlFreeHeap(ProcessHeap,
00703                 0,
00704                 Info.Buffer);
00705 
00706     return Status;
00707 }
00708 
00709 
00710 /************************************************************************
00711  *  RegCopyTreeW
00712  *
00713  * @implemented
00714  */
00715 LONG WINAPI
00716 RegCopyTreeW(IN HKEY hKeySrc,
00717              IN LPCWSTR lpSubKey  OPTIONAL,
00718              IN HKEY hKeyDest)
00719 {
00720     HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL;
00721     NTSTATUS Status;
00722 
00723     Status = MapDefaultKey(&KeyHandle,
00724                            hKeySrc);
00725     if (!NT_SUCCESS(Status))
00726     {
00727         return RtlNtStatusToDosError(Status);
00728     }
00729 
00730     Status = MapDefaultKey(&DestKeyHandle,
00731                            hKeyDest);
00732     if (!NT_SUCCESS(Status))
00733     {
00734         goto Cleanup2;
00735     }
00736 
00737     if (lpSubKey != NULL)
00738     {
00739         OBJECT_ATTRIBUTES ObjectAttributes;
00740         UNICODE_STRING SubKeyName;
00741 
00742         RtlInitUnicodeString(&SubKeyName,
00743                              (LPWSTR)lpSubKey);
00744 
00745         InitializeObjectAttributes(&ObjectAttributes,
00746                                    &SubKeyName,
00747                                    OBJ_CASE_INSENSITIVE,
00748                                    KeyHandle,
00749                                    NULL);
00750 
00751         Status = NtOpenKey(&SubKeyHandle,
00752                            KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
00753                            &ObjectAttributes);
00754         if (!NT_SUCCESS(Status))
00755         {
00756             goto Cleanup;
00757         }
00758 
00759         CurKey = SubKeyHandle;
00760     }
00761     else
00762         CurKey = KeyHandle;
00763 
00764     Status = RegpCopyTree(CurKey,
00765                           hKeyDest);
00766 
00767     if (SubKeyHandle != NULL)
00768     {
00769         NtClose(SubKeyHandle);
00770     }
00771 
00772 Cleanup:
00773     ClosePredefKey(DestKeyHandle);
00774 Cleanup2:
00775     ClosePredefKey(KeyHandle);
00776 
00777     if (!NT_SUCCESS(Status))
00778     {
00779         return RtlNtStatusToDosError(Status);
00780     }
00781 
00782     return ERROR_SUCCESS;
00783 }
00784 
00785 
00786 /************************************************************************
00787  *  RegCopyTreeA
00788  *
00789  * @implemented
00790  */
00791 LONG WINAPI
00792 RegCopyTreeA(IN HKEY hKeySrc,
00793              IN LPCSTR lpSubKey  OPTIONAL,
00794              IN HKEY hKeyDest)
00795 {
00796     UNICODE_STRING SubKeyName = { 0, 0, NULL };
00797     LONG Ret;
00798 
00799     if (lpSubKey != NULL &&
00800         !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
00801                                           (LPSTR)lpSubKey))
00802     {
00803         return ERROR_NOT_ENOUGH_MEMORY;
00804     }
00805 
00806     Ret = RegCopyTreeW(hKeySrc,
00807                        SubKeyName.Buffer,
00808                        hKeyDest);
00809 
00810     RtlFreeUnicodeString(&SubKeyName);
00811 
00812     return Ret;
00813 }
00814 
00815 
00816 /************************************************************************
00817  *  RegConnectRegistryA
00818  *
00819  * @implemented
00820  */
00821 LONG WINAPI
00822 RegConnectRegistryA(IN LPCSTR lpMachineName,
00823                     IN HKEY hKey,
00824                     OUT PHKEY phkResult)
00825 {
00826     UNICODE_STRING MachineName = { 0, 0, NULL };
00827     LONG Ret;
00828 
00829     if (lpMachineName != NULL &&
00830         !RtlCreateUnicodeStringFromAsciiz(&MachineName,
00831                                           (LPSTR)lpMachineName))
00832     {
00833         return ERROR_NOT_ENOUGH_MEMORY;
00834     }
00835 
00836     Ret = RegConnectRegistryW(MachineName.Buffer,
00837                               hKey,
00838                               phkResult);
00839 
00840     RtlFreeUnicodeString(&MachineName);
00841 
00842     return Ret;
00843 }
00844 
00845 
00846 /************************************************************************
00847  *  RegConnectRegistryW
00848  *
00849  * @unimplemented
00850  */
00851 LONG WINAPI
00852 RegConnectRegistryW(LPCWSTR lpMachineName,
00853                     HKEY hKey,
00854                     PHKEY phkResult)
00855 {
00856     LONG ret;
00857 
00858     TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
00859 
00860     if (!lpMachineName || !*lpMachineName)
00861     {
00862         /* Use the local machine name */
00863         ret = RegOpenKeyW( hKey, NULL, phkResult );
00864     }
00865     else
00866     {
00867         WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
00868         DWORD len = sizeof(compName) / sizeof(WCHAR);
00869 
00870         /* MSDN says lpMachineName must start with \\ : not so */
00871         if( lpMachineName[0] == '\\' &&  lpMachineName[1] == '\\')
00872             lpMachineName += 2;
00873 
00874         if (GetComputerNameW(compName, &len))
00875         {
00876             if (!_wcsicmp(lpMachineName, compName))
00877                 ret = RegOpenKeyW(hKey, NULL, phkResult);
00878             else
00879             {
00880                 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
00881                 ret = ERROR_BAD_NETPATH;
00882             }
00883         }
00884         else
00885             ret = GetLastError();
00886     }
00887 
00888     return ret;
00889 }
00890 
00891 
00892 /************************************************************************
00893  *  CreateNestedKey
00894  *
00895  *  Create key and all necessary intermediate keys
00896  */
00897 static NTSTATUS
00898 CreateNestedKey(PHKEY KeyHandle,
00899                 POBJECT_ATTRIBUTES ObjectAttributes,
00900                 PUNICODE_STRING ClassString,
00901                 DWORD dwOptions,
00902                 REGSAM samDesired,
00903                 DWORD *lpdwDisposition)
00904 {
00905     OBJECT_ATTRIBUTES LocalObjectAttributes;
00906     UNICODE_STRING LocalKeyName;
00907     ULONG Disposition;
00908     NTSTATUS Status;
00909     ULONG FullNameLength;
00910     ULONG Length;
00911     PWCHAR Ptr;
00912     HANDLE LocalKeyHandle;
00913 
00914     Status = NtCreateKey((PHANDLE) KeyHandle,
00915                          samDesired,
00916                          ObjectAttributes,
00917                          0,
00918                          ClassString,
00919                          dwOptions,
00920                          (PULONG)lpdwDisposition);
00921     TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
00922     if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
00923         return Status;
00924 
00925     /* Copy object attributes */
00926     RtlCopyMemory(&LocalObjectAttributes,
00927                   ObjectAttributes,
00928                   sizeof(OBJECT_ATTRIBUTES));
00929     RtlCreateUnicodeString(&LocalKeyName,
00930                            ObjectAttributes->ObjectName->Buffer);
00931     LocalObjectAttributes.ObjectName = &LocalKeyName;
00932     FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
00933 
00934   LocalKeyHandle = NULL;
00935 
00936     /* Remove the last part of the key name and try to create the key again. */
00937     while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
00938     {
00939         Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
00940         if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
00941         {
00942             Status = STATUS_UNSUCCESSFUL;
00943             break;
00944         }
00945 
00946         *Ptr = (WCHAR)0;
00947         LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
00948 
00949         Status = NtCreateKey(&LocalKeyHandle,
00950                              KEY_CREATE_SUB_KEY,
00951                              &LocalObjectAttributes,
00952                              0,
00953                              NULL,
00954                              0,
00955                              &Disposition);
00956         TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
00957     }
00958 
00959     if (!NT_SUCCESS(Status))
00960     {
00961         RtlFreeUnicodeString(&LocalKeyName);
00962         return Status;
00963     }
00964 
00965     /* Add removed parts of the key name and create them too. */
00966     Length = wcslen(LocalKeyName.Buffer);
00967     while (TRUE)
00968     {
00969         if (LocalKeyHandle)
00970             NtClose (LocalKeyHandle);
00971 
00972         LocalKeyName.Buffer[Length] = L'\\';
00973         Length = wcslen (LocalKeyName.Buffer);
00974         LocalKeyName.Length = Length * sizeof(WCHAR);
00975 
00976         if (Length == FullNameLength)
00977         {
00978             Status = NtCreateKey((PHANDLE) KeyHandle,
00979                                  samDesired,
00980                                  ObjectAttributes,
00981                                  0,
00982                                  ClassString,
00983                                  dwOptions,
00984                                  (PULONG)lpdwDisposition);
00985             break;
00986         }
00987 
00988         Status = NtCreateKey(&LocalKeyHandle,
00989                              KEY_CREATE_SUB_KEY,
00990                              &LocalObjectAttributes,
00991                              0,
00992                              NULL,
00993                              0,
00994                              &Disposition);
00995         TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
00996         if (!NT_SUCCESS(Status))
00997             break;
00998     }
00999 
01000     RtlFreeUnicodeString(&LocalKeyName);
01001 
01002     return Status;
01003 }
01004 
01005 
01006 /************************************************************************
01007  *  RegCreateKeyExA
01008  *
01009  * @implemented
01010  */
01011 LONG WINAPI
01012 RegCreateKeyExA(HKEY hKey,
01013                 LPCSTR lpSubKey,
01014                 DWORD Reserved,
01015                 LPSTR lpClass,
01016                 DWORD dwOptions,
01017                 REGSAM samDesired,
01018                 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
01019                 PHKEY phkResult,
01020                 LPDWORD lpdwDisposition)
01021 {
01022     UNICODE_STRING SubKeyString;
01023     UNICODE_STRING ClassString;
01024     OBJECT_ATTRIBUTES Attributes;
01025     HANDLE ParentKey;
01026     NTSTATUS Status;
01027 
01028     TRACE("RegCreateKeyExA() called\n");
01029 
01030     if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
01031         return ERROR_INVALID_USER_BUFFER;
01032 
01033     /* get the real parent key */
01034     Status = MapDefaultKey(&ParentKey,
01035                            hKey);
01036     if (!NT_SUCCESS(Status))
01037     {
01038         return RtlNtStatusToDosError(Status);
01039     }
01040 
01041     TRACE("ParentKey %p\n", ParentKey);
01042 
01043     if (lpClass != NULL)
01044     {
01045         RtlCreateUnicodeStringFromAsciiz(&ClassString,
01046                                          lpClass);
01047     }
01048 
01049     RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
01050                                      (LPSTR)lpSubKey);
01051     InitializeObjectAttributes(&Attributes,
01052                                &SubKeyString,
01053                                OBJ_CASE_INSENSITIVE,
01054                                (HANDLE)ParentKey,
01055                                lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
01056     Status = CreateNestedKey(phkResult,
01057                              &Attributes,
01058                              (lpClass == NULL)? NULL : &ClassString,
01059                              dwOptions,
01060                              samDesired,
01061                              lpdwDisposition);
01062     RtlFreeUnicodeString(&SubKeyString);
01063     if (lpClass != NULL)
01064     {
01065         RtlFreeUnicodeString(&ClassString);
01066     }
01067 
01068     ClosePredefKey(ParentKey);
01069 
01070     TRACE("Status %x\n", Status);
01071     if (!NT_SUCCESS(Status))
01072     {
01073         return RtlNtStatusToDosError(Status);
01074     }
01075 
01076     return ERROR_SUCCESS;
01077 }
01078 
01079 
01080 /************************************************************************
01081  *  RegCreateKeyExW
01082  *
01083  * @implemented
01084  */
01085 LONG WINAPI
01086 RegCreateKeyExW(HKEY hKey,
01087                 LPCWSTR lpSubKey,
01088                 DWORD Reserved,
01089                 LPWSTR lpClass,
01090                 DWORD dwOptions,
01091                 REGSAM samDesired,
01092                 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
01093                 PHKEY phkResult,
01094                 LPDWORD lpdwDisposition)
01095 {
01096     UNICODE_STRING SubKeyString;
01097     UNICODE_STRING ClassString;
01098     OBJECT_ATTRIBUTES Attributes;
01099     HANDLE ParentKey;
01100     NTSTATUS Status;
01101 
01102     TRACE("RegCreateKeyExW() called\n");
01103 
01104     if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
01105         return ERROR_INVALID_USER_BUFFER;
01106 
01107     /* get the real parent key */
01108     Status = MapDefaultKey(&ParentKey,
01109                            hKey);
01110     if (!NT_SUCCESS(Status))
01111     {
01112         return RtlNtStatusToDosError(Status);
01113     }
01114 
01115     TRACE("ParentKey %p\n", ParentKey);
01116 
01117     RtlInitUnicodeString(&ClassString,
01118                          lpClass);
01119     RtlInitUnicodeString(&SubKeyString,
01120                          lpSubKey);
01121     InitializeObjectAttributes(&Attributes,
01122                                &SubKeyString,
01123                                OBJ_CASE_INSENSITIVE,
01124                                (HANDLE)ParentKey,
01125                                lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
01126     Status = CreateNestedKey(phkResult,
01127                              &Attributes,
01128                              (lpClass == NULL)? NULL : &ClassString,
01129                              dwOptions,
01130                              samDesired,
01131                              lpdwDisposition);
01132 
01133     ClosePredefKey(ParentKey);
01134 
01135     TRACE("Status %x\n", Status);
01136     if (!NT_SUCCESS(Status))
01137     {
01138         return RtlNtStatusToDosError(Status);
01139     }
01140 
01141     return ERROR_SUCCESS;
01142 }
01143 
01144 
01145 /************************************************************************
01146  *  RegCreateKeyA
01147  *
01148  * @implemented
01149  */
01150 LONG WINAPI
01151 RegCreateKeyA(HKEY hKey,
01152               LPCSTR lpSubKey,
01153               PHKEY phkResult)
01154 {
01155     return RegCreateKeyExA(hKey,
01156                            lpSubKey,
01157                            0,
01158                            NULL,
01159                            0,
01160                            MAXIMUM_ALLOWED,
01161                            NULL,
01162                            phkResult,
01163                            NULL);
01164 }
01165 
01166 
01167 /************************************************************************
01168  *  RegCreateKeyW
01169  *
01170  * @implemented
01171  */
01172 LONG WINAPI
01173 RegCreateKeyW(HKEY hKey,
01174               LPCWSTR lpSubKey,
01175               PHKEY phkResult)
01176 {
01177     return RegCreateKeyExW(hKey,
01178                            lpSubKey,
01179                            0,
01180                            NULL,
01181                            0,
01182                            MAXIMUM_ALLOWED,
01183                            NULL,
01184                            phkResult,
01185                            NULL);
01186 }
01187 
01188 
01189 /************************************************************************
01190  *  RegDeleteKeyA
01191  *
01192  * @implemented
01193  */
01194 LONG WINAPI
01195 RegDeleteKeyA(HKEY hKey,
01196               LPCSTR lpSubKey)
01197 {
01198     OBJECT_ATTRIBUTES ObjectAttributes;
01199     UNICODE_STRING SubKeyName;
01200     HANDLE ParentKey;
01201     HANDLE TargetKey;
01202     NTSTATUS Status;
01203 
01204     /* Make sure we got a subkey */
01205     if (!lpSubKey)
01206     {
01207         /* Fail */
01208         return ERROR_INVALID_PARAMETER;
01209     }
01210 
01211     Status = MapDefaultKey(&ParentKey,
01212                            hKey);
01213     if (!NT_SUCCESS(Status))
01214     {
01215         return RtlNtStatusToDosError(Status);
01216     }
01217 
01218     RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
01219                                      (LPSTR)lpSubKey);
01220     InitializeObjectAttributes(&ObjectAttributes,
01221                                &SubKeyName,
01222                                OBJ_CASE_INSENSITIVE,
01223                                ParentKey,
01224                                NULL);
01225 
01226     Status = NtOpenKey(&TargetKey,
01227                        DELETE,
01228                        &ObjectAttributes);
01229     RtlFreeUnicodeString(&SubKeyName);
01230     if (!NT_SUCCESS(Status))
01231     {
01232         goto Cleanup;
01233     }
01234 
01235     Status = NtDeleteKey(TargetKey);
01236     NtClose (TargetKey);
01237 
01238 Cleanup:
01239     ClosePredefKey(ParentKey);
01240 
01241     if (!NT_SUCCESS(Status))
01242     {
01243         return RtlNtStatusToDosError(Status);
01244     }
01245 
01246     return ERROR_SUCCESS;
01247 }
01248 
01249 
01250 /************************************************************************
01251  *  RegDeleteKeyW
01252  *
01253  * @implemented
01254  */
01255 LONG WINAPI
01256 RegDeleteKeyW(HKEY hKey,
01257               LPCWSTR lpSubKey)
01258 {
01259     OBJECT_ATTRIBUTES ObjectAttributes;
01260     UNICODE_STRING SubKeyName;
01261     HANDLE ParentKey;
01262     HANDLE TargetKey;
01263     NTSTATUS Status;
01264 
01265     /* Make sure we got a subkey */
01266     if (!lpSubKey)
01267     {
01268         /* Fail */
01269         return ERROR_INVALID_PARAMETER;
01270     }
01271 
01272     Status = MapDefaultKey(&ParentKey,
01273                            hKey);
01274     if (!NT_SUCCESS(Status))
01275     {
01276         return RtlNtStatusToDosError(Status);
01277     }
01278 
01279     RtlInitUnicodeString(&SubKeyName,
01280                          (LPWSTR)lpSubKey);
01281     InitializeObjectAttributes(&ObjectAttributes,
01282                                &SubKeyName,
01283                                OBJ_CASE_INSENSITIVE,
01284                                ParentKey,
01285                                NULL);
01286     Status = NtOpenKey(&TargetKey,
01287                        DELETE,
01288                        &ObjectAttributes);
01289     if (!NT_SUCCESS(Status))
01290     {
01291         goto Cleanup;
01292     }
01293 
01294     Status = NtDeleteKey(TargetKey);
01295     NtClose(TargetKey);
01296 
01297 Cleanup:
01298     ClosePredefKey(ParentKey);
01299 
01300     if (!NT_SUCCESS(Status))
01301     {
01302         return RtlNtStatusToDosError(Status);
01303     }
01304 
01305     return ERROR_SUCCESS;
01306 }
01307 
01308 
01309 /************************************************************************
01310  *  RegDeleteKeyExA
01311  *
01312  * @unimplemented
01313  */
01314 LONG
01315 WINAPI
01316 RegDeleteKeyExA(HKEY hKey,
01317                 LPCSTR lpSubKey,
01318                 REGSAM samDesired,
01319                 DWORD Reserved)
01320 {
01321     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
01322     return ERROR_CALL_NOT_IMPLEMENTED;
01323 }
01324 
01325 
01326 /************************************************************************
01327  *  RegDeleteKeyExW
01328  *
01329  * @unimplemented
01330  */
01331 LONG
01332 WINAPI
01333 RegDeleteKeyExW(HKEY hKey,
01334                 LPCWSTR lpSubKey,
01335                 REGSAM samDesired,
01336                 DWORD Reserved)
01337 {
01338     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
01339     return ERROR_CALL_NOT_IMPLEMENTED;
01340 }
01341 
01342 
01343 /************************************************************************
01344  *  RegDeleteKeyValueW
01345  *
01346  * @implemented
01347  */
01348 LONG WINAPI
01349 RegDeleteKeyValueW(IN HKEY hKey,
01350                    IN LPCWSTR lpSubKey  OPTIONAL,
01351                    IN LPCWSTR lpValueName  OPTIONAL)
01352 {
01353     UNICODE_STRING ValueName;
01354     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
01355     NTSTATUS Status;
01356 
01357     Status = MapDefaultKey(&KeyHandle,
01358                            hKey);
01359     if (!NT_SUCCESS(Status))
01360     {
01361         return RtlNtStatusToDosError(Status);
01362     }
01363 
01364     if (lpSubKey != NULL)
01365     {
01366         OBJECT_ATTRIBUTES ObjectAttributes;
01367         UNICODE_STRING SubKeyName;
01368 
01369         RtlInitUnicodeString(&SubKeyName,
01370                              (LPWSTR)lpSubKey);
01371 
01372         InitializeObjectAttributes(&ObjectAttributes,
01373                                    &SubKeyName,
01374                                    OBJ_CASE_INSENSITIVE,
01375                                    KeyHandle,
01376                                    NULL);
01377 
01378         Status = NtOpenKey(&SubKeyHandle,
01379                            KEY_SET_VALUE,
01380                            &ObjectAttributes);
01381         if (!NT_SUCCESS(Status))
01382         {
01383             goto Cleanup;
01384         }
01385 
01386         CurKey = SubKeyHandle;
01387     }
01388     else
01389         CurKey = KeyHandle;
01390 
01391     RtlInitUnicodeString(&ValueName,
01392                          (LPWSTR)lpValueName);
01393 
01394     Status = NtDeleteValueKey(CurKey,
01395                               &ValueName);
01396 
01397     if (SubKeyHandle != NULL)
01398     {
01399         NtClose(SubKeyHandle);
01400     }
01401 
01402 Cleanup:
01403     ClosePredefKey(KeyHandle);
01404 
01405     if (!NT_SUCCESS(Status))
01406     {
01407         return RtlNtStatusToDosError(Status);
01408     }
01409 
01410     return ERROR_SUCCESS;
01411 }
01412 
01413 
01414 /************************************************************************
01415  *  RegDeleteKeyValueA
01416  *
01417  * @implemented
01418  */
01419 LONG WINAPI
01420 RegDeleteKeyValueA(IN HKEY hKey,
01421                    IN LPCSTR lpSubKey  OPTIONAL,
01422                    IN LPCSTR lpValueName  OPTIONAL)
01423 {
01424     UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL };
01425     LONG Ret;
01426 
01427     if (lpSubKey != NULL &&
01428         !RtlCreateUnicodeStringFromAsciiz(&SubKey,
01429                                           (LPSTR)lpSubKey))
01430     {
01431         return ERROR_NOT_ENOUGH_MEMORY;
01432     }
01433 
01434     if (lpValueName != NULL &&
01435         !RtlCreateUnicodeStringFromAsciiz(&ValueName,
01436                                           (LPSTR)lpValueName))
01437     {
01438         RtlFreeUnicodeString(&SubKey);
01439         return ERROR_NOT_ENOUGH_MEMORY;
01440     }
01441 
01442     Ret = RegDeleteKeyValueW(hKey,
01443                              SubKey.Buffer,
01444                              SubKey.Buffer);
01445 
01446     RtlFreeUnicodeString(&SubKey);
01447     RtlFreeUnicodeString(&ValueName);
01448 
01449     return Ret;
01450 }
01451 
01452 #if 0
01453 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
01454 static NTSTATUS
01455 RegpDeleteTree(IN HKEY hKey)
01456 {
01457     typedef struct
01458     {
01459         LIST_ENTRY ListEntry;
01460         HANDLE KeyHandle;
01461     } REGP_DEL_KEYS, *PREG_DEL_KEYS;
01462 
01463     LIST_ENTRY delQueueHead;
01464     PREG_DEL_KEYS delKeys, newDelKeys;
01465     HANDLE ProcessHeap;
01466     ULONG BufferSize;
01467     PKEY_BASIC_INFORMATION BasicInfo;
01468     PREG_DEL_KEYS KeyDelRoot;
01469     NTSTATUS Status = STATUS_SUCCESS;
01470     NTSTATUS Status2 = STATUS_SUCCESS;
01471 
01472     InitializeListHead(&delQueueHead);
01473 
01474     ProcessHeap = RtlGetProcessHeap();
01475 
01476     /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
01477              structure for the root key, we only do that for subkeys as we need to
01478              allocate REGP_DEL_KEYS structures anyway! */
01479     KeyDelRoot = RtlAllocateHeap(ProcessHeap,
01480                                  0,
01481                                  sizeof(REGP_DEL_KEYS));
01482     if (KeyDelRoot != NULL)
01483     {
01484         KeyDelRoot->KeyHandle = hKey;
01485         InsertTailList(&delQueueHead,
01486                        &KeyDelRoot->ListEntry);
01487 
01488         do
01489         {
01490             delKeys = CONTAINING_RECORD(delQueueHead.Flink,
01491                                         REGP_DEL_KEYS,
01492                                         ListEntry);
01493 
01494             BufferSize = 0;
01495             BasicInfo = NULL;
01496             newDelKeys = NULL;
01497 
01498 ReadFirstSubKey:
01499             /* check if this key contains subkeys and delete them first by queuing
01500                them at the head of the list */
01501             Status2 = NtEnumerateKey(delKeys->KeyHandle,
01502                                      0,
01503                                      KeyBasicInformation,
01504                                      BasicInfo,
01505                                      BufferSize,
01506                                      &BufferSize);
01507 
01508             if (NT_SUCCESS(Status2))
01509             {
01510                 OBJECT_ATTRIBUTES ObjectAttributes;
01511                 UNICODE_STRING SubKeyName;
01512 
01513                 ASSERT(newDelKeys != NULL);
01514                 ASSERT(BasicInfo != NULL);
01515 
01516                 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
01517                 SubKeyName.Length = BasicInfo->NameLength;
01518                 SubKeyName.MaximumLength = BasicInfo->NameLength;
01519                 SubKeyName.Buffer = BasicInfo->Name;
01520 
01521                 InitializeObjectAttributes(&ObjectAttributes,
01522                                            &SubKeyName,
01523                                            OBJ_CASE_INSENSITIVE,
01524                                            delKeys->KeyHandle,
01525                                            NULL);
01526 
01527                 /* open the subkey */
01528                 Status2 = NtOpenKey(&newDelKeys->KeyHandle,
01529                                     DELETE | KEY_ENUMERATE_SUB_KEYS,
01530                                     &ObjectAttributes);
01531                 if (!NT_SUCCESS(Status2))
01532                 {
01533                     goto SubKeyFailure;
01534                 }
01535 
01536                 /* enqueue this key to the head of the deletion queue */
01537                 InsertHeadList(&delQueueHead,
01538                                &newDelKeys->ListEntry);
01539 
01540                 /* try again from the head of the list */
01541                 continue;
01542             }
01543             else
01544             {
01545                 if (Status2 == STATUS_BUFFER_TOO_SMALL)
01546                 {
01547                     newDelKeys = RtlAllocateHeap(ProcessHeap,
01548                                                  0,
01549                                                  BufferSize + sizeof(REGP_DEL_KEYS));
01550                     if (newDelKeys != NULL)
01551                     {
01552                         BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
01553 
01554                         /* try again */
01555                         goto ReadFirstSubKey;
01556                     }
01557                     else
01558                     {
01559                         /* don't break, let's try to delete as many keys as possible */
01560                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
01561                         goto SubKeyFailureNoFree;
01562                     }
01563                 }
01564                 else if (Status2 == STATUS_BUFFER_OVERFLOW)
01565                 {
01566                     PREG_DEL_KEYS newDelKeys2;
01567 
01568                     ASSERT(newDelKeys != NULL);
01569 
01570                     /* we need more memory to query the key name */
01571                     newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
01572                                                     0,
01573                                                     newDelKeys,
01574                                                     BufferSize + sizeof(REGP_DEL_KEYS));
01575                     if (newDelKeys2 != NULL)
01576                     {
01577                         newDelKeys = newDelKeys2;
01578                         BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
01579 
01580                         /* try again */
01581                         goto ReadFirstSubKey;
01582                     }
01583                     else
01584                     {
01585                         /* don't break, let's try to delete as many keys as possible */
01586                         Status2 = STATUS_INSUFFICIENT_RESOURCES;
01587                     }
01588                 }
01589                 else if (Status2 == STATUS_NO_MORE_ENTRIES)
01590                 {
01591                     /* in some race conditions where another thread would delete
01592                        the same tree at the same time, newDelKeys could actually
01593                        be != NULL! */
01594                     if (newDelKeys != NULL)
01595                     {
01596                         RtlFreeHeap(ProcessHeap,
01597                                     0,
01598                                     newDelKeys);
01599                     }
01600                     break;
01601                 }
01602 
01603 SubKeyFailure:
01604                 /* newDelKeys can be NULL here when NtEnumerateKey returned an
01605                    error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
01606                 if (newDelKeys != NULL)
01607                 {
01608                     RtlFreeHeap(ProcessHeap,
01609                                 0,
01610                                 newDelKeys);
01611                 }
01612 
01613 SubKeyFailureNoFree:
01614                 /* don't break, let's try to delete as many keys as possible */
01615                 if (NT_SUCCESS(Status))
01616                 {
01617                     Status = Status2;
01618                 }
01619             }
01620 
01621             Status2 = NtDeleteKey(delKeys->KeyHandle);
01622 
01623             /* NOTE: do NOT close the handle anymore, it's invalid already! */
01624 
01625             if (!NT_SUCCESS(Status2))
01626             {
01627                 /* close the key handle so we don't leak handles for keys we were
01628                    unable to delete. But only do this for handles not supplied
01629                    by the caller! */
01630 
01631                 if (delKeys->KeyHandle != hKey)
01632                 {
01633                     NtClose(delKeys->KeyHandle);
01634                 }
01635 
01636                 if (NT_SUCCESS(Status))
01637                 {
01638                     /* don't break, let's try to delete as many keys as possible */
01639                     Status = Status2;
01640                 }
01641             }
01642 
01643             /* remove the entry from the list */
01644             RemoveEntryList(&delKeys->ListEntry);
01645 
01646             RtlFreeHeap(ProcessHeap,
01647                         0,
01648                         delKeys);
01649         } while (!IsListEmpty(&delQueueHead));
01650     }
01651     else
01652         Status = STATUS_INSUFFICIENT_RESOURCES;
01653 
01654     return Status;
01655 }
01656 
01657 
01658 /************************************************************************
01659  *  RegDeleteTreeW
01660  *
01661  * @implemented
01662  */
01663 LONG WINAPI
01664 RegDeleteTreeW(IN HKEY hKey,
01665                IN LPCWSTR lpSubKey  OPTIONAL)
01666 {
01667     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
01668     NTSTATUS Status;
01669 
01670     Status = MapDefaultKey(&KeyHandle,
01671                            hKey);
01672     if (!NT_SUCCESS(Status))
01673     {
01674         return RtlNtStatusToDosError(Status);
01675     }
01676 
01677     if (lpSubKey != NULL)
01678     {
01679         OBJECT_ATTRIBUTES ObjectAttributes;
01680         UNICODE_STRING SubKeyName;
01681 
01682         RtlInitUnicodeString(&SubKeyName,
01683                              (LPWSTR)lpSubKey);
01684 
01685         InitializeObjectAttributes(&ObjectAttributes,
01686                                    &SubKeyName,
01687                                    OBJ_CASE_INSENSITIVE,
01688                                    KeyHandle,
01689                                    NULL);
01690 
01691         Status = NtOpenKey(&SubKeyHandle,
01692                            DELETE | KEY_ENUMERATE_SUB_KEYS,
01693                            &ObjectAttributes);
01694         if (!NT_SUCCESS(Status))
01695         {
01696             goto Cleanup;
01697         }
01698 
01699         CurKey = SubKeyHandle;
01700     }
01701     else
01702         CurKey = KeyHandle;
01703 
01704     Status = RegpDeleteTree(CurKey);
01705 
01706     if (NT_SUCCESS(Status))
01707     {
01708         /* make sure we only close hKey (KeyHandle) when the caller specified a
01709            subkey, because the handle would be invalid already! */
01710         if (CurKey != KeyHandle)
01711         {
01712             ClosePredefKey(KeyHandle);
01713         }
01714 
01715         return ERROR_SUCCESS;
01716     }
01717     else
01718     {
01719         /* make sure we close all handles we created! */
01720         if (SubKeyHandle != NULL)
01721         {
01722             NtClose(SubKeyHandle);
01723         }
01724 
01725 Cleanup:
01726         ClosePredefKey(KeyHandle);
01727 
01728         return RtlNtStatusToDosError(Status);
01729     }
01730 }
01731 #endif
01732 
01733 
01734 /************************************************************************
01735  *  RegDeleteTreeW
01736  *
01737  * @implemented
01738  */
01739 LSTATUS
01740 WINAPI
01741 RegDeleteTreeW(HKEY hKey,
01742                LPCWSTR lpszSubKey)
01743 {
01744     LONG ret;
01745     DWORD dwMaxSubkeyLen, dwMaxValueLen;
01746     DWORD dwMaxLen, dwSize;
01747     NTSTATUS Status;
01748     HANDLE KeyHandle;
01749     HKEY hSubKey;
01750     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
01751 
01752     TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
01753 
01754     Status = MapDefaultKey(&KeyHandle,
01755                            hKey);
01756     if (!NT_SUCCESS(Status))
01757     {
01758         return RtlNtStatusToDosError(Status);
01759     }
01760 
01761     hSubKey = KeyHandle;
01762 
01763     if(lpszSubKey)
01764     {
01765         ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey);
01766         if (ret)
01767         {
01768             ClosePredefKey(KeyHandle);
01769             return ret;
01770         }
01771     }
01772 
01773     /* Get highest length for keys, values */
01774     ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
01775             &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
01776     if (ret) goto cleanup;
01777 
01778     dwMaxSubkeyLen++;
01779     dwMaxValueLen++;
01780     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
01781     if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
01782     {
01783         /* Name too big: alloc a buffer for it */
01784         if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
01785         {
01786             ret = ERROR_NOT_ENOUGH_MEMORY;
01787             goto cleanup;
01788         }
01789     }
01790 
01791 
01792     /* Recursively delete all the subkeys */
01793     while (TRUE)
01794     {
01795         dwSize = dwMaxLen;
01796         if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
01797                           NULL, NULL, NULL)) break;
01798 
01799         ret = RegDeleteTreeW(hSubKey, lpszName);
01800         if (ret) goto cleanup;
01801     }
01802 
01803     if (lpszSubKey)
01804         ret = RegDeleteKeyW(KeyHandle, lpszSubKey);
01805     else
01806         while (TRUE)
01807         {
01808             dwSize = dwMaxLen;
01809             if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize,
01810                   NULL, NULL, NULL, NULL)) break;
01811 
01812             ret = RegDeleteValueW(KeyHandle, lpszName);
01813             if (ret) goto cleanup;
01814         }
01815 
01816 cleanup:
01817     /* Free buffer if allocated */
01818     if (lpszName != szNameBuf)
01819         RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName);
01820     if(lpszSubKey)
01821         RegCloseKey(hSubKey);
01822 
01823     ClosePredefKey(KeyHandle);
01824 
01825     return ret;
01826 }
01827 
01828 
01829 /************************************************************************
01830  *  RegDeleteTreeA
01831  *
01832  * @implemented
01833  */
01834 LONG WINAPI
01835 RegDeleteTreeA(IN HKEY hKey,
01836                IN LPCSTR lpSubKey  OPTIONAL)
01837 {
01838     UNICODE_STRING SubKeyName = { 0, 0, NULL };
01839     LONG Ret;
01840 
01841     if (lpSubKey != NULL &&
01842         !RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
01843                                           (LPSTR)lpSubKey))
01844     {
01845         return ERROR_NOT_ENOUGH_MEMORY;
01846     }
01847 
01848     Ret = RegDeleteTreeW(hKey,
01849                          SubKeyName.Buffer);
01850 
01851     RtlFreeUnicodeString(&SubKeyName);
01852 
01853     return Ret;
01854 }
01855 
01856 
01857 /************************************************************************
01858  *  RegDisableReflectionKey
01859  *
01860  * @unimplemented
01861  */
01862 LONG WINAPI
01863 RegDisableReflectionKey(IN HKEY hBase)
01864 {
01865     FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
01866     return ERROR_CALL_NOT_IMPLEMENTED;
01867 }
01868 
01869 
01870 /************************************************************************
01871  *  RegEnableReflectionKey
01872  *
01873  * @unimplemented
01874  */
01875 LONG WINAPI
01876 RegEnableReflectionKey(IN HKEY hBase)
01877 {
01878     FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
01879     return ERROR_CALL_NOT_IMPLEMENTED;
01880 }
01881 
01882 
01883 /******************************************************************************
01884  * RegpApplyRestrictions   [internal]
01885  *
01886  * Helper function for RegGetValueA/W.
01887  */
01888 static VOID
01889 RegpApplyRestrictions(DWORD dwFlags,
01890                       DWORD dwType,
01891                       DWORD cbData,
01892                       PLONG ret)
01893 {
01894     /* Check if the type is restricted by the passed flags */
01895     if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
01896     {
01897         DWORD dwMask = 0;
01898 
01899         switch (dwType)
01900         {
01901         case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
01902         case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
01903         case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
01904         case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
01905         case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
01906         case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
01907         case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
01908         }
01909 
01910         if (dwFlags & dwMask)
01911         {
01912             /* Type is not restricted, check for size mismatch */
01913             if (dwType == REG_BINARY)
01914             {
01915                 DWORD cbExpect = 0;
01916 
01917                 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
01918                     cbExpect = 4;
01919                 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
01920                     cbExpect = 8;
01921 
01922                 if (cbExpect && cbData != cbExpect)
01923                     *ret = ERROR_DATATYPE_MISMATCH;
01924             }
01925         }
01926         else *ret = ERROR_UNSUPPORTED_TYPE;
01927     }
01928 }
01929 
01930 
01931 /******************************************************************************
01932  * RegGetValueW   [ADVAPI32.@]
01933  *
01934  * Retrieves the type and data for a value name associated with a key,
01935  * optionally expanding its content and restricting its type.
01936  *
01937  * PARAMS
01938  *  hKey      [I] Handle to an open key.
01939  *  pszSubKey [I] Name of the subkey of hKey.
01940  *  pszValue  [I] Name of value under hKey/szSubKey to query.
01941  *  dwFlags   [I] Flags restricting the value type to retrieve.
01942  *  pdwType   [O] Destination for the values type, may be NULL.
01943  *  pvData    [O] Destination for the values content, may be NULL.
01944  *  pcbData   [I/O] Size of pvData, updated with the size in bytes required to
01945  *                  retrieve the whole content, including the trailing '\0'
01946  *                  for strings.
01947  *
01948  * RETURNS
01949  *  Success: ERROR_SUCCESS
01950  *  Failure: nonzero error code from Winerror.h
01951  *
01952  * NOTES
01953  *  - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
01954  *    expanded and pdwType is set to REG_SZ instead.
01955  *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 
01956  *    without RRF_NOEXPAND is thus not allowed.
01957  *    An exception is the case where RRF_RT_ANY is specified, because then
01958  *    RRF_NOEXPAND is allowed.
01959  */
01960 LSTATUS WINAPI
01961 RegGetValueW(HKEY hKey,
01962              LPCWSTR pszSubKey,
01963              LPCWSTR pszValue,
01964              DWORD dwFlags,
01965              LPDWORD pdwType,
01966              PVOID pvData,
01967              LPDWORD pcbData)
01968 {
01969     DWORD dwType, cbData = pcbData ? *pcbData : 0;
01970     PVOID pvBuf = NULL;
01971     LONG ret;
01972 
01973     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
01974           hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
01975           pvData, pcbData, cbData);
01976 
01977     if (pvData && !pcbData)
01978         return ERROR_INVALID_PARAMETER;
01979     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
01980             ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
01981         return ERROR_INVALID_PARAMETER;
01982 
01983     if (pszSubKey && pszSubKey[0])
01984     {
01985         ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
01986         if (ret != ERROR_SUCCESS) return ret;
01987     }
01988 
01989     ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
01990 
01991     /* If we are going to expand we need to read in the whole the value even
01992      * if the passed buffer was too small as the expanded string might be
01993      * smaller than the unexpanded one and could fit into cbData bytes. */
01994     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
01995         dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
01996     {
01997         do
01998         {
01999             HeapFree(GetProcessHeap(), 0, pvBuf);
02000 
02001             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
02002             if (!pvBuf)
02003             {
02004                 ret = ERROR_NOT_ENOUGH_MEMORY;
02005                 break;
02006             }
02007 
02008             if (ret == ERROR_MORE_DATA || !pvData)
02009                 ret = RegQueryValueExW(hKey, pszValue, NULL,
02010                                        &dwType, pvBuf, &cbData);
02011             else
02012             {
02013                 /* Even if cbData was large enough we have to copy the
02014                  * string since ExpandEnvironmentStrings can't handle
02015                  * overlapping buffers. */
02016                 CopyMemory(pvBuf, pvData, cbData);
02017             }
02018 
02019             /* Both the type or the value itself could have been modified in
02020              * between so we have to keep retrying until the buffer is large
02021              * enough or we no longer have to expand the value. */
02022         }
02023         while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
02024 
02025         if (ret == ERROR_SUCCESS)
02026         {
02027             /* Recheck dwType in case it changed since the first call */
02028             if (dwType == REG_EXPAND_SZ)
02029             {
02030                 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
02031                                                    pcbData ? *pcbData : 0) * sizeof(WCHAR);
02032                 dwType = REG_SZ;
02033                 if (pvData && pcbData && cbData > *pcbData)
02034                     ret = ERROR_MORE_DATA;
02035             }
02036             else if (pvData)
02037                 CopyMemory(pvData, pvBuf, *pcbData);
02038         }
02039 
02040         HeapFree(GetProcessHeap(), 0, pvBuf);
02041     }
02042 
02043     if (pszSubKey && pszSubKey[0])
02044         RegCloseKey(hKey);
02045 
02046     RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
02047 
02048     if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
02049         ZeroMemory(pvData, *pcbData);
02050 
02051     if (pdwType)
02052         *pdwType = dwType;
02053 
02054     if (pcbData)
02055         *pcbData = cbData;
02056 
02057     return ret;
02058 }
02059 
02060 
02061 /******************************************************************************
02062  * RegGetValueA   [ADVAPI32.@]
02063  *
02064  * See RegGetValueW.
02065  */
02066 LSTATUS WINAPI
02067 RegGetValueA(HKEY hKey,
02068              LPCSTR pszSubKey,
02069              LPCSTR pszValue,
02070              DWORD dwFlags,
02071              LPDWORD pdwType,
02072              PVOID pvData,
02073              LPDWORD pcbData)
02074 {
02075     DWORD dwType, cbData = pcbData ? *pcbData : 0;
02076     PVOID pvBuf = NULL;
02077     LONG ret;
02078 
02079     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
02080           hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
02081           cbData);
02082 
02083     if (pvData && !pcbData)
02084         return ERROR_INVALID_PARAMETER;
02085     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
02086             ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
02087         return ERROR_INVALID_PARAMETER;
02088 
02089     if (pszSubKey && pszSubKey[0])
02090     {
02091         ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
02092         if (ret != ERROR_SUCCESS) return ret;
02093     }
02094 
02095     ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
02096 
02097     /* If we are going to expand we need to read in the whole the value even
02098      * if the passed buffer was too small as the expanded string might be
02099      * smaller than the unexpanded one and could fit into cbData bytes. */
02100     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
02101         (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
02102     {
02103         do {
02104             HeapFree(GetProcessHeap(), 0, pvBuf);
02105 
02106             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
02107             if (!pvBuf)
02108             {
02109                 ret = ERROR_NOT_ENOUGH_MEMORY;
02110                 break;
02111             }
02112 
02113             if (ret == ERROR_MORE_DATA || !pvData)
02114                 ret = RegQueryValueExA(hKey, pszValue, NULL,
02115                                        &dwType, pvBuf, &cbData);
02116             else
02117             {
02118                 /* Even if cbData was large enough we have to copy the
02119                  * string since ExpandEnvironmentStrings can't handle
02120                  * overlapping buffers. */
02121                 CopyMemory(pvBuf, pvData, cbData);
02122             }
02123 
02124             /* Both the type or the value itself could have been modified in
02125              * between so we have to keep retrying until the buffer is large
02126              * enough or we no longer have to expand the value. */
02127         } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
02128 
02129         if (ret == ERROR_SUCCESS)
02130         {
02131             /* Recheck dwType in case it changed since the first call */
02132             if (dwType == REG_EXPAND_SZ)
02133             {
02134                 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
02135                                                    pcbData ? *pcbData : 0);
02136                 dwType = REG_SZ;
02137                 if(pvData && pcbData && cbData > *pcbData)
02138                     ret = ERROR_MORE_DATA;
02139             }
02140             else if (pvData)
02141                 CopyMemory(pvData, pvBuf, *pcbData);
02142         }
02143 
02144         HeapFree(GetProcessHeap(), 0, pvBuf);
02145     }
02146 
02147     if (pszSubKey && pszSubKey[0])
02148         RegCloseKey(hKey);
02149 
02150     RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
02151 
02152     if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
02153         ZeroMemory(pvData, *pcbData);
02154 
02155     if (pdwType) *pdwType = dwType;
02156     if (pcbData) *pcbData = cbData;
02157 
02158     return ret;
02159 }
02160 
02161 
02162 /************************************************************************
02163  *  RegSetKeyValueW
02164  *
02165  * @implemented
02166  */
02167 LONG WINAPI
02168 RegSetKeyValueW(IN HKEY hKey,
02169                 IN LPCWSTR lpSubKey  OPTIONAL,
02170                 IN LPCWSTR lpValueName  OPTIONAL,
02171                 IN DWORD dwType,
02172                 IN LPCVOID lpData  OPTIONAL,
02173                 IN DWORD cbData)
02174 {
02175     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
02176     NTSTATUS Status;
02177     LONG Ret;
02178 
02179     Status = MapDefaultKey(&KeyHandle,
02180                            hKey);
02181     if (!NT_SUCCESS(Status))
02182     {
02183         return RtlNtStatusToDosError(Status);
02184     }
02185 
02186     if (lpSubKey != NULL)
02187     {
02188         OBJECT_ATTRIBUTES ObjectAttributes;
02189         UNICODE_STRING SubKeyName;
02190 
02191         RtlInitUnicodeString(&SubKeyName,
02192                              (LPWSTR)lpSubKey);
02193 
02194         InitializeObjectAttributes(&ObjectAttributes,
02195                                    &SubKeyName,
02196                                    OBJ_CASE_INSENSITIVE,
02197                                    KeyHandle,
02198                                    NULL);
02199 
02200         Status = NtOpenKey(&SubKeyHandle,
02201                            KEY_SET_VALUE,
02202                            &ObjectAttributes);
02203         if (!NT_SUCCESS(Status))
02204         {
02205             Ret = RtlNtStatusToDosError(Status);
02206             goto Cleanup;
02207         }
02208 
02209         CurKey = SubKeyHandle;
02210     }
02211     else
02212         CurKey = KeyHandle;
02213 
02214     Ret = RegSetValueExW(CurKey,
02215                          lpValueName,
02216                          0,
02217                          dwType,
02218                          lpData,
02219                          cbData);
02220 
02221     if (SubKeyHandle != NULL)
02222     {
02223         NtClose(SubKeyHandle);
02224     }
02225 
02226 Cleanup:
02227     ClosePredefKey(KeyHandle);
02228 
02229     return Ret;
02230 }
02231 
02232 
02233 /************************************************************************
02234  *  RegSetKeyValueA
02235  *
02236  * @implemented
02237  */
02238 LONG WINAPI
02239 RegSetKeyValueA(IN HKEY hKey,
02240                 IN LPCSTR lpSubKey  OPTIONAL,
02241                 IN LPCSTR lpValueName  OPTIONAL,
02242                 IN DWORD dwType,
02243                 IN LPCVOID lpData  OPTIONAL,
02244                 IN DWORD cbData)
02245 {
02246     HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
02247     NTSTATUS Status;
02248     LONG Ret;
02249 
02250     Status = MapDefaultKey(&KeyHandle,
02251                            hKey);
02252     if (!NT_SUCCESS(Status))
02253     {
02254         return RtlNtStatusToDosError(Status);
02255     }
02256 
02257     if (lpSubKey != NULL)
02258     {
02259         OBJECT_ATTRIBUTES ObjectAttributes;
02260         UNICODE_STRING SubKeyName;
02261 
02262         if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
02263                                               (LPSTR)lpSubKey))
02264         {
02265             Ret = ERROR_NOT_ENOUGH_MEMORY;
02266             goto Cleanup;
02267         }
02268 
02269         InitializeObjectAttributes(&ObjectAttributes,
02270                                    &SubKeyName,
02271                                    OBJ_CASE_INSENSITIVE,
02272                                    KeyHandle,
02273                                    NULL);
02274 
02275         Status = NtOpenKey(&SubKeyHandle,
02276                            KEY_SET_VALUE,
02277                            &ObjectAttributes);
02278 
02279         RtlFreeUnicodeString(&SubKeyName);
02280 
02281         if (!NT_SUCCESS(Status))
02282         {
02283             Ret = RtlNtStatusToDosError(Status);
02284             goto Cleanup;
02285         }
02286 
02287         CurKey = SubKeyHandle;
02288     }
02289     else
02290         CurKey = KeyHandle;
02291 
02292     Ret = RegSetValueExA(CurKey,
02293                          lpValueName,
02294                          0,
02295                          dwType,
02296                          lpData,
02297                          cbData);
02298 
02299     if (SubKeyHandle != NULL)
02300     {
02301         NtClose(SubKeyHandle);
02302     }
02303 
02304 Cleanup:
02305     ClosePredefKey(KeyHandle);
02306 
02307     return Ret;
02308 }
02309 
02310 
02311 /************************************************************************
02312  *  RegDeleteValueA
02313  *
02314  * @implemented
02315  */
02316 LONG WINAPI
02317 RegDeleteValueA(HKEY hKey,
02318                 LPCSTR lpValueName)
02319 {
02320     UNICODE_STRING ValueName;
02321     HANDLE KeyHandle;
02322     NTSTATUS Status;
02323 
02324     Status = MapDefaultKey(&KeyHandle,
02325                            hKey);
02326     if (!NT_SUCCESS(Status))
02327     {
02328         return RtlNtStatusToDosError(Status);
02329     }
02330 
02331     RtlCreateUnicodeStringFromAsciiz(&ValueName,
02332                                      (LPSTR)lpValueName);
02333     Status = NtDeleteValueKey(KeyHandle,
02334                               &ValueName);
02335     RtlFreeUnicodeString (&ValueName);
02336 
02337     ClosePredefKey(KeyHandle);
02338 
02339     if (!NT_SUCCESS(Status))
02340     {
02341         return RtlNtStatusToDosError(Status);
02342     }
02343 
02344     return ERROR_SUCCESS;
02345 }
02346 
02347 
02348 /************************************************************************
02349  *  RegDeleteValueW
02350  *
02351  * @implemented
02352  */
02353 LONG WINAPI
02354 RegDeleteValueW(HKEY hKey,
02355                 LPCWSTR lpValueName)
02356 {
02357     UNICODE_STRING ValueName;
02358     NTSTATUS Status;
02359     HANDLE KeyHandle;
02360 
02361     Status = MapDefaultKey(&KeyHandle,
02362                            hKey);
02363     if (!NT_SUCCESS(Status))
02364     {
02365         return RtlNtStatusToDosError(Status);
02366     }
02367 
02368     RtlInitUnicodeString(&ValueName,
02369                          (LPWSTR)lpValueName);
02370 
02371     Status = NtDeleteValueKey(KeyHandle,
02372                               &ValueName);
02373 
02374     ClosePredefKey(KeyHandle);
02375 
02376     if (!NT_SUCCESS(Status))
02377     {
02378         return RtlNtStatusToDosError(Status);
02379     }
02380 
02381     return ERROR_SUCCESS;
02382 }
02383 
02384 
02385 /************************************************************************
02386  *  RegEnumKeyA
02387  *
02388  * @implemented
02389  */
02390 LONG WINAPI
02391 RegEnumKeyA(HKEY hKey,
02392             DWORD dwIndex,
02393             LPSTR lpName,
02394             DWORD cbName)
02395 {
02396     DWORD dwLength;
02397 
02398     dwLength = cbName;
02399     return RegEnumKeyExA(hKey,
02400                          dwIndex,
02401                          lpName,
02402                          &dwLength,
02403                          NULL,
02404                          NULL,
02405                          NULL,
02406                          NULL);
02407 }
02408 
02409 
02410 /************************************************************************
02411  *  RegEnumKeyW
02412  *
02413  * @implemented
02414  */
02415 LONG WINAPI
02416 RegEnumKeyW(HKEY hKey,
02417             DWORD dwIndex,
02418             LPWSTR lpName,
02419             DWORD cbName)
02420 {
02421     DWORD dwLength;
02422 
02423     dwLength = cbName;
02424     return RegEnumKeyExW(hKey,
02425                          dwIndex,
02426                          lpName,
02427                          &dwLength,
02428                          NULL,
02429                          NULL,
02430                          NULL,
02431                          NULL);
02432 }
02433 
02434 
02435 /************************************************************************
02436  *  RegEnumKeyExA
02437  *
02438  * @implemented
02439  */
02440 LONG WINAPI
02441 RegEnumKeyExA(HKEY hKey,
02442               DWORD dwIndex,
02443               LPSTR lpName,
02444               LPDWORD lpcbName,
02445               LPDWORD lpReserved,
02446               LPSTR lpClass,
02447               LPDWORD lpcbClass,
02448               PFILETIME lpftLastWriteTime)
02449 {
02450     union
02451     {
02452         KEY_NODE_INFORMATION Node;
02453         KEY_BASIC_INFORMATION Basic;
02454     } *KeyInfo;
02455 
02456     UNICODE_STRING StringU;
02457     ANSI_STRING StringA;
02458     LONG ErrorCode = ERROR_SUCCESS;
02459     DWORD NameLength;
02460     DWORD ClassLength = 0;
02461     DWORD BufferSize;
02462     ULONG ResultSize;
02463     HANDLE KeyHandle;
02464     NTSTATUS Status;
02465 
02466     TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
02467           hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
02468 
02469     if ((lpClass) && (!lpcbClass))
02470     {
02471         return ERROR_INVALID_PARAMETER;
02472     }
02473 
02474     Status = MapDefaultKey(&KeyHandle, hKey);
02475     if (!NT_SUCCESS(Status))
02476     {
02477         return RtlNtStatusToDosError(Status);
02478     }
02479 
02480     if (*lpcbName > 0)
02481     {
02482         NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
02483     }
02484     else
02485     {
02486         NameLength = 0;
02487     }
02488 
02489     if (lpClass)
02490     {
02491         if (*lpcbClass > 0)
02492         {
02493             ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
02494         }
02495         else
02496         {
02497             ClassLength = 0;
02498         }
02499 
02500         /* The class name should start at a dword boundary */
02501         BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
02502     }
02503     else
02504     {
02505         BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
02506     }
02507 
02508     KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
02509     if (KeyInfo == NULL)
02510     {
02511         ErrorCode = ERROR_OUTOFMEMORY;
02512         goto Cleanup;
02513     }
02514 
02515     Status = NtEnumerateKey(KeyHandle,
02516                             (ULONG)dwIndex,
02517                             lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
02518                             KeyInfo,
02519                             BufferSize,
02520                             &ResultSize);
02521     TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
02522     if (!NT_SUCCESS(Status))
02523     {
02524         ErrorCode = RtlNtStatusToDosError (Status);
02525     }
02526     else
02527     {
02528         if (lpClass == NULL)
02529         {
02530             if (KeyInfo->Basic.NameLength > NameLength)
02531             {
02532                 ErrorCode = ERROR_BUFFER_OVERFLOW;
02533             }
02534             else
02535             {
02536                 StringU.Buffer = KeyInfo->Basic.Name;
02537                 StringU.Length = KeyInfo->Basic.NameLength;
02538                 StringU.MaximumLength = KeyInfo->Basic.NameLength;
02539             }
02540         }
02541         else
02542         {
02543             if (KeyInfo->Node.NameLength > NameLength ||
02544                 KeyInfo->Node.ClassLength > ClassLength)
02545             {
02546                 ErrorCode = ERROR_BUFFER_OVERFLOW;
02547             }
02548             else
02549             {
02550                 StringA.Buffer = lpClass;
02551                 StringA.Length = 0;
02552                 StringA.MaximumLength = *lpcbClass;
02553                 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
02554                 StringU.Length = KeyInfo->Node.ClassLength;
02555                 StringU.MaximumLength = KeyInfo->Node.ClassLength;
02556                 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
02557                 lpClass[StringA.Length] = 0;
02558                 *lpcbClass = StringA.Length;
02559                 StringU.Buffer = KeyInfo->Node.Name;
02560                 StringU.Length = KeyInfo->Node.NameLength;
02561                 StringU.MaximumLength = KeyInfo->Node.NameLength;
02562             }
02563         }
02564 
02565         if (ErrorCode == ERROR_SUCCESS)
02566         {
02567             StringA.Buffer = lpName;
02568             StringA.Length = 0;
02569             StringA.MaximumLength = *lpcbName;
02570             RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
02571             lpName[StringA.Length] = 0;
02572             *lpcbName = StringA.Length;
02573             if (lpftLastWriteTime != NULL)
02574             {
02575                 if (lpClass == NULL)
02576                 {
02577                     lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
02578                     lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
02579                 }
02580                 else
02581                 {
02582                     lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
02583                     lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
02584                 }
02585             }
02586         }
02587     }
02588 
02589     /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
02590     TRACE("Key Name1 Length %d\n", NameLength);
02591     TRACE("Key Name Length %d\n", *lpcbName);
02592     TRACE("Key Name %s\n", lpName);
02593 
02594     RtlFreeHeap(ProcessHeap,
02595                 0,
02596                 KeyInfo);
02597 
02598 Cleanup:
02599     ClosePredefKey(KeyHandle);
02600 
02601     return ErrorCode;
02602 }
02603 
02604 
02605 /************************************************************************
02606  *  RegEnumKeyExW
02607  *
02608  * @implemented
02609  */
02610 LONG WINAPI
02611 RegEnumKeyExW(HKEY hKey,
02612               DWORD dwIndex,
02613               LPWSTR lpName,
02614               LPDWORD lpcbName,
02615               LPDWORD lpReserved,
02616               LPWSTR lpClass,
02617               LPDWORD lpcbClass,
02618               PFILETIME lpftLastWriteTime)
02619 {
02620     union
02621     {
02622         KEY_NODE_INFORMATION Node;
02623         KEY_BASIC_INFORMATION Basic;
02624     } *KeyInfo;
02625 
02626     ULONG BufferSize;
02627     ULONG ResultSize;
02628     ULONG NameLength;
02629     ULONG ClassLength = 0;
02630     HANDLE KeyHandle;
02631     LONG ErrorCode = ERROR_SUCCESS;
02632     NTSTATUS Status;
02633 
02634     Status = MapDefaultKey(&KeyHandle,
02635                            hKey);
02636     if (!NT_SUCCESS(Status))
02637     {
02638         return RtlNtStatusToDosError(Status);
02639     }
02640 
02641     if (*lpcbName > 0)
02642     {
02643         NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
02644     }
02645     else
02646     {
02647         NameLength = 0;
02648     }
02649 
02650     if (lpClass)
02651     {
02652         if (*lpcbClass > 0)
02653         {
02654             ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
02655         }
02656         else
02657         {
02658             ClassLength = 0;
02659         }
02660 
02661         BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
02662     }
02663     else
02664     {
02665         BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
02666     }
02667 
02668     KeyInfo = RtlAllocateHeap(ProcessHeap,
02669                               0,
02670                               BufferSize);
02671     if (KeyInfo == NULL)
02672     {
02673         ErrorCode = ERROR_OUTOFMEMORY;
02674         goto Cleanup;
02675     }
02676 
02677     Status = NtEnumerateKey(KeyHandle,
02678                             (ULONG)dwIndex,
02679                             lpClass ? KeyNodeInformation : KeyBasicInformation,
02680                             KeyInfo,
02681                             BufferSize,
02682                             &ResultSize);
02683     TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
02684     if (!NT_SUCCESS(Status))
02685     {
02686         ErrorCode = RtlNtStatusToDosError (Status);
02687     }
02688     else
02689     {
02690         if (lpClass == NULL)
02691         {
02692             if (KeyInfo->Basic.NameLength > NameLength)
02693             {
02694                 ErrorCode = ERROR_BUFFER_OVERFLOW;
02695             }
02696             else
02697             {
02698                 RtlCopyMemory(lpName,
02699                               KeyInfo->Basic.Name,
02700                               KeyInfo->Basic.NameLength);
02701                 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
02702                 lpName[*lpcbName] = 0;
02703             }
02704         }
02705         else
02706         {
02707             if (KeyInfo->Node.NameLength > NameLength ||
02708                 KeyInfo->Node.ClassLength > ClassLength)
02709             {
02710                 ErrorCode = ERROR_BUFFER_OVERFLOW;
02711             }
02712             else
02713             {
02714                 RtlCopyMemory(lpName,
02715                               KeyInfo->Node.Name,
02716                               KeyInfo->Node.NameLength);
02717                 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR);
02718                 lpName[*lpcbName] = 0;
02719                 RtlCopyMemory(lpClass,
02720                               (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),
02721                               KeyInfo->Node.ClassLength);
02722                 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));
02723                 lpClass[*lpcbClass] = 0;
02724             }
02725         }
02726 
02727         if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL)
02728         {
02729             if (lpClass == NULL)
02730             {
02731                 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
02732                 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
02733             }
02734             else
02735             {
02736                 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
02737                 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
02738             }
02739         }
02740     }
02741 
02742     RtlFreeHeap(ProcessHeap,
02743                 0,
02744                 KeyInfo);
02745 
02746 Cleanup:
02747     ClosePredefKey(KeyHandle);
02748 
02749     return ErrorCode;
02750 }
02751 
02752 
02753 /************************************************************************
02754  *  RegEnumValueA
02755  *
02756  * @implemented
02757  */
02758 LONG WINAPI
02759 RegEnumValueA(HKEY hKey,
02760               DWORD index,
02761               LPSTR value,
02762               LPDWORD val_count,
02763               LPDWORD reserved,
02764               LPDWORD type,
02765               LPBYTE data,
02766               LPDWORD count)
02767 {
02768     HANDLE KeyHandle;
02769     NTSTATUS status;
02770     ULONG total_size;
02771     char buffer[256], *buf_ptr = buffer;
02772     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
02773     static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
02774 
02775     //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
02776       //    hkey, index, value, val_count, reserved, type, data, count );
02777 
02778     /* NT only checks count, not val_count */
02779     if ((data && !count) || reserved)
02780         return ERROR_INVALID_PARAMETER;
02781 
02782     status = MapDefaultKey(&KeyHandle, hKey);
02783     if (!NT_SUCCESS(status))
02784     {
02785         return RtlNtStatusToDosError(status);
02786     }
02787 
02788     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
02789     if (data) total_size += *count;
02790     total_size = min( sizeof(buffer), total_size );
02791 
02792     status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
02793                                   buffer, total_size, &total_size );
02794     if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
02795 
02796     /* we need to fetch the contents for a string type even if not requested,
02797      * because we need to compute the length of the ASCII string. */
02798     if (value || data || is_string(info->Type))
02799     {
02800         /* retry with a dynamically allocated buffer */
02801         while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
02802         {
02803             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
02804             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
02805             {
02806                 status = STATUS_INSUFFICIENT_RESOURCES;
02807                 goto done;
02808             }
02809             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
02810             status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
02811                                           buf_ptr, total_size, &total_size );
02812         }
02813 
02814         if (status) goto done;
02815 
02816         if (is_string(info->Type))
02817         {
02818             ULONG len;
02819             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
02820                                        info->DataLength );
02821             if (data && len)
02822             {
02823                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
02824                 else
02825                 {
02826                     RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
02827                                             info->DataLength );
02828                     /* if the type is REG_SZ and data is not 0-terminated
02829                      * and there is enough space in the buffer NT appends a \0 */
02830                     if (len < *count && data[len-1]) data[len] = 0;
02831                 }
02832             }
02833             info->DataLength = len;
02834         }
02835         else if (data)
02836         {
02837             if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
02838             else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
02839         }
02840 
02841         if (value && !status)
02842         {
02843             ULONG len;
02844 
02845             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
02846             if (len >= *val_count)
02847             {
02848                 status = STATUS_BUFFER_OVERFLOW;
02849                 if (*val_count)
02850                 {
02851                     len = *val_count - 1;
02852                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
02853                     value[len] = 0;
02854                 }
02855             }
02856             else
02857             {
02858                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
02859                 value[len] = 0;
02860                 *val_count = len;
02861             }
02862         }
02863     }
02864     else status = STATUS_SUCCESS;
02865 
02866     if (type) *type = info->Type;
02867     if (count) *count = info->DataLength;
02868 
02869  done:
02870     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
02871     ClosePredefKey(KeyHandle);
02872     return RtlNtStatusToDosError(status);
02873 }
02874 
02875 
02876 /******************************************************************************
02877  * RegEnumValueW   [ADVAPI32.@]
02878  * @implemented
02879  *
02880  * PARAMS
02881  *  hkey       [I] Handle to key to query
02882  *  index      [I] Index of value to query
02883  *  value      [O] Value string
02884  *  val_count  [I/O] Size of value buffer (in wchars)
02885  *  reserved   [I] Reserved
02886  *  type       [O] Type code
02887  *  data       [O] Value data
02888  *  count      [I/O] Size of data buffer (in bytes)
02889  *
02890  * RETURNS
02891  *  Success: ERROR_SUCCESS
02892  *  Failure: nonzero error code from Winerror.h
02893  */
02894 LONG WINAPI
02895 RegEnumValueW(HKEY hKey,
02896               DWORD index,
02897               LPWSTR value,
02898               PDWORD val_count,
02899               PDWORD reserved,
02900               PDWORD type,
02901               LPBYTE data,
02902               PDWORD count)
02903 {
02904     HANDLE KeyHandle;
02905     NTSTATUS status;
02906     ULONG total_size;
02907     char buffer[256], *buf_ptr = buffer;
02908     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
02909     static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
02910 
02911     //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
02912     //      hkey, index, value, val_count, reserved, type, data, count );
02913 
02914     /* NT only checks count, not val_count */
02915     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
02916 
02917     status = MapDefaultKey(&KeyHandle, hKey);
02918     if (!NT_SUCCESS(status))
02919     {
02920         return RtlNtStatusToDosError(status);
02921     }
02922 
02923     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
02924     if (data) total_size += *count;
02925     total_size = min( sizeof(buffer), total_size );
02926 
02927     status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
02928                                   buffer, total_size, &total_size );
02929     if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
02930 
02931     if (value || data)
02932     {
02933         /* retry with a dynamically allocated buffer */
02934         while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
02935         {
02936             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
02937             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
02938             {
02939                 status = ERROR_NOT_ENOUGH_MEMORY;
02940                 goto done;
02941             }
02942             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
02943             status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
02944                                           buf_ptr, total_size, &total_size );
02945         }
02946 
02947         if (status) goto done;
02948 
02949         if (value)
02950         {
02951             if (info->NameLength/sizeof(WCHAR) >= *val_count)
02952             {
02953                 status = STATUS_BUFFER_OVERFLOW;
02954                 goto overflow;
02955             }
02956             memcpy( value, info->Name, info->NameLength );
02957             *val_count = info->NameLength / sizeof(WCHAR);
02958             value[*val_count] = 0;
02959         }
02960 
02961         if (data)
02962         {
02963             if (info->DataLength > *count)
02964             {
02965                 status = STATUS_BUFFER_OVERFLOW;
02966                 goto overflow;
02967             }
02968             memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
02969             if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
02970             {
02971                 /* if the type is REG_SZ and data is not 0-terminated
02972                  * and there is enough space in the buffer NT appends a \0 */
02973                 WCHAR *ptr = (WCHAR *)(data + info->DataLength);
02974                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
02975             }
02976         }
02977     }
02978     else status = STATUS_SUCCESS;
02979 
02980  overflow:
02981     if (type) *type = info->Type;
02982     if (count) *count = info->DataLength;
02983 
02984  done:
02985     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
02986     ClosePredefKey(KeyHandle);
02987     return RtlNtStatusToDosError(status);
02988 }
02989 
02990 
02991 /************************************************************************
02992  *  RegFlushKey
02993  *
02994  * @implemented
02995  */
02996 LONG WINAPI
02997 RegFlushKey(HKEY hKey)
02998 {
02999     HANDLE KeyHandle;
03000     NTSTATUS Status;
03001 
03002     if (hKey == HKEY_PERFORMANCE_DATA)
03003     {
03004         return ERROR_SUCCESS;
03005     }
03006 
03007     Status = MapDefaultKey(&KeyHandle,
03008                            hKey);
03009     if (!NT_SUCCESS(Status))
03010     {
03011         return RtlNtStatusToDosError(Status);
03012     }
03013 
03014     Status = NtFlushKey(KeyHandle);
03015 
03016     ClosePredefKey(KeyHandle);
03017 
03018     if (!NT_SUCCESS(Status))
03019     {
03020         return RtlNtStatusToDosError(Status);
03021     }
03022 
03023     return ERROR_SUCCESS;
03024 }
03025 
03026 
03027 /************************************************************************
03028  *  RegGetKeySecurity
03029  *
03030  * @implemented
03031  */
03032 LONG WINAPI
03033 RegGetKeySecurity(HKEY hKey,
03034                   SECURITY_INFORMATION SecurityInformation,
03035                   PSECURITY_DESCRIPTOR pSecurityDescriptor,
03036                   LPDWORD lpcbSecurityDescriptor)
03037 {
03038     HANDLE KeyHandle;
03039     NTSTATUS Status;
03040 
03041     if (hKey == HKEY_PERFORMANCE_DATA)
03042     {
03043         return ERROR_INVALID_HANDLE;
03044     }
03045 
03046     Status = MapDefaultKey(&KeyHandle,
03047                            hKey);
03048     if (!NT_SUCCESS(Status))
03049     {
03050         TRACE("MapDefaultKey() failed (Status %lx)\n", Status);
03051         return RtlNtStatusToDosError(Status);
03052     }
03053 
03054 #if 0
03055     Status = NtQuerySecurityObject(KeyHandle,
03056                                    SecurityInformation,
03057                                    pSecurityDescriptor,
03058                                    *lpcbSecurityDescriptor,
03059                                    lpcbSecurityDescriptor);
03060 #endif
03061 
03062     ClosePredefKey(KeyHandle);
03063 
03064     if (!NT_SUCCESS(Status))
03065     {
03066          WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status);
03067          return RtlNtStatusToDosError(Status);
03068     }
03069 
03070     return ERROR_SUCCESS;
03071 }
03072 
03073 
03074 /************************************************************************
03075  *  RegLoadKeyA
03076  *
03077  * @implemented
03078  */
03079 LONG WINAPI
03080 RegLoadKeyA(HKEY hKey,
03081             LPCSTR lpSubKey,
03082             LPCSTR lpFile)
03083 {
03084     UNICODE_STRING FileName;
03085     UNICODE_STRING KeyName;
03086     LONG ErrorCode;
03087 
03088     RtlCreateUnicodeStringFromAsciiz(&KeyName,
03089                                      (LPSTR)lpSubKey);
03090     RtlCreateUnicodeStringFromAsciiz(&FileName,
03091                                      (LPSTR)lpFile);
03092 
03093     ErrorCode = RegLoadKeyW(hKey,
03094                             KeyName.Buffer,
03095                             FileName.Buffer);
03096 
03097     RtlFreeUnicodeString(&FileName);
03098     RtlFreeUnicodeString(&KeyName);
03099 
03100     return ErrorCode;
03101 }
03102 
03103 
03104 /************************************************************************
03105  *  RegLoadKeyW
03106  *
03107  * @implemented
03108  */
03109 LONG WINAPI
03110 RegLoadKeyW(HKEY hKey,
03111             LPCWSTR lpSubKey,
03112             LPCWSTR lpFile)
03113 {
03114     OBJECT_ATTRIBUTES FileObjectAttributes;
03115     OBJECT_ATTRIBUTES KeyObjectAttributes;
03116     UNICODE_STRING FileName;
03117     UNICODE_STRING KeyName;
03118     HANDLE KeyHandle;
03119     NTSTATUS Status;
03120     LONG ErrorCode = ERROR_SUCCESS;
03121 
03122     if (hKey == HKEY_PERFORMANCE_DATA)
03123     {
03124         return ERROR_INVALID_HANDLE;
03125     }
03126 
03127     Status = MapDefaultKey(&KeyHandle,
03128                            hKey);
03129     if (!NT_SUCCESS(Status))
03130     {
03131         return RtlNtStatusToDosError(Status);
03132     }
03133 
03134     if (!RtlDosPathNameToNtPathName_U(lpFile,
03135                                       &FileName,
03136                                       NULL,
03137                                       NULL))
03138     {
03139       ErrorCode = ERROR_BAD_PATHNAME;
03140       goto Cleanup;
03141     }
03142 
03143     InitializeObjectAttributes(&FileObjectAttributes,
03144                                &FileName,
03145                                OBJ_CASE_INSENSITIVE,
03146                                NULL,
03147                                NULL);
03148 
03149     RtlInitUnicodeString(&KeyName,
03150                          (LPWSTR)lpSubKey);
03151 
03152     InitializeObjectAttributes(&KeyObjectAttributes,
03153                                &KeyName,
03154                                OBJ_CASE_INSENSITIVE,
03155                                KeyHandle,
03156                                NULL);
03157 
03158     Status = NtLoadKey(&KeyObjectAttributes,
03159                        &FileObjectAttributes);
03160 
03161     RtlFreeHeap(RtlGetProcessHeap(),
03162                 0,
03163                 FileName.Buffer);
03164 
03165     if (!NT_SUCCESS(Status))
03166     {
03167         ErrorCode = RtlNtStatusToDosError(Status);
03168         goto Cleanup;
03169     }
03170 
03171 Cleanup:
03172     ClosePredefKey(KeyHandle);
03173 
03174     return ErrorCode;
03175 }
03176 
03177 
03178 /************************************************************************
03179  *  RegNotifyChangeKeyValue
03180  *
03181  * @unimplemented
03182  */
03183 LONG WINAPI
03184 RegNotifyChangeKeyValue(HKEY hKey,
03185                         BOOL bWatchSubtree,
03186                         DWORD dwNotifyFilter,
03187                         HANDLE hEvent,
03188                         BOOL fAsynchronous)
03189 {
03190     IO_STATUS_BLOCK IoStatusBlock;
03191     HANDLE KeyHandle;
03192     NTSTATUS Status;
03193     LONG ErrorCode = ERROR_SUCCESS;
03194 
03195     if (hKey == HKEY_PERFORMANCE_DATA)
03196     {
03197         return ERROR_INVALID_HANDLE;
03198     }
03199 
03200     if (fAsynchronous == TRUE && hEvent == NULL)
03201     {
03202         return ERROR_INVALID_PARAMETER;
03203     }
03204 
03205     Status = MapDefaultKey(&KeyHandle,
03206                            hKey);
03207     if (!NT_SUCCESS(Status))
03208     {
03209         return RtlNtStatusToDosError(Status);
03210     }
03211 
03212     /* FIXME: Remote key handles must fail */
03213 
03214     Status = NtNotifyChangeKey(KeyHandle,
03215                                hEvent,
03216                                0,
03217                                0,
03218                                &IoStatusBlock,
03219                                dwNotifyFilter,
03220                                bWatchSubtree,
03221                                0,
03222                                0,
03223                                fAsynchronous);
03224     if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
03225     {
03226         ErrorCode = RtlNtStatusToDosError(Status);
03227     }
03228 
03229     ClosePredefKey(KeyHandle);
03230 
03231     return ErrorCode;
03232 }
03233 
03234 
03235 /************************************************************************
03236  *  RegOpenCurrentUser
03237  *
03238  * @implemented
03239  */
03240 LONG WINAPI
03241 RegOpenCurrentUser(IN REGSAM samDesired,
03242                    OUT PHKEY phkResult)
03243 {
03244     NTSTATUS Status;
03245 
03246     Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired,
03247                                 (PHANDLE)phkResult);
03248     if (!NT_SUCCESS(Status))
03249     {
03250         /* NOTE - don't set the last error code! just return the error! */
03251         return RtlNtStatusToDosError(Status);
03252     }
03253 
03254     return ERROR_SUCCESS;
03255 }
03256 
03257 
03258 /************************************************************************
03259  *  RegOpenKeyA
03260  *
03261  *  20050503 Fireball - imported from WINE
03262  *
03263  * @implemented
03264  */
03265 LONG WINAPI
03266 RegOpenKeyA(HKEY hKey,
03267             LPCSTR lpSubKey,
03268             PHKEY phkResult)
03269 {
03270     TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
03271           hKey, lpSubKey, phkResult);
03272 
03273     if (!phkResult)
03274         return ERROR_INVALID_PARAMETER;
03275 
03276     if (!hKey && lpSubKey && phkResult)
03277     {
03278         return ERROR_INVALID_HANDLE;
03279     }
03280 
03281     if (!lpSubKey || !*lpSubKey)
03282     {
03283         *phkResult = hKey;
03284         return ERROR_SUCCESS;
03285     }
03286 
03287     return RegOpenKeyExA(hKey,
03288                          lpSubKey,
03289                          0,
03290                          MAXIMUM_ALLOWED,
03291                          phkResult);
03292 }
03293 
03294 
03295 /************************************************************************
03296  *  RegOpenKeyW
03297  *
03298  *  19981101 Ariadne
03299  *  19990525 EA
03300  *  20050503 Fireball - imported from WINE
03301  *
03302  * @implemented
03303  */
03304 LONG WINAPI
03305 RegOpenKeyW(HKEY hKey,
03306             LPCWSTR lpSubKey,
03307             PHKEY phkResult)
03308 {
03309     TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
03310           hKey, lpSubKey, phkResult);
03311 
03312     if (!phkResult)
03313         return ERROR_INVALID_PARAMETER;
03314 
03315     if (!hKey && lpSubKey && phkResult)
03316     {
03317         return ERROR_INVALID_HANDLE;
03318     }
03319 
03320     if (!lpSubKey || !*lpSubKey)
03321     {
03322         *phkResult = hKey;
03323         return ERROR_SUCCESS;
03324     }
03325 
03326     return RegOpenKeyExW(hKey,
03327                          lpSubKey,
03328                          0,
03329                          MAXIMUM_ALLOWED,
03330                          phkResult);
03331 }
03332 
03333 
03334 /************************************************************************
03335  *  RegOpenKeyExA
03336  *
03337  * @implemented
03338  */
03339 LONG WINAPI
03340 RegOpenKeyExA(HKEY hKey,
03341               LPCSTR lpSubKey,
03342               DWORD ulOptions,
03343               REGSAM samDesired,
03344               PHKEY phkResult)
03345 {
03346     OBJECT_ATTRIBUTES ObjectAttributes;
03347     UNICODE_STRING SubKeyString;
03348     HANDLE KeyHandle;
03349     NTSTATUS Status;
03350     LONG ErrorCode = ERROR_SUCCESS;
03351 
03352     TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
03353           hKey, lpSubKey, ulOptions, samDesired, phkResult);
03354     if (!phkResult)
03355     {
03356         return ERROR_INVALID_PARAMETER;
03357     }
03358 
03359     Status = MapDefaultKey(&KeyHandle,
03360                            hKey);
03361     if (!NT_SUCCESS(Status))
03362     {
03363         return RtlNtStatusToDosError(Status);
03364     }
03365 
03366     RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
03367                                      (LPSTR)lpSubKey);
03368     InitializeObjectAttributes(&ObjectAttributes,
03369                                &SubKeyString,
03370                                OBJ_CASE_INSENSITIVE,
03371                                KeyHandle,
03372                                NULL);
03373 
03374     Status = NtOpenKey((PHANDLE)phkResult,
03375                        samDesired,
03376                        &ObjectAttributes);
03377     RtlFreeUnicodeString(&SubKeyString);
03378     if (!NT_SUCCESS(Status))
03379     {
03380         ErrorCode = RtlNtStatusToDosError(Status);
03381     }
03382 
03383     ClosePredefKey(KeyHandle);
03384 
03385     return ErrorCode;
03386 }
03387 
03388 
03389 /************************************************************************
03390  *  RegOpenKeyExW
03391  *
03392  * @implemented
03393  */
03394 LONG WINAPI
03395 RegOpenKeyExW(HKEY hKey,
03396               LPCWSTR lpSubKey,
03397               DWORD ulOptions,
03398               REGSAM samDesired,
03399               PHKEY phkResult)
03400 {
03401     OBJECT_ATTRIBUTES ObjectAttributes;
03402     UNICODE_STRING SubKeyString;
03403     HANDLE KeyHandle;
03404     NTSTATUS Status;
03405     LONG ErrorCode = ERROR_SUCCESS;
03406 
03407     TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
03408           hKey, lpSubKey, ulOptions, samDesired, phkResult);
03409     if (!phkResult)
03410     {
03411         return ERROR_INVALID_PARAMETER;
03412     }
03413 
03414     Status = MapDefaultKey(&KeyHandle, hKey);
03415     if (!NT_SUCCESS(Status))
03416     {
03417         return RtlNtStatusToDosError(Status);
03418     }
03419 
03420     if (lpSubKey != NULL)
03421         RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
03422     else
03423         RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
03424 
03425     InitializeObjectAttributes(&ObjectAttributes,
03426                                &SubKeyString,
03427                                OBJ_CASE_INSENSITIVE,
03428                                KeyHandle,
03429                                NULL);
03430 
03431     Status = NtOpenKey((PHANDLE)phkResult,
03432                        samDesired,
03433                        &ObjectAttributes);
03434     if (!NT_SUCCESS(Status))
03435     {
03436         ErrorCode = RtlNtStatusToDosError(Status);
03437     }
03438 
03439     ClosePredefKey(KeyHandle);
03440 
03441     return ErrorCode;
03442 }
03443 
03444 
03445 /************************************************************************
03446  *  RegOpenUserClassesRoot
03447  *
03448  * @implemented
03449  */
03450 LONG WINAPI
03451 RegOpenUserClassesRoot(IN HANDLE hToken,
03452                        IN DWORD dwOptions,
03453                        IN REGSAM samDesired,
03454                        OUT PHKEY phkResult)
03455 {
03456     const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
03457     const WCHAR UserClassesKeySuffix[] = L"_Classes";
03458     PTOKEN_USER TokenUserData;
03459     ULONG RequiredLength;
03460     UNICODE_STRING UserSidString, UserClassesKeyRoot;
03461     OBJECT_ATTRIBUTES ObjectAttributes;
03462     NTSTATUS Status;
03463 
03464     /* check parameters */
03465     if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
03466     {
03467         return ERROR_INVALID_PARAMETER;
03468     }
03469 
03470     /*
03471      * Get the user sid from the token
03472      */
03473 
03474 ReadTokenSid:
03475     /* determine how much memory we need */
03476     Status = NtQueryInformationToken(hToken,
03477                                      TokenUser,
03478                                      NULL,
03479                                      0,
03480                                      &RequiredLength);
03481     if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
03482     {
03483         /* NOTE - as opposed to all other registry functions windows does indeed
03484                   change the last error code in case the caller supplied a invalid
03485                   handle for example! */
03486         return RtlNtStatusToDosError(Status);
03487     }
03488     RegInitialize(); /* HACK until delay-loading is implemented */
03489     TokenUserData = RtlAllocateHeap(ProcessHeap,
03490                                     0,
03491                                     RequiredLength);
03492     if (TokenUserData == NULL)
03493     {
03494         return ERROR_NOT_ENOUGH_MEMORY;
03495     }
03496 
03497     /* attempt to read the information */
03498     Status = NtQueryInformationToken(hToken,
03499                                      TokenUser,
03500                                      TokenUserData,
03501                                      RequiredLength,
03502                                      &RequiredLength);
03503     if (!NT_SUCCESS(Status))
03504     {
03505         RtlFreeHeap(ProcessHeap,
03506                     0,
03507                     TokenUserData);
03508         if (Status == STATUS_BUFFER_TOO_SMALL)
03509         {
03510             /* the information appears to have changed?! try again */
03511             goto ReadTokenSid;
03512         }
03513 
03514         /* NOTE - as opposed to all other registry functions windows does indeed
03515                   change the last error code in case the caller supplied a invalid
03516                   handle for example! */
03517         return RtlNtStatusToDosError(Status);
03518     }
03519 
03520     /*
03521      * Build the absolute path for the user's registry in the form
03522      * "\Registry\User<SID>_Classes"
03523      */
03524     Status = RtlConvertSidToUnicodeString(&UserSidString,
03525                                           TokenUserData->User.Sid,
03526                                           TRUE);
03527 
03528     /* we don't need the user data anymore, free it */
03529     RtlFreeHeap(ProcessHeap,
03530                 0,
03531                 TokenUserData);
03532 
03533     if (!NT_SUCCESS(Status))
03534     {
03535         return RtlNtStatusToDosError(Status);
03536     }
03537 
03538     /* allocate enough memory for the entire key string */
03539     UserClassesKeyRoot.Length = 0;
03540     UserClassesKeyRoot.MaximumLength = UserSidString.Length +
03541                                        sizeof(UserClassesKeyPrefix) +
03542                                        sizeof(UserClassesKeySuffix);
03543     UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
03544                                                 0,
03545                                                 UserClassesKeyRoot.MaximumLength);
03546     if (UserClassesKeyRoot.Buffer == NULL)
03547     {
03548         RtlFreeUnicodeString(&UserSidString);
03549         return RtlNtStatusToDosError(Status);
03550     }
03551 
03552     /* build the string */
03553     RtlAppendUnicodeToString(&UserClassesKeyRoot,
03554                              UserClassesKeyPrefix);
03555     RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
03556                                    &UserSidString);
03557     RtlAppendUnicodeToString(&UserClassesKeyRoot,
03558                              UserClassesKeySuffix);
03559 
03560     TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
03561 
03562     /*
03563      * Open the key
03564      */
03565     InitializeObjectAttributes(&ObjectAttributes,
03566                                &UserClassesKeyRoot,
03567                                OBJ_CASE_INSENSITIVE,
03568                                NULL,
03569                                NULL);
03570 
03571     Status = NtOpenKey((PHANDLE)phkResult,
03572                        samDesired,
03573                        &ObjectAttributes);
03574 
03575     RtlFreeUnicodeString(&UserSidString);
03576     RtlFreeUnicodeString(&UserClassesKeyRoot);
03577 
03578     if (!NT_SUCCESS(Status))
03579     {
03580         return RtlNtStatusToDosError(Status);
03581     }
03582 
03583     return ERROR_SUCCESS;
03584 }
03585 
03586 
03587 /************************************************************************
03588  *  RegQueryInfoKeyA
03589  *
03590  * @implemented
03591  */
03592 LONG WINAPI
03593 RegQueryInfoKeyA(HKEY hKey,
03594                  LPSTR lpClass,
03595                  LPDWORD lpcbClass,
03596                  LPDWORD lpReserved,
03597                  LPDWORD lpcSubKeys,
03598                  LPDWORD lpcbMaxSubKeyLen,
03599                  LPDWORD lpcbMaxClassLen,
03600                  LPDWORD lpcValues,
03601                  LPDWORD lpcbMaxValueNameLen,
03602                  LPDWORD lpcbMaxValueLen,
03603                  LPDWORD lpcbSecurityDescriptor,
03604                  PFILETIME lpftLastWriteTime)
03605 {
03606     WCHAR ClassName[MAX_PATH];
03607     UNICODE_STRING UnicodeString;
03608     ANSI_STRING AnsiString;
03609     LONG ErrorCode;
03610 
03611     RtlInitUnicodeString(&UnicodeString,
03612                          NULL);
03613     if (lpClass != NULL)
03614     {
03615         UnicodeString.Buffer = &ClassName[0];
03616         UnicodeString.MaximumLength = sizeof(ClassName);
03617         AnsiString.MaximumLength = *lpcbClass;
03618     }
03619 
03620     ErrorCode = RegQueryInfoKeyW(hKey,
03621                                  UnicodeString.Buffer,
03622                                  lpcbClass,
03623                                  lpReserved,
03624                                  lpcSubKeys,
03625                                  lpcbMaxSubKeyLen,
03626                                  lpcbMaxClassLen,
03627                                  lpcValues,
03628                                  lpcbMaxValueNameLen,
03629                                  lpcbMaxValueLen,
03630                                  lpcbSecurityDescriptor,
03631                                  lpftLastWriteTime);
03632     if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
03633     {
03634         AnsiString.Buffer = lpClass;
03635         AnsiString.Length = 0;
03636         UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
03637         RtlUnicodeStringToAnsiString(&AnsiString,
03638                                      &UnicodeString,
03639                                      FALSE);
03640         *lpcbClass = AnsiString.Length;
03641         lpClass[AnsiString.Length] = 0;
03642     }
03643 
03644     return ErrorCode;
03645 }
03646 
03647 
03648 /************************************************************************
03649  *  RegQueryInfoKeyW
03650  *
03651  * @implemented
03652  */
03653 LONG WINAPI
03654 RegQueryInfoKeyW(HKEY hKey,
03655                  LPWSTR lpClass,
03656                  LPDWORD lpcbClass,
03657                  LPDWORD lpReserved,
03658                  LPDWORD lpcSubKeys,
03659                  LPDWORD lpcbMaxSubKeyLen,
03660                  LPDWORD lpcbMaxClassLen,
03661                  LPDWORD lpcValues,
03662                  LPDWORD lpcbMaxValueNameLen,
03663                  LPDWORD lpcbMaxValueLen,
03664                  LPDWORD lpcbSecurityDescriptor,
03665                  PFILETIME lpftLastWriteTime)
03666 {
03667     KEY_FULL_INFORMATION FullInfoBuffer;
03668     PKEY_FULL_INFORMATION FullInfo;
03669     ULONG FullInfoSize;
03670     ULONG ClassLength = 0;
03671     HANDLE KeyHandle;
03672     NTSTATUS Status;
03673     ULONG Length;
03674     LONG ErrorCode = ERROR_SUCCESS;
03675 
03676     if ((lpClass) && (!lpcbClass))
03677     {
03678         return ERROR_INVALID_PARAMETER;
03679     }
03680 
03681     Status = MapDefaultKey(&KeyHandle,
03682                            hKey);
03683     if (!NT_SUCCESS(Status))
03684     {
03685         return RtlNtStatusToDosError(Status);
03686     }
03687 
03688     if (lpClass != NULL)
03689     {
03690         if (*lpcbClass > 0)
03691         {
03692             ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
03693         }
03694         else
03695         {
03696             ClassLength = 0;
03697         }
03698 
03699         FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
03700         FullInfo = RtlAllocateHeap(ProcessHeap,
03701                                    0,
03702                                    FullInfoSize);
03703         if (FullInfo == NULL)
03704         {
03705             ErrorCode = ERROR_OUTOFMEMORY;
03706             goto Cleanup;
03707         }
03708 
03709         FullInfo->ClassLength = ClassLength;
03710     }
03711     else
03712     {
03713         FullInfoSize = sizeof(KEY_FULL_INFORMATION);
03714         FullInfo = &FullInfoBuffer;
03715         FullInfo->ClassLength = 0;
03716     }
03717     FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
03718 
03719     Status = NtQueryKey(KeyHandle,
03720                         KeyFullInformation,
03721                         FullInfo,
03722                         FullInfoSize,
03723                         &Length);
03724     TRACE("NtQueryKey() returned status 0x%X\n", Status);
03725     if (!NT_SUCCESS(Status))
03726     {
03727         if (lpClass != NULL)
03728         {
03729             RtlFreeHeap(ProcessHeap,
03730                         0,
03731                         FullInfo);
03732         }
03733 
03734         ErrorCode = RtlNtStatusToDosError(Status);
03735         goto Cleanup;
03736     }
03737 
03738     TRACE("SubKeys %d\n", FullInfo->SubKeys);
03739     if (lpcSubKeys != NULL)
03740     {
03741         *lpcSubKeys = FullInfo->SubKeys;
03742     }
03743 
03744     TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
03745     if (lpcbMaxSubKeyLen != NULL)
03746     {
03747         *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
03748     }
03749 
03750     TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
03751     if (lpcbMaxClassLen != NULL)
03752     {
03753         *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
03754     }
03755 
03756     TRACE("Values %lu\n", FullInfo->Values);
03757     if (lpcValues != NULL)
03758     {
03759         *lpcValues = FullInfo->Values;
03760     }
03761 
03762     TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
03763     if (lpcbMaxValueNameLen != NULL)
03764     {
03765         *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
03766     }
03767 
03768     TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
03769     if (lpcbMaxValueLen != NULL)
03770     {
03771         *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
03772     }
03773 
03774 #if 0
03775     if (lpcbSecurityDescriptor != NULL)
03776     {
03777         Status = NtQuerySecurityObject(KeyHandle,
03778                                        OWNER_SECURITY_INFORMATION |
03779                                        GROUP_SECURITY_INFORMATION |
03780                                        DACL_SECURITY_INFORMATION,
03781                                        NULL,
03782                                        0,
03783                                        lpcbSecurityDescriptor);
03784         if (!NT_SUCCESS(Status))
03785         {
03786             if (lpClass != NULL)
03787             {
03788                 RtlFreeHeap(ProcessHeap,
03789                             0,
03790                             FullInfo);
03791             }
03792 
03793             ErrorCode = RtlNtStatusToDosError(Status);
03794             goto Cleanup;
03795         }
03796     }
03797 #endif
03798 
03799     if (lpftLastWriteTime != NULL)
03800     {
03801         lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
03802         lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
03803     }
03804 
03805     if (lpClass != NULL)
03806     {
03807         if (FullInfo->ClassLength > ClassLength)
03808         {
03809             ErrorCode = ERROR_BUFFER_OVERFLOW;
03810         }
03811         else
03812         {
03813             RtlCopyMemory(lpClass,
03814                           FullInfo->Class,
03815                           FullInfo->ClassLength);
03816             *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
03817             lpClass[*lpcbClass] = 0;
03818         }
03819 
03820         RtlFreeHeap(ProcessHeap,
03821                     0,
03822                     FullInfo);
03823     }
03824 
03825 Cleanup:
03826     ClosePredefKey(KeyHandle);
03827 
03828     return ErrorCode;
03829 }
03830 
03831 
03832 /************************************************************************
03833  *  RegQueryMultipleValuesA
03834  *
03835  * @implemented
03836  */
03837 LONG WINAPI
03838 RegQueryMultipleValuesA(HKEY hKey,
03839                         PVALENTA val_list,
03840                         DWORD num_vals,
03841                         LPSTR lpValueBuf,
03842                         LPDWORD ldwTotsize)
03843 {
03844     ULONG i;
03845     DWORD maxBytes = *ldwTotsize;
03846     LPSTR bufptr = (LPSTR)lpValueBuf;
03847     LONG ErrorCode;
03848 
03849     if (maxBytes >= (1024*1024))
03850         return ERROR_TRANSFER_TOO_LONG;
03851 
03852     *ldwTotsize = 0;
03853 
03854     TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
03855           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
03856 
03857     for (i = 0; i < num_vals; i++)
03858     {
03859         val_list[i].ve_valuelen = 0;
03860         ErrorCode = RegQueryValueExA(hKey,
03861                                      val_list[i].ve_valuename,
03862                                      NULL,
03863                                      NULL,
03864                                      NULL,
03865                                      &val_list[i].ve_valuelen);
03866         if (ErrorCode != ERROR_SUCCESS)
03867         {
03868             return ErrorCode;
03869         }
03870 
03871         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
03872         {
03873             ErrorCode = RegQueryValueExA(hKey,
03874                                          val_list[i].ve_valuename,
03875                                          NULL,
03876                                          &val_list[i].ve_type,
03877                                          (LPBYTE)bufptr,
03878                                          &val_list[i].ve_valuelen);
03879             if (ErrorCode != ERROR_SUCCESS)
03880             {
03881                 return ErrorCode;
03882             }
03883 
03884             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
03885 
03886             bufptr += val_list[i].ve_valuelen;
03887         }
03888 
03889         *ldwTotsize += val_list[i].ve_valuelen;
03890     }
03891 
03892     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
03893 }
03894 
03895 
03896 /************************************************************************
03897  *  RegQueryMultipleValuesW
03898  *
03899  * @implemented
03900  */
03901 LONG WINAPI
03902 RegQueryMultipleValuesW(HKEY hKey,
03903                         PVALENTW val_list,
03904                         DWORD num_vals,
03905                         LPWSTR lpValueBuf,
03906                         LPDWORD ldwTotsize)
03907 {
03908     ULONG i;
03909     DWORD maxBytes = *ldwTotsize;
03910     LPSTR bufptr = (LPSTR)lpValueBuf;
03911     LONG ErrorCode;
03912 
03913     if (maxBytes >= (1024*1024))
03914         return ERROR_TRANSFER_TOO_LONG;
03915 
03916     *ldwTotsize = 0;
03917 
03918     TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
03919           hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
03920 
03921     for (i = 0; i < num_vals; i++)
03922     {
03923         val_list[i].ve_valuelen = 0;
03924         ErrorCode = RegQueryValueExW(hKey,
03925                                      val_list[i].ve_valuename,
03926                                      NULL,
03927                                      NULL,
03928                                      NULL,
03929                                      &val_list[i].ve_valuelen);
03930         if (ErrorCode != ERROR_SUCCESS)
03931         {
03932             return ErrorCode;
03933          }
03934 
03935         if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
03936         {
03937             ErrorCode = RegQueryValueExW(hKey,
03938                                          val_list[i].ve_valuename,
03939                                          NULL,
03940                                          &val_list[i].ve_type,
03941                                          (LPBYTE)bufptr,
03942                                          &val_list[i].ve_valuelen);
03943             if (ErrorCode != ERROR_SUCCESS)
03944             {
03945                 return ErrorCode;
03946             }
03947 
03948             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
03949 
03950             bufptr += val_list[i].ve_valuelen;
03951         }
03952 
03953         *ldwTotsize += val_list[i].ve_valuelen;
03954     }
03955 
03956     return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
03957 }
03958 
03959 
03960 /************************************************************************
03961  *  RegQueryReflectionKey
03962  *
03963  * @unimplemented
03964  */
03965 LONG WINAPI
03966 RegQueryReflectionKey(IN HKEY hBase,
03967                       OUT BOOL* bIsReflectionDisabled)
03968 {
03969     FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
03970           hBase, bIsReflectionDisabled);
03971     return ERROR_CALL_NOT_IMPLEMENTED;
03972 }
03973 
03974 
03975 /******************************************************************************
03976  * RegQueryValueExA   [ADVAPI32.@]
03977  *
03978  * Get the type and contents of a specified value under with a key.
03979  *
03980  * PARAMS
03981  *  hkey      [I]   Handle of the key to query
03982  *  name      [I]   Name of value under hkey to query
03983  *  reserved  [I]   Reserved - must be NULL
03984  *  type      [O]   Destination for the value type, or NULL if not required
03985  *  data      [O]   Destination for the values contents, or NULL if not required
03986  *  count     [I/O] Size of data, updated with the number of bytes returned
03987  *
03988  * RETURNS
03989  *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
03990  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
03991  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
03992  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
03993  *                     
03994  * NOTES
03995  *   MSDN states that if data is too small it is partially filled. In reality 
03996  *   it remains untouched.
03997  */
03998 LONG
03999 WINAPI
04000 RegQueryValueExA(HKEY hkeyorg,
04001                  LPCSTR name,
04002                  LPDWORD reserved,
04003                  LPDWORD type,
04004                  LPBYTE data,
04005                  LPDWORD count)
04006 {
04007     HANDLE hkey;
04008     NTSTATUS status;
04009     ANSI_STRING nameA;
04010     UNICODE_STRING nameW;
04011     DWORD total_size, datalen = 0;
04012     char buffer[256], *buf_ptr = buffer;
04013     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
04014     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
04015 
04016     TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
04017           hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
04018 
04019     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
04020     status = MapDefaultKey(&hkey, hkeyorg);
04021     if (!NT_SUCCESS(status))
04022     {
04023         return RtlNtStatusToDosError(status);
04024     }
04025 
04026     if (count) datalen = *count;
04027     if (!data && count) *count = 0;
04028 
04029     RtlInitAnsiString( &nameA, name );
04030     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
04031     {
04032         ClosePredefKey(hkey);
04033         return RtlNtStatusToDosError(status);
04034     }
04035 
04036     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
04037                               buffer, sizeof(buffer), &total_size );
04038     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
04039 
04040     /* we need to fetch the contents for a string type even if not requested,
04041      * because we need to compute the length of the ASCII string. */
04042     if (data || is_string(info->Type))
04043     {
04044         /* retry with a dynamically allocated buffer */
04045         while (status == STATUS_BUFFER_OVERFLOW)
04046         {
04047             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
04048             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
04049             {
04050                 status = STATUS_NO_MEMORY;
04051                 goto done;
04052             }
04053             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
04054             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
04055                                       buf_ptr, total_size, &total_size );
04056         }
04057 
04058         if (status) goto done;
04059 
04060         if (is_string(info->Type))
04061         {
04062             DWORD len;
04063 
04064             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
04065                                        total_size - info_size );
04066             if (data && len)
04067             {
04068                 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
04069                 else
04070                 {
04071                     RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
04072                                             total_size - info_size );
04073                     /* if the type is REG_SZ and data is not 0-terminated
04074                      * and there is enough space in the buffer NT appends a \0 */
04075                     if (len < datalen && data[len-1]) data[len] = 0;
04076                 }
04077             }
04078             total_size = len + info_size;
04079         }
04080         else if (data)
04081         {
04082             if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
04083             else memcpy( data, buf_ptr + info_size, total_size - info_size );
04084         }
04085     }
04086     else status = STATUS_SUCCESS;
04087 
04088     if (type) *type = info->Type;
04089     if (count) *count = total_size - info_size;
04090 
04091  done:
04092     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
04093     RtlFreeUnicodeString( &nameW );
04094     ClosePredefKey(hkey);
04095     return RtlNtStatusToDosError(status);
04096 }
04097 
04098 
04099 /************************************************************************
04100  *  RegQueryValueExW
04101  *
04102  * @implemented
04103  */
04104 LONG
04105 WINAPI
04106 RegQueryValueExW(HKEY hkeyorg,
04107                  LPCWSTR name,
04108                  LPDWORD reserved,
04109                  LPDWORD type,
04110                  LPBYTE data,
04111                  LPDWORD count)
04112 {
04113     HANDLE hkey;
04114     NTSTATUS status;
04115     UNICODE_STRING name_str;
04116     DWORD total_size;
04117     char buffer[256], *buf_ptr = buffer;
04118     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
04119     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
04120 
04121     TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
04122           hkeyorg, debugstr_w(name), reserved, type, data, count,
04123           (count && data) ? *count : 0 );
04124 
04125     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
04126 
04127     status = MapDefaultKey(&hkey, hkeyorg);
04128     if (!NT_SUCCESS(status))
04129     {
04130         return RtlNtStatusToDosError(status);
04131     }
04132 
04133     RtlInitUnicodeString( &name_str, name );
04134 
04135     if (data) total_size = min( sizeof(buffer), *count + info_size );
04136     else
04137     {
04138         total_size = info_size;
04139         if (count) *count = 0;
04140     }
04141 
04142     /* this matches Win9x behaviour - NT sets *type to a random value */
04143     if (type) *type = REG_NONE;
04144 
04145     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
04146                               buffer, total_size, &total_size );
04147     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
04148 
04149     if (data)
04150     {
04151         /* retry with a dynamically allocated buffer */
04152         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
04153         {
04154             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
04155             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
04156             {
04157                 ClosePredefKey(hkey);
04158                 return ERROR_NOT_ENOUGH_MEMORY;
04159             }
04160             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
04161             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
04162                                       buf_ptr, total_size, &total_size );
04163         }
04164 
04165         if (NT_SUCCESS(status))
04166         {
04167             memcpy( data, buf_ptr + info_size, total_size - info_size );
04168             /* if the type is REG_SZ and data is not 0-terminated
04169              * and there is enough space in the buffer NT appends a \0 */
04170             if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR))
04171             {
04172                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
04173                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
04174             }
04175         }
04176         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
04177     }
04178     else status = STATUS_SUCCESS;
04179 
04180     if (type) *type = info->Type;
04181     if (count) *count = total_size - info_size;
04182 
04183  done:
04184     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
04185     ClosePredefKey(hkey);
04186     return RtlNtStatusToDosError(status);
04187 }
04188 
04189 
04190 /************************************************************************
04191  *  RegQueryValueA
04192  *
04193  * @implemented
04194  */
04195 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
04196 {
04197     DWORD ret;
04198     HKEY subkey = hkey;
04199 
04200     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
04201 
04202     if (name && name[0])
04203     {
04204     if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
04205     }
04206     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
04207     if (subkey != hkey) RegCloseKey( subkey );
04208     if (ret == ERROR_FILE_NOT_FOUND)
04209     {
04210     /* return empty string if default value not found */
04211     if (data) *data = 0;
04212     if (count) *count = 1;
04213     ret = ERROR_SUCCESS;
04214     }
04215     return ret;
04216 }
04217 
04218 
04219 /************************************************************************
04220  *  RegQueryValueW
04221  *
04222  * @implemented
04223  */
04224 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
04225 {
04226     DWORD ret;
04227     HKEY subkey = hkey;
04228 
04229     TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
04230     if (hkey == NULL)
04231     {
04232        return ERROR_INVALID_HANDLE;
04233     }
04234     if (name && name[0])
04235     {
04236         ret = RegOpenKeyW( hkey, name, &subkey);
04237         if (ret != ERROR_SUCCESS) 
04238         {
04239             return ret;
04240         }
04241     }
04242 
04243     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
04244     
04245     if (subkey != hkey) 
04246     {
04247         RegCloseKey( subkey );
04248     }
04249 
04250     if (ret == ERROR_FILE_NOT_FOUND)
04251     {
04252         /* return empty string if default value not found */
04253         if (data) 
04254             *data = 0;
04255         if (count) 
04256             *count = sizeof(WCHAR);
04257         ret = ERROR_SUCCESS;
04258     }
04259     return ret;
04260 }
04261 
04262 
04263 /************************************************************************
04264  *  RegReplaceKeyA
04265  *
04266  * @implemented
04267  */
04268 LONG WINAPI
04269 RegReplaceKeyA(HKEY hKey,
04270                LPCSTR lpSubKey,
04271                LPCSTR lpNewFile,
04272                LPCSTR lpOldFile)
04273 {
04274     UNICODE_STRING SubKey;
04275     UNICODE_STRING NewFile;
04276     UNICODE_STRING OldFile;
04277     LONG ErrorCode;
04278 
04279     RtlCreateUnicodeStringFromAsciiz(&SubKey,
04280                                      (PCSZ)lpSubKey);
04281     RtlCreateUnicodeStringFromAsciiz(&OldFile,
04282                                      (PCSZ)lpOldFile);
04283     RtlCreateUnicodeStringFromAsciiz(&NewFile,
04284                                      (PCSZ)lpNewFile);
04285 
04286     ErrorCode = RegReplaceKeyW(hKey,
04287                                SubKey.Buffer,
04288                                NewFile.Buffer,
04289                                OldFile.Buffer);
04290 
04291     RtlFreeUnicodeString(&OldFile);
04292     RtlFreeUnicodeString(&NewFile);
04293     RtlFreeUnicodeString(&SubKey);
04294 
04295     return ErrorCode;
04296 }
04297 
04298 
04299 /************************************************************************
04300  *  RegReplaceKeyW
04301  *
04302  * @unimplemented
04303  */
04304 LONG WINAPI
04305 RegReplaceKeyW(HKEY hKey,
04306                LPCWSTR lpSubKey,
04307                LPCWSTR lpNewFile,
04308                LPCWSTR lpOldFile)
04309 {
04310     OBJECT_ATTRIBUTES KeyObjectAttributes;
04311     OBJECT_ATTRIBUTES NewObjectAttributes;
04312     OBJECT_ATTRIBUTES OldObjectAttributes;
04313     UNICODE_STRING SubKeyName;
04314     UNICODE_STRING NewFileName;
04315     UNICODE_STRING OldFileName;
04316     BOOLEAN CloseRealKey;
04317     HANDLE RealKeyHandle;
04318     HANDLE KeyHandle;
04319     NTSTATUS Status;
04320     LONG ErrorCode = ERROR_SUCCESS;
04321 
04322     if (hKey == HKEY_PERFORMANCE_DATA)
04323     {
04324         return ERROR_INVALID_HANDLE;
04325     }
04326 
04327     Status = MapDefaultKey(&KeyHandle,
04328                            hKey);
04329     if (!NT_SUCCESS(Status))
04330     {
04331         return RtlNtStatusToDosError(Status);
04332     }
04333 
04334     /* Open the real key */
04335     if (lpSubKey != NULL && *lpSubKey != (WCHAR)0)
04336     {
04337         RtlInitUnicodeString(&SubKeyName,
04338                              (PWSTR)lpSubKey);
04339         InitializeObjectAttributes(&KeyObjectAttributes,
04340                                    &SubKeyName,
04341                                    OBJ_CASE_INSENSITIVE,
04342                                    KeyHandle,
04343                                    NULL);
04344         Status = NtOpenKey(&RealKeyHandle,
04345                            MAXIMUM_ALLOWED,
04346                            &KeyObjectAttributes);
04347         if (!NT_SUCCESS(Status))
04348         {
04349             ErrorCode = RtlNtStatusToDosError(Status);
04350             goto Cleanup;
04351         }
04352 
04353         CloseRealKey = TRUE;
04354     }
04355     else
04356     {
04357         RealKeyHandle = KeyHandle;
04358         CloseRealKey = FALSE;
04359     }
04360 
04361     /* Convert new file name */
04362     if (!RtlDosPathNameToNtPathName_U(lpNewFile,
04363                                       &NewFileName,
04364                                       NULL,
04365                                       NULL))
04366     {
04367         if (CloseRealKey)
04368         {
04369             NtClose(RealKeyHandle);
04370         }
04371 
04372         ErrorCode = ERROR_INVALID_PARAMETER;
04373         goto Cleanup;
04374     }
04375 
04376     InitializeObjectAttributes(&NewObjectAttributes,
04377                                &NewFileName,
04378                                OBJ_CASE_INSENSITIVE,
04379                                NULL,
04380                                NULL);
04381 
04382     /* Convert old file name */
04383     if (!RtlDosPathNameToNtPathName_U(lpOldFile,
04384                                       &OldFileName,
04385                                       NULL,
04386                                       NULL))
04387     {
04388         RtlFreeHeap(RtlGetProcessHeap (),
04389                     0,
04390                     NewFileName.Buffer);
04391         if (CloseRealKey)
04392         {
04393             NtClose(RealKeyHandle);
04394         }
04395 
04396         ErrorCode = ERROR_INVALID_PARAMETER;
04397         goto Cleanup;
04398     }
04399 
04400     InitializeObjectAttributes(&OldObjectAttributes,
04401                                &OldFileName,
04402                                OBJ_CASE_INSENSITIVE,
04403                                NULL,
04404                                NULL);
04405 
04406     Status = NtReplaceKey(&NewObjectAttributes,
04407                           RealKeyHandle,
04408                           &OldObjectAttributes);
04409 
04410     RtlFreeHeap(RtlGetProcessHeap(),
04411                 0,
04412                 OldFileName.Buffer);
04413     RtlFreeHeap(RtlGetProcessHeap(),
04414                 0,
04415                 NewFileName.Buffer);
04416 
04417     if (CloseRealKey)
04418     {
04419         NtClose(RealKeyHandle);
04420     }
04421 
04422     if (!NT_SUCCESS(Status))
04423     {
04424         return RtlNtStatusToDosError(Status);
04425     }
04426 
04427 Cleanup:
04428     ClosePredefKey(KeyHandle);
04429 
04430     return ErrorCode;
04431 }
04432 
04433 
04434 /************************************************************************
04435  *  RegRestoreKeyA
04436  *
04437  * @implemented
04438  */
04439 LONG WINAPI
04440 RegRestoreKeyA(HKEY hKey,
04441                LPCSTR lpFile,
04442                DWORD dwFlags)
04443 {
04444     UNICODE_STRING FileName;
04445     LONG ErrorCode;
04446 
04447     RtlCreateUnicodeStringFromAsciiz(&FileName,
04448                                      (PCSZ)lpFile);
04449 
04450     ErrorCode = RegRestoreKeyW(hKey,
04451                                FileName.Buffer,
04452                                dwFlags);
04453 
04454     RtlFreeUnicodeString(&FileName);
04455 
04456     return ErrorCode;
04457 }
04458 
04459 
04460 /************************************************************************
04461  *  RegRestoreKeyW
04462  *
04463  * @implemented
04464  */
04465 LONG WINAPI
04466 RegRestoreKeyW(HKEY hKey,
04467                LPCWSTR lpFile,
04468                DWORD dwFlags)
04469 {
04470     OBJECT_ATTRIBUTES ObjectAttributes;
04471     IO_STATUS_BLOCK IoStatusBlock;
04472     UNICODE_STRING FileName;
04473     HANDLE FileHandle;
04474     HANDLE KeyHandle;
04475     NTSTATUS Status;
04476 
04477     if (hKey == HKEY_PERFORMANCE_DATA)
04478     {
04479         return ERROR_INVALID_HANDLE;
04480     }
04481 
04482     Status = MapDefaultKey(&KeyHandle,
04483                            hKey);
04484     if (!NT_SUCCESS(Status))
04485     {
04486         return RtlNtStatusToDosError(Status);
04487     }
04488 
04489     if (!RtlDosPathNameToNtPathName_U(lpFile,
04490                                       &FileName,
04491                                       NULL,
04492                                       NULL))
04493     {
04494         Status = STATUS_INVALID_PARAMETER;
04495         goto Cleanup;
04496     }
04497 
04498     InitializeObjectAttributes(&ObjectAttributes,
04499                                &FileName,
04500                                OBJ_CASE_INSENSITIVE,
04501                                NULL,
04502                                NULL);
04503 
04504     Status = NtOpenFile(&FileHandle,
04505                         FILE_GENERIC_READ,
04506                         &ObjectAttributes,
04507                         &IoStatusBlock,
04508                         FILE_SHARE_READ,
04509                         FILE_SYNCHRONOUS_IO_NONALERT);
04510     RtlFreeHeap(RtlGetProcessHeap(),
04511                 0,
04512                 FileName.Buffer);
04513     if (!NT_SUCCESS(Status))
04514     {
04515         goto Cleanup;
04516     }
04517 
04518     Status = NtRestoreKey(KeyHandle,
04519                           FileHandle,
04520                           (ULONG)dwFlags);
04521     NtClose (FileHandle);
04522 
04523 Cleanup:
04524     ClosePredefKey(KeyHandle);
04525 
04526     if (!NT_SUCCESS(Status))
04527     {
04528         return RtlNtStatusToDosError(Status);
04529     }
04530 
04531     return ERROR_SUCCESS;
04532 }
04533 
04534 
04535 /************************************************************************
04536  *  RegSaveKeyA
04537  *
04538  * @implemented
04539  */
04540 LONG WINAPI
04541 RegSaveKeyA(HKEY hKey,
04542             LPCSTR lpFile,
04543             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
04544 {
04545     UNICODE_STRING FileName;
04546     LONG ErrorCode;
04547 
04548     RtlCreateUnicodeStringFromAsciiz(&FileName,
04549                                      (LPSTR)lpFile);
04550     ErrorCode = RegSaveKeyW(hKey,
04551                             FileName.Buffer,
04552                             lpSecurityAttributes);
04553     RtlFreeUnicodeString(&FileName);
04554 
04555     return ErrorCode;
04556 }
04557 
04558 
04559 /************************************************************************
04560  *  RegSaveKeyW
04561  *
04562  * @implemented
04563  */
04564 LONG WINAPI
04565 RegSaveKeyW(HKEY hKey,
04566             LPCWSTR lpFile,
04567             LPSECURITY_ATTRIBUTES lpSecurityAttributes)
04568 {
04569     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
04570     OBJECT_ATTRIBUTES ObjectAttributes;
04571     UNICODE_STRING FileName;
04572     IO_STATUS_BLOCK IoStatusBlock;
04573     HANDLE FileHandle;
04574     HANDLE KeyHandle;
04575     NTSTATUS Status;
04576 
04577     Status = MapDefaultKey(&KeyHandle,
04578                            hKey);
04579     if (!NT_SUCCESS(Status))
04580     {
04581         return RtlNtStatusToDosError(Status);
04582     }
04583 
04584     if (!RtlDosPathNameToNtPathName_U(lpFile,
04585                                       &FileName,
04586                                       NULL,
04587                                       NULL))
04588     {
04589         Status = STATUS_INVALID_PARAMETER;
04590         goto Cleanup;
04591     }
04592 
04593     if (lpSecurityAttributes != NULL)
04594     {
04595         SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
04596     }
04597 
04598     InitializeObjectAttributes(&ObjectAttributes,
04599                                &FileName,
04600                                OBJ_CASE_INSENSITIVE,
04601                                NULL,
04602                                SecurityDescriptor);
04603     Status = NtCreateFile(&FileHandle,
04604                           GENERIC_WRITE | SYNCHRONIZE,
04605                           &ObjectAttributes,
04606                           &IoStatusBlock,
04607                           NULL,
04608                           FILE_ATTRIBUTE_NORMAL,
04609                           FILE_SHARE_READ,
04610                           FILE_CREATE,
04611                           FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
04612                           NULL,
04613                           0);
04614     RtlFreeHeap(RtlGetProcessHeap(),
04615                 0,
04616                 FileName.Buffer);
04617     if (!NT_SUCCESS(Status))
04618     {
04619         goto Cleanup;
04620     }
04621 
04622     Status = NtSaveKey(KeyHandle,
04623                        FileHandle);
04624     NtClose (FileHandle);
04625 
04626 Cleanup:
04627     ClosePredefKey(KeyHandle);
04628 
04629     if (!NT_SUCCESS(Status))
04630     {
04631         return RtlNtStatusToDosError(Status);
04632     }
04633 
04634     return ERROR_SUCCESS;
04635 }
04636 
04637 
04638 /************************************************************************
04639  *  RegSaveKeyExA
04640  *
04641  * @implemented
04642  */
04643 LONG
04644 WINAPI
04645 RegSaveKeyExA(HKEY hKey,
04646               LPCSTR lpFile,
04647               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
04648               DWORD Flags)
04649 {
04650     UNICODE_STRING FileName;
04651     LONG ErrorCode;
04652 
04653     RtlCreateUnicodeStringFromAsciiz(&FileName,
04654                                      (LPSTR)lpFile);
04655     ErrorCode = RegSaveKeyExW(hKey,
04656                               FileName.Buffer,
04657                               lpSecurityAttributes,
04658                               Flags);
04659     RtlFreeUnicodeString(&FileName);
04660 
04661     return ErrorCode;
04662 }
04663 
04664 
04665 /************************************************************************
04666  *  RegSaveKeyExW
04667  *
04668  * @unimplemented
04669  */
04670 LONG
04671 WINAPI
04672 RegSaveKeyExW(HKEY hKey,
04673               LPCWSTR lpFile,
04674               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
04675               DWORD Flags)
04676 {
04677     switch (Flags)
04678     {
04679         case REG_STANDARD_FORMAT:
04680         case REG_LATEST_FORMAT:
04681         case REG_NO_COMPRESSION:
04682             break;
04683         default:
04684             return ERROR_INVALID_PARAMETER;
04685     }
04686 
04687     FIXME("RegSaveKeyExW(): Flags ignored!\n");
04688 
04689     return RegSaveKeyW(hKey,
04690                        lpFile,
04691                        lpSecurityAttributes);
04692 }
04693 
04694 
04695 /************************************************************************
04696  *  RegSetKeySecurity
04697  *
04698  * @implemented
04699  */
04700 LONG WINAPI
04701 RegSetKeySecurity(HKEY hKey,
04702                   SECURITY_INFORMATION SecurityInformation,
04703                   PSECURITY_DESCRIPTOR pSecurityDescriptor)
04704 {
04705     HANDLE KeyHandle;
04706     NTSTATUS Status;
04707 
04708     if (hKey == HKEY_PERFORMANCE_DATA)
04709     {
04710         return ERROR_INVALID_HANDLE;
04711     }
04712 
04713     Status = MapDefaultKey(&KeyHandle,
04714                            hKey);
04715     if (!NT_SUCCESS(Status))
04716     {
04717         return RtlNtStatusToDosError(Status);
04718     }
04719 
04720     Status = NtSetSecurityObject(KeyHandle,
04721                                  SecurityInformation,
04722                                  pSecurityDescriptor);
04723 
04724     ClosePredefKey(KeyHandle);
04725 
04726     if (!NT_SUCCESS(Status))
04727     {
04728         return RtlNtStatusToDosError(Status);
04729     }
04730 
04731     return ERROR_SUCCESS;
04732 }
04733 
04734 
04735 /************************************************************************
04736  *  RegSetValueExA
04737  *
04738  * @implemented
04739  */
04740 LONG WINAPI
04741 RegSetValueExA(HKEY hKey,
04742                LPCSTR lpValueName,
04743                DWORD Reserved,
04744                DWORD dwType,
04745                CONST BYTE* lpData,
04746                DWORD cbData)
04747 {
04748     UNICODE_STRING ValueName;
04749     LPWSTR pValueName;
04750     ANSI_STRING AnsiString;
04751     UNICODE_STRING Data;
04752     LONG ErrorCode;
04753     LPBYTE pData;
04754     DWORD DataSize;
04755     NTSTATUS Status;
04756 
04757     /* Convert SubKey name to Unicode */
04758     if (lpValueName != NULL && lpValueName[0] != '\0')
04759     {
04760         BOOL bConverted;
04761         bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
04762                                                   (PSTR)lpValueName);
04763         if(!bConverted)
04764             return ERROR_NOT_ENOUGH_MEMORY;
04765     }
04766     else
04767     {
04768         ValueName.Buffer = NULL;
04769     }
04770 
04771     pValueName = (LPWSTR)ValueName.Buffer;
04772 
04773 
04774     if (is_string(dwType) && (cbData != 0))
04775     {
04776         /* Convert ANSI string Data to Unicode */
04777         /* If last character NOT zero then increment length */
04778         LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0);
04779         AnsiString.Buffer = (PSTR)lpData;
04780         AnsiString.Length = cbData + bNoNulledStr;
04781         AnsiString.MaximumLength = cbData + bNoNulledStr;
04782         Status = RtlAnsiStringToUnicodeString(&Data,
04783                                      &AnsiString,
04784                                      TRUE);
04785 
04786         if (!NT_SUCCESS(Status))
04787         {
04788             if (pValueName != NULL)
04789                 RtlFreeUnicodeString(&ValueName);
04790 
04791             return RtlNtStatusToDosError(Status);
04792         }
04793         pData = (LPBYTE)Data.Buffer;
04794         DataSize = cbData * sizeof(WCHAR);
04795     }
04796     else
04797     {
04798         Data.Buffer = NULL;
04799         pData = (LPBYTE)lpData;
04800         DataSize = cbData;
04801     }
04802 
04803     ErrorCode = RegSetValueExW(hKey,
04804                                pValueName,
04805                                Reserved,
04806                                dwType,
04807                                pData,
04808                                DataSize);
04809 
04810     if (pValueName != NULL)
04811         RtlFreeUnicodeString(&ValueName);
04812 
04813     if (Data.Buffer != NULL)
04814         RtlFreeUnicodeString(&Data);
04815 
04816     return ErrorCode;
04817 }
04818 
04819 
04820 /************************************************************************
04821  *  RegSetValueExW
04822  *
04823  * @implemented
04824  */
04825 LONG WINAPI
04826 RegSetValueExW(HKEY hKey,
04827                LPCWSTR lpValueName,
04828                DWORD Reserved,
04829                DWORD dwType,
04830                CONST BYTE* lpData,
04831                DWORD cbData)
04832 {
04833     UNICODE_STRING ValueName;
04834     PUNICODE_STRING pValueName;
04835     HANDLE KeyHandle;
04836     NTSTATUS Status;
04837 
04838     Status = MapDefaultKey(&KeyHandle,
04839                            hKey);
04840     if (!NT_SUCCESS(Status))
04841     {
04842         return RtlNtStatusToDosError(Status);
04843     }
04844 
04845     RtlInitUnicodeString(&ValueName, lpValueName);
04846     pValueName = &ValueName;
04847 
04848     if (is_string(dwType) && (cbData != 0))
04849     {
04850         PWSTR pwsData = (PWSTR)lpData;
04851 
04852         if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
04853             (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
04854         {
04855             /* Increment length if last character is not zero and next is zero */
04856             cbData += sizeof(WCHAR);
04857         }
04858     }
04859 
04860     Status = NtSetValueKey(KeyHandle,
04861                            pValueName,
04862                            0,
04863                            dwType,
04864                            (PVOID)lpData,
04865                            (ULONG)cbData);
04866 
04867     ClosePredefKey(KeyHandle);
04868 
04869     if (!NT_SUCCESS(Status))
04870     {
04871         return RtlNtStatusToDosError(Status);
04872     }
04873 
04874     return ERROR_SUCCESS;
04875 }
04876 
04877 
04878 /************************************************************************
04879  *  RegSetValueA
04880  *
04881  * @implemented
04882  */
04883 LONG WINAPI
04884 RegSetValueA(HKEY hKeyOriginal,
04885              LPCSTR lpSubKey,
04886              DWORD dwType,
04887              LPCSTR lpData,
04888              DWORD cbData)
04889 {
04890     HKEY subkey;
04891     HANDLE hKey;
04892     DWORD ret;
04893     NTSTATUS Status;
04894 
04895     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData );
04896 
04897     if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER;
04898 
04899     Status = MapDefaultKey(&hKey, hKeyOriginal);
04900     if (!NT_SUCCESS(Status))
04901     {
04902         return RtlNtStatusToDosError (Status);
04903     }
04904     subkey = hKey;
04905 
04906     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
04907     {
04908         ret = RegCreateKeyA(hKey, lpSubKey, &subkey);
04909         if (ret != ERROR_SUCCESS)
04910             goto Cleanup;
04911     }
04912 
04913     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 );
04914     if (subkey != hKey)
04915         RegCloseKey(subkey);
04916 
04917 Cleanup:
04918     ClosePredefKey(hKey);
04919 
04920     return ret;
04921 }
04922 
04923 
04924 /************************************************************************
04925  *  RegSetValueW
04926  *
04927  * @implemented
04928  */
04929 LONG WINAPI
04930 RegSetValueW(HKEY hKeyOriginal,
04931              LPCWSTR lpSubKey,
04932              DWORD dwType,
04933              LPCWSTR lpData,
04934              DWORD cbData)
04935 {
04936     HKEY subkey;
04937     HANDLE hKey;
04938     DWORD ret;
04939     NTSTATUS Status;
04940 
04941     TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData );
04942 
04943     if (dwType != REG_SZ || !lpData)
04944         return ERROR_INVALID_PARAMETER;
04945 
04946     Status = MapDefaultKey(&hKey,
04947                            hKeyOriginal);
04948     if (!NT_SUCCESS(Status))
04949     {
04950         return RtlNtStatusToDosError(Status);
04951     }
04952     subkey = hKey;
04953 
04954     if (lpSubKey && lpSubKey[0])  /* need to create the subkey */
04955     {
04956         ret = RegCreateKeyW(hKey, lpSubKey, &subkey);
04957         if (ret != ERROR_SUCCESS)
04958             goto Cleanup;
04959     }
04960 
04961     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData,
04962                           (wcslen( lpData ) + 1) * sizeof(WCHAR) );
04963     if (subkey != hKey)
04964         RegCloseKey(subkey);
04965 
04966 Cleanup:
04967     ClosePredefKey(hKey);
04968 
04969     return ret;
04970 }
04971 
04972 
04973 /************************************************************************
04974  *  RegUnLoadKeyA
04975  *
04976  * @implemented
04977  */
04978 LONG WINAPI
04979 RegUnLoadKeyA(HKEY hKey,
04980               LPCSTR lpSubKey)
04981 {
04982     UNICODE_STRING KeyName;
04983     DWORD ErrorCode;
04984 
04985     RtlCreateUnicodeStringFromAsciiz(&KeyName,
04986                                      (LPSTR)lpSubKey);
04987 
04988     ErrorCode = RegUnLoadKeyW(hKey,
04989                               KeyName.Buffer);
04990 
04991     RtlFreeUnicodeString (&KeyName);
04992 
04993     return ErrorCode;
04994 }
04995 
04996 
04997 /************************************************************************
04998  *  RegUnLoadKeyW
04999  *
05000  * @implemented
05001  */
05002 LONG WINAPI
05003 RegUnLoadKeyW(HKEY hKey,
05004               LPCWSTR lpSubKey)
05005 {
05006     OBJECT_ATTRIBUTES ObjectAttributes;
05007     UNICODE_STRING KeyName;
05008     HANDLE KeyHandle;
05009     NTSTATUS Status;
05010 
05011     if (hKey == HKEY_PERFORMANCE_DATA)
05012     {
05013       return ERROR_INVALID_HANDLE;
05014     }
05015 
05016     Status = MapDefaultKey(&KeyHandle, hKey);
05017     if (!NT_SUCCESS(Status))
05018     {
05019         return RtlNtStatusToDosError(Status);
05020     }
05021 
05022     RtlInitUnicodeString(&KeyName,
05023                          (LPWSTR)lpSubKey);
05024 
05025     InitializeObjectAttributes(&ObjectAttributes,
05026                                &KeyName,
05027                                OBJ_CASE_INSENSITIVE,
05028                                KeyHandle,
05029                                NULL);
05030 
05031     Status = NtUnloadKey(&ObjectAttributes);
05032 
05033     ClosePredefKey(KeyHandle);
05034 
05035     if (!NT_SUCCESS(Status))
05036     {
05037         return RtlNtStatusToDosError(Status);
05038     }
05039 
05040     return ERROR_SUCCESS;
05041 }
05042 
05043 
05044 /******************************************************************************
05045  * load_string [Internal]
05046  *
05047  * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
05048  * avoid importing user32, which is higher level than advapi32. Helper for
05049  * RegLoadMUIString.
05050  */
05051 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
05052 {
05053     HGLOBAL hMemory;
05054     HRSRC hResource;
05055     WCHAR *pString;
05056     int idxString;
05057 
05058     /* Negative values have to be inverted. */
05059     if (HIWORD(resId) == 0xffff)
05060         resId = (UINT)(-((INT)resId));
05061 
05062     /* Load the resource into memory and get a pointer to it. */
05063     hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
05064     if (!hResource) return 0;
05065     hMemory = LoadResource(hModule, hResource);
05066     if (!hMemory) return 0;
05067     pString = LockResource(hMemory);
05068 
05069     /* Strings are length-prefixed. Lowest nibble of resId is an index. */
05070     idxString = resId & 0xf;
05071     while (idxString--) pString += *pString + 1;
05072 
05073     /* If no buffer is given, return length of the string. */
05074     if (!pwszBuffer) return *pString;
05075 
05076     /* Else copy over the string, respecting the buffer size. */
05077     cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
05078     if (cMaxChars >= 0)
05079     {
05080         memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
05081         pwszBuffer[cMaxChars] = L'\0';
05082     }
05083 
05084     return cMaxChars;
05085 }
05086 
05087 
05088 /************************************************************************
05089  *  RegLoadMUIStringW
05090  *
05091  * @implemented
05092  */
05093 LONG WINAPI
05094 RegLoadMUIStringW(IN HKEY hKey,
05095                   IN LPCWSTR pszValue  OPTIONAL,
05096                   OUT LPWSTR pszOutBuf,
05097                   IN DWORD cbOutBuf,
05098                   OUT LPDWORD pcbData OPTIONAL,
05099                   IN DWORD Flags,
05100                   IN LPCWSTR pszDirectory  OPTIONAL)
05101 {
05102     DWORD dwValueType, cbData;
05103     LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
05104     LONG result;
05105 
05106     /* Parameter sanity checks. */
05107     if (!hKey || !pszOutBuf)
05108         return ERROR_INVALID_PARAMETER;
05109 
05110     if (pszDirectory && *pszDirectory)
05111     {
05112         FIXME("BaseDir parameter not yet supported!\n");
05113         return ERROR_INVALID_PARAMETER;
05114     }
05115 
05116     /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
05117     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
05118     if (result != ERROR_SUCCESS) goto cleanup;
05119     if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
05120     {
05121         result = ERROR_FILE_NOT_FOUND;
05122         goto cleanup;
05123     }
05124     pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
05125     if (!pwszTempBuffer)
05126     {
05127         result = ERROR_NOT_ENOUGH_MEMORY;
05128         goto cleanup;
05129     }
05130     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
05131     if (result != ERROR_SUCCESS) goto cleanup;
05132 
05133     /* Expand environment variables, if appropriate, or copy the original string over. */
05134     if (dwValueType == REG_EXPAND_SZ)
05135     {
05136         cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
05137         if (!cbData) goto cleanup;
05138         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
05139         if (!pwszExpandedBuffer)
05140         {
05141             result = ERROR_NOT_ENOUGH_MEMORY;
05142             goto cleanup;
05143         }
05144         ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
05145     }
05146     else
05147     {
05148         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
05149         memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
05150     }
05151 
05152     /* If the value references a resource based string, parse the value and load the string.
05153      * Else just copy over the original value. */
05154     result = ERROR_SUCCESS;
05155     if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
05156     {
05157         lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
05158     }
05159     else
05160     {
05161         WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
05162         UINT uiStringId;
05163         HMODULE hModule;
05164 
05165         /* Format of the expanded value is 'path_to_dll,-resId' */
05166         if (!pComma || pComma[1] != L'-')
05167         {
05168             result = ERROR_BADKEY;
05169             goto cleanup;
05170         }
05171 
05172         uiStringId = _wtoi(pComma+2);
05173         *pComma = L'\0';
05174 
05175         hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
05176         if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
05177             result = ERROR_BADKEY;
05178         FreeLibrary(hModule);
05179     }
05180 
05181 cleanup:
05182     HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
05183     HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
05184     return result;
05185 }
05186 
05187 
05188 /************************************************************************
05189  *  RegLoadMUIStringA
05190  *
05191  * @implemented
05192  */
05193 LONG WINAPI
05194 RegLoadMUIStringA(IN HKEY hKey,
05195                   IN LPCSTR pszValue  OPTIONAL,
05196                   OUT LPSTR pszOutBuf,
05197                   IN DWORD cbOutBuf,
05198                   OUT LPDWORD pcbData OPTIONAL,
05199                   IN DWORD Flags,
05200                   IN LPCSTR pszDirectory  OPTIONAL)
05201 {
05202     UNICODE_STRING valueW, baseDirW;
05203     WCHAR *pwszBuffer;
05204     DWORD cbData = cbOutBuf * sizeof(WCHAR);
05205     LONG result;
05206 
05207     valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
05208     if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
05209         !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
05210         !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
05211     {
05212         result = ERROR_NOT_ENOUGH_MEMORY;
05213         goto cleanup;
05214     }
05215 
05216     result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
05217                                baseDirW.Buffer);
05218 
05219     if (result == ERROR_SUCCESS)
05220     {
05221         cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
05222         if (pcbData)
05223             *pcbData = cbData;
05224     }
05225 
05226 cleanup:
05227     HeapFree(GetProcessHeap(), 0, pwszBuffer);
05228     RtlFreeUnicodeString(&baseDirW);
05229     RtlFreeUnicodeString(&valueW);
05230 
05231     return result;
05232 }
05233 
05234 /* EOF */

Generated on Sat May 26 2012 04:15:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.