none
Callback Funktion für Standardausgaben von Konsolen-Programmen? RRS feed

  • Frage

  • Hallo Forum

    Wenn ich ein Konsolen-Programm von meinem Programm aus starten will und dann aber alle Ausgaben auf die Standardausgabe selber bekommen will ... wie mache ich das?

    Ich würde mir wünschen, dass ich die Standardausgabe irgendwie auf mein Programm umleiten könnte und dann mit _spawnlp (oder ähnlich) ein Konsolenprogramm aufrufen. Die Ausgabe dieses Programms sollte dann irgendwie zu mir rein kommen.

    Ist so was mit vertretbarem Aufwand möglich?

    Grüße

    FireHeart

    Dienstag, 20. Dezember 2016 15:12

Antworten

  • Hier mein Vorschlag:

    HANDLE hOutputRead, hOutputWrite, hErrorWrite;
    HANDLE hInputWrite, hInputRead;
    
    SECURITY_ATTRIBUTES sa;
      sa.nLength = sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;
    
    ::CreatePipe(&hOutputRead, &hOutputWrite, &sa, 0);
    ::CreatePipe(&hInputRead, &hInputWrite, &sa, 0);
    ::DuplicateHandle(::GetCurrentProcess(), hOutputWrite, ::GetCurrentProcess(), &hErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS);
    
    ::SetHandleInformation(hOutputRead, HANDLE_FLAG_INHERIT, 0);
    ::SetHandleInformation(hInputWrite, HANDLE_FLAG_INHERIT, 0);
    
    STARTUPINFO si;
      memset(&si, 0, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.hStdOutput = hOutputWrite;
      si.hStdInput = hInputRead;
      si.hStdError = hErrorWrite;
    
      // Use this if you want to hide the child:
      //     si.wShowWindow = SW_HIDE;
      // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
      // use the wShowWindow flags.
    
    PROCESS_INFORMATION pi;
    
    // more info on  http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/94275f12-7fab-4dd4-b38b-d8a3047a6b5a/
    
    wchar_t strParam[MAX_PATH];
    swprintf(strParam, MAX_PATH, L"path.exe /whatever"); // exe expects its name as first param
    
    if(!::CreateProcessW(L"path.exe", strParam, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, strDirectoryPath, &si, &pi))
    {
      // handle error -> GetLastError
    
      ::CloseHandle(hOutputWrite);
      ::CloseHandle(hInputRead);
      ::CloseHandle(hErrorWrite);
    
      ::CloseHandle(hOutputRead);
      ::CloseHandle(hInputWrite);
    
      return -1;
    }
    
    ::CloseHandle(pi.hThread); // we don't need it
    
    // close handles we passed -> now the process is responsible for closing them
    ::CloseHandle(hOutputWrite);
    ::CloseHandle(hInputRead);
    ::CloseHandle(hErrorWrite);
    
    // read pipe until the process terminates
    
    int iResult = 0;
    
    char strBuffer[256];
    DWORD rd;
    
    while(true)
    {
      if(!ReadFile(hOutputRead, strBuffer, 256, &rd, NULL))
      {
        if(::GetLastError() == ERROR_BROKEN_PIPE)
          break; // terminated
        else
        {
          // process terminated in an unusual way -> GetLastError
    
          iResult = -1;
          break;
        }
      }
    
      INT iTest = IS_TEXT_UNICODE_CONTROLS;
    
      if(::IsTextUnicode(strBuffer, rd, &iTest))
        wprintf((wchar_t *)strBuffer);
      else
        printf((char *)strBuffer);
    }
    
    ::CloseHandle(pi.hProcess);
    
    ::CloseHandle(hOutputRead);
    ::CloseHandle(hInputWrite);

    Rudolf


    Dienstag, 20. Dezember 2016 22:27

Alle Antworten

  • Hi,

    C++ ist zwar nicht meine Welt, lt. MSDN geht das aber identisch wie auch bei C# und VB.NET.

      https://msdn.microsoft.com/de-de/library/system.diagnostics.process.standardoutput.aspx

    Dort findest Du auch ein Codebeispiel.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    • Bearbeitet Stefan Falz Mittwoch, 21. Dezember 2016 08:51
    Dienstag, 20. Dezember 2016 16:05
  • Hier mein Vorschlag:

    HANDLE hOutputRead, hOutputWrite, hErrorWrite;
    HANDLE hInputWrite, hInputRead;
    
    SECURITY_ATTRIBUTES sa;
      sa.nLength = sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;
    
    ::CreatePipe(&hOutputRead, &hOutputWrite, &sa, 0);
    ::CreatePipe(&hInputRead, &hInputWrite, &sa, 0);
    ::DuplicateHandle(::GetCurrentProcess(), hOutputWrite, ::GetCurrentProcess(), &hErrorWrite, 0, TRUE, DUPLICATE_SAME_ACCESS);
    
    ::SetHandleInformation(hOutputRead, HANDLE_FLAG_INHERIT, 0);
    ::SetHandleInformation(hInputWrite, HANDLE_FLAG_INHERIT, 0);
    
    STARTUPINFO si;
      memset(&si, 0, sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.hStdOutput = hOutputWrite;
      si.hStdInput = hInputRead;
      si.hStdError = hErrorWrite;
    
      // Use this if you want to hide the child:
      //     si.wShowWindow = SW_HIDE;
      // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
      // use the wShowWindow flags.
    
    PROCESS_INFORMATION pi;
    
    // more info on  http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/94275f12-7fab-4dd4-b38b-d8a3047a6b5a/
    
    wchar_t strParam[MAX_PATH];
    swprintf(strParam, MAX_PATH, L"path.exe /whatever"); // exe expects its name as first param
    
    if(!::CreateProcessW(L"path.exe", strParam, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, strDirectoryPath, &si, &pi))
    {
      // handle error -> GetLastError
    
      ::CloseHandle(hOutputWrite);
      ::CloseHandle(hInputRead);
      ::CloseHandle(hErrorWrite);
    
      ::CloseHandle(hOutputRead);
      ::CloseHandle(hInputWrite);
    
      return -1;
    }
    
    ::CloseHandle(pi.hThread); // we don't need it
    
    // close handles we passed -> now the process is responsible for closing them
    ::CloseHandle(hOutputWrite);
    ::CloseHandle(hInputRead);
    ::CloseHandle(hErrorWrite);
    
    // read pipe until the process terminates
    
    int iResult = 0;
    
    char strBuffer[256];
    DWORD rd;
    
    while(true)
    {
      if(!ReadFile(hOutputRead, strBuffer, 256, &rd, NULL))
      {
        if(::GetLastError() == ERROR_BROKEN_PIPE)
          break; // terminated
        else
        {
          // process terminated in an unusual way -> GetLastError
    
          iResult = -1;
          break;
        }
      }
    
      INT iTest = IS_TEXT_UNICODE_CONTROLS;
    
      if(::IsTextUnicode(strBuffer, rd, &iTest))
        wprintf((wchar_t *)strBuffer);
      else
        printf((char *)strBuffer);
    }
    
    ::CloseHandle(pi.hProcess);
    
    ::CloseHandle(hOutputRead);
    ::CloseHandle(hInputWrite);

    Rudolf


    Dienstag, 20. Dezember 2016 22:27
  • Hallo Rudolf

    Das sieht auf den ersten Blick vielversprechend aus. Ich werde mir das mal reinziehen....

    Danke

    FireHeart

    Donnerstag, 22. Dezember 2016 08:05