📄 reg.c
字号:
do
{
delKeys = CONTAINING_RECORD(delQueueHead.Flink,
REGP_DEL_KEYS,
ListEntry);
BufferSize = 0;
BasicInfo = NULL;
newDelKeys = NULL;
ReadFirstSubKey:
/* check if this key contains subkeys and delete them first by queuing
them at the head of the list */
Status2 = NtEnumerateKey(delKeys->KeyHandle,
0,
KeyBasicInformation,
BasicInfo,
BufferSize,
&BufferSize);
if (NT_SUCCESS(Status2))
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyName;
ASSERT(newDelKeys != NULL);
ASSERT(BasicInfo != NULL);
/* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
SubKeyName.Length = BasicInfo->NameLength;
SubKeyName.MaximumLength = BasicInfo->NameLength;
SubKeyName.Buffer = BasicInfo->Name;
InitializeObjectAttributes(&ObjectAttributes,
&SubKeyName,
OBJ_CASE_INSENSITIVE,
delKeys->KeyHandle,
NULL);
/* open the subkey */
Status2 = NtOpenKey(&newDelKeys->KeyHandle,
DELETE | KEY_ENUMERATE_SUB_KEYS,
&ObjectAttributes);
if (!NT_SUCCESS(Status2))
{
goto SubKeyFailure;
}
/* enqueue this key to the head of the deletion queue */
InsertHeadList(&delQueueHead,
&newDelKeys->ListEntry);
/* try again from the head of the list */
continue;
}
else
{
if (Status2 == STATUS_BUFFER_TOO_SMALL)
{
newDelKeys = RtlAllocateHeap(ProcessHeap,
0,
BufferSize + sizeof(REGP_DEL_KEYS));
if (newDelKeys != NULL)
{
BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
/* try again */
goto ReadFirstSubKey;
}
else
{
/* don't break, let's try to delete as many keys as possible */
Status2 = STATUS_INSUFFICIENT_RESOURCES;
goto SubKeyFailureNoFree;
}
}
else if (Status2 == STATUS_BUFFER_OVERFLOW)
{
PREG_DEL_KEYS newDelKeys2;
ASSERT(newDelKeys != NULL);
/* we need more memory to query the key name */
newDelKeys2 = RtlReAllocateHeap(ProcessHeap,
0,
newDelKeys,
BufferSize + sizeof(REGP_DEL_KEYS));
if (newDelKeys2 != NULL)
{
newDelKeys = newDelKeys2;
BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1);
/* try again */
goto ReadFirstSubKey;
}
else
{
/* don't break, let's try to delete as many keys as possible */
Status2 = STATUS_INSUFFICIENT_RESOURCES;
}
}
else if (Status2 == STATUS_NO_MORE_ENTRIES)
{
/* in some race conditions where another thread would delete
the same tree at the same time, newDelKeys could actually
be != NULL! */
if (newDelKeys != NULL)
{
RtlFreeHeap(ProcessHeap,
0,
newDelKeys);
}
break;
}
SubKeyFailure:
/* newDelKeys can be NULL here when NtEnumerateKey returned an
error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
if (newDelKeys != NULL)
{
RtlFreeHeap(ProcessHeap,
0,
newDelKeys);
}
SubKeyFailureNoFree:
/* don't break, let's try to delete as many keys as possible */
if (NT_SUCCESS(Status))
{
Status = Status2;
}
}
Status2 = NtDeleteKey(delKeys->KeyHandle);
/* NOTE: do NOT close the handle anymore, it's invalid already! */
if (!NT_SUCCESS(Status2))
{
/* close the key handle so we don't leak handles for keys we were
unable to delete. But only do this for handles not supplied
by the caller! */
if (delKeys->KeyHandle != hKey)
{
NtClose(delKeys->KeyHandle);
}
if (NT_SUCCESS(Status))
{
/* don't break, let's try to delete as many keys as possible */
Status = Status2;
}
}
/* remove the entry from the list */
RemoveEntryList(&delKeys->ListEntry);
RtlFreeHeap(ProcessHeap,
0,
delKeys);
} while (!IsListEmpty(&delQueueHead));
}
else
Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
/************************************************************************
* RegDeleteTreeW
*
* @implemented
*/
LONG STDCALL
RegDeleteTreeW(IN HKEY hKey,
IN LPCWSTR lpSubKey OPTIONAL)
{
HANDLE KeyHandle, CurKey, SubKeyHandle = NULL;
NTSTATUS Status;
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
return RtlNtStatusToDosError(Status);
}
if (lpSubKey != NULL)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyName;
RtlInitUnicodeString(&SubKeyName,
(LPWSTR)lpSubKey);
InitializeObjectAttributes(&ObjectAttributes,
&SubKeyName,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey(&SubKeyHandle,
DELETE | KEY_ENUMERATE_SUB_KEYS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
CurKey = SubKeyHandle;
}
else
CurKey = KeyHandle;
Status = RegpDeleteTree(CurKey);
if (NT_SUCCESS(Status))
{
/* make sure we only close hKey (KeyHandle) when the caller specified a
subkey, because the handle would be invalid already! */
if (CurKey != KeyHandle)
{
ClosePredefKey(KeyHandle);
}
return ERROR_SUCCESS;
}
else
{
/* make sure we close all handles we created! */
if (SubKeyHandle != NULL)
{
NtClose(SubKeyHandle);
}
Cleanup:
ClosePredefKey(KeyHandle);
return RtlNtStatusToDosError(Status);
}
}
/************************************************************************
* RegDeleteTreeA
*
* @implemented
*/
LONG STDCALL
RegDeleteTreeA(IN HKEY hKey,
IN LPCSTR lpSubKey OPTIONAL)
{
UNICODE_STRING SubKeyName = {0};
LONG Ret;
if (lpSubKey != NULL &&
!RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
(LPSTR)lpSubKey))
{
return ERROR_NOT_ENOUGH_MEMORY;
}
Ret = RegDeleteTreeW(hKey,
SubKeyName.Buffer);
RtlFreeUnicodeString(&SubKeyName);
return Ret;
}
/************************************************************************
* RegDisableReflectionKey
*
* @unimplemented
*/
LONG WINAPI
RegDisableReflectionKey(IN HKEY hBase)
{
DPRINT1("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
return ERROR_CALL_NOT_IMPLEMENTED;
}
/************************************************************************
* RegEnableReflectionKey
*
* @unimplemented
*/
LONG WINAPI
RegEnableReflectionKey(IN HKEY hBase)
{
DPRINT1("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase);
return ERROR_CALL_NOT_IMPLEMENTED;
}
/******************************************************************************
* RegpApplyRestrictions [internal]
*
* Helper function for RegGetValueA/W.
*/
static VOID
RegpApplyRestrictions( DWORD dwFlags, DWORD dwType, DWORD cbData,
PLONG ret )
{
/* Check if the type is restricted by the passed flags */
if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
{
DWORD dwMask = 0;
switch (dwType)
{
case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
}
if (dwFlags & dwMask)
{
/* Type is not restricted, check for size mismatch */
if (dwType == REG_BINARY)
{
DWORD cbExpect = 0;
if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
cbExpect = 4;
else if ((dwFlags & RRF_RT_DWORD) == RRF_RT_QWORD)
cbExpect = 8;
if (cbExpect && cbData != cbExpect)
*ret = ERROR_DATATYPE_MISMATCH;
}
}
else *ret = ERROR_UNSUPPORTED_TYPE;
}
}
/******************************************************************************
* RegGetValueW [ADVAPI32.@]
*
* Retrieves the type and data for a value name associated with a key
* optionally expanding it's content and restricting it's type.
*
* PARAMS
* hKey [I] Handle to an open key.
* pszSubKey [I] Name of the subkey of hKey.
* pszValue [I] Name of value under hKey/szSubKey to query.
* dwFlags [I] Flags restricting the value type to retrieve.
* pdwType [O] Destination for the values type, may be NULL.
* pvData [O] Destination for the values content, may be NULL.
* pcbData [I/O] Size of pvData, updated with the size required to
* retrieve the whole content.
*
* RETURNS
* Success: ERROR_SUCCESS
* Failure: nonzero error code from Winerror.h
*
* NOTES
* - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
* and REG_SZ is retrieved instead.
* - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
* without RRF_NOEXPAND is thus not allowed.
*/
LONG WINAPI
RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
LPDWORD pcbData )
{
DWORD dwType, cbData = pcbData ? *pcbData : 0;
PVOID pvBuf = NULL;
LONG ret;
TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
pvData, pcbData, cbData);
if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
return ERROR_INVALID_PARAMETER;
if (pszSubKey && pszSubKey[0])
{
ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
if (ret != ERROR_SUCCESS) return ret;
}
ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
/* If we are going to expand we need to read in the whole the value even
* if the passed buffer was too small as the expanded string might be
* smaller than the unexpanded one and could fit into cbData bytes. */
if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
(dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
{
do {
if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
if (!pvBuf)
{
ret = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (ret == ERROR_MORE_DATA)
ret = RegQueryValueExW(hKey, pszValue, NULL,
&dwType, pvBuf, &cbData);
else
{
/* Even if cbData was large enough we have to copy the
* string since ExpandEnvironmentStrings can't handle
* overlapping buffers. */
CopyMemory(pvBuf, pvData, cbData);
}
/* Both the type or the value itself could have been modified in
* between so we have to keep retrying until the buffer is large
* enough or we no longer have to expand the value. */
} while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
if (ret == ERROR_SUCCESS)
{
if (dwType == REG_EXPAND_SZ)
{
cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
pcbData ? *pcbData : 0);
dwType = REG_SZ;
if(pcbData && cbData > *pcbData)
ret = ERROR_MORE_DATA;
}
else if (pcbData)
CopyMemory(pvData, pvBuf, *pcbData);
}
if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
}
if (pszSubKey && pszSubKey[0])
RegCloseKey(hKey);
RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
ZeroMemory(pvData, *pcbData);
if (pdwType) *pdwType = dwType;
if (pcbData) *pcbData = cbData;
return ret;
}
/******************************************************************************
* RegGetValueA [ADVAPI32.@]
*
* See RegGetValueW.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -