Announcement

Collapse
No announcement yet.

DOS-Programmausgabe abfangen...

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • DOS-Programmausgabe abfangen...

    Hallo zusammen
    Ich bin noch ganz neu hier in der Delphi-Welt. Aber ich habe schon viele Erfahrungen in Turbo-Pascal. Nun möchte ich mein Programm, welches das Handling von parameterorientierten Programmen regelte neu für Windows programmieren. Unter DOS habe ich die Ausgabe des "fremden" Programms einfach abgefangen indem ich den Interrupt 29 umbog (Mit Getintvec und Setintvec, falls das jem. interessiert) und die Daten in einen Texteditor umleitete. Unter Delphi geht das aber nicht mehr. Trotzdem möchte ich aber die Bildschirmausgaben irgendwie abfangen und in ein Edit-Fenster kriegen. Kann mir jemand sagen, wie das geht?

  • #2
    Hallo,

    wenn eine <b>Consolen</b>-Anwendung (32-Bit-Programm, das ohne grafische Benutzeroberfläche im Fenster der <i>Eingabeaufforderung</i> ausgeführt wird) entwickelt werden soll, gibt es für diese Aufgabe mehrere Alternativen. <br>
    a) Die Consolenanwendung leitet die <b>Standard-Ausgabe</b> (StdOut) um, so das ein anderes Programm die Ausgabe der Consolenanwendung direkt übernehmen kann. <br>
    b) Ein anderes Programm liest ständig über den Aufruf der Win32-APPI-Funktion <b>ReadConsoleOutput</b> den Inhalt des aktuellen Consolenfensters aus. Dies ist auch dann erfolgreich, wenn StdOut nicht gesondert von der Consolenanwendung gesetzt wird.

    Beispiel für beide Fälle finden sich in meinem neuen (demnächst erscheinenden) Buch <b>Delphi Win32-Lösungen</b>

    Comment


    • #3
      Hallo Herr Kosch

      Vielen Dank für die prompte Reaktion. Die Standard-Ausgabe umzuleiten ist nicht möglich, da ich nicht für alle Programme, die kontrolliert werden sollen den Code habe, also muss ich ReadConsoleOutput verwenden. Aber wie krieg ich das Handle der Anwendung raus, wenn ich sie mit Winexec aufrufe. Funktioniert das auch, wenn ich das Programm mit sw_hide im Hintergrund aufrufe ( WINEXEC(@Programm[1],sw_hide) ) ?

      Matthias Hei

      Comment


      • #4
        Hallo,

        zuerst zur letzten Frage: Ein echtes Verstecken über SW_HIDE ist nicht notwendig, es reicht doch völlig aus, das Fenster über <b>SetWindowPos</b> aus dem sichtbaren Bereich des Desktops hinauszuschlieben (negative Koordinaten). Somit ist es für den Benutzer "unsichtbar".
        Anstelle von <b>WinExec</b> (alte "16-Bit-Funktion") würde ich das 32-Bit-Gegenstück <b>CreateProcess</b> verwenden:

        <pre>

        var
        hConsole : THandle;
        aPI : TProcessInformation;
        hWndPrg : hWnd;
        ...
        // neue Console für diesen Prozess anfordern
        if AllocConsole then
        begin
        StrPCopy(szAppName, EditPrg.Text);
        // TStartupInfo-Datenstruktur initialisieren
        FillChar(aSI, Sizeof(aSI), #0);
        with aSI do begin
        cb := Sizeof(aSI);
        dwFlags := STARTF_USESHOWWINDOW;
        wShowWindow := SW_SHOWDEFAULT;
        end;
        // Programm als neuen Process starten
        if CreateProcess(nil, szAppName, nil, nil, False,
        CREATE_SEPARATE_WOW_VDM or NORMAL_PRIORITY_CLASS,
        nil, nil, aSI, aPI) then
        begin
        // Überschrift des Consolen-Fensters setzen
        SetConsoleTitle(PChar(cTITEL));
        // Handle für den Standard-Output der Console holen
        hConsole := GetStdHandle(STD_OUTPUT_HANDLE);
        ...
        end
        </pre>

        Über <b>ReadConsoleOutput(hConsole,...)</b> wird das in hConsole abgelegte Handle verwendet. Falls das Fensterhandle gesucht wird, hilft der folgende Aufruf weiter:
        <pre>
        var
        szTitel : array[0..254] of Char;
        begin
        // Consolen-Fensterzeilenbeschriftung auslesen
        GetConsoleTitle(szTitel, SizeOf(szTitel));
        // Fensterhandle suchen
        hWndFUSIN := FindWindow(nil, szTitel);
        </pre&gt

        Comment


        • #5
          Hallo

          Jetzt habe ich das ganze mit ReadConsoleOutput probiert. Scheint aber, dass ich doch auf noch zu wackligen Delphi-Füssen stehe.
          Obwohl ich den vordefinierten Code, den ich im Entwicklerforum unter "Betriebssysteme/Win32/Fehlermeldungen im Dosfenster ausdrucken" benutzte, kriegte ich das nicht hin.
          Unten noch einmal der Code für Interessierte (von Andreas Kosch, 01:40pm Nov 15, 1999 GMT):
          Zuerst aber zu meinem neuen Problem, auch nachdem ich "pcInfo" durch "PCharInfo" ersetzte, und alle "btnGrab:=..." entfernte (Kann mir jemand den Sinn dieser Variable erklären?) kriegte ich doch noch jedesmal wenn ich das Programm aufrief einen Speicherzugrifffehler bei der zweiten FOR-Schleife ( sLineBuff := sLineBuff + pGrabBuff^[i * X + j].AsciiChar; ). Wahrscheinlich wurde vorher die Consolenfenstergrösse falsch ermittelt(?). Und so sehr ich mich auch durch die Online-Hilfe schlängle, ich krieg den Fehler nicht raus. Wie krieg ich die Ausgabe von ReadConsoleOutput in ein Memo rein?
          Ach übrigens, was passiert, wenn der Output des Programms länger als die üblichen 25 Consolenzeilen ist?

          MfG Matthias Heim

          Hier nun der Code der von mit benutzten Procedure:

          procedure TFormMain.btnGrabClick(Sender: TObject);
          var
          aDest : TCoord;
          aCSBI : TConsoleScreenBufferInfo;
          i, j : integer;
          sLineBuff : String;
          szOemChar : array[0..254] of Char;
          pGrabBuff : pcInfo;
          begin
          btnGrab.Enabled := False;
          aDest.X := 0;
          aDest.Y := 0;
          try
          // Eigenschaften (Breite+Höhe) des Consolenfensters auslesen
          GetConsoleScreenBufferInfo(hConsole, aCSBI);
          // Platz für den Zeilenpuffer reservieren
          SetLength(sLineBuff, aCSBI.dwMaximumWindowSize.X + 1);
          // Platz für den Consolenpuffer reservieren
          // (= Breite * Höhe * Größe von TCharInfo)
          with aCSBI.dwMaximumWindowSize do
          GetMem(pGrabBuff, X * Y * SizeOf(TCharInfo));
          try
          // Inhalt des Consolen-Fensters in den Puffer einlesen
          with aCSBI do
          ReadConsoleOutput(hConsole, pGrabBuff,
          dwMaximumWindowSize, aDest, srWindow);
          // Daten aus dem Puffer in die TMemo-Instanz einsetzen
          Memo1.Clear;
          with aCSBI.dwMaximumWindowSize do begin
          // Inhalt des Consolenfensters Zeilenweise auslesen
          for i := 0 to Y - 1 do begin
          // Zeilenpuffer leeren
          sLineBuff := '';
          // alle Zeichen dieser Zeile in den Zeilenpuffer kopieren
          for j := 1 to X do
          sLineBuff := sLineBuff + pGrabBuff^[i * X + j].AsciiChar;
          // Zeichensatz (OEM) nach ANSI konvertieren
          OemToChar(PChar(sLineBuff), szOemChar);
          // gefüllten Zeilenpuffer in die TMemo-Instanz einsetzen
          Memo1.Lines.Add(szOemChar);
          end;
          end;
          StatBar.Panels[1].Text := Format('%d x %d Zeichen',
          [aCSBI.dwMaximumWindowSize.X,
          aCSBI.dwMaximumWindowSize.Y]);
          finally
          Freemem(pGrabBuff);
          end;
          finally
          btnGrab.Enabled := true;
          end;
          end

          Comment


          • #6
            Sorry für die fürchterliche Formatierung. (Bin selbst erschrocken). Aber ich kann kein Wort HTML (Eine Bildungslücke, ich weiss).
            Unter "Entwickler Forum/Betriebssysteme/Win32/fehlermeldungen im dosfenster ausdrucken!!" findet ihr den Quelltext besser formatiert.

            Matthia

            Comment


            • #7
              Hallo

              Ich habe gesehen, dass man bei CreateProcess über Startupinformationen auch einen Parameter "Handle Stdoutput" übergeben kann. Ist es nicht auch möglich, die Daten über dieses Handle abzuleiten. Wenn ja, wie?

              MfG Matthia

              Comment

              Working...
              X