I've attempted to implement RtlQueryRegistryValues()
This code is probably buggy, as I haven't tested it much, but it makes safedisc 
happy.
If it's OK I'll send a patch to add it to ntdll, ntoskrnl will then forward 
calls.
comments/corrections/thoughts welcome.

Ivan.
/*
 * Copyright 2004-2005 Marcus Meissner, Ivan Leo Puoti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdarg.h>
#include <math.h>

#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "winnt.h"
#include "ntstatus.h"
#include "ntoskrnl.h"
#define DATA Info+Info->DataOffset
static HKEY RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path);

WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);

DWORD NtBuildNumber;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if(fdwReason == DLL_PROCESS_ATTACH)
    {
        OSVERSIONINFOW i;
        i.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
        GetVersionExW(&i);
        if(i.dwMajorVersion == 4 && i.dwMinorVersion == 0 && i.dwPlatformId == VER_PLATFORM_WIN32_NT) /* Windows NT 4.0 */
            NtBuildNumber = 0xf0000565;
        if(i.dwMajorVersion == 5 && i.dwMinorVersion == 0) /* Windows 2000 */
            NtBuildNumber = 0xf0000893;
        if(i.dwMajorVersion == 5 && i.dwMinorVersion == 1) /* Windows XP */
            NtBuildNumber = 0xf0000a28;
        if(i.dwMajorVersion == 5 && i.dwMinorVersion == 2) /* Windows Server 2003 */
            NtBuildNumber = 0xf0000ece;
    }
    return TRUE;
}

/* might be at least 12 byte ... */
DWORD KeTickCount[3] =   {
    0xdead4242,
    0xdeadcafe, 0xdeadcafe  /* must be the same */
};

VOID WINAPI IoDeleteDevice(IN PDEVICE_OBJECT  DeviceObject)
{
    FIXME("(%p), stub!\n", DeviceObject);
}

BOOLEAN WINAPI PsGetVersion(PULONG  MajorVersion  OPTIONAL, PULONG  MinorVersion  OPTIONAL,
                            PULONG  BuildNumber  OPTIONAL, PUNICODE_STRING  CSDVersion  OPTIONAL)
{
    OSVERSIONINFOW i;
    i.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
    GetVersionExW(&i);
    if (MajorVersion)
        *MajorVersion = i.dwMajorVersion;
    if (MinorVersion)
        *MinorVersion = i.dwMinorVersion;
    if (BuildNumber)
        *BuildNumber = i.dwBuildNumber;
    if (CSDVersion)
    {
        CSDVersion->Length = 0;
        RtlAppendUnicodeToString(CSDVersion,i.szCSDVersion);
    }
    return 0;
}

 /* We need to add some structs to ntoskrnl.h to use the correct parameter types */
VOID WINAPI IofCompleteRequest/*(IN PIRP Irp, IN CCHAR PriorityBoost)*/(LPVOID Irp, DWORD* PriorityBoots)
{
    FIXME("(%p, %p),stub!\n", Irp, PriorityBoots);
}

NTSTATUS WINAPI IoDeleteSymbolicLink(IN PUNICODE_STRING SymbolicLinkName)
{
    FIXME("(%p), stub!\n", SymbolicLinkName);
    return STATUS_SUCCESS;
}

NTSTATUS WINAPI IoCreateSymbolicLink(IN PUNICODE_STRING  SymbolicLinkName, IN PUNICODE_STRING  DeviceName)
{
    FIXME("(%p, %p), stub!\n", SymbolicLinkName, DeviceName);
    return STATUS_SUCCESS;
}

NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
                                       IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
                                       IN PVOID Environment OPTIONAL)
{
    UNICODE_STRING Value;
    HKEY handle;
    ULONG Length;
    KEY_VALUE_FULL_INFORMATION *Info = NULL;
    KEY_FULL_INFORMATION *KeyInfo = NULL;
    PWSTR buf = NULL;
    LPWSTR String;
    INT count = 0, add = 0, counter = 0, i;

    /* get a valid handle */
    if (RelativeTo & RTL_REGISTRY_HANDLE)
        handle = (HANDLE)Path;
    else
        handle = RTL_GetKeyHandle(RelativeTo, Path);
    if(!handle)
        return STATUS_OBJECT_NAME_NOT_FOUND;

    NtQueryKey(handle, KeyFullInformation, KeyInfo,0,&Length);
    KeyInfo = (KEY_FULL_INFORMATION *)RtlAllocateHeap(GetProcessHeap(),0,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+Length);
    NtQueryKey(handle, KeyFullInformation, KeyInfo,Length,&Length);

    /* at this point we have a valid handle */
    while(QueryTable->QueryRoutine!=NULL && QueryTable->Name!=NULL)
    {
        if(QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
            handle = RTL_GetKeyHandle((ULONG)QueryTable->Name,Path);

        if(QueryTable->Flags & RTL_QUERY_REGISTRY_TOPKEY);
            handle = RTL_GetKeyHandle(RelativeTo, Path);

        if(!handle)
            return STATUS_OBJECT_NAME_NOT_FOUND;

        if(QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
        {
            QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0, Context, QueryTable->EntryContext);
            goto done;
        }

       /* take appropriate action if we have no subkeys and Name is NULL */
       if(KeyInfo->SubKeys==0 && QueryTable->Name==NULL)
       {
           if(QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
               return STATUS_OBJECT_NAME_NOT_FOUND;
           else
           {
               QueryTable++;
               continue;
           }
       }

       if(QueryTable->Name==NULL)
       {
           /* Loop trough all subkeys */
           KeyInfo->SubKeys=counter;
           for(i=0; i<counter; i++)
           {
               NtEnumerateValueKey(handle, i, KeyValueFullInformation, Info, 0, &Length);
               Info=(KEY_VALUE_FULL_INFORMATION*)RtlAllocateHeap(GetProcessHeap(),0,sizeof(KEY_VALUE_FULL_INFORMATION)+Length);
               NtEnumerateValueKey(handle, i, KeyValueFullInformation, Info, Length, &Length);
               RtlInitUnicodeString(&Value,Info->Name);
               NtQueryValueKey(handle, &Value, KeyValueFullInformation, Info, Length,  &Length);
               /* We *may* need expantion here, this is being tested */
               QueryTable->QueryRoutine(Info->Name, Info->Type,DATA,Info->DataLength,Context,QueryTable->EntryContext);
               RtlFreeHeap(GetProcessHeap,0,Info);
               if(QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
                   NtDeleteValueKey(handle, &Value);
           }
           QueryTable++;
           continue;
       }

       RtlInitUnicodeString(&Value,QueryTable->Name);
       /* check if we have a valid value name */
       if(NtQueryValueKey(handle, &Value, KeyValueFullInformation, Info, 0,  &Length)==STATUS_OBJECT_NAME_NOT_FOUND && (QueryTable->Flags &  RTL_QUERY_REGISTRY_REQUIRED))
       {
           if(KeyInfo->SubKeys > 0)
               QueryTable->QueryRoutine(QueryTable->Name, QueryTable->DefaultType, QueryTable->DefaultData,
                                        QueryTable->DefaultLength, Context, QueryTable->EntryContext);
           else
           {
               QueryTable++;
               continue;
           }
       }
       Info=(KEY_VALUE_FULL_INFORMATION*)RtlAllocateHeap(GetProcessHeap(),0,sizeof(KEY_VALUE_FULL_INFORMATION)+Length);
       NtQueryValueKey(handle, &Value, KeyValueFullInformation, Info, Length,  &Length);

       if((Info->Type == REG_EXPAND_SZ) && (!QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
       {
           buf=RtlAllocateHeap(GetProcessHeap(), 0, 32767 * sizeof(WCHAR));
           ExpandEnvironmentStringsW((LPWSTR)DATA,buf,32767);
           QueryTable->QueryRoutine(QueryTable->Name, Info->Type, buf, Info->DataLength, Context, QueryTable->EntryContext);
           RtlFreeHeap(GetProcessHeap(),0,buf);
       }

       if((Info->Type == REG_MULTI_SZ) && (!(QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
       {
           while(count<=Length)
           {
               String = (LPWSTR)DATA+count;
               count+=strlenW(String)+1;
               QueryTable->QueryRoutine(QueryTable->Name, Info->Type, String, Info->DataLength, Context, QueryTable->EntryContext);
           }
       }

       if(QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
       {
           if(Info->Type == REG_SZ || Info->Type == REG_EXPAND_SZ || Info->Type == REG_LINK)
           {
               if(QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
               {
                   if(!QueryTable->EntryContext)
                       QueryTable->EntryContext=RtlAllocateHeap(GetProcessHeap(),0,Info->DataLength);
                   else
                       if(((PUNICODE_STRING)QueryTable->EntryContext)->MaximumLength < Info->DataLength)
                           return STATUS_BUFFER_TOO_SMALL;
                   ((PUNICODE_STRING)QueryTable->EntryContext)->Length = 0;
                   RtlAppendUnicodeToString(QueryTable->EntryContext, (PCWSTR)DATA);

               }
               else
               {
                   ExpandEnvironmentStringsW((LPWSTR)DATA,buf,32767);
                   if(!((PUNICODE_STRING)QueryTable->EntryContext)->Buffer)
                       QueryTable->EntryContext=RtlAllocateHeap(GetProcessHeap(),0,strlenW(buf));
                   else
                       if(((PUNICODE_STRING)QueryTable->EntryContext)->MaximumLength < strlenW(buf))
                           return STATUS_BUFFER_TOO_SMALL;
                   ((PUNICODE_STRING)QueryTable->EntryContext)->Length = 0;
                   RtlAppendUnicodeToString(QueryTable->EntryContext, (buf));
               }
               goto done;
           }
           if(Info->Type == REG_MULTI_SZ)
           {
               if(!(QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
                   return STATUS_INVALID_PARAMETER;
               if(!QueryTable->EntryContext)
                   QueryTable->EntryContext=RtlAllocateHeap(GetProcessHeap(),0,Info->DataLength);
               if(((PUNICODE_STRING)QueryTable->EntryContext)->MaximumLength < Info->DataLength)
                   return STATUS_BUFFER_TOO_SMALL;
               count = strlenW((PWSTR)DATA);
               RtlAppendUnicodeToString((PUNICODE_STRING)(QueryTable->EntryContext),(PWSTR)DATA);
               while(Info->DataLength > count)
               {
                   add = strlenW((PWSTR)DATA) + count + 1;
                   RtlAppendUnicodeToString(&Value,(PWSTR)DATA+add);
                   count = strlenW((PWSTR)DATA+add);
               }
               goto done;
           }
           if(Info->DataLength <= sizeof(ULONG))
               memcpy(QueryTable->EntryContext,DATA,Info->DataLength);
           if(Info->DataLength > sizeof(ULONG))
           {
               if(QueryTable->EntryContext<0)
               {
                   if(fabs((ULONG)QueryTable->EntryContext) < Info->DataLength)
                       return STATUS_BUFFER_TOO_SMALL;
                   QueryTable->EntryContext = DATA;
               }
               else
               {
                   if(fabs((ULONG)QueryTable->EntryContext) < (Info->DataLength+2))
                       return STATUS_BUFFER_TOO_SMALL;
                   QueryTable->EntryContext = &Info->DataLength;
                   *((PULONG) (QueryTable->EntryContext) + 1) = Info->Type;
                   memcpy((PULONG) (QueryTable->EntryContext)+2, DATA, Info->DataLength);
               }
               goto done;
           }           
       }

       /* RTL_QUERY_REGISTRY_NOEXPAND case */
       QueryTable->QueryRoutine(QueryTable->Name, Info->Type, DATA, Info->DataLength, Context, QueryTable->EntryContext);
        
       done:
       if(QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
           NtDeleteValueKey(handle, &Value);

       QueryTable++;
    }
    RtlFreeHeap(GetProcessHeap(), 0, KeyInfo);
    NtClose(handle);
    return STATUS_SUCCESS;
}

static HKEY RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path)
{
    UNICODE_STRING KeyString;
    OBJECT_ATTRIBUTES regkey;
    HKEY handle;
    static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
    '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t',' ','C','o','n','t','r','o','l','S','e','t','\\',
    'C','o','n','t','r','o','l',0};

    static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
    'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p',0};

    static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
    'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
    'S','e','r','v','i','c','e','s',0};

    static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
    'C','u','r','r','e','n','t','U','s','e','r',0};

    static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
    'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
    'W','i','n','d','o','w','s','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};

    switch (RelativeTo)
    {
        case RTL_REGISTRY_ABSOLUTE   :
        RtlInitUnicodeString(&KeyString,Path);
        break;

        case RTL_REGISTRY_CONTROL    :
        RtlInitUnicodeString(&KeyString,control);
        break;

        case RTL_REGISTRY_DEVICEMAP  :
        RtlInitUnicodeString(&KeyString,devicemap);
        break;

        case RTL_REGISTRY_SERVICES   :
        RtlInitUnicodeString(&KeyString,services);
        break;

        case RTL_REGISTRY_USER       :
        RtlInitUnicodeString(&KeyString,user);
        break;

        case RTL_REGISTRY_WINDOWS_NT :
        RtlInitUnicodeString(&KeyString,windows_nt);
        break;
    }
    KeyString.MaximumLength+=strlenW(Path)+1;
    RtlInitUnicodeString(&KeyString,Path);
    InitializeObjectAttributes(&regkey, &KeyString, 0,NULL,NULL);
    if(NtOpenKey(&handle,KEY_READ,&regkey)!=STATUS_SUCCESS)
        return NULL;
    return handle;
}

NTSTATUS WINAPI IoCreateDevice(IN LPVOID driverobject, IN ULONG deviceextsize,
                               IN PUNICODE_STRING devicename, IN DWORD devicetype,
                               IN ULONG devicecharacteristics, IN BOOLEAN excl,
                               OUT LPVOID *devobject) 
{
    FIXME("(%p,%ld,%s,%ld,%ld,%d,%p), stub!\n",driverobject,deviceextsize,debugstr_w(devicename->Buffer),devicetype,devicecharacteristics,excl,devobject);
    return STATUS_SUCCESS;
}

Reply via email to