上一篇博文中主要介绍了Reactos中大部分函数的思路和HKEY和HANDLE之间的关系,本文将介绍一些Reactos中有意思的函数和存在bug的函数。(转载请指明出处)
CreateNestedKey是一个辅助创建键的函数,比如我们要创建\Regsitry\User\3\2\1,而我们只是存在\Regsitry\User\,我们最终将调用此函数将在User下创建键3,然后在3键下创建键2,最后在2键下创建键1。假如你是这个函数的实现者,你要思考这个函数的实现思路。最容易的办法是将\Regsitry\User\3\2\1路径拆成一系列键名(\Regsitry\User、3、2、1),然后从根键一步一步的调用NtCreateKey,这样就可以保证路径上的所有键都被创建。这个方法的优点是简单。但是Reactos实现的思路却不是这样的。我列一下我改写的该函数。
NTSTATUS OriCreateNestedKey(
PHANDLE pKeyHandle,
POBJECT_ATTRIBUTES ObjectAttributes,
PUNICODE_STRING ClassString,
DWORD dwOptions,
REGSAM samDesired,
DWORD *lpdwDisposition )
{
UNICODE_STRING LocalKeyName;
NTSTATUS lRes = STATUS_INVALID_PARAMETER;
do {
if ( NULL == ObjectAttributes || NULL == ObjectAttributes->ObjectName ) {
break;
}
lRes = RtlCreateUnicodeString_( &LocalKeyName, ObjectAttributes->ObjectName->Buffer );
CHECKRESULT(lRes);
lRes = GETORIFUNC(CreateKey)( pKeyHandle, samDesired,
ObjectAttributes, 0, ClassString, dwOptions, (PULONG)lpdwDisposition );
if ( STATUS_OBJECT_NAME_NOT_FOUND != lRes ) {
return lRes;
}
OBJECT_ATTRIBUTES LocalObjectAttributes;
RtlCopyMemory( &LocalObjectAttributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
LocalObjectAttributes.ObjectName = &LocalKeyName;
ULONG FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
HANDLE LocalKeyHandle = NULL;
PWCHAR Ptr = NULL;
ULONG Disposition = 0;
// 通过将\\改成结尾符,逐个去掉最后一个键名,查看什么路径的注册表键存在
while ( STATUS_OBJECT_NAME_NOT_FOUND == lRes ) {
Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
if ( NULL == Ptr || Ptr == LocalKeyName.Buffer ) {
lRes = STATUS_UNSUCCESSFUL;
break;
}
// 通过将\\改成结尾符,通过长度去掉键名
*Ptr = (WCHAR)0;
LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
lRes = GETORIFUNC(CreateKey)( &LocalKeyHandle, KEY_CREATE_SUB_KEY,
&LocalObjectAttributes, 0, NULL, 0, &Disposition );
}
CHECKRESULT(lRes);
// 通过将结尾符改成\\,重新拼接上键名,逐个创建键
ULONG Length = wcslen(LocalKeyName.Buffer);
while ( TRUE ) {
if ( NULL != LocalKeyHandle ) {
GETORIFUNC(Close) (LocalKeyHandle);
}
// 通过将结尾符改成\\,重新拼接上键名
LocalKeyName.Buffer[Length] = L'\\';
Length = wcslen (LocalKeyName.Buffer);
LocalKeyName.Length = Length * sizeof(WCHAR);
if ( Length == FullNameLength ) {
// 如果已经拼接回以前的键名了,则执行完后就退出
lRes = GETORIFUNC(CreateKey)( pKeyHandle, samDesired,
ObjectAttributes, 0, ClassString, dwOptions, (PULONG)lpdwDisposition);
break;
}
// 创建祖宗键
lRes = GETORIFUNC(CreateKey)( &LocalKeyHandle, KEY_CREATE_SUB_KEY,
&LocalObjectAttributes, 0, NULL, 0, &Disposition);
if ( NT_FAILED(lRes) ) {
break;
}
}
} while (0);
RtlFreeUnicodeString_(&LocalKeyName);
return lRes;
}
大致说下这个函数的流程:
我很欣赏这样的思路,通过改改内存达到目的,效率方面会好很多。