Beispiel #1
0
PPH_STRING PhGetTreeNewText(
    __in HWND TreeNewHandle,
    __reserved ULONG Reserved
    )
{
    PH_STRING_BUILDER stringBuilder;
    PULONG displayToId;
    ULONG rows;
    ULONG columns;
    ULONG i;
    ULONG j;

    PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns);
    rows = TreeNew_GetFlatNodeCount(TreeNewHandle);

    PhInitializeStringBuilder(&stringBuilder, 0x100);

    for (i = 0; i < rows; i++)
    {
        PH_TREENEW_GET_CELL_TEXT getCellText;

        getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i);
        assert(getCellText.Node);

        if (!getCellText.Node->Selected)
            continue;

        for (j = 0; j < columns; j++)
        {
            getCellText.Id = displayToId[j];
            PhInitializeEmptyStringRef(&getCellText.Text);
            TreeNew_GetCellText(TreeNewHandle, &getCellText);

            PhAppendStringBuilderEx(&stringBuilder, getCellText.Text.Buffer, getCellText.Text.Length);
            PhAppendStringBuilder2(&stringBuilder, L", ");
        }

        // Remove the trailing comma and space.
        if (stringBuilder.String->Length != 0)
            PhRemoveStringBuilder(&stringBuilder, stringBuilder.String->Length / 2 - 2, 2);

        PhAppendStringBuilder2(&stringBuilder, L"\r\n");
    }

    PhFree(displayToId);

    return PhFinalStringBuilderString(&stringBuilder);
}
VOID ToolbarSaveButtonSettings(
    VOID
    )
{
    INT buttonIndex = 0;
    INT buttonCount = 0;
    PPH_STRING settingsString;
    PH_STRING_BUILDER stringBuilder;

    PhInitializeStringBuilder(&stringBuilder, 100);

    buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0);

    PhAppendFormatStringBuilder(
        &stringBuilder,
        L"%d|",
        buttonCount
        );

    for (buttonIndex = 0; buttonIndex < buttonCount; buttonIndex++)
    {
        TBBUTTONINFO buttonInfo = 
        {
            sizeof(TBBUTTONINFO),
            TBIF_BYINDEX | TBIF_IMAGE | TBIF_STYLE | TBIF_COMMAND
        };

        // Get button information.
        if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, buttonIndex, (LPARAM)&buttonInfo) == -1)
            break;

        PhAppendFormatStringBuilder(
            &stringBuilder,
            L"%d|", 
            buttonInfo.idCommand
            );
    }

    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    settingsString = PhFinalStringBuilderString(&stringBuilder);
    PhSetStringSetting2(SETTING_NAME_TOOLBAR_CONFIG, &settingsString->sr);
    PhDereferenceObject(settingsString);
}
Beispiel #3
0
PPH_STRING SaveFilterList(
    _Inout_ PPH_LIST FilterList
    )
{
    PH_STRING_BUILDER stringBuilder;
    SIZE_T i;
    SIZE_T j;
    WCHAR temp[2];

    PhInitializeStringBuilder(&stringBuilder, 100);

    temp[0] = '\\';

    for (i = 0; i < FilterList->Count; i++)
    {
        PFILTER_ENTRY entry = FilterList->Items[i];
        SIZE_T length;

        // Write the entry type.

        temp[1] = entry->Type == FilterInclude ? 'i' : 'e';

        PhAppendStringBuilderEx(&stringBuilder, temp, 4);

        // Write the filter string.

        length = entry->Filter->Length / 2;

        for (j = 0; j < length; j++)
        {
            if (entry->Filter->Buffer[j] == '\\') // escape backslashes
            {
                temp[1] = entry->Filter->Buffer[j];
                PhAppendStringBuilderEx(&stringBuilder, temp, 4);
            }
            else
            {
                PhAppendCharStringBuilder(&stringBuilder, entry->Filter->Buffer[j]);
            }
        }
    }

    return PhFinalStringBuilderString(&stringBuilder);
}
Beispiel #4
0
VOID NetAdaptersSaveList(
    VOID
    )
{
    PH_STRING_BUILDER stringBuilder;
    PPH_STRING settingsString;

    PhInitializeStringBuilder(&stringBuilder, 260);

    PhAcquireQueuedLockShared(&NetworkAdaptersListLock);

    for (ULONG i = 0; i < NetworkAdaptersList->Count; i++)
    {
        PDV_NETADAPTER_ENTRY entry = PhReferenceObjectSafe(NetworkAdaptersList->Items[i]);

        if (!entry)
            continue;

        if (entry->UserReference)
        {
            PhAppendFormatStringBuilder(
                &stringBuilder,
                L"%lu,%I64u,%s,",
                entry->AdapterId.InterfaceIndex, // This value is UNSAFE and will change after reboot.
                entry->AdapterId.InterfaceLuid.Value, // This value is SAFE and does not change (Vista+).
                entry->AdapterId.InterfaceGuid->Buffer
                );
        }

        PhDereferenceObjectDeferDelete(entry);
    }

    PhReleaseQueuedLockShared(&NetworkAdaptersListLock);

    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));
    PhSetStringSetting2(SETTING_NAME_INTERFACE_LIST, &settingsString->sr);
}
Beispiel #5
0
PPH_STRING PhGetDiagnosticsString(
    VOID
    )
{
    PH_STRING_BUILDER stringBuilder;

    PhInitializeStringBuilder(&stringBuilder, 50);

    PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n");

#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \
    L#Type L": %u objects\r\n", PhpGetObjectTypeObjectCount(Type))

    // ref
    OBJECT_TYPE_COUNT(PhObjectTypeObject);

    // basesup
    OBJECT_TYPE_COUNT(PhStringType);
    OBJECT_TYPE_COUNT(PhBytesType);
    OBJECT_TYPE_COUNT(PhListType);
    OBJECT_TYPE_COUNT(PhPointerListType);
    OBJECT_TYPE_COUNT(PhHashtableType);
    OBJECT_TYPE_COUNT(PhFileStreamType);

    // ph
    OBJECT_TYPE_COUNT(PhSymbolProviderType);
    OBJECT_TYPE_COUNT(PhProcessItemType);
    OBJECT_TYPE_COUNT(PhServiceItemType);
    OBJECT_TYPE_COUNT(PhNetworkItemType);
    OBJECT_TYPE_COUNT(PhModuleProviderType);
    OBJECT_TYPE_COUNT(PhModuleItemType);
    OBJECT_TYPE_COUNT(PhThreadProviderType);
    OBJECT_TYPE_COUNT(PhThreadItemType);
    OBJECT_TYPE_COUNT(PhHandleProviderType);
    OBJECT_TYPE_COUNT(PhHandleItemType);
    OBJECT_TYPE_COUNT(PhMemoryItemType);

    return PhFinalStringBuilderString(&stringBuilder);
}
VOID PhSaveSettingsColumnList(
    _In_ PWSTR SettingName,
    _In_ PPH_LIST ColumnSetList
    )
{
    ULONG index;
    PPH_STRING settingsString;
    PH_STRING_BUILDER stringBuilder;

    PhInitializeStringBuilder(&stringBuilder, 100);
    PhAppendFormatStringBuilder(
        &stringBuilder,
        L"%lu-",
        ColumnSetList->Count
        );

    for (index = 0; index < ColumnSetList->Count; index++)
    {
        PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[index];

        if (PhIsNullOrEmptyString(entry->Name))
            continue;

        PhAppendFormatStringBuilder(
            &stringBuilder,
            L"%s-%s-%s-",
            entry->Name->Buffer,
            PhGetStringOrEmpty(entry->Setting),
            PhGetStringOrEmpty(entry->Sorting)
            );
    }

    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));
    PhSetStringSetting2(SettingName, &settingsString->sr);
}
Beispiel #7
0
static PPH_STRING SaveCounterList(
    _Inout_ PPH_LIST FilterList
    )
{
    PH_STRING_BUILDER stringBuilder;
    WCHAR temp[2];

    PhInitializeStringBuilder(&stringBuilder, 100);

    temp[0] = '\\';

    for (SIZE_T i = 0; i < FilterList->Count; i++)
    {
        PPH_PERFMON_ENTRY entry = (PPH_PERFMON_ENTRY)FilterList->Items[i];

        SIZE_T length = entry->Name->Length / 2;

        for (SIZE_T ii = 0; ii < length; ii++)
        {
            if (entry->Name->Buffer[ii] == '\\') // escape backslashes
            {
                temp[1] = entry->Name->Buffer[ii];
                PhAppendStringBuilderEx(&stringBuilder, temp, 4);
            }
            else
            {
                PhAppendCharStringBuilder(&stringBuilder, entry->Name->Buffer[ii]);
            }
        }

        PhAppendCharStringBuilder(&stringBuilder, ',');
    }

    if (stringBuilder.String->Length != 0)
        PhRemoveStringBuilder(&stringBuilder, stringBuilder.String->Length / 2 - 1, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}
VOID DiskDrivesSaveList(
    VOID
    )
{
    PH_STRING_BUILDER stringBuilder;
    PPH_STRING settingsString;

    PhInitializeStringBuilder(&stringBuilder, 260);

    PhAcquireQueuedLockShared(&DiskDrivesListLock);

    for (ULONG i = 0; i < DiskDrivesList->Count; i++)
    {
        PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);

        if (!entry)
            continue;

        if (entry->UserReference)
        {
            PhAppendFormatStringBuilder(
                &stringBuilder,
                L"%s,",
                entry->Id.DevicePath->Buffer // This value is SAFE and does not change.
                );
        }

        PhDereferenceObjectDeferDelete(entry);
    }

    PhReleaseQueuedLockShared(&DiskDrivesListLock);

    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));
    PhSetStringSetting2(SETTING_NAME_DISK_LIST, &settingsString->sr);
}
PPH_STRING EtpGetGpuNameString(
    VOID
    )
{
    ULONG i;
    ULONG count;
    PH_STRING_BUILDER sb;

    count = EtGetGpuAdapterCount();
    PhInitializeStringBuilder(&sb, 100);

    for (i = 0; i < count; i++)
    {
        PPH_STRING description;

        description = EtGetGpuAdapterDescription(i);

        if (!PhIsNullOrEmptyString(description))
        {
            // Ignore "Microsoft Basic Render Driver" unless we don't have any other adapters.
            // This does not take into account localization.
            if (count == 1 || !PhEqualString2(description, L"Microsoft Basic Render Driver", TRUE))
            {
                PhAppendStringBuilder(&sb, &description->sr);
                PhAppendStringBuilder2(&sb, L", ");
            }
        }

        if (description)
            PhDereferenceObject(description);
    }

    if (sb.String->Length != 0)
        PhRemoveEndStringBuilder(&sb, 2);

    return PhFinalStringBuilderString(&sb);
}
Beispiel #10
0
PPH_STRING PhGetServiceTooltipText(
    __in PPH_SERVICE_ITEM Service
    )
{
    PH_STRING_BUILDER stringBuilder;
    PPH_STRING tempString;
    SC_HANDLE serviceHandle;

    PhInitializeStringBuilder(&stringBuilder, 200);

    if (serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_QUERY_CONFIG))
    {
        //LPQUERY_SERVICE_CONFIG config;

        // File information
        // (Disabled for now because of file name resolution issues)

        /*if (config = PhGetServiceConfig(serviceHandle))
        {
            PPH_STRING fileName;
            PPH_STRING newFileName;
            PH_IMAGE_VERSION_INFO versionInfo;

            fileName = PhCreateString(config->lpBinaryPathName);
            newFileName = PhGetFileName(fileName);
            PhDereferenceObject(fileName);
            fileName = newFileName;

            if (PhInitializeImageVersionInfo(
                &versionInfo,
                fileName->Buffer
                ))
            {
                tempString = PhFormatImageVersionInfo(
                    fileName,
                    &versionInfo,
                    L"    ",
                    0
                    );

                if (!PhIsNullOrEmptyString(tempString))
                {
                    PhAppendStringBuilder2(&stringBuilder, L"File:\n");
                    PhAppendStringBuilder(&stringBuilder, tempString);
                    PhAppendCharStringBuilder(&stringBuilder, '\n');
                }

                if (tempString)
                    PhDereferenceObject(tempString);

                PhDeleteImageVersionInfo(&versionInfo);
            }

            PhDereferenceObject(fileName);
            PhFree(config);
        }*/

        // Description

        if (tempString = PhGetServiceDescription(serviceHandle))
        {
            PhAppendStringBuilder(&stringBuilder, tempString);
            PhAppendCharStringBuilder(&stringBuilder, '\n');
            PhDereferenceObject(tempString);
        }

        CloseServiceHandle(serviceHandle);
    }

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveStringBuilder(&stringBuilder, stringBuilder.String->Length / 2 - 1, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}
Beispiel #11
0
/**
 * Formats a text table to a list of lines.
 *
 * \param Table A pointer to the text table.
 * \param Rows The number of rows in the table.
 * \param Columns The number of columns in the table.
 * \param Mode The export formatting mode.
 *
 * \return A list of strings for each line in the output. The list object and
 * string objects are not auto-dereferenced.
 */
