VOID CreateDotNetTraceQueryThread( _In_ HWND WindowHandle, _In_ ULONG ClrVersions, _In_ HANDLE ProcessId ) { HANDLE threadHandle; PASMPAGE_QUERY_CONTEXT context; context = PhAllocate(sizeof(ASMPAGE_QUERY_CONTEXT)); memset(context, 0, sizeof(ASMPAGE_QUERY_CONTEXT)); context->WindowHandle = WindowHandle; context->ClrVersions = ClrVersions; context->ProcessId = ProcessId; context->NodeList = PhCreateList(64); context->NodeRootList = PhCreateList(2); if (threadHandle = PhCreateThread(0, DotNetTraceQueryThreadStart, context)) { NtClose(threadHandle); } else { DestroyDotNetTraceQuery(context); } }
VOID InitializeVirusTotalProcessMonitor( VOID ) { VirusTotalList = PhCreateList(100); VirusTotalHandle = PhCreateThread(0, VirusTotalProcessApiThread, NULL); }
VOID PhGetSelectedListViewItemParams( _In_ HWND hWnd, _Out_ PVOID **Items, _Out_ PULONG NumberOfItems ) { PPH_LIST list; ULONG index; PVOID param; list = PhCreateList(2); index = -1; while ((index = PhFindListViewItemByFlags( hWnd, index, LVNI_SELECTED )) != -1) { if (PhGetListViewItemParam( hWnd, index, ¶m )) { PhAddItemList(list, param); } } *Items = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); *NumberOfItems = list->Count; PhDereferenceObject(list); }
VOID PhShowGdiHandlesDialog( _In_ HWND ParentWindowHandle, _In_ PPH_PROCESS_ITEM ProcessItem ) { GDI_HANDLES_CONTEXT context; ULONG i; context.ProcessItem = ProcessItem; context.List = PhCreateList(20); DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_GDIHANDLES), ParentWindowHandle, PhpGdiHandlesDlgProc, (LPARAM)&context ); for (i = 0; i < context.List->Count; i++) { PPH_GDI_HANDLE_ITEM gdiHandleItem = context.List->Items[i]; if (gdiHandleItem->Information) PhDereferenceObject(gdiHandleItem->Information); PhFree(context.List->Items[i]); } PhDereferenceObject(context.List); }
VOID PhShowChooseColumnsDialog( __in HWND ParentWindowHandle, __in HWND ControlHandle, __in ULONG Type ) { COLUMNS_DIALOG_CONTEXT context; context.ControlHandle = ControlHandle; context.Type = Type; if (Type == PH_CONTROL_TYPE_TREE_NEW) context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle)); else return; DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_CHOOSECOLUMNS), ParentWindowHandle, PhpColumnsDlgProc, (LPARAM)&context ); PhDereferenceObject(context.Columns); }
VOID NetAdaptersInitialize( VOID ) { NetworkAdaptersList = PhCreateList(1); NetAdapterEntryType = PhCreateObjectType(L"NetAdapterEntry", 0, AdapterEntryDeleteProcedure); }
NTSTATUS PhpEnumHiddenProcessesCsrHandles( _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, _In_opt_ PVOID Context ) { NTSTATUS status; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; PPH_LIST pids; CSR_HANDLES_CONTEXT context; if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) return status; pids = PhCreateList(40); process = PH_FIRST_PROCESS(processes); do { PhAddItemList(pids, process->UniqueProcessId); } while (process = PH_NEXT_PROCESS(process)); PhFree(processes); context.Callback = Callback; context.Context = Context; context.Pids = pids; status = PhEnumCsrProcessHandles(PhpCsrProcessHandlesCallback, &context); PhDereferenceObject(pids); return status; }
PPH_LIST DiskDriveQueryMountPointHandles( _In_ ULONG DeviceNumber ) { ULONG driveMask; PPH_LIST deviceList; WCHAR deviceNameBuffer[7] = L"\\\\.\\?:"; driveMask = DiskDriveQueryDeviceMap(); deviceList = PhCreateList(2); // NOTE: This isn't the best way of doing this but it works. for (INT i = 0; i < 0x1A; i++) { if (driveMask & (0x1 << i)) { HANDLE deviceHandle; deviceNameBuffer[4] = (WCHAR)('A' + i); if (NT_SUCCESS(PhCreateFileWin32( &deviceHandle, deviceNameBuffer, PhGetOwnTokenAttributes().Elevated ? FILE_GENERIC_READ : FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { ULONG deviceNumber = ULONG_MAX; // Note: Do not initialize to zero. DEVICE_TYPE deviceType = 0; if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &deviceNumber, &deviceType ))) { // BUG: Device numbers are re-used on seperate device controllers and this // causes drive letters to be assigned to disks at those same indexes. // For now, just filter CD_ROM devices but we may need to be a lot more strict and // only allow devices of type FILE_DEVICE_DISK to be scanned for mount points. if (deviceNumber == DeviceNumber && deviceType != FILE_DEVICE_CD_ROM) { PDISK_HANDLE_ENTRY entry = PhAllocate(sizeof(DISK_HANDLE_ENTRY)); memset(entry, 0, sizeof(DISK_HANDLE_ENTRY)); entry->DeviceLetter = deviceNameBuffer[4]; entry->DeviceHandle = deviceHandle; PhAddItemList(deviceList, entry); } } } } } return deviceList; }
VOID DiskDrivesInitialize( VOID ) { DiskDrivesList = PhCreateList(1); DiskDriveEntryType = PhCreateObjectType(L"DiskDriveEntry", 0, DiskEntryDeleteProcedure); }
PPH_LIST VirusTotalJsonToResultList( _In_ PVOID JsonObject ) { ULONG i; ULONG arrayLength; PPH_LIST results; if (!(arrayLength = PhGetJsonArrayLength(JsonObject))) return NULL; results = PhCreateList(arrayLength); for (i = 0; i < arrayLength; i++) { PVIRUSTOTAL_API_RESULT result; PVOID jsonArrayObject; if (!(jsonArrayObject = PhGetJsonArrayIndexObject(JsonObject, i))) continue; result = PhAllocate(sizeof(VIRUSTOTAL_API_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_API_RESULT)); result->FileHash = PhGetJsonValueAsString(jsonArrayObject, "hash"); result->Found = PhGetJsonObjectBool(jsonArrayObject, "found") == TRUE; result->Positives = PhGetJsonValueAsLong64(jsonArrayObject, "positives"); result->Total = PhGetJsonValueAsLong64(jsonArrayObject, "total"); PhAddItemList(results, result); } return results; }
VOID StatusBarLoadSettings( VOID ) { ULONG64 buttonCount = 0; PPH_STRING settingsString; PH_STRINGREF remaining; PH_STRINGREF part; settingsString = PhaGetStringSetting(SETTING_NAME_STATUSBAR_CONFIG); remaining = settingsString->sr; if (remaining.Length == 0) { // Load default settings StatusBarLoadDefault(); return; } // Query the number of buttons to insert if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) { // Load default settings StatusBarLoadDefault(); return; } if (!PhStringToInteger64(&part, 10, &buttonCount)) { // Load default settings StatusBarLoadDefault(); return; } StatusBarItemList = PhCreateList((ULONG)buttonCount); for (ULONG i = 0; i < (ULONG)buttonCount; i++) { PH_STRINGREF idPart; ULONG64 idInteger; if (remaining.Length == 0) break; PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); if (PhStringToInteger64(&idPart, 10, &idInteger)) { PSTATUSBAR_ITEM statusItem; statusItem = PhAllocate(sizeof(STATUSBAR_ITEM)); memset(statusItem, 0, sizeof(STATUSBAR_ITEM)); statusItem->Id = (ULONG)idInteger; PhInsertItemList(StatusBarItemList, i, statusItem); } } }
static NTSTATUS PhpRefreshThreadStack( _In_ HWND hwnd, _In_ PTHREAD_STACK_CONTEXT ThreadStackContext ) { ULONG i; ThreadStackContext->StopWalk = FALSE; PhSwapReference2(&ThreadStackContext->StatusMessage, PhCreateString(L"Loading stack...")); DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_PROGRESS), hwnd, PhpThreadStackProgressDlgProc, (LPARAM)ThreadStackContext ); if (!ThreadStackContext->StopWalk && NT_SUCCESS(ThreadStackContext->WalkStatus)) { for (i = 0; i < ThreadStackContext->List->Count; i++) PhpFreeThreadStackItem(ThreadStackContext->List->Items[i]); PhDereferenceObject(ThreadStackContext->List); ThreadStackContext->List = ThreadStackContext->NewList; ThreadStackContext->NewList = PhCreateList(10); ListView_DeleteAllItems(ThreadStackContext->ListViewHandle); SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, FALSE, 0); for (i = 0; i < ThreadStackContext->List->Count; i++) { PTHREAD_STACK_ITEM item = ThreadStackContext->List->Items[i]; INT lvItemIndex; WCHAR integerString[PH_INT32_STR_LEN_1]; PhPrintUInt32(integerString, item->Index); lvItemIndex = PhAddListViewItem(ThreadStackContext->ListViewHandle, MAXINT, integerString, item); PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 1, PhGetStringOrDefault(item->Symbol, L"???")); } SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, TRUE, 0); InvalidateRect(ThreadStackContext->ListViewHandle, NULL, FALSE); } else { for (i = 0; i < ThreadStackContext->NewList->Count; i++) PhpFreeThreadStackItem(ThreadStackContext->NewList->Items[i]); PhClearList(ThreadStackContext->NewList); } if (ThreadStackContext->StopWalk) return STATUS_ABANDONED; return ThreadStackContext->WalkStatus; }
VOID PhRegisterDialog( _In_ HWND DialogWindowHandle ) { if (!DialogList) DialogList = PhCreateList(2); PhAddItemList(DialogList, (PVOID)DialogWindowHandle); }
VOID PhWorkQueueInitialization( VOID ) { PhInitializeFreeList(&PhWorkQueueItemFreeList, sizeof(PH_WORK_QUEUE_ITEM), 32); #ifdef DEBUG PhDbgWorkQueueList = PhCreateList(4); #endif }
/** * Creates a root menu. */ PPH_EMENU PhCreateEMenu( VOID ) { PPH_EMENU menu; menu = PhAllocate(sizeof(PH_EMENU)); memset(menu, 0, sizeof(PH_EMENU)); menu->Items = PhCreateList(16); return menu; }
NTSTATUS PhpOpenCsrProcesses( _Out_ PHANDLE *ProcessHandles, _Out_ PULONG NumberOfProcessHandles ) { NTSTATUS status; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; PPH_LIST processHandleList; if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) return status; processHandleList = PhCreateList(8); process = PH_FIRST_PROCESS(processes); do { HANDLE processHandle; PH_KNOWN_PROCESS_TYPE knownProcessType; if (NT_SUCCESS(PhOpenProcess( &processHandle, ProcessQueryAccess | PROCESS_DUP_HANDLE, process->UniqueProcessId ))) { if (NT_SUCCESS(PhGetProcessKnownType( processHandle, &knownProcessType )) && (knownProcessType & KnownProcessTypeMask) == WindowsSubsystemProcessType) { PhAddItemList(processHandleList, processHandle); } else { NtClose(processHandle); } } } while (process = PH_NEXT_PROCESS(process)); PhFree(processes); *ProcessHandles = PhAllocateCopy(processHandleList->Items, processHandleList->Count * sizeof(HANDLE)); *NumberOfProcessHandles = processHandleList->Count; PhDereferenceObject(processHandleList); return status; }
VOID PhpExecuteCallbackForAllPlugins( _In_ PH_PLUGIN_CALLBACK Callback, _In_ BOOLEAN StartupParameters ) { PPH_AVL_LINKS links; links = PhMinimumElementAvlTree(&PhPluginsByName); while (links) { PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); PPH_LIST parameters = NULL; // Find relevant startup parameters for this plugin. if (StartupParameters && PhStartupParameters.PluginParameters) { ULONG i; for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++) { PPH_STRING string = PhStartupParameters.PluginParameters->Items[i]; PH_STRINGREF pluginName; PH_STRINGREF parameter; if (PhSplitStringRefAtChar(&string->sr, ':', &pluginName, ¶meter) && PhEqualStringRef(&pluginName, &plugin->Name, FALSE) && parameter.Length != 0) { if (!parameters) parameters = PhCreateList(3); PhAddItemList(parameters, PhCreateString2(¶meter)); } } } PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters); if (parameters) { ULONG i; for (i = 0; i < parameters->Count; i++) PhDereferenceObject(parameters->Items[i]); PhDereferenceObject(parameters); } links = PhSuccessorElementAvlTree(links); } }
static VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_STRING string = NULL; CountersList = PhCreateList(5); string = PhGetStringSetting(SETTING_NAME_PERFMON_LIST); LoadCounterList(CountersList, string); PhDereferenceObject(string); }
static VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_STRING string = NULL; DiskDrivesList = PhCreateList(1); string = PhGetStringSetting(SETTING_NAME_DISK_LIST); LoadDiskDriveList(DiskDrivesList, string); PhDereferenceObject(string); }
PPH_LIST PhInitializeColumnSetList( _In_ PWSTR SettingName ) { PPH_LIST columnSetList; PPH_STRING settingsString; ULONG64 count; ULONG64 index; PH_STRINGREF remaining; PH_STRINGREF part; columnSetList = PhCreateList(10); settingsString = PhaGetStringSetting(SettingName); remaining = settingsString->sr; if (remaining.Length == 0) goto CleanupExit; if (!PhSplitStringRefAtChar(&remaining, '-', &part, &remaining)) goto CleanupExit; if (!PhStringToInteger64(&part, 10, &count)) goto CleanupExit; for (index = 0; index < count; index++) { PH_STRINGREF columnSetNamePart; PH_STRINGREF columnSetSettingPart; PH_STRINGREF columnSetSortPart; if (remaining.Length == 0) break; PhSplitStringRefAtChar(&remaining, '-', &columnSetNamePart, &remaining); PhSplitStringRefAtChar(&remaining, '-', &columnSetSettingPart, &remaining); PhSplitStringRefAtChar(&remaining, '-', &columnSetSortPart, &remaining); { PPH_COLUMN_SET_ENTRY entry; entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY)); entry->Name = PhCreateString2(&columnSetNamePart); entry->Setting = PhCreateString2(&columnSetSettingPart); entry->Sorting = PhCreateString2(&columnSetSortPart); PhAddItemList(columnSetList, entry); } } CleanupExit: return columnSetList; }
VOID PhSettingsInitialization( VOID ) { PhSettingsHashtable = PhCreateHashtable( sizeof(PH_SETTING), PhpSettingsHashtableEqualFunction, PhpSettingsHashtableHashFunction, 256 ); PhIgnoredSettings = PhCreateList(4); PhAddDefaultSettings(); PhUpdateCachedSettings(); }
struct _PH_MESSAGE_LOOP_FILTER_ENTRY *PhRegisterMessageLoopFilter( _In_ PPH_MESSAGE_LOOP_FILTER Filter, _In_opt_ PVOID Context ) { PPH_MESSAGE_LOOP_FILTER_ENTRY entry; if (!FilterList) FilterList = PhCreateList(2); entry = PhAllocate(sizeof(PH_MESSAGE_LOOP_FILTER_ENTRY)); entry->Filter = Filter; entry->Context = Context; PhAddItemList(FilterList, entry); return entry; }
VOID PhCmSetNotifyPlugin( _In_ PPH_CM_MANAGER Manager, _In_ struct _PH_PLUGIN *Plugin ) { if (!Manager->NotifyList) { Manager->NotifyList = PhCreateList(8); } else { if (PhFindItemList(Manager->NotifyList, Plugin) != -1) return; } PhAddItemList(Manager->NotifyList, Plugin); }
BOOLEAN EtGpuMonitorInitialization(VOID) { //@@ gdi32.dll and setupapi.dll 함수 후킹으로 함수 address 획득. /*if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) && WindowsVersion >= WINDOWS_7) {*/ HMODULE gdi32Handle; HMODULE setupapiHandle; if (gdi32Handle = GetModuleHandle(L"gdi32.dll")) { D3DKMTOpenAdapterFromDeviceName_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTOpenAdapterFromDeviceName"); D3DKMTCloseAdapter_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTCloseAdapter"); D3DKMTQueryStatistics_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics"); /*if (D3DKMTOpenAdapterFromDeviceName_I == NULL) printf("failed got D3DKMTDeviceName_l addr \n"); else printf("success got D3DKMTDeviceName_l addr %x \n", D3DKMTOpenAdapterFromDeviceName_I);*/ } if (setupapiHandle = LoadLibrary(L"setupapi.dll")) { SetupDiGetClassDevsW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetClassDevsW"); SetupDiDestroyDeviceInfoList_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiDestroyDeviceInfoList"); SetupDiEnumDeviceInterfaces_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiEnumDeviceInterfaces"); SetupDiGetDeviceInterfaceDetailW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceInterfaceDetailW"); SetupDiGetDeviceRegistryPropertyW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceRegistryPropertyW"); } if ( D3DKMTOpenAdapterFromDeviceName_I && D3DKMTCloseAdapter_I && D3DKMTQueryStatistics_I && SetupDiGetClassDevsW_I && SetupDiDestroyDeviceInfoList_I && SetupDiEnumDeviceInterfaces_I && SetupDiGetDeviceInterfaceDetailW_I ) { EtpGpuAdapterList = PhCreateList(4); //@@ D3DStatistics 초기화 및 D3DStatistics에서 gpu adapter list를 받아옮. if (EtpInitializeD3DStatistics() && EtpGpuAdapterList->Count != 0) return TRUE; } return FALSE; }
VOID PhInitializeLayoutManager( _Out_ PPH_LAYOUT_MANAGER Manager, _In_ HWND RootWindowHandle ) { Manager->List = PhCreateList(4); Manager->LayoutNumber = 0; Manager->RootItem.Handle = RootWindowHandle; GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect); Manager->RootItem.OrigRect = Manager->RootItem.Rect; Manager->RootItem.ParentItem = NULL; Manager->RootItem.LayoutParentItem = NULL; Manager->RootItem.LayoutNumber = 0; Manager->RootItem.NumberOfChildren = 0; Manager->RootItem.DeferHandle = NULL; }
VOID StatusBarLoadDefault( VOID ) { if (!StatusBarItemList) StatusBarItemList = PhCreateList(MAX_DEFAULT_STATUSBAR_ITEMS); for (ULONG i = 0; i < MAX_DEFAULT_STATUSBAR_ITEMS; i++) { PSTATUSBAR_ITEM statusItem; statusItem = PhAllocate(sizeof(STATUSBAR_ITEM)); memset(statusItem, 0, sizeof(STATUSBAR_ITEM)); statusItem->Id = StatusBarItems[i]; PhAddItemList(StatusBarItemList, statusItem); } }
/** * Loads a plugin. * * \param FileName The full file name of the plugin. */ BOOLEAN PhLoadPlugin( _In_ PPH_STRING FileName ) { BOOLEAN success; PPH_STRING fileName; PPH_STRING errorMessage; fileName = PhGetFullPath(FileName->Buffer, NULL); if (!fileName) PhSetReference(&fileName, FileName); success = TRUE; if (!LoadLibrary(fileName->Buffer)) { success = FALSE; errorMessage = PhGetWin32Message(GetLastError()); } if (!success) { PPHP_PLUGIN_LOAD_ERROR loadError; loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); PhSetReference(&loadError->FileName, fileName); PhSetReference(&loadError->ErrorMessage, errorMessage); if (!LoadErrors) LoadErrors = PhCreateList(2); PhAddItemList(LoadErrors, loadError); if (errorMessage) PhDereferenceObject(errorMessage); } PhDereferenceObject(fileName); return success; }
PDNA_NODE AddNode( _Inout_ PASMPAGE_QUERY_CONTEXT Context ) { PDNA_NODE node; node = PhAllocate(sizeof(DNA_NODE)); memset(node, 0, sizeof(DNA_NODE)); PhInitializeTreeNewNode(&node->Node); memset(node->TextCache, 0, sizeof(PH_STRINGREF) * DNATNC_MAXIMUM); node->Node.TextCache = node->TextCache; node->Node.TextCacheSize = DNATNC_MAXIMUM; node->Children = PhCreateList(1); PhAddItemList(Context->NodeList, node); return node; }
/** * Adds a menu hook. * * \param MenuInfo The plugin menu information structure. * \param Plugin A plugin instance structure. * \param Context A user-defined value that is later accessible from the callback. * * \remarks The \ref PluginCallbackMenuHook callback is invoked when any menu item * from the menu is chosen. */ BOOLEAN PhPluginAddMenuHook( _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, _In_ PPH_PLUGIN Plugin, _In_opt_ PVOID Context ) { PPHP_PLUGIN_MENU_HOOK hook; if (MenuInfo->Flags & PH_PLUGIN_MENU_DISALLOW_HOOKS) return FALSE; if (!MenuInfo->PluginHookList) MenuInfo->PluginHookList = PhAutoDereferenceObject(PhCreateList(2)); hook = PhAutoDereferenceObject(PhCreateAlloc(sizeof(PHP_PLUGIN_MENU_HOOK))); hook->Plugin = Plugin; hook->Context = Context; PhAddItemList(MenuInfo->PluginHookList, hook); return TRUE; }
/** * Inserts a menu item into a parent menu item. * * \param Parent The parent menu item. * \param Item The menu item to insert. * \param Index The index at which to insert the menu item. * If the index is too large, the menu item is inserted * at the last position. */ VOID PhInsertEMenuItem( __inout PPH_EMENU_ITEM Parent, __inout PPH_EMENU_ITEM Item, __in ULONG Index ) { // Remove the item from its old parent if it has one. if (Item->Parent) PhRemoveEMenuItem(Item->Parent, Item, 0); if (!Parent->Items) Parent->Items = PhCreateList(16); if (Index > Parent->Items->Count) Index = Parent->Items->Count; if (Index == -1) PhAddItemList(Parent->Items, Item); else PhInsertItemList(Parent->Items, Index, Item); Item->Parent = Parent; }