mirror of
https://github.com/reactos/reactos.git
synced 2024-07-03 19:24:20 +00:00
f9dc3a86b6
The main motivation to port all that back is to get rid of Win32K-BSODs 0x50 like CORE-13907 that could be triggered by user-mode-applications. Technical reason was CORE-14857 "RtlImageNtHeaderEx needs SEH" and issues with hooks+callbacks. All other tickets mentioned in here were regressions that we experienced on the long journey towards perfecting the fixes on master head, and those were not happening yet in the older builds, so they are mentioned in here only to allow tracking where that code went into. Thanks to Jim Tabor, Mark Jansen & Thomas Faber By squashed backmerge of the following commits: 0.4.15-dev-3440-ga89844f740
0.4.15-dev-3430-g9cff384c22
0.4.14-dev-1287-g568b6d0558
0.4.14-dev-1255-g177ae91bf6
0.4.14-dev-1241-g915a5764a9
0.4.14-dev-1240-gd8add40e89
0.4.14-dev-1002-gfeb7df42b4
JIRA-tickets: CORE-13907, CORE-16769, CORE-14857, CORE-17856, CORE-17857, partially CORE-13019. We also had some more dupes of CORE-13907 in JIRA, but I linked all of them (transitively) towards the initial report, and resolved them without setting a fixVer for them. In more detail: -------------- [USER32] Fix BSOD 0x50 in 'WineVDM + Castle Of Winds' CORE-17856 CORE-17857 CORE-17856 BSOD 0x50 when starting Castle of the Winds second time, with WineVDM CORE-17857 BSOD 0x50 on shutdown after closing Castle of the Winds with WineVDM 0.4.15-dev-3430-g9cff384c22
0.4.15-dev-3440-ga89844f740
-------------- [NTUSER] Fix Strings and Format to Hooks Allocate heap instead of data segment to be used for callbacks on user side. Move and correct initial hook call out setup. Use it in more than one hook call. This fixes issues with strings out of alignment and use of kernel pointers. See CORE-13907 (HXD-portable BSOD) and CORE-16769 (HXD-portable exception) Small wow update. cherry picked from commit 0.4.14-dev-1287-g568b6d0558
-------------- [RTL] Introduce RtlpImageNtHeader, which implements the required functionality. ntdll and ntoskrnl now have a wrapper for this, with SEH. This protects the function against malformed / bad images, whilst still being able to use the code in freeldr et al. Idea from Thomas. CORE-14857 cherry picked from commit 0.4.14-dev-1255-g177ae91bf6
-------------- [WIN32SS] Form Sanity to Hook Callbacks Fix WH_CALLWNDPROC/RET data to user hook calls. Helps with CORE-13907 "(HXD-portable BSOD)" Fixes the logging of "(win32ss/user/ntuser/callback.c:748) err: Failure to make Callback! Status 0xc00000fd" within CORE-13019, but not the whole ticket. cherry picked from commit 0.4.14-dev-1241-g915a5764a9
-------------- [USER32] Fix null return. See CORE-16769 "HxD 1.7.7.0 portable unhandled exception" cherry picked from commit 0.4.14-dev-1240-gd8add40e89
-------------- [WIN32SS] Fix a typo in dbg print cherry picked from commit 0.4.14-dev-1002-gfeb7df42b4
795 lines
20 KiB
C
795 lines
20 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS NT User-Mode DLL
|
|
* FILE: lib/ntdll/rtl/libsup.c
|
|
* PURPOSE: RTL Support Routines
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
* Gunnar Dalsnes
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntdll.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
|
|
PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
|
|
PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS;
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlpCheckForActiveDebugger(VOID)
|
|
{
|
|
/* Return the flag in the PEB */
|
|
return NtCurrentPeb()->BeingDebugged;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlpSetInDbgPrint(VOID)
|
|
{
|
|
/* Check if it's already set and return TRUE if so */
|
|
if (NtCurrentTeb()->InDbgPrint) return TRUE;
|
|
|
|
/* Set it and return */
|
|
NtCurrentTeb()->InDbgPrint = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpClearInDbgPrint(VOID)
|
|
{
|
|
/* Clear the flag */
|
|
NtCurrentTeb()->InDbgPrint = FALSE;
|
|
}
|
|
|
|
KPROCESSOR_MODE
|
|
NTAPI
|
|
RtlpGetMode(VOID)
|
|
{
|
|
return UserMode;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PPEB
|
|
NTAPI
|
|
RtlGetCurrentPeb(VOID)
|
|
{
|
|
return NtCurrentPeb();
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID NTAPI
|
|
RtlAcquirePebLock(VOID)
|
|
{
|
|
PPEB Peb = NtCurrentPeb ();
|
|
RtlEnterCriticalSection(Peb->FastPebLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID NTAPI
|
|
RtlReleasePebLock(VOID)
|
|
{
|
|
PPEB Peb = NtCurrentPeb ();
|
|
RtlLeaveCriticalSection(Peb->FastPebLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
RtlGetNtGlobalFlags(VOID)
|
|
{
|
|
PPEB pPeb = NtCurrentPeb();
|
|
return pPeb->NtGlobalFlag;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
|
|
{
|
|
return RtlDeleteCriticalSection(&Lock->CriticalSection);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
|
|
{
|
|
UNREFERENCED_PARAMETER(Exclusive);
|
|
|
|
return RtlEnterCriticalSection(&Lock->CriticalSection);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
|
|
{
|
|
UNREFERENCED_PARAMETER(Exclusive);
|
|
|
|
return RtlTryEnterCriticalSection(&Lock->CriticalSection);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
|
|
{
|
|
return RtlInitializeCriticalSection(&(*Lock)->CriticalSection);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
|
|
{
|
|
return RtlLeaveCriticalSection(&Lock->CriticalSection);
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
RtlpAllocateMemory(UINT Bytes,
|
|
ULONG Tag)
|
|
{
|
|
UNREFERENCED_PARAMETER(Tag);
|
|
|
|
return RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
Bytes);
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpFreeMemory(PVOID Mem,
|
|
ULONG Tag)
|
|
{
|
|
UNREFERENCED_PARAMETER(Tag);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
Mem);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID FASTCALL
|
|
CHECK_PAGED_CODE_RTL(char *file, int line)
|
|
{
|
|
/* meaningless in user mode */
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
|
|
{
|
|
PPEB Peb;
|
|
|
|
/* Get PEB */
|
|
Peb = RtlGetCurrentPeb();
|
|
|
|
/* Apply defaults for non-set parameters */
|
|
if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit;
|
|
if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve;
|
|
if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
|
|
if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
|
|
IN ULONG_PTR RegistrationFrameEnd,
|
|
IN OUT PULONG_PTR StackLow,
|
|
IN OUT PULONG_PTR StackHigh)
|
|
{
|
|
/* There's no such thing as a DPC stack in user-mode */
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PCONTEXT ContextRecord,
|
|
IN PVOID ContextData,
|
|
IN ULONG Size)
|
|
{
|
|
/* Exception logging is not done in user-mode */
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
|
|
IN ULONG_PTR *StackBegin,
|
|
IN ULONG_PTR *StackEnd)
|
|
{
|
|
/* FIXME: Verify */
|
|
*StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
|
|
*StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef _M_AMD64
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
RtlWalkFrameChain(OUT PVOID *Callers,
|
|
IN ULONG Count,
|
|
IN ULONG Flags)
|
|
{
|
|
ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
|
|
ULONG Eip;
|
|
BOOLEAN Result, StopSearch = FALSE;
|
|
ULONG i = 0;
|
|
|
|
/* Get current EBP */
|
|
#if defined(_M_IX86)
|
|
#if defined __GNUC__
|
|
__asm__("mov %%ebp, %0" : "=r" (Stack) : );
|
|
#elif defined(_MSC_VER)
|
|
__asm mov Stack, ebp
|
|
#endif
|
|
#elif defined(_M_MIPS)
|
|
__asm__("move $sp, %0" : "=r" (Stack) : );
|
|
#elif defined(_M_PPC)
|
|
__asm__("mr %0,1" : "=r" (Stack) : );
|
|
#elif defined(_M_ARM)
|
|
#if defined __GNUC__
|
|
__asm__("mov sp, %0" : "=r"(Stack) : );
|
|
#elif defined(_MSC_VER)
|
|
// FIXME: Hack. Probably won't work if this ever actually manages to run someday.
|
|
Stack = (ULONG_PTR)&Stack;
|
|
#endif
|
|
#else
|
|
#error Unknown architecture
|
|
#endif
|
|
|
|
/* Set it as the stack begin limit as well */
|
|
StackBegin = (ULONG_PTR)Stack;
|
|
|
|
/* Check if we're called for non-logging mode */
|
|
if (!Flags)
|
|
{
|
|
/* Get the actual safe limits */
|
|
Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
|
|
&StackBegin,
|
|
&StackEnd);
|
|
if (!Result) return 0;
|
|
}
|
|
|
|
/* Use a SEH block for maximum protection */
|
|
_SEH2_TRY
|
|
{
|
|
/* Loop the frames */
|
|
for (i = 0; i < Count; i++)
|
|
{
|
|
/*
|
|
* Leave if we're past the stack,
|
|
* if we're before the stack,
|
|
* or if we've reached ourselves.
|
|
*/
|
|
if ((Stack >= StackEnd) ||
|
|
(!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
|
|
((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
|
|
{
|
|
/* We're done or hit a bad address */
|
|
break;
|
|
}
|
|
|
|
/* Get new stack and EIP */
|
|
NewStack = *(PULONG_PTR)Stack;
|
|
Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
|
|
|
|
/* Check if the new pointer is above the oldone and past the end */
|
|
if (!((Stack < NewStack) && (NewStack < StackEnd)))
|
|
{
|
|
/* Stop searching after this entry */
|
|
StopSearch = TRUE;
|
|
}
|
|
|
|
/* Also make sure that the EIP isn't a stack address */
|
|
if ((StackBegin < Eip) && (Eip < StackEnd)) break;
|
|
|
|
/* FIXME: Check that EIP is inside a loaded module */
|
|
|
|
/* Save this frame */
|
|
Callers[i] = (PVOID)Eip;
|
|
|
|
/* Check if we should continue */
|
|
if (StopSearch)
|
|
{
|
|
/* Return the next index */
|
|
i++;
|
|
break;
|
|
}
|
|
|
|
/* Move to the next stack */
|
|
Stack = NewStack;
|
|
}
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* No index */
|
|
i = 0;
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Return frames parsed */
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _AMD64_
|
|
VOID
|
|
NTAPI
|
|
RtlpGetStackLimits(
|
|
OUT PULONG_PTR LowLimit,
|
|
OUT PULONG_PTR HighLimit)
|
|
{
|
|
*LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
|
|
*HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
RtlIsThreadWithinLoaderCallout(VOID)
|
|
{
|
|
return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
|
|
}
|
|
|
|
/* RTL Atom Tables ************************************************************/
|
|
|
|
typedef struct _RTL_ATOM_HANDLE
|
|
{
|
|
RTL_HANDLE_TABLE_ENTRY Handle;
|
|
PRTL_ATOM_TABLE_ENTRY AtomEntry;
|
|
} RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
|
|
|
|
NTSTATUS
|
|
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlInitializeCriticalSection(&AtomTable->CriticalSection);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlDeleteCriticalSection(&AtomTable->CriticalSection);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlEnterCriticalSection(&AtomTable->CriticalSection);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlLeaveCriticalSection(&AtomTable->CriticalSection);
|
|
}
|
|
|
|
|
|
/* handle functions */
|
|
|
|
BOOLEAN
|
|
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlInitializeHandleTable(0xCFFF,
|
|
sizeof(RTL_ATOM_HANDLE),
|
|
&AtomTable->RtlHandleTable);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
|
|
}
|
|
|
|
PRTL_ATOM_TABLE
|
|
RtlpAllocAtomTable(ULONG Size)
|
|
{
|
|
return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
Size);
|
|
}
|
|
|
|
VOID
|
|
RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
AtomTable);
|
|
}
|
|
|
|
PRTL_ATOM_TABLE_ENTRY
|
|
RtlpAllocAtomTableEntry(ULONG Size)
|
|
{
|
|
return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
Size);
|
|
}
|
|
|
|
VOID
|
|
RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
Entry);
|
|
}
|
|
|
|
VOID
|
|
RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
|
|
{
|
|
PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
|
|
|
|
if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
|
|
(ULONG)Entry->HandleIndex,
|
|
&RtlHandleEntry))
|
|
{
|
|
RtlFreeHandle(&AtomTable->RtlHandleTable,
|
|
RtlHandleEntry);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
|
|
{
|
|
ULONG HandleIndex;
|
|
PRTL_HANDLE_TABLE_ENTRY RtlHandle;
|
|
|
|
RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
|
|
&HandleIndex);
|
|
if (RtlHandle != NULL)
|
|
{
|
|
PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
|
|
|
|
/* FIXME - Handle Indexes >= 0xC000 ?! */
|
|
if (HandleIndex < 0xC000)
|
|
{
|
|
Entry->HandleIndex = (USHORT)HandleIndex;
|
|
Entry->Atom = 0xC000 + (USHORT)HandleIndex;
|
|
|
|
AtomHandle->AtomEntry = Entry;
|
|
AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* set the valid flag, otherwise RtlFreeHandle will fail! */
|
|
AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
|
|
|
|
RtlFreeHandle(&AtomTable->RtlHandleTable,
|
|
RtlHandle);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
PRTL_ATOM_TABLE_ENTRY
|
|
RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
|
|
{
|
|
PRTL_HANDLE_TABLE_ENTRY RtlHandle;
|
|
|
|
if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
|
|
Index,
|
|
&RtlHandle))
|
|
{
|
|
PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
|
|
|
|
return AtomHandle->AtomEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Ldr SEH-Protected access to IMAGE_NT_HEADERS */
|
|
|
|
/* Rtl SEH-Free version of this */
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlpImageNtHeaderEx(
|
|
_In_ ULONG Flags,
|
|
_In_ PVOID Base,
|
|
_In_ ULONG64 Size,
|
|
_Out_ PIMAGE_NT_HEADERS *OutHeaders);
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
* @note: This is here, so that we do not drag SEH into rosload, freeldr and bootmgfw
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlImageNtHeaderEx(
|
|
_In_ ULONG Flags,
|
|
_In_ PVOID Base,
|
|
_In_ ULONG64 Size,
|
|
_Out_ PIMAGE_NT_HEADERS *OutHeaders)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Assume failure. This is also done in RtlpImageNtHeaderEx, but this is guarded by SEH. */
|
|
if (OutHeaders != NULL)
|
|
*OutHeaders = NULL;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
Status = RtlpImageNtHeaderEx(Flags, Base, Size, OutHeaders);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Fail with the SEH error */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Ldr Resource support code
|
|
*/
|
|
|
|
IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
|
|
LPCWSTR name, void *root,
|
|
int want_dir );
|
|
IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
|
|
WORD id, void *root, int want_dir );
|
|
IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
|
|
void *root, int want_dir );
|
|
int push_language( USHORT *list, ULONG pos, WORD lang );
|
|
|
|
/**********************************************************************
|
|
* find_entry
|
|
*
|
|
* Find a resource entry
|
|
*/
|
|
NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
|
|
ULONG level, void **ret, int want_dir )
|
|
{
|
|
ULONG size;
|
|
void *root;
|
|
IMAGE_RESOURCE_DIRECTORY *resdirptr;
|
|
USHORT list[9]; /* list of languages to try */
|
|
int i, pos = 0;
|
|
LCID user_lcid, system_lcid;
|
|
|
|
root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
|
|
if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
resdirptr = root;
|
|
|
|
if (!level--) goto done;
|
|
if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
|
|
return STATUS_RESOURCE_TYPE_NOT_FOUND;
|
|
if (!level--) return STATUS_SUCCESS;
|
|
|
|
resdirptr = *ret;
|
|
if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
|
|
return STATUS_RESOURCE_NAME_NOT_FOUND;
|
|
if (!level--) return STATUS_SUCCESS;
|
|
if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
|
|
|
|
/* 1. specified language */
|
|
pos = push_language( list, pos, info->Language );
|
|
|
|
/* 2. specified language with neutral sublanguage */
|
|
pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
|
|
|
|
/* 3. neutral language with neutral sublanguage */
|
|
pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
|
|
|
|
/* if no explicitly specified language, try some defaults */
|
|
if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
|
|
{
|
|
/* user defaults, unless SYS_DEFAULT sublanguage specified */
|
|
if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
|
|
{
|
|
/* 4. current thread locale language */
|
|
pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
|
|
|
|
if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
|
|
{
|
|
/* 5. user locale language */
|
|
pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
|
|
|
|
/* 6. user locale language with neutral sublanguage */
|
|
pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
|
|
}
|
|
}
|
|
|
|
/* now system defaults */
|
|
|
|
if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
|
|
{
|
|
/* 7. system locale language */
|
|
pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
|
|
|
|
/* 8. system locale language with neutral sublanguage */
|
|
pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
|
|
}
|
|
|
|
/* 9. English */
|
|
pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
|
|
}
|
|
|
|
resdirptr = *ret;
|
|
for (i = 0; i < pos; i++)
|
|
if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
|
|
|
|
/* if no explicitly specified language, return the first entry */
|
|
if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
|
|
{
|
|
if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
|
|
}
|
|
return STATUS_RESOURCE_LANG_NOT_FOUND;
|
|
|
|
done:
|
|
*ret = resdirptr;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PVOID NTAPI
|
|
RtlPcToFileHeader(IN PVOID PcValue,
|
|
PVOID* BaseOfImage)
|
|
{
|
|
PLIST_ENTRY ModuleListHead;
|
|
PLIST_ENTRY Entry;
|
|
PLDR_DATA_TABLE_ENTRY Module;
|
|
PVOID ImageBase = NULL;
|
|
|
|
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
|
|
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
|
Entry = ModuleListHead->Flink;
|
|
while (Entry != ModuleListHead)
|
|
{
|
|
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
|
|
if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
|
|
(ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
|
|
{
|
|
ImageBase = Module->DllBase;
|
|
break;
|
|
}
|
|
Entry = Entry->Flink;
|
|
}
|
|
RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
|
|
|
|
*BaseOfImage = ImageBase;
|
|
return ImageBase;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
|
|
IN PUNICODE_STRING OriginalName,
|
|
IN PUNICODE_STRING Extension,
|
|
IN OUT PUNICODE_STRING StaticString,
|
|
IN OUT PUNICODE_STRING DynamicString,
|
|
IN OUT PUNICODE_STRING *NewName,
|
|
IN PULONG NewFlags,
|
|
IN PSIZE_T FileNameSize,
|
|
IN PSIZE_T RequiredLength)
|
|
{
|
|
return STATUS_SXS_KEY_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
|
|
{
|
|
/* This is what Windows returns on x86 */
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
|
|
OUT PVOID *OldFsRedirectionLevel)
|
|
{
|
|
/* This is what Windows returns on x86 */
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlComputeImportTableHash(IN HANDLE FileHandle,
|
|
OUT PCHAR Hash,
|
|
IN ULONG ImportTableHashSize)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlpSafeCopyMemory(
|
|
_Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
|
|
_In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
|
|
_In_ SIZE_T Length)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
RtlCopyMemory(Destination, Source, Length);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* FIXME: code duplication with kernel32/client/time.c */
|
|
ULONG
|
|
NTAPI
|
|
RtlGetTickCount(VOID)
|
|
{
|
|
ULARGE_INTEGER TickCount;
|
|
|
|
#ifdef _WIN64
|
|
TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
|
|
#else
|
|
while (TRUE)
|
|
{
|
|
TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
|
|
TickCount.LowPart = SharedUserData->TickCount.LowPart;
|
|
|
|
if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
|
|
break;
|
|
|
|
YieldProcessor();
|
|
}
|
|
#endif
|
|
|
|
return (ULONG)((UInt32x32To64(TickCount.LowPart,
|
|
SharedUserData->TickCountMultiplier) >> 24) +
|
|
UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
|
|
SharedUserData->TickCountMultiplier));
|
|
}
|
|
|
|
/* EOF */
|