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))
{
* 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.
{
if (KeyInfo->Basic.NameLength > NameLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_MORE_DATA;
}
else
{
if (KeyInfo->Node.NameLength > NameLength ||
KeyInfo->Node.ClassLength > ClassLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_MORE_DATA;
}
else
{
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)
return ERROR_INVALID_HANDLE;
}
- if (fAsynchronous == TRUE && hEvent == NULL)
+ if ((fAsynchronous != FALSE) && (hEvent == NULL))
{
return ERROR_INVALID_PARAMETER;
}
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);
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)
{
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;
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)
{
ULONG Length;
LONG ErrorCode = ERROR_SUCCESS;
- if ((lpClass) && (!lpcbClass))
+ if ((lpClass) && (!lpcClass))
{
return ERROR_INVALID_PARAMETER;
}
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
{
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,
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;
}
}
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);
}
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)
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)
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;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
- return ERROR_TRANSFER_TOO_LONG;
+ return ERROR_MORE_DATA;
*ldwTotsize = 0;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
- return ERROR_TRANSFER_TOO_LONG;
+ return ERROR_MORE_DATA;
*ldwTotsize = 0;
* 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
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)
{
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 );
}
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;
}
/* 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
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 */