C++ cmd 在我的程序输出之前显示当前目录

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

我已经制作了一个程序,如果它从

cmd
运行,它会附加到控制台,创建一个子进程,并将子进程的输出重定向到控制台。

程序运行良好,但有一个烦人的问题:由于某种原因,当我从 Windows 终端运行我的程序时,显示当前目录的行显示在程序输出之前:

程序本身在输出后关闭(可执行文件在任务管理器中不可见)。

在我按下 Enter 后(其他键都不起作用,我什至可以输入批处理命令并且它们起作用,例如

echo hello
并且它会显示
hello
):

程序如下:

#include <future>
#include <Windows.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>

// help binding IOs to the attached console
void bindCrtHandleToStdHandle()
{
    FILE* dummyFile;
    freopen_s(&dummyFile, "nul", "w", stdout);

    // Redirect unbuffered stdout to the current standard output handle
    HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (stdHandle != INVALID_HANDLE_VALUE)
    {
        int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
        if (fileDescriptor != -1)
        {
            FILE* file = _fdopen(fileDescriptor, "w");
            if (file != NULL)
            {
                int dup2Result = _dup2(_fileno(file), _fileno(stdout));
                if (dup2Result == 0)
                {
                    setvbuf(stdout, NULL, _IONBF, 0);
                }
            }
        }
    }
    std::cout.clear();
}

void readOutput(HANDLE hStdoutRead, std::atomic<bool>& exit) {
    const int bufferSize = 4096;
    char buffer[bufferSize];
    DWORD bytesRead;

    while (!exit) {
        // Check if there is data available to read from the pipe
        bool peekSuccess = PeekNamedPipe(hStdoutRead, NULL, 0, NULL, &bytesRead, NULL);
        if (!peekSuccess || bytesRead == 0) {
            // No data available, sleep for a short time before checking again
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            continue;
        }

        bool readSuccess = ReadFile(hStdoutRead, buffer, bufferSize, &bytesRead, NULL);
        if (readSuccess && bytesRead > 0) {
            std::cout.write(buffer, bytesRead);
        }
    }
}

int APIENTRY wWinMain(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine,
    _In_ int nShowCmd
)
{
    // Attach to the console is run from cmd to redirect stdout from the child process
    bool runFromConsole = AttachConsole(ATTACH_PARENT_PROCESS);
    if (runFromConsole) {
        bindCrtHandleToStdHandle();
    }

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    HANDLE hStdoutRead, hStdoutWrite;
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&hStdoutRead, &hStdoutWrite, &saAttr, 0)) {
        return EXIT_FAILURE;
    }

    // Auto close the handles
    std::unique_ptr<void, decltype(&CloseHandle)> stdoutReadHandle(hStdoutRead, &CloseHandle);
    std::unique_ptr<void, decltype(&CloseHandle)> stdoutWriteHandle(hStdoutWrite, &CloseHandle);

    // Ensure the read handle to the pipe for stdout is not inherited.
    if (!SetHandleInformation(hStdoutRead, HANDLE_FLAG_INHERIT, 0)) {
        return EXIT_FAILURE;
    }

    si.hStdOutput = hStdoutWrite;
    si.dwFlags |= STARTF_USESTDHANDLES;

    std::wstring commandLine = L"hello.exe";
    if (!CreateProcessW(
        NULL,
        &commandLine[0],
        NULL,
        NULL,
        TRUE,
        CREATE_UNICODE_ENVIRONMENT,
        NULL,
        NULL,
        &si,
        &pi)
        )
    {
        return EXIT_FAILURE;
    }

    // Launch the threads to read from the pipes
    std::atomic<bool> exit(false);
    std::thread outputThread(readOutput, hStdoutRead, std::ref(exit));

    // Wait for the process to finish
    WaitForSingleObject(pi.hProcess, INFINITE);
    exit = true;

    // Wait for the threads to finish
    outputThread.join();

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return EXIT_SUCCESS;
}

hello.exe
测试程序:

int main()
{
    std::cout << "HELLO WORLD!" << std::endl;

    return 0;
}

此外,我注意到如果我使用

program.exe > out.txt & pause
从批处理脚本调用我的程序,输出不会重定向到文件,而是在控制台中可见。但是,如果我在现有终端中执行
program.exe > out.txt
,则文件或终端中没有输出。

对于某些上下文,我的程序的作用是修改环境变量并将它们传递给另一个程序,它可以是控制台应用程序或 GUI 应用程序。这就是为什么我需要

wWinMain()
并连接到控制台(如果有的话)的原因。

有什么想法吗?

c++ windows winapi
© www.soinside.com 2019 - 2024. All rights reserved.