Вспомогательный класс для управления LPPROC_THREAD_ATTRIBUTE_LIST

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

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

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

#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 без дополнительных оболочек. Копирование запрещено, чтобы два объекта не попытались освободить один указатель. Для добавления каждого атрибута следует вызывать UpdateProcThreadAttribute и проверять результат; память, на которую ссылаются значения атрибутов, должна оставаться действительной до вызова DeleteProcThreadAttributeList. Для создания процесса с расширённой информацией необходима структура STARTUPINFOEX и флаг EXTENDED_STARTUPINFO_PRESENT при вызове CreateProcess.

Перед использованием примера проверьте его сборку и обработку ошибок в целевой конфигурации Windows SDK.