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(®key, &KeyString, 0,NULL,NULL); if(NtOpenKey(&handle,KEY_READ,®key)!=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; }