嗨,这是我关于堆栈溢出的第一个问题 (我是一名初级程序员: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 :(得分:2)
我知道有两种方法可以直接与子进程通信。一种是使用管道..这允许您写入子进程并从中读取: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;
}
它的工作原理是创建一个带有输入输出句柄的子进程...然后创建一个不断轮询/读取管道的线程,并打印出它正在编写的内容。完成后清理..
下一种方法是根据WinAPI文档调用AttachConsole(ATTACH_PARENT_PROCESS)
..这会将子进程附加到父进程的控制台。完成后需要调用FreeConsole
以从父进程的控制台分离:https://docs.microsoft.com/en-us/windows/console/attachconsole
答案 1 :(得分:0)
Finnaly我找到了实现我想要的方法
我通过参数将父PID传递给子进程,然后我使用了AttachConsole(PID)
瞧!
感谢大家的帮助