winapi — Как вывести текст на другую консоль, уже открытую Переполнение стека

Привет это мой первый вопрос по переполнению стека
(Я младший программист: P и французский тоже … Так что заранее извиняюсь за грубую ошибку, которую я делаю)

Я пытаюсь запустить процесс с повышенными правами, чтобы прикрепить обратно к консоли родителя, чтобы записать свой вывод

(без сбоев, без ошибок, просто простота)

Вот мой код:

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);
}
}
}

И из класса UAC, который я написал:

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;
};

0

Решение

Есть два способа, которыми я знаю, чтобы общаться с дочерним процессом напрямую. Один из них — использовать каналы. Это позволяет вам писать дочернему процессу, а также читать из него: 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;
}

Он работает, создавая дочерний процесс с дескриптором ввода-вывода в канал … затем создайте поток, который постоянно опрашивает / читает канал и выводит на печать все, что он пишет … очистка после завершения …

Следующий способ — позвонить AttachConsole(ATTACH_PARENT_PROCESS) в соответствии с документацией WinAPI. Это прикрепит дочерний процесс к консоли родительского процесса. Вам нужно позвонить FreeConsole когда сделано, чтобы отсоединиться от консоли родительского процесса: https://docs.microsoft.com/en-us/windows/console/attachconsole

2

Другие решения

В конце концов я нашел способ добиться того, чего хотел

Я передал родительский PID дочернему процессу по аргументу, а затем использовал AttachConsole (PID)

вуаля!

Спасибо всем за помощь

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector