How can I output text to another console already open C++

半城伤御伤魂 提交于 2019-12-08 11:21:42

问题


Hi this is my first question on stack overflow (Im a junior programmer :P and french too...So apologies in advance for gramatical mistake I make)

Im trying to start a elevated process to attach back to the console of the parent to write its output

(no crash no error just plain nothingness)

Here is my code:

int main(int argc, char *argv[])
{

    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    if (UAC::IsAppRunningAsAdminMode())
    {
        printf("Process Already elevated\nChecking if self invocated from unprevileged previous run...\n");
         if (argc > 1)
        {
            std::string consoleTextOutputBuffer("Elevated privileges session started...\n");
             WriteConsoleA((HANDLE)argv[2], consoleTextOutputBuffer.c_str(), consoleTextOutputBuffer.size(), NULL, NULL);
        }
    }
    else
    {
        printf("Process need elevation...\n");
        if (UAC::BeginPrivilegeElevationPrompt(consoleHandle))
        {
            printf("Elevation succesfull!\n");
        }
        else
        {
            printf("Elevation failed\n");
            system("pause>nul");
            exit(-1);
        }
    }
}

And From the class UAC that I wrote:

BOOL BeginPrivilegeElevationPrompt(const HANDLE& oldConsoleHandle)
{
    wchar_t szPath[MAX_PATH];
    if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
    {
        // Launch itself as admin
        std::string oldConsoleHandleToString = std::to_string((int)oldConsoleHandle);
        std::wstring wsConsoleString(oldConsoleHandleToString.begin(), oldConsoleHandleToString.end());
        SHELLEXECUTEINFO sei = { sizeof(sei) };
        sei.lpVerb = L"runas";
        sei.lpFile = szPath;
        sei.hwnd = NULL;
        sei.lpParameters = wsConsoleString.c_str();
        sei.nShow = SW_NORMAL;
        if (!ShellExecuteEx(&sei))
        {
            DWORD dwError = GetLastError();
            if (dwError == ERROR_CANCELLED)
            {
                // The user refused to allow privileges elevation.
                printf("User did not allow elevation.\n");
                return false;
            }
            return false;
        }
        else
        {
            return true;
            _exit(1);  // Quit itself
        }
    }
    printf("Could not load module name.\n");
    return false;
};

回答1:


There are TWO ways that I know of to communicate with a child process directly.. One is to use pipes.. This allows you to write to the child process and also read from it: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx

#include <windows.h>
#include <string>
#include <fstream>
#include <thread>
#include <chrono>

PROCESS_INFORMATION CreateChildProcess(std::string CommandLine, std::string StartDirectory, DWORD WaitTime, HANDLE hInRead, HANDLE hOutWrite)
{
    STARTUPINFO SI;
    PROCESS_INFORMATION PI;
    ZeroMemory(&SI, sizeof(SI));
    ZeroMemory(&PI, sizeof(PI));

    SI.cb = sizeof(SI);
    SI.hStdInput = hInRead;
    SI.hStdError = hOutWrite;
    SI.hStdOutput = hOutWrite;
    SI.dwFlags |= STARTF_USESTDHANDLES;

    bool success = CreateProcess(0, &CommandLine[0], 0, 0, true, NORMAL_PRIORITY_CLASS, 0, StartDirectory.c_str(), &SI, &PI);

    if (success)
    {
        if (WaitTime != 0)
        {
            WaitForSingleObject(PI.hProcess, WaitTime);
            CloseHandle(PI.hProcess);
            CloseHandle(PI.hThread);
            return {0};
        }
        return PI;
    }

    return {0};
}


void RedirectInputPipe(HANDLE& hRead, HANDLE& hWrite)
{
    SECURITY_ATTRIBUTES attr;
    ZeroMemory(&attr, sizeof(attr));
    attr.nLength = sizeof(attr);
    attr.bInheritHandle = true;

    CreatePipe(&hRead, &hWrite, &attr, 0);
    SetHandleInformation(hWrite, HANDLE_FLAG_INHERIT, 0);
}


void RedirectOutputPipe(HANDLE& hRead, HANDLE& hWrite)
{
    SECURITY_ATTRIBUTES attr;
    ZeroMemory(&attr, sizeof(attr));
    attr.nLength = sizeof(attr);
    attr.bInheritHandle = true;

    CreatePipe(&hRead, &hWrite, &attr, 0);
    SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
}

bool ReadPipe(HANDLE hOutput, std::string& Buffer)
{
    DWORD dwRead = 0;
    Buffer.clear();
    Buffer.resize(256);
    bool Result = ReadFile(hOutput, &Buffer[0], Buffer.size(), &dwRead, NULL);
    Buffer.resize(dwRead);
    return Result && dwRead;
}

bool WritePipe(HANDLE hInput, const char* Buffer, unsigned int BufferSize)
{
    DWORD dwWritten = 0;
    return WriteFile(hInput, Buffer, BufferSize, &dwWritten, NULL) && (dwWritten == BufferSize);
}

void HandleRead(HANDLE hOutputRead, bool &Termination)
{
    std::string Buffer;
    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    while(!Termination)
    {
        if (!ReadPipe(hOutputRead, Buffer))
        {
            if (GetLastError() == ERROR_BROKEN_PIPE)
                break;
        }

        WritePipe(ConsoleOutput, Buffer.c_str(), Buffer.size());
        if (output)
        {
            std::cout.write(Buffer.c_str(), Buffer.size());
        }
        Buffer.clear();
    }

    CloseHandle(ConsoleOutput);
}

int main()
{
    std::string process = "ChildProcess.exe";
    std::string startdir = "C:/Users/Brandon/Desktop/Test/bin";


    HANDLE hInputRead, hInputWrite, hOutputRead, hOutputWrite;
    RedirectInputPipe(hInputRead, hInputWrite);
    RedirectOutputPipe(hOutputRead, hOutputWrite);

    PROCESS_INFORMATION PI = CreateChildProcess(process, startdir, 0, hInputRead, hOutputWrite);

    bool Termination = false;
    std::thread(HandleRead, hOutputRead, std::ref(Termination)).detach();
    WaitForSingleObject(PI.hProcess, INFINITE);
    Termination = true;
    CloseHandle(PI.hProcess);
    CloseHandle(PI.hThread);
    CloseHandle(hInputRead);
    CloseHandle(hInputWrite);
    CloseHandle(hOutputRead);
    CloseHandle(hOutputWrite);

    return 0;
}

It works by creating the child process with an input output handle to a pipe.. then create a thread that constantly polls/reads the pipe and prints out whatever it is writing.. cleanup when done..

The next way is to call AttachConsole(ATTACH_PARENT_PROCESS) according to the WinAPI docs.. This will attach the child process to the parent process' console. You need to call FreeConsole when done to detach from the parent process' console: https://docs.microsoft.com/en-us/windows/console/attachconsole




回答2:


Finnaly I found a way to achieve what I wanted

I passed the parent PID to the child process by argument and then I used AttachConsole(PID)

voila!

Thank for the help of everyone



来源:https://stackoverflow.com/questions/46311795/how-can-i-output-text-to-another-console-already-open-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!