2017-09-20 13 views
0

こんにちは、これは、スタックオーバーフロー 上の私の最初の質問です開くことができます(イムジュニアプログラマ:私が作るgramatical間違いを事前に謝罪だから...あまりにもPとフランス語)どのように私は別のコンソールに出力テキストすでにC++

Imはここでは、その出力

(ノークラッシュエラーがない単なる虚無)

を書くために戻って、親のコンソールに接続する昇格プロセスを開始しようとしているが、私のコードです:

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

を直接、子プロセスと通信するために私が知っている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

最初の例は、書面によるOPとは関係ありません。せいぜい 'ShellExecuteEx'は、親と子のコンソールアプリケーション間の暗黙の標準ハンドル継承しかサポートしていません。その上、OPは "runas"を介して昇格しています。アプリケーション情報サービスは、 'bInheritHandles = FALSE'と' CREATE_NEW_CONSOLE'フラグなしで 'CreateProcessAsUser'を呼び出します。したがって暗黙的な継承のための機会はありません。別の方法として、名前付きパイプを使用してコマンドラインで名前を渡す方法があります。 – eryksun

+0

これは、 '' bInheritHandles = FALSE'で "CreateProcessAsUser' *を呼び出しているはずです。私はもともと「継承なし」と入力し、編集を不明瞭にしました。 – eryksun

0

はFinnaly私は、引数によって子プロセスに親PIDを通過した後、私が使用し

を望んでいたものを達成する方法を発見しましたAttachConsole(PID)

voila!みんな

+1

'ATTACH_PARENT_PROCESS'が動作するはずです。昇格プロセスを作成するアプリケーション情報サービスは、 'PROC_THREAD_ATTRIBUTE_PARENT_PROCESS'作成アトリビュート を使用して、要求プロセスを親プロセス(この場合は' ShellExecuteEx'を呼び出すプロセス)として設定します。 – eryksun

関連する問題