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

匿名 (未验证) 提交于 2019-12-03 01:38:01

问题:

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



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