_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting( _In_ PWSTR Name ) { PPH_SETTING setting; PH_STRINGREF name; PH_INTEGER_PAIR value; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockShared(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == IntegerPairSettingType) { value = setting->u.IntegerPair; } else { setting = NULL; } PhReleaseQueuedLockShared(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); return value; }
_May_raise_ VOID PhSetScalableIntegerPairSetting( _In_ PWSTR Name, _In_ PH_SCALABLE_INTEGER_PAIR Value ) { PPH_SETTING setting; PH_STRINGREF name; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockExclusive(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == ScalableIntegerPairSettingType) { PhpFreeSettingValue(ScalableIntegerPairSettingType, setting); setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR)); } PhReleaseQueuedLockExclusive(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); }
_May_raise_ VOID PhSetStringSetting2( _In_ PWSTR Name, _In_ PPH_STRINGREF Value ) { PPH_SETTING setting; PH_STRINGREF name; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockExclusive(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == StringSettingType) { PhpFreeSettingValue(StringSettingType, setting); setting->u.Pointer = PhCreateString2(Value); } PhReleaseQueuedLockExclusive(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); }
/** * Retrieves a pointer to a general callback. * * \param Callback The type of callback. * * \remarks The program invokes general callbacks for system-wide * notifications. */ PPH_CALLBACK PhGetGeneralCallback( _In_ PH_GENERAL_CALLBACK Callback ) { if (Callback >= GeneralCallbackMaximum) PhRaiseStatus(STATUS_INVALID_PARAMETER_2); return &GeneralCallbacks[Callback]; }
/** * Dereferences the specified object. * The object will be freed if its reference count reaches 0. * * \param Object A pointer to the object to dereference. * \param RefCount The number of references to remove. * \param DeferDelete Whether to defer deletion of the object. * * \return The new reference count of the object. */ __mayRaise LONG PhDereferenceObjectEx( __in PVOID Object, __in LONG RefCount, __in BOOLEAN DeferDelete ) { PPH_OBJECT_HEADER objectHeader; LONG oldRefCount; LONG newRefCount; #ifdef PHOBJ_STRICT_CHECKS /* Make sure we're not subtracting a negative reference count. */ if (RefCount < 0) PhRaiseStatus(STATUS_INVALID_PARAMETER_2); #else assert(!(RefCount < 0)); #endif objectHeader = PhObjectToObjectHeader(Object); /* Decrease the reference count. */ oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount); newRefCount = oldRefCount - RefCount; /* Free the object if it has 0 references. */ if (newRefCount == 0) { if (DeferDelete) { PhpDeferDeleteObject(objectHeader); } else { /* Free the object. */ PhpFreeObject(objectHeader); } } else if (newRefCount < 0) { PhRaiseStatus(STATUS_INVALID_PARAMETER); } return newRefCount; }
/** * Retrieves a pointer to a plugin callback. * * \param Plugin A plugin instance structure. * \param Callback The type of callback. * * \remarks The program invokes plugin callbacks for notifications * specific to a plugin. */ PPH_CALLBACK PhGetPluginCallback( _In_ PPH_PLUGIN Plugin, _In_ PH_PLUGIN_CALLBACK Callback ) { if (Callback >= PluginCallbackMaximum) PhRaiseStatus(STATUS_INVALID_PARAMETER_2); return &Plugin->Callbacks[Callback]; }
/** * Adds an object to the current auto-dereference * pool for the current thread. * If the current thread does not have an auto-dereference * pool, the function raises an exception. * * \param Object A pointer to an object. The object * will be dereferenced when the current auto-dereference * pool is drained or freed. */ __mayRaise VOID PhaDereferenceObject( __in PVOID Object ) { PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool(); #ifdef DEBUG // If we don't have an auto-dereference pool, // we don't want to leak the object (unlike what // Apple does with NSAutoreleasePool). if (!autoPool) PhRaiseStatus(STATUS_UNSUCCESSFUL); #endif // See if we can use the static array. if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE) { autoPool->StaticObjects[autoPool->StaticCount++] = Object; return; } // Use the dynamic array. // Allocate the array if we haven't already. if (!autoPool->DynamicObjects) { autoPool->DynamicAllocated = 64; autoPool->DynamicObjects = PhAllocate( sizeof(PVOID) * autoPool->DynamicAllocated ); REF_STAT_UP(RefAutoPoolsDynamicAllocated); } // See if we need to resize the array. if (autoPool->DynamicCount == autoPool->DynamicAllocated) { autoPool->DynamicAllocated *= 2; autoPool->DynamicObjects = PhReAllocate( autoPool->DynamicObjects, sizeof(PVOID) * autoPool->DynamicAllocated ); REF_STAT_UP(RefAutoPoolsDynamicResized); } autoPool->DynamicObjects[autoPool->DynamicCount++] = Object; }
/** * Unblocks a wait block. * * \param WaitBlock A wait block. * * \remarks The wait block is in an undefined state after it is * unblocked. Do not attempt to read any values from it. All relevant * information should be saved before unblocking the wait block. */ __mayRaise FORCEINLINE VOID PhpUnblockQueuedWaitBlock( __inout PPH_QUEUED_WAIT_BLOCK WaitBlock ) { NTSTATUS status; if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) { if (!NT_SUCCESS(status = NtReleaseKeyedEvent( PhQueuedLockKeyedEventHandle, WaitBlock, FALSE, NULL ))) PhRaiseStatus(status); } }
/** * Waits for a wait block to be unblocked. * * \param WaitBlock A wait block. * \param Spin TRUE to spin, FALSE to block immediately. * \param Timeout A timeout value. */ __mayRaise FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock( __inout PPH_QUEUED_WAIT_BLOCK WaitBlock, __in BOOLEAN Spin, __in_opt PLARGE_INTEGER Timeout ) { NTSTATUS status; ULONG i; if (Spin) { PHLIB_INC_STATISTIC(QlBlockSpins); for (i = PhQueuedLockSpinCount; i != 0; i--) { if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)) return STATUS_SUCCESS; YieldProcessor(); } } if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) { PHLIB_INC_STATISTIC(QlBlockWaits); status = NtWaitForKeyedEvent( PhQueuedLockKeyedEventHandle, WaitBlock, FALSE, Timeout ); // If an error occurred (timeout is not an error), raise an exception // as it is nearly impossible to recover from this situation. if (!NT_SUCCESS(status)) PhRaiseStatus(status); } else { status = STATUS_SUCCESS; } return status; }
_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting( _In_ PWSTR Name, _In_ BOOLEAN ScaleToCurrent ) { PPH_SETTING setting; PH_STRINGREF name; PH_SCALABLE_INTEGER_PAIR value; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockShared(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == ScalableIntegerPairSettingType) { value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer; } else { setting = NULL; } PhReleaseQueuedLockShared(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); if (ScaleToCurrent) { ULONG currentScale; currentScale = PhpGetCurrentScale(); if (value.Scale != currentScale && value.Scale != 0) { value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale); value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale); value.Scale = currentScale; } } return value; }
/** * Deletes an auto-dereference pool. * The function will dereference any objects * currently in the pool. If a pool other than * the current pool is passed to the function, * an exception is raised. * * \param AutoPool The auto-dereference pool to delete. */ __mayRaise VOID PhDeleteAutoPool( __inout PPH_AUTO_POOL AutoPool ) { PhDrainAutoPool(AutoPool); if (PhpGetCurrentAutoPool() != AutoPool) PhRaiseStatus(STATUS_UNSUCCESSFUL); // Remove the pool from the stack. PhpSetCurrentAutoPool(AutoPool->NextPool); // Free the dynamic array if it hasn't been freed yet. if (AutoPool->DynamicObjects) PhFree(AutoPool->DynamicObjects); REF_STAT_UP(RefAutoPoolsDestroyed); }
_May_raise_ PPH_STRING PhGetStringSetting( _In_ PWSTR Name ) { PPH_SETTING setting; PH_STRINGREF name; PPH_STRING value; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockShared(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == StringSettingType) { if (setting->u.Pointer) { PhSetReference(&value, setting->u.Pointer); } else { // Set to NULL, create an empty string // outside of the lock. value = NULL; } } else { setting = NULL; } PhReleaseQueuedLockShared(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); if (!value) value = PhReferenceEmptyString(); return value; }
/** * Sets the current auto-dereference pool for the * current thread. */ __mayRaise FORCEINLINE VOID PhpSetCurrentAutoPool( __in PPH_AUTO_POOL AutoPool ) { if (!TlsSetValue(PhpAutoPoolTlsIndex, AutoPool)) PhRaiseStatus(STATUS_UNSUCCESSFUL); #ifdef DEBUG { PPHP_BASE_THREAD_DBG dbg; dbg = (PPHP_BASE_THREAD_DBG)TlsGetValue(PhDbgThreadDbgTlsIndex); if (dbg) { dbg->CurrentAutoPool = AutoPool; } } #endif }
VOID EtInitializeDiskInformation( VOID ) { NTSTATUS status; LARGE_INTEGER performanceCounter; if (!NT_SUCCESS(status = PhCreateObjectType( &EtDiskItemType, L"DiskItem", 0, EtpDiskItemDeleteProcedure ))) PhRaiseStatus(status); EtDiskHashtable = PhCreateHashtable( sizeof(PET_DISK_ITEM), EtpDiskHashtableCompareFunction, EtpDiskHashtableHashFunction, 128 ); InitializeListHead(&EtDiskAgeListHead); PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64); RtlInitializeSListHead(&EtDiskPacketListHead); EtFileNameHashtable = PhCreateSimpleHashtable(128); NtQueryPerformanceCounter(&performanceCounter, &EtpPerformanceFrequency); EtDiskEnabled = TRUE; // Collect all existing file names. EtStartEtwRundown(); PhRegisterCallback( &PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration ); }
/** * References the specified object. * * \param Object A pointer to the object to reference. * \param RefCount The number of references to add. * * \return The new reference count of the object. */ __mayRaise LONG PhReferenceObjectEx( __in PVOID Object, __in LONG RefCount ) { PPH_OBJECT_HEADER objectHeader; LONG oldRefCount; #ifdef PHOBJ_STRICT_CHECKS /* Make sure we're not adding a negative reference count. */ if (RefCount < 0) PhRaiseStatus(STATUS_INVALID_PARAMETER_2); #else assert(!(RefCount < 0)); #endif objectHeader = PhObjectToObjectHeader(Object); /* Increase the reference count. */ oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount); return oldRefCount + RefCount; }
_May_raise_ VOID PhSetIntegerPairSetting( _In_ PWSTR Name, _In_ PH_INTEGER_PAIR Value ) { PPH_SETTING setting; PH_STRINGREF name; PhInitializeStringRef(&name, Name); PhAcquireQueuedLockExclusive(&PhSettingsLock); setting = PhpLookupSetting(&name); if (setting && setting->Type == IntegerPairSettingType) { setting->u.IntegerPair = Value; } PhReleaseQueuedLockExclusive(&PhSettingsLock); if (!setting) PhRaiseStatus(STATUS_NOT_FOUND); }
/** * Allocates storage for an object. * * \param ObjectType The type of the object. * \param ObjectSize The size of the object, excluding the header. * \param Flags A combination of flags specifying how the object is to be allocated. */ PPH_OBJECT_HEADER PhpAllocateObject( __in PPH_OBJECT_TYPE ObjectType, __in SIZE_T ObjectSize, __in ULONG Flags ) { PPH_OBJECT_HEADER objectHeader; if (ObjectType->Flags & PHOBJTYPE_USE_FREE_LIST) { #ifdef PHOBJ_STRICT_CHECKS if (ObjectType->FreeList.Size != PhpAddObjectHeaderSize(ObjectSize)) PhRaiseStatus(STATUS_INVALID_PARAMETER); #else assert(ObjectType->FreeList.Size == PhpAddObjectHeaderSize(ObjectSize)); #endif objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList); objectHeader->Flags = PHOBJ_FROM_TYPE_FREE_LIST; REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList); } else if (ObjectSize <= PHOBJ_SMALL_OBJECT_SIZE) { objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList); objectHeader->Flags = PHOBJ_FROM_SMALL_FREE_LIST; REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList); } else { objectHeader = PhAllocate(PhpAddObjectHeaderSize(ObjectSize)); objectHeader->Flags = 0; REF_STAT_UP(RefObjectsAllocated); } return objectHeader; }
VOID PhpLayoutItemLayout( _Inout_ PPH_LAYOUT_MANAGER Manager, _Inout_ PPH_LAYOUT_ITEM Item ) { RECT rect; BOOLEAN hasDummyParent; if (Item->NumberOfChildren > 0 && !Item->DeferHandle) Item->DeferHandle = BeginDeferWindowPos(Item->NumberOfChildren); if (Item->LayoutNumber == Manager->LayoutNumber) return; // If this is the root item we must stop here. if (!Item->ParentItem) return; PhpLayoutItemLayout(Manager, Item->ParentItem); if (Item->ParentItem != Item->LayoutParentItem) { PhpLayoutItemLayout(Manager, Item->LayoutParentItem); hasDummyParent = TRUE; } else { hasDummyParent = FALSE; } GetWindowRect(Item->Handle, &Item->Rect); MapWindowPoints(NULL, Item->LayoutParentItem->Handle, (POINT *)&Item->Rect, 2); if (Item->Anchor & PH_LAYOUT_TAB_CONTROL) { // We want to convert the tab control rectangle to the tab page display rectangle. TabCtrl_AdjustRect(Item->Handle, FALSE, &Item->Rect); } if (!(Item->Anchor & PH_LAYOUT_DUMMY_MASK)) { // Convert right/bottom into margins to make the calculations // easier. rect = Item->Rect; PhConvertRect(&rect, &Item->LayoutParentItem->Rect); if (!(Item->Anchor & (PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT))) { // TODO PhRaiseStatus(STATUS_NOT_IMPLEMENTED); } else if (Item->Anchor & PH_ANCHOR_RIGHT) { if (Item->Anchor & PH_ANCHOR_LEFT) { rect.left = (hasDummyParent ? Item->ParentItem->Rect.left : 0) + Item->Margin.left; rect.right = Item->Margin.right; } else { ULONG diff = Item->Margin.right - rect.right; rect.left -= diff; rect.right += diff; } } if (!(Item->Anchor & (PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM))) { // TODO PhRaiseStatus(STATUS_NOT_IMPLEMENTED); } else if (Item->Anchor & PH_ANCHOR_BOTTOM) { if (Item->Anchor & PH_ANCHOR_TOP) { // tab control hack rect.top = (hasDummyParent ? Item->ParentItem->Rect.top : 0) + Item->Margin.top; rect.bottom = Item->Margin.bottom; } else { ULONG diff = Item->Margin.bottom - rect.bottom; rect.top -= diff; rect.bottom += diff; } } // Convert the right/bottom back into co-ordinates. PhConvertRect(&rect, &Item->LayoutParentItem->Rect); Item->Rect = rect; if (!(Item->Anchor & PH_LAYOUT_IMMEDIATE_RESIZE)) { Item->LayoutParentItem->DeferHandle = DeferWindowPos( Item->LayoutParentItem->DeferHandle, Item->Handle, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER ); } else { // This is needed for tab controls, so that TabCtrl_AdjustRect will give us an up-to-date result. SetWindowPos( Item->Handle, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER ); } } Item->LayoutNumber = Manager->LayoutNumber; }
/** * Allocates a object. * * \param Object A variable which receives a pointer to the newly allocated object. * \param ObjectSize The size of the object. * \param Flags A combination of flags specifying how the object is to be allocated. * \li \c PHOBJ_RAISE_ON_FAIL An exception will be raised if the object cannot be * allocated. * \param ObjectType The type of the object. */ __mayRaise NTSTATUS PhCreateObject( __out PVOID *Object, __in SIZE_T ObjectSize, __in ULONG Flags, __in PPH_OBJECT_TYPE ObjectType ) { NTSTATUS status = STATUS_SUCCESS; PPH_OBJECT_HEADER objectHeader; #ifdef PHOBJ_STRICT_CHECKS /* Check the flags. */ if ((Flags & PHOBJ_VALID_FLAGS) != Flags) /* Valid flag mask */ { status = STATUS_INVALID_PARAMETER_3; } #else assert(!((Flags & PHOBJ_VALID_FLAGS) != Flags)); #endif #ifdef PHOBJ_STRICT_CHECKS if (NT_SUCCESS(status)) { #endif /* Allocate storage for the object. Note that this includes * the object header followed by the object body. */ objectHeader = PhpAllocateObject(ObjectType, ObjectSize, Flags); #ifndef PHOBJ_ALLOCATE_NEVER_NULL if (!objectHeader) status = STATUS_NO_MEMORY; #endif #ifdef PHOBJ_STRICT_CHECKS } #endif #ifndef PHOBJ_ALLOCATE_NEVER_NULL if (!NT_SUCCESS(status)) { if (!(Flags & PHOBJ_RAISE_ON_FAIL)) return status; else PhRaiseStatus(status); } #endif /* Object type statistics. */ _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects); /* Initialize the object header. */ objectHeader->RefCount = 1; // objectHeader->Flags is initialized by PhpAllocateObject. objectHeader->Size = ObjectSize; objectHeader->Type = ObjectType; REF_STAT_UP(RefObjectsCreated); #ifdef DEBUG { USHORT capturedFrames; capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL); memset( &objectHeader->StackBackTrace[capturedFrames], 0, sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID) ); } PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry); PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); { PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook; dbgCreateObjectHook = PhDbgCreateObjectHook; if (dbgCreateObjectHook) { dbgCreateObjectHook( PhObjectHeaderToObject(objectHeader), ObjectSize, Flags, ObjectType ); } } #endif /* Pass a pointer to the object body back to the caller. */ *Object = PhObjectHeaderToObject(objectHeader); return status; }
NTSTATUS PhInitializeMappedArchive( _Out_ PPH_MAPPED_ARCHIVE MappedArchive, _In_ PVOID ViewBase, _In_ SIZE_T Size ) { NTSTATUS status; PCHAR start; start = (PCHAR)ViewBase; memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE)); MappedArchive->ViewBase = ViewBase; MappedArchive->Size = Size; __try { // Verify the file signature. PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE); if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0) PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT); } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } // Get the members. // Note: the names are checked. // First linker member status = PhpGetMappedArchiveMemberFromHeader( MappedArchive, (PIMAGE_ARCHIVE_MEMBER_HEADER)(start + IMAGE_ARCHIVE_START_SIZE), &MappedArchive->FirstLinkerMember ); if (!NT_SUCCESS(status)) return status; if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType) return STATUS_INVALID_PARAMETER; MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember; // Second linker member status = PhGetNextMappedArchiveMember( &MappedArchive->FirstLinkerMember, &MappedArchive->SecondLinkerMember ); if (!NT_SUCCESS(status)) return status; if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType) return STATUS_INVALID_PARAMETER; // Longnames member // This member doesn't seem to be mandatory, contrary to the specification. // So we'll check if it's actually a longnames member, and if not, ignore it. status = PhGetNextMappedArchiveMember( &MappedArchive->SecondLinkerMember, &MappedArchive->LongnamesMember ); if ( NT_SUCCESS(status) && MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType ) { MappedArchive->HasLongnamesMember = TRUE; MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember; } else { MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember; } return STATUS_SUCCESS; }