reactos/dll/ntdll/rtl/libsupp.c
Joachim Henze 4de8a0d96f [0.4.9] revert [NTDLL/LDR] Overhaul sxs work
This reverts commit 0.4.8-dev-502-g
7000fe2340.

This reverts commit 0.4.8-dev-503-g
f318a25e10.

The two changes were done once to work towards better
shim-supporting APIs of newer Windows versions on demand
in the future. Luckily we do not depend on them yet.

Giannis already fixed most regressions of the 2 commits
before branching 0.4.8RC (e.g. 2nd stage theme-selector).

Unfortunately we still have issues atm with the existing mixture
of Wine comctl32 v5 vs v6.
The image-lists of both are not compatible as Giannis told us.

We revert both commits for this release to fix CORE-14433
(missing icons due to incompatible image-lists). We can not
simply add a manifest here, because 3rd party apps are affected.

I double-checked, all of those (formerly affected) apps
are working fine and show the icons after the revert:
2nd-stage-theme-selection, MS Excel Viewer 2007 open-dlg,
MSVCPP 6 installer open-dlg, FaxViewer save-dlg,
MS Word Viewer 2003 open-dlg

This revert also obsoletes works/fixes like
2f11904000.

(cherry picked from commit 11bf8fa047)
2018-05-20 23:40:47 +02:00

752 lines
19 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 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 */