Небольшой вспомогательный класс для управления LPPROC_THREAD_ATTRIBUTE_LISTs

Список LPPROC_THREAD_ATTRIBUTE_LIST требует двух разных действий при завершении: удалить внутренние атрибуты, затем освободить выделенный буфер. Удобно связать этот порядок с временем жизни C++-объекта.

Двухфазная инициализация

Первый вызов InitializeProcThreadAttributeList с nullptr запрашивает размер и по документации ожидаемо возвращает ошибку. После выделения буфера нужен второй вызов. Если он не удался, освобождается только память: удалять ещё не инициализированный список нельзя.

#include <windows.h>
#include <new>
#include <system_error>

struct Attributes final {
    LPPROC_THREAD_ATTRIBUTE_LIST value = nullptr;

    explicit Attributes(DWORD capacity) {
        SIZE_T bytes = 0;
        InitializeProcThreadAttributeList(nullptr, capacity, 0, &bytes);
        if (!bytes)
            throw std::system_error(GetLastError(), std::system_category());
        void* storage = HeapAlloc(GetProcessHeap(), 0, bytes);
        if (!storage) throw std::bad_alloc();
        auto candidate = static_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(storage);
        if (!InitializeProcThreadAttributeList(candidate, capacity, 0, &bytes)) {
            DWORD error = GetLastError();
            HeapFree(GetProcessHeap(), 0, storage);
            throw std::system_error(error, std::system_category());
        }
        value = candidate;
    }
    ~Attributes() {
        if (value) {
            DeleteProcThreadAttributeList(value);
            HeapFree(GetProcessHeap(), 0, value);
        }
    }
    Attributes(const Attributes&) = delete;
    Attributes& operator=(const Attributes&) = delete;
};

Это самостоятельный минимальный пример владения для Windows SDK, без шаблонных WIL-перегрузок. Копирование запрещено, чтобы два объекта не освободили один указатель. Для добавления каждого атрибута вызывайте UpdateProcThreadAttribute и проверяйте результат; память, на которую ссылаются значения, должна оставаться действительной во время использования списка. Для CreateProcess нужны STARTUPINFOEX и флаг EXTENDED_STARTUPINFO_PRESENT.

Схема основана на The Old New Thing от 13 августа 2026 года и проверена по контрактам инициализации и удаления списка. Сборка этого фрагмента в конкретной конфигурации здесь не выполнялась.