2017-09-20 27 views
0

안녕하세요이 스택 오버 플로우 내 첫 번째 질문입니다 출력 텍스트 (임 주니어 프로그래머 : gramatical 실수에 미리 사과는 내가 만들 그래서 P 너무 불어 ...)어떻게 내가 이미 다른 콘솔 열린 C++

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

제목은 질문이지만, 귀하의 코드와 어떤 관련이 있는지 잘 모르겠습니다. 그것은 작동하지 않는 것은 무엇입니까? –

+0

콘솔 화면 버퍼 핸들 값은 상승 된 프로세스에서 의미가 없습니다. 논쟁으로 그것을 전달하는 것은 무의미하다. 출력을 쓰려면 상위 콘솔에 다시 연결하는 상승 된 프로세스를 찾고 있습니까? 가능합니다. – eryksun

+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)을 호출하는 것입니다. 이것은 자식 프로세스를 부모 프로세스의 콘솔에 연결합니다. https://docs.microsoft.com/en-us/windows/console/attachconsole

+1

첫 번째 예는 OP와 관련이 없습니다. 기껏해야'ShellExecuteEx'는 부모와 자식 콘솔 어플리케이션 간의 암시 적 표준 핸들 상속만을 지원합니다. 그 외에, OP는 "runas"를 통해 승격되고 있습니다. 응용 프로그램 정보 서비스는 요청을'bInheritHandles = FALSE' 및'CREATE_NEW_CONSOLE' 플래그없이'CreateProcessAsUser'를 호출합니다. 암묵적인 상속을위한 기회조차 없습니다. 또 다른 방법은 명명 된 파이프를 사용하고 명령 줄에서 이름을 전달하는 것입니다. – eryksun

+0

"bInheritHandles = FALSE'로"CreateProcessAsUser' *를 호출합니다. 원래 "상속없이"입력하고 분명히 편집을 더듬습니다. – eryksun

0

가 Finnaly 나는 내가 인수로 자식 프로세스에 부모 PID를 통과

원하는 것을 달성 할 수있는 방법을 발견하고 내가 사용 : 부모 프로세스에서 '콘솔을 분리 할 때 FreeConsole를 호출 할 필요가 AttachConsole (PID)

voila!

모두의 도움에 감사드립니다.

+1

'ATTACH_PARENT_PROCESS'가 작동해야합니다. 상승 된 프로세스를 생성하는 응용 프로그램 정보 서비스는 'PROC_THREAD_ATTRIBUTE_PARENT_PROCESS' 생성 속성 인 을 사용하여 요청 프로세스를 부모 프로세스 (이 경우'ShellExecuteEx '를 호출하는 프로세스)로 설정합니다. – eryksun