PPH_LIST PhaFormatTextTable(
    __in PPH_STRING **Table,
    __in ULONG Rows,
    __in ULONG Columns,
    __in ULONG Mode
    )
{
    PPH_LIST lines;
    // The tab count array contains the number of tabs need to fill the biggest
    // row cell in each column.
    PULONG tabCount;
    ULONG i;
    ULONG j;

    if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES)
    {
        // Create the tab count array.

        PhCreateAlloc(&tabCount, sizeof(ULONG) * Columns);
        PhaDereferenceObject(tabCount);
        memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values

        for (i = 0; i < Rows; i++)
        {
            for (j = 0; j < Columns; j++)
            {
                ULONG newCount;

                if (Table[i][j])
                    newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);
                else
                    newCount = 0;

                // Replace the existing count if this tab count is bigger.
                if (tabCount[j] < newCount)
                    tabCount[j] = newCount;
            }
        }
    }

    // Create the final list of lines by going through each cell and appending
    // the proper tab count (if we are using tabs). This will make sure each column
    // is properly aligned.

    lines = PhCreateList(Rows);

    for (i = 0; i < Rows; i++)
    {
        PH_STRING_BUILDER stringBuilder;

        PhInitializeStringBuilder(&stringBuilder, 100);

        switch (Mode)
        {
        case PH_EXPORT_MODE_TABS:
            {
                for (j = 0; j < Columns; j++)
                {
                    ULONG k;

                    if (Table[i][j])
                    {
                        // Calculate the number of tabs needed.
                        k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE);

                        PhAppendStringBuilder(&stringBuilder, Table[i][j]);
                    }
                    else
                    {
                        k = tabCount[j] + 1;
                    }

                    PhAppendCharStringBuilder2(&stringBuilder, '\t', k);
                }
            }
            break;
        case PH_EXPORT_MODE_SPACES:
            {
                for (j = 0; j < Columns; j++)
                {
                    ULONG k;

                    if (Table[i][j])
                    {
                        // Calculate the number of spaces needed.
                        k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR));

                        PhAppendStringBuilder(&stringBuilder, Table[i][j]);
                    }
                    else
                    {
                        k = (tabCount[j] + 1) * TAB_SIZE;
                    }

                    PhAppendCharStringBuilder2(&stringBuilder, ' ', k);
                }
            }
            break;
        case PH_EXPORT_MODE_CSV:
            {
                for (j = 0; j < Columns; j++)
                {
                    PhAppendCharStringBuilder(&stringBuilder, '\"');

                    if (Table[i][j])
                    {
                        PhpEscapeStringForCsv(&stringBuilder, Table[i][j]);
                    }

                    PhAppendCharStringBuilder(&stringBuilder, '\"');

                    if (j != Columns - 1)
                        PhAppendCharStringBuilder(&stringBuilder, ',');
                }
            }
            break;
        }

        PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder));
    }

    return lines;
}
Beispiel #12
0
PPH_STRING PhGetServiceTooltipText(
    _In_ PPH_SERVICE_ITEM Service
    )
{
    PH_STRING_BUILDER stringBuilder;
    SC_HANDLE serviceHandle;

    PhInitializeStringBuilder(&stringBuilder, 200);

    if (serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_QUERY_CONFIG))
    {
        PPH_STRING fileName;
        PPH_STRING description;

        // File information

        if (fileName = PhGetServiceRelevantFileName(&Service->Name->sr, serviceHandle))
        {
            PH_IMAGE_VERSION_INFO versionInfo;
            PPH_STRING versionInfoText;

            if (PhInitializeImageVersionInfo(
                &versionInfo,
                fileName->Buffer
                ))
            {
                versionInfoText = PhFormatImageVersionInfo(
                    fileName,
                    &versionInfo,
                    &StandardIndent,
                    0
                    );

                if (!PhIsNullOrEmptyString(versionInfoText))
                {
                    PhAppendStringBuilder2(&stringBuilder, L"File:\n");
                    PhAppendStringBuilder(&stringBuilder, &versionInfoText->sr);
                    PhAppendCharStringBuilder(&stringBuilder, '\n');
                }

                PhClearReference(&versionInfoText);
                PhDeleteImageVersionInfo(&versionInfo);
            }

            PhDereferenceObject(fileName);
        }

        // Description

        if (description = PhGetServiceDescription(serviceHandle))
        {
            PhAppendStringBuilder2(&stringBuilder, L"Description:\n    ");
            PhAppendStringBuilder(&stringBuilder, &description->sr);
            PhAppendCharStringBuilder(&stringBuilder, '\n');
            PhDereferenceObject(description);
        }

        CloseServiceHandle(serviceHandle);
    }

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}
Beispiel #13
0
VOID LoadFilterList(
    _Inout_ PPH_LIST FilterList,
    _In_ PPH_STRING String
    )
{
    PH_STRING_BUILDER stringBuilder;
    SIZE_T length;
    SIZE_T i;
    PFILTER_ENTRY entry;

    length = String->Length / 2;
    PhInitializeStringBuilder(&stringBuilder, 20);

    entry = NULL;

    for (i = 0; i < length; i++)
    {
        if (String->Buffer[i] == '\\')
        {
            if (i != length - 1)
            {
                i++;

                switch (String->Buffer[i])
                {
                case 'i':
                case 'e':
                    if (entry)
                    {
                        entry->Filter = PhFinalStringBuilderString(&stringBuilder);
                        PhAddItemList(FilterList, entry);
                        PhInitializeStringBuilder(&stringBuilder, 20);
                    }

                    entry = PhAllocate(sizeof(FILTER_ENTRY));
                    entry->Type = String->Buffer[i] == 'i' ? FilterInclude : FilterExclude;

                    break;

                default:
                    PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
                    break;
                }
            }
            else
            {
                // Trailing backslash. Just ignore it.
                break;
            }
        }
        else
        {
            PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
        }
    }

    if (entry)
    {
        entry->Filter = PhFinalStringBuilderString(&stringBuilder);
        PhAddItemList(FilterList, entry);
    }
    else
    {
        PhDeleteStringBuilder(&stringBuilder);
    }
}
Beispiel #14
0
PPH_STRING PhCmSaveSettingsEx(
    _In_ HWND TreeNewHandle,
    _In_opt_ PPH_CM_MANAGER Manager,
    _In_ ULONG Flags,
    _Out_opt_ PPH_STRING *SortSettings
    )
{
    PH_STRING_BUILDER stringBuilder;
    ULONG i = 0;
    ULONG count = 0;
    ULONG total;
    ULONG increment;
    PH_TREENEW_COLUMN column;

    total = TreeNew_GetColumnCount(TreeNewHandle);

    if (TreeNew_GetFixedColumn(TreeNewHandle))
        increment = 1; // the first normal column should have a display index that starts with 1, for compatibility
    else
        increment = 0;

    PhInitializeStringBuilder(&stringBuilder, 100);

    while (count < total)
    {
        if (TreeNew_GetColumn(TreeNewHandle, i, &column))
        {
            if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
            {
                if (column.Visible)
                {
                    if (!Manager || i < Manager->MinId)
                    {
                        PhAppendFormatStringBuilder(
                            &stringBuilder,
                            L"%u,%u,%u|",
                            i,
                            column.Fixed ? 0 : column.DisplayIndex + increment,
                            column.Width
                            );
                    }
                    else
                    {
                        PPH_CM_COLUMN cmColumn;

                        cmColumn = column.Context;
                        PhAppendFormatStringBuilder(
                            &stringBuilder,
                            L"+%s+%u,%u,%u|",
                            cmColumn->Plugin->Name.Buffer,
                            cmColumn->SubId,
                            column.DisplayIndex + increment,
                            column.Width
                            );
                    }
                }
            }
            else
            {
                if (!Manager || i < Manager->MinId)
                {
                    PhAppendFormatStringBuilder(
                        &stringBuilder,
                        L"%u,,%u|",
                        i,
                        column.Width
                        );
                }
                else
                {
                    PPH_CM_COLUMN cmColumn;

                    cmColumn = column.Context;
                    PhAppendFormatStringBuilder(
                        &stringBuilder,
                        L"+%s+%u,,%u|",
                        cmColumn->Plugin->Name.Buffer,
                        cmColumn->SubId,
                        column.Width
                        );
                }
            }

            count++;
        }

        i++;
    }

    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    if (SortSettings)
    {
        ULONG sortColumn;
        PH_SORT_ORDER sortOrder;

        if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder))
        {
            if (sortOrder != NoSortOrder)
            {
                if (!Manager || sortColumn < Manager->MinId)
                {
                    *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder);
                }
                else
                {
                    PH_TREENEW_COLUMN column;
                    PPH_CM_COLUMN cmColumn;

                    if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column))
                    {
                        cmColumn = column.Context;
                        *SortSettings = PhFormatString(L"+%s+%u,%u", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder);
                    }
                    else
                    {
                        *SortSettings = PhReferenceEmptyString();
                    }
                }
            }
            else
            {
                *SortSettings = PhCreateString(L"0,0");
            }
        }
        else
        {
            *SortSettings = PhReferenceEmptyString();
        }
    }

    return PhFinalStringBuilderString(&stringBuilder);
}
Beispiel #15
0
PPH_STRING PhGetProcessTooltipText(
    __in PPH_PROCESS_ITEM Process
    )
{
    PH_STRING_BUILDER stringBuilder;
    PPH_STRING tempString;

    PhInitializeStringBuilder(&stringBuilder, 200);

    // Command line

    if (Process->CommandLine)
    {
        PhAppendStringBuilder(&stringBuilder, Process->CommandLine);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    // File information

    tempString = PhFormatImageVersionInfo(
        Process->FileName,
        &Process->VersionInfo,
        L"    ",
        0
        );

    if (!PhIsNullOrEmptyString(tempString))
    {
        PhAppendStringBuilder2(&stringBuilder, L"File:\n");
        PhAppendStringBuilder(&stringBuilder, tempString);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    if (tempString)
        PhDereferenceObject(tempString);

    // Known command line information

    if (Process->CommandLine && Process->QueryHandle)
    {
        PH_KNOWN_PROCESS_TYPE knownProcessType;
        PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine;

        if (NT_SUCCESS(PhGetProcessKnownType(
            Process->QueryHandle,
            &knownProcessType
            )) && PhaGetProcessKnownCommandLine(
            Process->CommandLine,
            knownProcessType,
            &knownCommandLine
            ))
        {
            switch (knownProcessType & KnownProcessTypeMask)
            {
            case ServiceHostProcessType:
                PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n    ");
                PhAppendStringBuilder(&stringBuilder, knownCommandLine.ServiceHost.GroupName);
                PhAppendCharStringBuilder(&stringBuilder, '\n');
                break;
            case RunDllAsAppProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;

                    if (PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.RunDllAsApp.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.RunDllAsApp.FileName,
                            &versionInfo,
                            L"    ",
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n");
                            PhAppendStringBuilder(&stringBuilder, tempString);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            case ComSurrogateProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;
                    PPH_STRING guidString;

                    PhAppendStringBuilder2(&stringBuilder, L"COM target:\n");

                    if (knownCommandLine.ComSurrogate.Name)
                    {
                        PhAppendStringBuilder2(&stringBuilder, L"    ");
                        PhAppendStringBuilder(&stringBuilder, knownCommandLine.ComSurrogate.Name);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid))
                    {
                        PhAppendStringBuilder2(&stringBuilder, L"    ");
                        PhAppendStringBuilder(&stringBuilder, guidString);
                        PhDereferenceObject(guidString);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.ComSurrogate.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.ComSurrogate.FileName,
                            &versionInfo,
                            L"    ",
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n");
                            PhAppendStringBuilder(&stringBuilder, tempString);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            }
        }
    }

    // Services

    if (Process->ServiceList && Process->ServiceList->Count != 0)
    {
        ULONG enumerationKey = 0;
        PPH_SERVICE_ITEM serviceItem;
        PPH_LIST serviceList;
        ULONG i;

        // Copy the service list into our own list so we can sort it.

        serviceList = PhCreateList(Process->ServiceList->Count);

        PhAcquireQueuedLockShared(&Process->ServiceListLock);

        while (PhEnumPointerList(
            Process->ServiceList,
            &enumerationKey,
            &serviceItem
            ))
        {
            PhReferenceObject(serviceItem);
            PhAddItemList(serviceList, serviceItem);
        }

        PhReleaseQueuedLockShared(&Process->ServiceListLock);

        qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare);

        PhAppendStringBuilder2(&stringBuilder, L"Services:\n");

        // Add the services.
        for (i = 0; i < serviceList->Count; i++)
        {
            serviceItem = serviceList->Items[i];

            PhAppendStringBuilder2(&stringBuilder, L"    ");
            PhAppendStringBuilder(&stringBuilder, serviceItem->Name);
            PhAppendStringBuilder2(&stringBuilder, L" (");
            PhAppendStringBuilder(&stringBuilder, serviceItem->DisplayName);
            PhAppendStringBuilder2(&stringBuilder, L")\n");
        }

        PhDereferenceObjects(serviceList->Items, serviceList->Count);
        PhDereferenceObject(serviceList);
    }

    // Tasks
    if (PhEqualString2(Process->ProcessName, L"taskeng.exe", TRUE) ||
        PhEqualString2(Process->ProcessName, L"taskhost.exe", TRUE))
    {
        PH_STRING_BUILDER tasks;

        PhInitializeStringBuilder(&tasks, 40);

        PhpFillRunningTasks(Process, &tasks);

        if (tasks.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n");
            PhAppendStringBuilder(&stringBuilder, tasks.String);
        }

        PhDeleteStringBuilder(&tasks);
    }

    // Plugin
    if (PhPluginsEnabled)
    {
        PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText;

        getTooltipText.Parameter = Process;
        getTooltipText.StringBuilder = &stringBuilder;

        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText);
    }

    // Notes

    {
        PH_STRING_BUILDER notes;

        PhInitializeStringBuilder(&notes, 40);

        if (Process->FileName)
        {
            if (Process->VerifyResult == VrTrusted)
            {
                if (!PhIsNullOrEmptyString(Process->VerifySignerName))
                    PhAppendFormatStringBuilder(&notes, L"    Signer: %s\n", Process->VerifySignerName->Buffer);
                else
                    PhAppendStringBuilder2(&notes, L"    Signed.\n");
            }
            else if (Process->VerifyResult == VrUnknown)
            {
                // Nothing
            }
            else if (Process->VerifyResult != VrNoSignature)
            {
                PhAppendStringBuilder2(&notes, L"    Signature invalid.\n");
            }
        }

        if (Process->IsPacked)
        {
            PhAppendFormatStringBuilder(
                &notes,
                L"    Image is probably packed (%u imports over %u modules).\n",
                Process->ImportFunctions,
                Process->ImportModules
                );
        }

        if (Process->ConsoleHostProcessId)
        {
            CLIENT_ID clientId;
            PPH_STRING clientIdString;

            clientId.UniqueProcess = Process->ConsoleHostProcessId;
            clientId.UniqueThread = NULL;

            clientIdString = PhGetClientIdName(&clientId);
            PhAppendFormatStringBuilder(&notes, L"    Console host: %s\n", clientIdString->Buffer);
            PhDereferenceObject(clientIdString);
        }

        if (Process->IsDotNet)
            PhAppendStringBuilder2(&notes, L"    Process is managed (.NET).\n");
        if (Process->IsElevated)
            PhAppendStringBuilder2(&notes, L"    Process is elevated.\n");
        if (Process->IsInJob)
            PhAppendStringBuilder2(&notes, L"    Process is in a job.\n");
        if (Process->IsPosix)
            PhAppendStringBuilder2(&notes, L"    Process is POSIX.\n");
        if (Process->IsWow64)
            PhAppendStringBuilder2(&notes, L"    Process is 32-bit (WOW64).\n");

        if (notes.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Notes:\n");
            PhAppendStringBuilder(&stringBuilder, notes.String);
        }

        PhDeleteStringBuilder(&notes);
    }

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveStringBuilder(&stringBuilder, stringBuilder.String->Length / 2 - 1, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}
BOOLEAN QueryUpdateData(
    _Inout_ PPH_UPDATER_CONTEXT Context
    )
{
    BOOLEAN success = FALSE;
    PPH_HTTP_CONTEXT httpContext = NULL;
    PPH_BYTES jsonString = NULL;
    PVOID jsonObject = NULL;

    if (!PhHttpSocketCreate(&httpContext, NULL))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }

    if (!PhHttpSocketConnect(
        httpContext, 
        L"wj32.org", 
        PH_HTTP_DEFAULT_HTTPS_PORT
        ))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }

    if (!PhHttpSocketBeginRequest(
        httpContext, 
        NULL, 
        L"/processhacker/nightly.php?phupdater", 
        PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE
        ))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }
  
    {
        PPH_STRING versionHeader;
        PPH_STRING windowsHeader;

        if (versionHeader = UpdateVersionString())
        {
            PhHttpSocketAddRequestHeaders(httpContext, versionHeader->Buffer, (ULONG)versionHeader->Length / sizeof(WCHAR));
            PhDereferenceObject(versionHeader);
        }

        if (windowsHeader = UpdateWindowsString())
        {
            PhHttpSocketAddRequestHeaders(httpContext, windowsHeader->Buffer, (ULONG)windowsHeader->Length / sizeof(WCHAR));
            PhDereferenceObject(windowsHeader);
        }
    }

    if (!PhHttpSocketSendRequest(httpContext, NULL, 0))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }

    if (!PhHttpSocketEndRequest(httpContext))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }

    if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE)))
    {
        Context->ErrorCode = GetLastError();
        goto CleanupExit;
    }

    if (!(jsonObject = PhCreateJsonParser(jsonString->Buffer)))
        goto CleanupExit;

    Context->Version = PhGetJsonValueAsString(jsonObject, "version");
    Context->RelDate = PhGetJsonValueAsString(jsonObject, "updated");
    Context->SetupFileDownloadUrl = PhGetJsonValueAsString(jsonObject, "setup_url");
    Context->SetupFileLength = PhFormatSize(PhGetJsonValueAsLong64(jsonObject, "setup_length"), 2);
    Context->SetupFileHash = PhGetJsonValueAsString(jsonObject, "setup_hash");
    Context->SetupFileSignature = PhGetJsonValueAsString(jsonObject, "setup_sig");
    Context->BuildMessage = PhGetJsonValueAsString(jsonObject, "changelog");

    PhFreeJsonParser(jsonObject);

    if (PhIsNullOrEmptyString(Context->Version))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->RelDate))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->SetupFileLength))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->SetupFileHash))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->SetupFileSignature))
        goto CleanupExit;
    if (PhIsNullOrEmptyString(Context->BuildMessage))
        goto CleanupExit;

    success = TRUE;

