问题
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