Misc addendum to CORE-14271 (#1529)
[reactos.git] / dll / win32 / advapi32 / reg / reg.c
index 9341020..8841c15 100644 (file)
@@ -425,11 +425,16 @@ RegCloseKey(HKEY hKey)
     NTSTATUS Status;
 
     /* don't close null handle or a pseudo handle */
-    if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
+    if (!hKey)
     {
         return ERROR_INVALID_HANDLE;
     }
 
+    if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)
+    {
+        return ERROR_SUCCESS;
+    }
+
     Status = NtClose(hKey);
     if (!NT_SUCCESS(Status))
     {
@@ -1961,7 +1966,7 @@ RegpApplyRestrictions(DWORD dwFlags,
  * NOTES
  *  - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
  *    expanded and pdwType is set to REG_SZ instead.
- *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 
+ *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
  *    without RRF_NOEXPAND is thus not allowed.
  *    An exception is the case where RRF_RT_ANY is specified, because then
  *    RRF_NOEXPAND is allowed.
@@ -2632,7 +2637,7 @@ RegEnumKeyExW(
         {
             if (KeyInfo->Basic.NameLength > NameLength)
             {
-                ErrorCode = ERROR_BUFFER_OVERFLOW;
+                ErrorCode = ERROR_MORE_DATA;
             }
             else
             {
@@ -2648,7 +2653,7 @@ RegEnumKeyExW(
             if (KeyInfo->Node.NameLength > NameLength ||
                 KeyInfo->Node.ClassLength > ClassLength)
             {
-                ErrorCode = ERROR_BUFFER_OVERFLOW;
+                ErrorCode = ERROR_MORE_DATA;
             }
             else
             {
@@ -2720,12 +2725,15 @@ RegEnumValueA(
     if ((lpData && !lpcbData) || lpdwReserved)
         return ERROR_INVALID_PARAMETER;
 
-    /* Get the size of the buffer we must use for the first call ro RegEnumValueW */
+    /* Get the size of the buffer we must use for the first call to RegEnumValueW */
     ErrorCode = RegQueryInfoKeyW(
         hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
     if (ErrorCode != ERROR_SUCCESS)
         return ErrorCode;
 
+    /* Add space for the null terminator */
+    NameBufferSize++;
+
     /* Allocate the buffer for the unicode name */
     NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR));
     if (NameBuffer == NULL)
@@ -3195,7 +3203,7 @@ RegNotifyChangeKeyValue(HKEY hKey,
         return ERROR_INVALID_HANDLE;
     }
 
-    if (fAsynchronous == TRUE && hEvent == NULL)
+    if ((fAsynchronous != FALSE) && (hEvent == NULL))
     {
         return ERROR_INVALID_PARAMETER;
     }
@@ -3421,6 +3429,39 @@ RegOpenKeyExW(HKEY hKey,
                        samDesired,
                        &ObjectAttributes);
 
+    if (Status == STATUS_DATATYPE_MISALIGNMENT)
+    {
+        HANDLE hAligned;
+        UNICODE_STRING AlignedString;
+
+        Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                                           &SubKeyString,
+                                           &AlignedString);
+        if (NT_SUCCESS(Status))
+        {
+            /* Try again with aligned parameters */
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       &AlignedString,
+                                       Attributes,
+                                       KeyHandle,
+                                       NULL);
+
+            Status = NtOpenKey(&hAligned,
+                               samDesired,
+                               &ObjectAttributes);
+
+            RtlFreeUnicodeString(&AlignedString);
+
+            if (NT_SUCCESS(Status))
+                *phkResult = hAligned;
+        }
+        else
+        {
+            /* Restore the original error */
+            Status = STATUS_DATATYPE_MISALIGNMENT;
+        }
+    }
+
     if (!NT_SUCCESS(Status))
     {
         ErrorCode = RtlNtStatusToDosError(Status);
@@ -3583,14 +3624,14 @@ ReadTokenSid:
 LONG WINAPI
 RegQueryInfoKeyA(HKEY hKey,
                  LPSTR lpClass,
-                 LPDWORD lpcbClass,
+                 LPDWORD lpcClass,
                  LPDWORD lpReserved,
                  LPDWORD lpcSubKeys,
-                 LPDWORD lpcbMaxSubKeyLen,
-                 LPDWORD lpcbMaxClassLen,
+                 LPDWORD lpcMaxSubKeyLen,
+                 LPDWORD lpcMaxClassLen,
                  LPDWORD lpcValues,
-                 LPDWORD lpcbMaxValueNameLen,
-                 LPDWORD lpcbMaxValueLen,
+                 LPDWORD lpcMaxValueNameLen,
+                 LPDWORD lpcMaxValueLen,
                  LPDWORD lpcbSecurityDescriptor,
                  PFILETIME lpftLastWriteTime)
 {
@@ -3598,38 +3639,56 @@ RegQueryInfoKeyA(HKEY hKey,
     UNICODE_STRING UnicodeString;
     ANSI_STRING AnsiString;
     LONG ErrorCode;
+    NTSTATUS Status;
+    DWORD cClass = 0;
+
+    if ((lpClass) && (!lpcClass))
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
 
     RtlInitUnicodeString(&UnicodeString,
                          NULL);
     if (lpClass != NULL)
     {
-        UnicodeString.Buffer = &ClassName[0];
-        UnicodeString.MaximumLength = sizeof(ClassName);
-        AnsiString.MaximumLength = *lpcbClass;
+        RtlInitEmptyUnicodeString(&UnicodeString,
+                                  ClassName,
+                                  sizeof(ClassName));
+        cClass = sizeof(ClassName) / sizeof(WCHAR);
     }
 
     ErrorCode = RegQueryInfoKeyW(hKey,
                                  UnicodeString.Buffer,
-                                 lpcbClass,
+                                 &cClass,
                                  lpReserved,
                                  lpcSubKeys,
-                                 lpcbMaxSubKeyLen,
-                                 lpcbMaxClassLen,
+                                 lpcMaxSubKeyLen,
+                                 lpcMaxClassLen,
                                  lpcValues,
-                                 lpcbMaxValueNameLen,
-                                 lpcbMaxValueLen,
+                                 lpcMaxValueNameLen,
+                                 lpcMaxValueLen,
                                  lpcbSecurityDescriptor,
                                  lpftLastWriteTime);
     if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
     {
-        AnsiString.Buffer = lpClass;
-        AnsiString.Length = 0;
-        UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
-        RtlUnicodeStringToAnsiString(&AnsiString,
-                                     &UnicodeString,
-                                     FALSE);
-        *lpcbClass = AnsiString.Length;
-        lpClass[AnsiString.Length] = 0;
+        if (*lpcClass == 0)
+        {
+            return ErrorCode;
+        }
+
+        RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
+        UnicodeString.Length = cClass * sizeof(WCHAR);
+        Status = RtlUnicodeStringToAnsiString(&AnsiString,
+                                              &UnicodeString,
+                                              FALSE);
+        ErrorCode = RtlNtStatusToDosError(Status);
+        cClass = AnsiString.Length;
+        lpClass[cClass] = ANSI_NULL;
+    }
+
+    if (lpcClass != NULL)
+    {
+        *lpcClass = cClass;
     }
 
     return ErrorCode;
@@ -3644,14 +3703,14 @@ RegQueryInfoKeyA(HKEY hKey,
 LONG WINAPI
 RegQueryInfoKeyW(HKEY hKey,
                  LPWSTR lpClass,
-                 LPDWORD lpcbClass,
+                 LPDWORD lpcClass,
                  LPDWORD lpReserved,
                  LPDWORD lpcSubKeys,
-                 LPDWORD lpcbMaxSubKeyLen,
-                 LPDWORD lpcbMaxClassLen,
+                 LPDWORD lpcMaxSubKeyLen,
+                 LPDWORD lpcMaxClassLen,
                  LPDWORD lpcValues,
-                 LPDWORD lpcbMaxValueNameLen,
-                 LPDWORD lpcbMaxValueLen,
+                 LPDWORD lpcMaxValueNameLen,
+                 LPDWORD lpcMaxValueLen,
                  LPDWORD lpcbSecurityDescriptor,
                  PFILETIME lpftLastWriteTime)
 {
@@ -3664,7 +3723,7 @@ RegQueryInfoKeyW(HKEY hKey,
     ULONG Length;
     LONG ErrorCode = ERROR_SUCCESS;
 
-    if ((lpClass) && (!lpcbClass))
+    if ((lpClass) && (!lpcClass))
     {
         return ERROR_INVALID_PARAMETER;
     }
@@ -3678,9 +3737,9 @@ RegQueryInfoKeyW(HKEY hKey,
 
     if (lpClass != NULL)
     {
-        if (*lpcbClass > 0)
+        if (*lpcClass > 0)
         {
-            ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+            ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
         }
         else
         {
@@ -3696,16 +3755,15 @@ RegQueryInfoKeyW(HKEY hKey,
             ErrorCode = ERROR_OUTOFMEMORY;
             goto Cleanup;
         }
-
-        FullInfo->ClassLength = ClassLength;
     }
     else
     {
         FullInfoSize = sizeof(KEY_FULL_INFORMATION);
         FullInfo = &FullInfoBuffer;
-        FullInfo->ClassLength = 0;
     }
-    FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
+
+    if (lpcbSecurityDescriptor != NULL)
+        *lpcbSecurityDescriptor = 0;
 
     Status = NtQueryKey(KeyHandle,
                         KeyFullInformation,
@@ -3713,15 +3771,8 @@ RegQueryInfoKeyW(HKEY hKey,
                         FullInfoSize,
                         &Length);
     TRACE("NtQueryKey() returned status 0x%X\n", Status);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
     {
-        if (lpClass != NULL)
-        {
-            RtlFreeHeap(ProcessHeap,
-                        0,
-                        FullInfo);
-        }
-
         ErrorCode = RtlNtStatusToDosError(Status);
         goto Cleanup;
     }
@@ -3733,15 +3784,15 @@ RegQueryInfoKeyW(HKEY hKey,
     }
 
     TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
-    if (lpcbMaxSubKeyLen != NULL)
+    if (lpcMaxSubKeyLen != NULL)
     {
-        *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
+        *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
     }
 
     TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
-    if (lpcbMaxClassLen != NULL)
+    if (lpcMaxClassLen != NULL)
     {
-        *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
+        *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
     }
 
     TRACE("Values %lu\n", FullInfo->Values);
@@ -3751,15 +3802,15 @@ RegQueryInfoKeyW(HKEY hKey,
     }
 
     TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
-    if (lpcbMaxValueNameLen != NULL)
+    if (lpcMaxValueNameLen != NULL)
     {
-        *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
+        *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
     }
 
     TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
-    if (lpcbMaxValueLen != NULL)
+    if (lpcMaxValueLen != NULL)
     {
-        *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
+        *lpcMaxValueLen = FullInfo->MaxValueDataLen;
     }
 
     if (lpcbSecurityDescriptor != NULL)
@@ -3771,18 +3822,7 @@ RegQueryInfoKeyW(HKEY hKey,
                                        NULL,
                                        0,
                                        lpcbSecurityDescriptor);
-        if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
-        {
-            if (lpClass != NULL)
-            {
-                RtlFreeHeap(ProcessHeap,
-                            0,
-                            FullInfo);
-            }
-
-            ErrorCode = RtlNtStatusToDosError(Status);
-            goto Cleanup;
-        }
+        TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
     }
 
     if (lpftLastWriteTime != NULL)
@@ -3793,25 +3833,37 @@ RegQueryInfoKeyW(HKEY hKey,
 
     if (lpClass != NULL)
     {
+        if (*lpcClass == 0)
+        {
+            goto Cleanup;
+        }
+
         if (FullInfo->ClassLength > ClassLength)
         {
-            ErrorCode = ERROR_BUFFER_OVERFLOW;
+            ErrorCode = ERROR_INSUFFICIENT_BUFFER;
         }
         else
         {
             RtlCopyMemory(lpClass,
                           FullInfo->Class,
                           FullInfo->ClassLength);
-            *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
-            lpClass[*lpcbClass] = 0;
+            lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
         }
+    }
 
+    if (lpcClass != NULL)
+    {
+        *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
+    }
+
+Cleanup:
+    if (lpClass != NULL)
+    {
         RtlFreeHeap(ProcessHeap,
                     0,
                     FullInfo);
     }
 
-Cleanup:
     ClosePredefKey(KeyHandle);
 
     return ErrorCode;
@@ -3836,7 +3888,7 @@ RegQueryMultipleValuesA(HKEY hKey,
     LONG ErrorCode;
 
     if (maxBytes >= (1024*1024))
-        return ERROR_TRANSFER_TOO_LONG;
+        return ERROR_MORE_DATA;
 
     *ldwTotsize = 0;
 
@@ -3900,7 +3952,7 @@ RegQueryMultipleValuesW(HKEY hKey,
     LONG ErrorCode;
 
     if (maxBytes >= (1024*1024))
-        return ERROR_TRANSFER_TOO_LONG;
+        return ERROR_MORE_DATA;
 
     *ldwTotsize = 0;
 
@@ -3979,9 +4031,9 @@ RegQueryReflectionKey(IN HKEY hBase,
  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
- *                     
+ *
  * NOTES
- *   MSDN states that if data is too small it is partially filled. In reality 
+ *   MSDN states that if data is too small it is partially filled. In reality
  *   it remains untouched.
  */
 LONG
@@ -4116,19 +4168,31 @@ RegQueryValueExW(
 
     RtlInitUnicodeString( &name_str, name );
 
-    if (data) total_size = min( sizeof(buffer), *count + info_size );
+    if (data)
+        total_size = min( sizeof(buffer), *count + info_size );
     else
-    {
         total_size = info_size;
-        if (count) *count = 0;
-    }
 
-    /* this matches Win9x behaviour - NT sets *type to a random value */
-    if (type) *type = REG_NONE;
 
     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
                               buffer, total_size, &total_size );
-    if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
+
+    if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW)
+    {
+        // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
+        // On windows these conditions are likely to be side effects of the implementation...
+        if (status == STATUS_INVALID_HANDLE && hkey)
+        {
+            if (type) *type = REG_NONE;
+            if (count) *count = 0;
+        }
+        else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+        {
+            if (type) *type = REG_NONE;
+            if (data == NULL && count) *count = 0;
+        }
+        goto done;
+    }
 
     if (data)
     {
@@ -4218,15 +4282,15 @@ LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG coun
     if (name && name[0])
     {
         ret = RegOpenKeyW( hkey, name, &subkey);
-        if (ret != ERROR_SUCCESS) 
+        if (ret != ERROR_SUCCESS)
         {
             return ret;
         }
     }
 
     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
-    
-    if (subkey != hkey) 
+
+    if (subkey != hkey)
     {
         RegCloseKey( subkey );
     }
@@ -4234,9 +4298,9 @@ LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG coun
     if (ret == ERROR_FILE_NOT_FOUND)
     {
         /* return empty string if default value not found */
-        if (data) 
+        if (data)
             *data = 0;
-        if (count) 
+        if (count)
             *count = sizeof(WCHAR);
         ret = ERROR_SUCCESS;
     }
@@ -4783,10 +4847,7 @@ RegSetValueExA(HKEY hKey,
     /* Convert SubKey name to Unicode */
     if (lpValueName != NULL && lpValueName[0] != '\0')
     {
-        BOOL bConverted;
-        bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
-                                                  (PSTR)lpValueName);
-        if(!bConverted)
+        if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, (PSTR)lpValueName))
             return ERROR_NOT_ENOUGH_MEMORY;
     }
     else
@@ -5087,195 +5148,4 @@ RegUnLoadKeyW(HKEY hKey,
     return ERROR_SUCCESS;
 }
 
-
-/******************************************************************************
- * load_string [Internal]
- *
- * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
- * avoid importing user32, which is higher level than advapi32. Helper for
- * RegLoadMUIString.
- */
-static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
-{
-    HGLOBAL hMemory;
-    HRSRC hResource;
-    WCHAR *pString;
-    int idxString;
-
-    /* Negative values have to be inverted. */
-    if (HIWORD(resId) == 0xffff)
-        resId = (UINT)(-((INT)resId));
-
-    /* Load the resource into memory and get a pointer to it. */
-    hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
-    if (!hResource) return 0;
-    hMemory = LoadResource(hModule, hResource);
-    if (!hMemory) return 0;
-    pString = LockResource(hMemory);
-
-    /* Strings are length-prefixed. Lowest nibble of resId is an index. */
-    idxString = resId & 0xf;
-    while (idxString--) pString += *pString + 1;
-
-    /* If no buffer is given, return length of the string. */
-    if (!pwszBuffer) return *pString;
-
-    /* Else copy over the string, respecting the buffer size. */
-    cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
-    if (cMaxChars >= 0)
-    {
-        memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
-        pwszBuffer[cMaxChars] = L'\0';
-    }
-
-    return cMaxChars;
-}
-
-
-/************************************************************************
- *  RegLoadMUIStringW
- *
- * @implemented
- */
-LONG WINAPI
-RegLoadMUIStringW(IN HKEY hKey,
-                  IN LPCWSTR pszValue  OPTIONAL,
-                  OUT LPWSTR pszOutBuf,
-                  IN DWORD cbOutBuf,
-                  OUT LPDWORD pcbData OPTIONAL,
-                  IN DWORD Flags,
-                  IN LPCWSTR pszDirectory  OPTIONAL)
-{
-    DWORD dwValueType, cbData;
-    LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
-    LONG result;
-
-    /* Parameter sanity checks. */
-    if (!hKey || !pszOutBuf)
-        return ERROR_INVALID_PARAMETER;
-
-    if (pszDirectory && *pszDirectory)
-    {
-        FIXME("BaseDir parameter not yet supported!\n");
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
-    result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
-    if (result != ERROR_SUCCESS) goto cleanup;
-    if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
-    {
-        result = ERROR_FILE_NOT_FOUND;
-        goto cleanup;
-    }
-    pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
-    if (!pwszTempBuffer)
-    {
-        result = ERROR_NOT_ENOUGH_MEMORY;
-        goto cleanup;
-    }
-    result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
-    if (result != ERROR_SUCCESS) goto cleanup;
-
-    /* Expand environment variables, if appropriate, or copy the original string over. */
-    if (dwValueType == REG_EXPAND_SZ)
-    {
-        cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
-        if (!cbData) goto cleanup;
-        pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
-        if (!pwszExpandedBuffer)
-        {
-            result = ERROR_NOT_ENOUGH_MEMORY;
-            goto cleanup;
-        }
-        ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
-    }
-    else
-    {
-        pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
-        memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
-    }
-
-    /* If the value references a resource based string, parse the value and load the string.
-     * Else just copy over the original value. */
-    result = ERROR_SUCCESS;
-    if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
-    {
-        lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
-    }
-    else
-    {
-        WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
-        UINT uiStringId;
-        HMODULE hModule;
-
-        /* Format of the expanded value is 'path_to_dll,-resId' */
-        if (!pComma || pComma[1] != L'-')
-        {
-            result = ERROR_BADKEY;
-            goto cleanup;
-        }
-
-        uiStringId = _wtoi(pComma+2);
-        *pComma = L'\0';
-
-        hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
-        if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
-            result = ERROR_BADKEY;
-        FreeLibrary(hModule);
-    }
-
-cleanup:
-    HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
-    HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
-    return result;
-}
-
-
-/************************************************************************
- *  RegLoadMUIStringA
- *
- * @implemented
- */
-LONG WINAPI
-RegLoadMUIStringA(IN HKEY hKey,
-                  IN LPCSTR pszValue  OPTIONAL,
-                  OUT LPSTR pszOutBuf,
-                  IN DWORD cbOutBuf,
-                  OUT LPDWORD pcbData OPTIONAL,
-                  IN DWORD Flags,
-                  IN LPCSTR pszDirectory  OPTIONAL)
-{
-    UNICODE_STRING valueW, baseDirW;
-    WCHAR *pwszBuffer;
-    DWORD cbData = cbOutBuf * sizeof(WCHAR);
-    LONG result;
-
-    valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
-    if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
-        !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
-        !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
-    {
-        result = ERROR_NOT_ENOUGH_MEMORY;
-        goto cleanup;
-    }
-
-    result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
-                               baseDirW.Buffer);
-
-    if (result == ERROR_SUCCESS)
-    {
-        cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
-        if (pcbData)
-            *pcbData = cbData;
-    }
-
-cleanup:
-    HeapFree(GetProcessHeap(), 0, pwszBuffer);
-    RtlFreeUnicodeString(&baseDirW);
-    RtlFreeUnicodeString(&valueW);
-
-    return result;
-}
-
 /* EOF */