CleanupExit:

    if (httpContext)
        PhHttpSocketDestroy(httpContext);

    if (jsonString)
        PhDereferenceObject(jsonString);

    if (success && !PhIsNullOrEmptyString(Context->BuildMessage))
    {
        PH_STRING_BUILDER sb;

        PhInitializeStringBuilder(&sb, 0x100);

        for (SIZE_T i = 0; i < Context->BuildMessage->Length / sizeof(WCHAR); i++)
        {
            if (Context->BuildMessage->Data[i] == '\n')
                PhAppendStringBuilder2(&sb, L"\r\n");
            else
                PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]);
        }

        PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb));
    }

    return success;
}
Beispiel #17
0
PPH_STRING PhGetProcessTooltipText(
    _In_ PPH_PROCESS_ITEM Process,
    _Out_opt_ PULONG ValidToTickCount
    )
{
    PH_STRING_BUILDER stringBuilder;
    ULONG validForMs = 60 * 60 * 1000; // 1 hour
    PPH_STRING tempString;
    PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType;

    PhInitializeStringBuilder(&stringBuilder, 200);

    // Command line

    if (Process->CommandLine)
    {
        tempString = PhEllipsisString(Process->CommandLine, 100 * 10);

        // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping
        // algorithm.
        PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL);
        PhAppendCharStringBuilder(&stringBuilder, '\n');

        PhDereferenceObject(tempString);
    }

    // File information

    tempString = PhFormatImageVersionInfo(
        Process->FileName,
        &Process->VersionInfo,
        &StandardIndent,
        0
        );

    if (!PhIsNullOrEmptyString(tempString))
    {
        PhAppendStringBuilder2(&stringBuilder, L"File:\n");
        PhAppendStringBuilder(&stringBuilder, &tempString->sr);
        PhAppendCharStringBuilder(&stringBuilder, '\n');
    }

    if (tempString)
        PhDereferenceObject(tempString);

    // Known command line information

    if (Process->QueryHandle)
        PhGetProcessKnownType(Process->QueryHandle, &knownProcessType);

    if (Process->CommandLine && Process->QueryHandle)
    {
        PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine;

        if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine(
            Process->CommandLine,
            knownProcessType,
            &knownCommandLine
            ))
        {
            switch (knownProcessType & KnownProcessTypeMask)
            {
            case ServiceHostProcessType:
                PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n    ");
                PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr);
                PhAppendCharStringBuilder(&stringBuilder, '\n');
                break;
            case RunDllAsAppProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;

                    if (PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.RunDllAsApp.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.RunDllAsApp.FileName,
                            &versionInfo,
                            &StandardIndent,
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n");
                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            case ComSurrogateProcessType:
                {
                    PH_IMAGE_VERSION_INFO versionInfo;
                    PPH_STRING guidString;

                    PhAppendStringBuilder2(&stringBuilder, L"COM target:\n");

                    if (knownCommandLine.ComSurrogate.Name)
                    {
                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);
                        PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid))
                    {
                        PhAppendStringBuilder(&stringBuilder, &StandardIndent);
                        PhAppendStringBuilder(&stringBuilder, &guidString->sr);
                        PhDereferenceObject(guidString);
                        PhAppendCharStringBuilder(&stringBuilder, '\n');
                    }

                    if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo(
                        &versionInfo,
                        knownCommandLine.ComSurrogate.FileName->Buffer
                        ))
                    {
                        tempString = PhFormatImageVersionInfo(
                            knownCommandLine.ComSurrogate.FileName,
                            &versionInfo,
                            &StandardIndent,
                            0
                            );

                        if (!PhIsNullOrEmptyString(tempString))
                        {
                            PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n");
                            PhAppendStringBuilder(&stringBuilder, &tempString->sr);
                            PhAppendCharStringBuilder(&stringBuilder, '\n');
                        }

                        if (tempString)
                            PhDereferenceObject(tempString);

                        PhDeleteImageVersionInfo(&versionInfo);
                    }
                }
                break;
            }
        }
    }

    // Services

    if (Process->ServiceList && Process->ServiceList->Count != 0)
    {
        ULONG enumerationKey = 0;
        PPH_SERVICE_ITEM serviceItem;
        PPH_LIST serviceList;
        ULONG i;

        // Copy the service list into our own list so we can sort it.

        serviceList = PhCreateList(Process->ServiceList->Count);

        PhAcquireQueuedLockShared(&Process->ServiceListLock);

        while (PhEnumPointerList(
            Process->ServiceList,
            &enumerationKey,
            &serviceItem
            ))
        {
            PhReferenceObject(serviceItem);
            PhAddItemList(serviceList, serviceItem);
        }

        PhReleaseQueuedLockShared(&Process->ServiceListLock);

        qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare);

        PhAppendStringBuilder2(&stringBuilder, L"Services:\n");

        // Add the services.
        for (i = 0; i < serviceList->Count; i++)
        {
            serviceItem = serviceList->Items[i];

            PhAppendStringBuilder(&stringBuilder, &StandardIndent);
            PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr);
            PhAppendStringBuilder2(&stringBuilder, L" (");
            PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr);
            PhAppendStringBuilder2(&stringBuilder, L")\n");
        }

        PhDereferenceObjects(serviceList->Items, serviceList->Count);
        PhDereferenceObject(serviceList);
    }

    // Tasks, Drivers
    switch (knownProcessType & KnownProcessTypeMask)
    {
    case TaskHostProcessType:
        {
            PH_STRING_BUILDER tasks;

            PhInitializeStringBuilder(&tasks, 40);

            PhpFillRunningTasks(Process, &tasks);

            if (tasks.String->Length != 0)
            {
                PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n");
                PhAppendStringBuilder(&stringBuilder, &tasks.String->sr);
            }

            PhDeleteStringBuilder(&tasks);
        }
        break;
    case UmdfHostProcessType:
        {
            PH_STRING_BUILDER drivers;

            PhInitializeStringBuilder(&drivers, 40);

            PhpFillUmdfDrivers(Process, &drivers);

            if (drivers.String->Length != 0)
            {
                PhAppendStringBuilder2(&stringBuilder, L"Drivers:\n");
                PhAppendStringBuilder(&stringBuilder, &drivers.String->sr);
            }

            PhDeleteStringBuilder(&drivers);

            validForMs = 10 * 1000; // 10 seconds
        }
        break;
    }

    // Plugin
    if (PhPluginsEnabled)
    {
        PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText;

        getTooltipText.Parameter = Process;
        getTooltipText.StringBuilder = &stringBuilder;
        getTooltipText.ValidForMs = validForMs;

        PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText);
        validForMs = getTooltipText.ValidForMs;
    }

    // Notes

    {
        PH_STRING_BUILDER notes;

        PhInitializeStringBuilder(&notes, 40);

        if (Process->FileName)
        {
            if (Process->VerifyResult == VrTrusted)
            {
                if (!PhIsNullOrEmptyString(Process->VerifySignerName))
                    PhAppendFormatStringBuilder(&notes, L"    Signer: %s\n", Process->VerifySignerName->Buffer);
                else
                    PhAppendStringBuilder2(&notes, L"    Signed.\n");
            }
            else if (Process->VerifyResult == VrUnknown)
            {
                // Nothing
            }
            else if (Process->VerifyResult != VrNoSignature)
            {
                PhAppendStringBuilder2(&notes, L"    Signature invalid.\n");
            }
        }

        if (Process->IsPacked)
        {
            PhAppendFormatStringBuilder(
                &notes,
                L"    Image is probably packed (%u imports over %u modules).\n",
                Process->ImportFunctions,
                Process->ImportModules
                );
        }

        if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3)
        {
            CLIENT_ID clientId;
            PWSTR description = L"Console host";
            PPH_STRING clientIdString;

            clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3);
            clientId.UniqueThread = NULL;

            if ((ULONG_PTR)Process->ConsoleHostProcessId & 2)
                description = L"Console application";

            clientIdString = PhGetClientIdName(&clientId);
            PhAppendFormatStringBuilder(&notes, L"    %s: %s\n", description, clientIdString->Buffer);
            PhDereferenceObject(clientIdString);
        }

        if (Process->PackageFullName)
        {
            PhAppendFormatStringBuilder(&notes, L"    Package name: %s\n", Process->PackageFullName->Buffer);
        }

        if (Process->IsDotNet)
            PhAppendStringBuilder2(&notes, L"    Process is managed (.NET).\n");
        if (Process->IsElevated)
            PhAppendStringBuilder2(&notes, L"    Process is elevated.\n");
        if (Process->IsImmersive)
            PhAppendStringBuilder2(&notes, L"    Process is a Modern UI app.\n");
        if (Process->IsInJob)
            PhAppendStringBuilder2(&notes, L"    Process is in a job.\n");
        if (Process->IsPosix)
            PhAppendStringBuilder2(&notes, L"    Process is POSIX.\n");
        if (Process->IsWow64)
            PhAppendStringBuilder2(&notes, L"    Process is 32-bit (WOW64).\n");

        if (notes.String->Length != 0)
        {
            PhAppendStringBuilder2(&stringBuilder, L"Notes:\n");
            PhAppendStringBuilder(&stringBuilder, &notes.String->sr);
        }

        PhDeleteStringBuilder(&notes);
    }

    if (ValidToTickCount)
        *ValidToTickCount = GetTickCount() + validForMs;

    // Remove the trailing newline.
    if (stringBuilder.String->Length != 0)
        PhRemoveEndStringBuilder(&stringBuilder, 1);

    return PhFinalStringBuilderString(&stringBuilder);
}