带有 EXTENDED_STARTUPINFO_PRESENT 标志的 CreateProcessW() 返回错误代码 87?

问题描述 投票:0回答:1

我正在努力让 CreateProcessW 在 msvc 下使用 EXTENDED_STARTUPINFO_PRESENT 选项。我创建了一个最小的示例,它调用 ping.exe 并将标准输出重定向到句柄。如果没有 EXTENDED_STARTUPINFO_PRESENT 选项,这也可以正常工作(但不是线程安全的),因此尝试将句柄显式传递给子进程,如下面的最小示例所示。

#include <windows.h> 
#include <processthreadsapi.h>
#include <WinBase.h>
#include <iostream>
using namespace std;


void TestFunctionW()
{
    STARTUPINFOEXW startup_info = { 0 };
    PROCESS_INFORMATION process_info = { 0 };

    SECURITY_ATTRIBUTES saAttr;

    // Set the bInheritHandle flag so pipe handles are inherited. 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    HANDLE          m_hChildStd_OUT_Rd;
    HANDLE          m_hChildStd_OUT_Wr;

    // Create a pipe for the child process's STDOUT. (m_hChildStd_OUT_Wr->m_hChildStd_OUT_Rd)
    if (!CreatePipe(&m_hChildStd_OUT_Rd, &m_hChildStd_OUT_Wr, &saAttr, 0)) {
        std::cerr << "CreatePipe Failed" << endl;
    }

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(m_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)){
        std::cerr << "SetHandleInformation Failed" << endl;
    }


    startup_info.StartupInfo.hStdError = NULL;
    startup_info.StartupInfo.hStdOutput = m_hChildStd_OUT_Wr;
    startup_info.StartupInfo.hStdInput = NULL;
    startup_info.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;


    // Newstuff relating to handle lists
    BOOL fSuccess = true;
    BOOL fInitialized = FALSE;
    SIZE_T size = 0;
    LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;

    int cHandlesToInherit = 2;
    HANDLE rgHandlesToInherit[] = { m_hChildStd_OUT_Wr, m_hChildStd_OUT_Rd };

    if (fSuccess) {
        fSuccess = InitializeProcThreadAttributeList(NULL, 1, 0, &size) || GetLastError() == ERROR_INSUFFICIENT_BUFFER;
    }
    if (fSuccess) {
        lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, size));
        fSuccess = lpAttributeList != NULL;
    }
    if (fSuccess) {
        fSuccess = InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &size);
    }
    if (fSuccess) {
        fInitialized = TRUE;
        fSuccess = UpdateProcThreadAttribute(lpAttributeList,
            0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
            rgHandlesToInherit,
            cHandlesToInherit * sizeof(HANDLE), NULL, NULL);
    }

    if (!fSuccess) {
        cerr << "Handle list stuff failed" << endl;
        exit(-1);
    }

    startup_info.lpAttributeList = lpAttributeList;

    cerr << "Handle stuff succeeded.." << endl;


    startup_info.StartupInfo.cb = sizeof(startup_info);

    DWORD flags = EXTENDED_STARTUPINFO_PRESENT;
    //DWORD flags = 0;

    std::wstring cmd(L"ping.exe");
    BOOL ret = CreateProcessW(NULL, (LPWSTR)cmd.c_str(), NULL, NULL, FALSE, flags, NULL, NULL, (LPSTARTUPINFOW)&startup_info, &process_info);
    if (!ret)
    {
        DWORD err = GetLastError();
        std::cout << "Failed: code " << err << std::endl;
    }
}

int main(int argc, char* argv)
{
    TestFunctionW();
}

错误代码 87 似乎意味着参数无效。

我在 MSVC 2017 下编译了该示例。没有选项 DWORD flags = EXTENDED_STARTUPINFO_PRESENT;它工作正常(如预期),使用该选项会失败并显示错误代码 87(不是预期的)。

c++ winapi visual-c++
1个回答
1
投票

根据https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute

使用时必须启用句柄继承

PROC_THREAD_ATTRIBUTE_HANDLE_LIST

注意,如果使用此属性,请为

TRUE
函数的
bInheritHandles
参数传入
CreateProcess
值。

这是第五个参数,您将在其中传递

FALSE
。因此句柄不会被继承,并且在子进程中句柄无效 -> 错误 87。

© www.soinside.com 2019 - 2024. All rights reserved.