Announcement

Collapse
No announcement yet.

Bildschirminhalt einer DOS-Anwendung auslesen

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

  • Bildschirminhalt einer DOS-Anwendung auslesen

    Wir verwenden im Windows-Fenster eine alte DOS-Anwendung (leider zur Zeit keine WIN-Alternative existent).

    Weiß jemand eine Möglichkeit, den Inhalt des DOS-Fensters auszulesen (Damit ich weiß, an welcher Stelle im Anwendungsablauf das Fenster sich befindet.) und die vom Anwender getätigten Eingaben mitzuverfolgen. Der Sinn des Ganzen ist es, bei bestimmten Eingaben dem Anwender Hilfestellungen (in Form von Messageboxen) zu geben, die das alte DOS-Programm noch nicht kennt und mangels geeigneter Weiterentwicklung auch nie kennen wird.

    Nachdem wir für die DOS-Anwendung voraussichtlich erst in 2-3 Jahren eine WIN-Alternative bekommen können, wäre eine Idee zur Lösung des o. g. Problems eine große Hilfe.

    MfG und herzlichen Dank

    Hauke Gintner

  • #2
    Hallo Hauke,

    schau Dir mal die Komponente TDosCommand an. Zu finden bei http://www.torry.ru .

    Tschau

    Torste

    Comment


    • #3
      Hallo,

      das Thema interessiert mich auch schon länger. Obige Komponente kommt jedoch nicht direkt mit XP zurecht (hat jemand noch was anderes? *g*). Vor 2k mußte man die Kommandos afaik über "command.com ..." und später über "cmd /c ..." übergeben.

      Nerviger ist das Problem, daß die Art des Kommandos bestimmt, ob obige Angaben vorangesetzt werden müssen, CD benötigt es z.B. CLS nicht. Gibts da irgendeine Tabelle, aus der ich ersehen könnte, welche Befehle wie aufgerufen werden müssen?

      Oder besser gibts ne Komponente die das schon implementiert hat

      Comment


      • #4
        Hallo,

        für dieses Problem gibt es verschiedene Ansätze, ohne auf externe Komponenten zugreifen zu müssen. Der einfachste Fall nutzt einen Trick:
        <pre>
        <b>procedure</b> TForm1.ToolButton1Click(Sender: TObject);
        <b>var</b>
        aSA : TSecurityAttributes;
        aSI : TStartupInfo;
        aPI : TProcessInformation;
        szTemp : <b>array</b>[0..199] <b>of</b> Char;
        FName : <b>String</b>;
        hLogFile : THandle;
        dwExit : DWORD;
        <b>begin</b>
        FillChar(aSA, SizeOf(aSA), #0);
        aSA.nLength := SizeOf(aSA);
        aSA.bInheritHandle := True;
        <font color="#003399"><i>// temp. Dateinamen für Output generieren</i></font>
        FillChar(szTemp, SizeOf(szTemp), #0);
        GetEnvironmentVariable(PCHar(<font color="#9933CC">'TEMP'</font>), szTemp, 180);
        FName := szTemp + <font color="#9933CC">'\netstat.txt'</font>;
        <font color="#003399"><i>// Output-Datei öffnen</i></font>
        hLogFile := CreateFile(PCHar(FName), GENERIC_WRITE <b>or</b> GENERIC_READ,
        FILE_SHARE_READ <b>or</b> FILE_SHARE_WRITE,
        @aSA, CREATE_ALWAYS, 0, 0);
        <font color="#003399"><i>// Standard-Output in Datei umleiten</i></font>
        GetStartupInfo(aSI);
        aSI.dwflags := STARTF_USESTDHANDLES <b>or</b> STARTF_USESHOWWINDOW;
        aSI.wShowWindow := SW_HIDE;
        aSI.hStdOutput := hLogFile;
        aSI.hStdError := hLogFile;
        <b>if</b> CreateProcess(<b>nil</b>,PChar(<font color="#9933CC">'netstat'</font>), <b>nil</b>, <b>nil</b>, True,
        NORMAL_PRIORITY_CLASS,
        <b>nil</b>, <b>nil</b>, aSI, aPI) <b>then</b>
        <b>begin</b>
        <b>repeat</b>
        Application.ProcessMessages;
        GetExitCodeProcess(aPI.hProcess, dwExit)
        <b>until</b> dwExit &lt;&gt; STILL_ACTIVE;
        CloseHandle(aPI.hThread);
        CloseHandle(aPI.hProcess);
        CloseHandle(hLogFile);
        <b>end</b>
        <b>else</b>
        Abort;

        Memo1.Lines.LoadFromFile(FName);
        DeleteFile(FName);
        <b>end</b>;
        </pre>
        Die Standard-Ausgabe des "DOS-Fensters" (<b>hStdOutput</b>) wird in eine temporäre Datei umgeleitet, die dann ins TMemo geladen wird.

        In meinem Buch <i>Delphi Win32-Lösungen</i> greife ich in einem anderen Beispiel direkt über die Win32-API-Funktion <b>ReadConsoleOutput</b> auf den ConsoleScreenBuffer zu. Das eigene Delphi-Programm kann somit den vollständigen Inhalt des Fenster <i>Eingabeaufforderung</i> ermitteln. Dieses Beispiel ist hier im FORUM zu finden, wenn nach der Zeichenkette "ReadConsoleOutput" gesucht wird

        Comment


        • #5
          Genial das sehe ich mir mal an

          Comment


          • #6
            Leider wird es einige Zeit dauern, bis ich mich damit auseinandersetzen kann ---- meine Chefin hat gerade die Prioritäten neu gesetzt.
            Aber aufgeschoben ist nicht aufgehoben.

            Herzlichen Dabnk für die Tips

            MfG

            Hauke Gintne

            Comment


            • #7
              Ich habe das Beispiel von Herrn Kosch ausprobiert - es funktioniert.

              Problem für mich ist jedoch, daß innerhalb des Konsolenfensters nicht gearbeitet werden kann. d. h. die Anwendung, die "beobachtet" werden soll lässt sich zwar starten und deren Startbildschirm wird ausgelesen, es sind jedoch in der Konsolenanwendung keine Eingaben möglich.

              Ich muß jedoch die eigentliche Anwendung starten und darin arbeiten. Der beobachtende Prozess soll bei Auftauchen einer vorbestimmten Zeichenfolge auf dem Bildschirm, anspringen und nach Auswertung einiger Bildschirmpositionen das Auswertungsergebnis in einer Messagebox anzeigen.

              Danke und Gruß

              Hauke Gintne

              Comment


              • #8
                Hallo,

                &gt;..Ich muß jedoch die eigentliche Anwendung starten und darin arbeiten..

                in diesem Fall muss der Weg über die Win32-API-Funktion <b>ReadConsoleOutput</b> gegangen werden (siehe oben)

                Comment


                • #9
                  Moin Moin,

                  das war ein Mißverständnis.

                  Ich habe das Beispiel mit ReadConsoleOutput aus Ihrem Buch versucht.

                  Das Konsolenfenster ist zwas zu aktivieren, ich kann auch mit der Maus Teile markieren, aber das Fenster reagiert nicht auf sonstige Eingaben.

                  MfG

                  Hauke Gintne

                  Comment


                  • #10
                    Hallo,

                    mit dem folgenden Tool habe ich seinerzeit ein im Kermit-Fenster laufende Console für ein UNIX-Programm fernbedient. Wenn eine bestimmte Maske vorgefunden wurde, habe ich die Eingaben über SendKeys eingespielt. Das ist die Mini-Testfassung:
                    <pre>
                    <font color="#003399"><i>{
                    Text aus einem DOS-Fenster auslesen
                    Version 0.9 vom 20.03.1998
                    }</i></font>

                    <b>unit</b> FUSINGrabberFrm;

                    <b>interface</b>

                    <b>uses</b>
                    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
                    Dialogs, StdCtrls, ExtCtrls, Buttons, ComCtrls, Menus;

                    <b>type</b>
                    TFormMain = <b>class</b>(TForm)
                    Panel1: TPanel;
                    Memo1: TMemo;
                    SBtnClose: TSpeedButton;
                    StatBar: TStatusBar;
                    btnGrab: TSpeedButton;
                    btnKeyboard: TSpeedButton;
                    EditKeyboard: TEdit;
                    EditPrg: TEdit;
                    btnStart: TSpeedButton;
                    btnStop: TSpeedButton;
                    MemoScript: TMemo;
                    BitBtnSend: TBitBtn;
                    SaveDialogScript: TSaveDialog;
                    PopupMenu1: TPopupMenu;
                    PSaveAs: TMenuItem;
                    SBtnHelp: TSpeedButton;
                    POpen: TMenuItem;
                    OpenDialogScript: TOpenDialog;
                    <b>procedure</b> SBtnCloseClick(Sender: TObject);
                    <b>procedure</b> btnStartClick(Sender: TObject);
                    <b>procedure</b> btnGrabClick(Sender: TObject);
                    <b>procedure</b> btnStopClick(Sender: TObject);
                    <b>procedure</b> btnKeyboardClick(Sender: TObject);
                    <b>procedure</b> BitBtnSendClick(Sender: TObject);
                    <b>procedure</b> PSaveAsClick(Sender: TObject);
                    <b>procedure</b> SBtnHelpClick(Sender: TObject);
                    <b>procedure</b> POpenClick(Sender: TObject);
                    <b>procedure</b> FormCreate(Sender: TObject);
                    <b>procedure</b> FormClose(Sender: TObject; <b>var</b> Action: TCloseAction);
                    <b>private</b>
                    <font color="#003399"><i>{ Private-Deklarationen }</i></font>
                    hConsole : THandle;
                    aPI : TProcessInformation;
                    hWndFUSIN : hWnd;
                    <b>procedure</b> FindFUSINWnd;
                    <b>public</b>
                    <font color="#003399"><i>{ Public-Deklarationen }</i></font>
                    <b>end</b>;

                    <b>var</b>
                    FormMain: TFormMain;

                    <b>implementation</b>

                    <font color="#003399"><i>{$R *.DFM}</i></font>

                    <b>uses</b> sndkey32, FUSINGrabberAbout, Registry;

                    <font color="#003399"><i>(*
                    TCharInfo = packed record
                    case Integer of 0: (UnicodeChar: WCHAR; Attributes: Word);
                    1: (AsciiChar: CHAR);
                    end;
                    *)</i></font>

                    <b>type</b>
                    <font color="#003399"><i>// Pufferstruktur für die ausgelesenen Daten</i></font>
                    cInfo = <b>array</b>[1..MAXINT <b>div</b> SizeOf(TCharInfo)] <b>of</b> TCharInfo;
                    pcInfo = ^cInfo;

                    <b>resourcestring</b>
                    REG_NAME = <font color="#9933CC">'FUSINGrabber'</font>;
                    REG_SECTION = <font color="#9933CC">'ExecPath'</font>;
                    REG_IDENT = <font color="#9933CC">'Command'</font>;
                    REG_DEFAULT = <font color="#9933CC">'K95.EXE -y USER.INI'</font>;

                    <b>procedure</b> TFormMain.FormCreate(Sender: TObject);
                    <b>var</b>
                    aReg : TRegIniFile;
                    <b>begin</b>
                    aReg := TRegIniFile.Create(REG_NAME);
                    <b>try</b>
                    EditPrg.Text := aReg.ReadString(REG_SECTION, REG_IDENT, REG_DEFAULT);
                    <b>finally</b>
                    aReg.Free;
                    <b>end</b>;
                    <b>end</b>;

                    <b>procedure</b> TFormMain.FormClose(Sender: TObject; <b>var</b> Action: TCloseAction);
                    <b>var</b>
                    aReg : TRegIniFile;
                    <b>begin</b>
                    aReg := TRegIniFile.Create(REG_NAME);
                    <b>try</b>
                    aReg.WriteString(REG_SECTION, REG_IDENT, EditPrg.Text);
                    <b>finally</b>
                    aReg.Free;
                    <b>end</b>;
                    <b>end</b>;

                    <font color="#003399"><i>{ Schritt 1: DOS-Programm in einem neuen Consolen-Fenster
                    ausführen und ein Handle auf die Standardausgabe
                    in diesem Fenster sinchern. }</i></font>

                    <b>procedure</b> TFormMain.btnStartClick(Sender: TObject);
                    <b>resourcestring</b>
                    cTITEL = <font color="#9933CC">'FUSIN-Grabber'</font>;
                    <b>var</b>
                    szAppName : <b>array</b>[0..512] <b>of</b> Char;
                    aSI : TStartupInfo;
                    <b>begin</b>
                    btnStart.Enabled := False;
                    <font color="#003399"><i>// neue Console für diesen Process anfordern</i></font>
                    <b>if</b> AllocConsole <b>then</b> <b>begin</b>
                    <font color="#003399"><i>// auszuführender DOS-Befehl</i></font>
                    StrPCopy(szAppName, EditPrg.Text);
                    <font color="#003399"><i>// TStartupInfo-Datenstruktur initialisieren</i></font>
                    FillChar(aSI, Sizeof(aSI), #0);
                    <b>with</b> aSI <b>do</b> <b>begin</b>
                    cb := Sizeof(aSI);
                    dwFlags := STARTF_USESHOWWINDOW;
                    wShowWindow := SW_SHOWDEFAULT;
                    <b>end</b>;
                    <font color="#003399"><i>// DOS-Programm als neuen Process starten</i></font>
                    <b>if</b> CreateProcess(<b>nil</b>, szAppName, <b>nil</b>, <b>nil</b>, False,
                    CREATE_SEPARATE_WOW_VDM <b>or</b> NORMAL_PRIORITY_CLASS,
                    <b>nil</b>, <b>nil</b>, aSI, aPI) <b>then</b> <b>begin</b>
                    <font color="#003399"><i>// Überschrift des Consolen-Fensters setzen</i></font>
                    SetConsoleTitle(PChar(cTITEL));
                    <font color="#003399"><i>// Handle für den Standard-Output der Console holen</i></font>
                    hConsole := GetStdHandle(STD_OUTPUT_HANDLE);
                    btnStop.Enabled := true;
                    btnGrab.Enabled := true;
                    <b>end</b>
                    <b>else</b>
                    <b>begin</b>
                    btnStart.Enabled := true;
                    <b>end</b>;
                    <b>end</b>;
                    <b>end</b>;

                    <font color="#003399"><i>{ Schritt 2: Inhalt des DOS-Fensters auslesen und in die TMemo-
                    Instanz im Formular einsetzen.

                    TCoord = packed record
                    X: SHORT;
                    Y: SHORT;
                    end; }</i></font>

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

                    <font color="#003399"><i>{ Schritt 3: Consolen-Fenster schließen }</i></font>

                    <b>procedure</b> TFormMain.btnStopClick(Sender: TObject);
                    <b>var</b>
                    iResult : Integer;
                    <b>begin</b>
                    <b>try</b>
                    <font color="#003399"><i>// Sicherheitsabfrage: Programm bereits zu Ende ?</i></font>
                    WaitforSingleObject(aPI.hProcess, INFINITE);
                    <font color="#003399"><i>// Exit-Code des DOS-Programms holen</i></font>
                    GetExitCodeProcess(aPI.hProcess, iResult);
                    <font color="#003399"><i>// allozierte Handles freigeben</i></font>
                    CloseHandle(aPI.hProcess );
                    CloseHandle(aPI.hThread );
                    CloseHandle(hConsole);
                    <font color="#003399"><i>// Consolenobjekt freigeben</i></font>
                    FreeConsole;
                    btnStop.Enabled := False;
                    btnGrab.Enabled := False;
                    btnStart.Enabled := True;
                    <b>except</b>
                    MessageBeep(-1);
                    <b>end</b>;
                    <b>end</b>;

                    <b>procedure</b> TFormMain.btnKeyboardClick(Sender: TObject);
                    <b>var</b>
                    szTitel : <b>array</b>[0..254] <b>of</b> Char;
                    <b>begin</b>
                    <font color="#003399"><i>// Consolen-Fensterzeilenbeschriftung auslesen</i></font>
                    GetConsoleTitle(szTitel, SizeOf(szTitel));
                    StatBar.Panels[0].Text := szTitel;
                    AppActivate(szTitel);
                    Sleep(50);
                    SendKeys(EditKeyboard.Text);
                    SendKeys(<font color="#9933CC">'{ENTER}'</font>);
                    <b>end</b>;

                    <b>procedure</b> TFormMain.BitBtnSendClick(Sender: TObject);
                    <b>var</b>
                    szTitel : <b>array</b>[0..254] <b>of</b> Char;
                    iCnt : Integer;
                    <b>begin</b>
                    <font color="#003399"><i>// Consolen-Fensterzeilenbeschriftung auslesen</i></font>
                    GetConsoleTitle(szTitel, SizeOf(szTitel));
                    StatBar.Panels[0].Text := szTitel;
                    AppActivate(szTitel);
                    Sleep(50);
                    <b>with</b> MemoScript <b>do</b> <b>begin</b>
                    <b>for</b> iCnt := 0 <b>to</b> Lines.Count - 1 <b>do</b>
                    SendKeys(Lines[iCnt]);
                    <b>end</b>;
                    <b>end</b>;

                    <b>procedure</b> TFormMain.PSaveAsClick(Sender: TObject);
                    <b>begin</b>
                    <b>with</b> SaveDialogScript <b>do</b>
                    <b>if</b> Execute
                    <b>then</b> MemoScript.Lines.SaveToFile(Filename);
                    <b>end</b>;

                    <b>procedure</b> TFormMain.POpenClick(Sender: TObject);
                    <b>begin</b>
                    <b>with</b> OpenDialogScript <b>do</b>
                    <b>if</b> Execute <b>then</b> <b>begin</b>
                    MemoScript.Lines.Clear;
                    MemoScript.Lines.LoadFromFile(Filename);
                    <b>end</b>;
                    <b>end</b>;

                    <b>procedure</b> TFormMain.SBtnHelpClick(Sender: TObject);
                    <b>begin</b>
                    AboutBox := TAboutBox.Create(self);
                    <b>try</b>
                    AboutBox.ShowModal;
                    <b>finally</b>
                    AboutBox.Free;
                    <b>end</b>;
                    <b>end</b>;

                    <b>procedure</b> TFormMain.SBtnCloseClick(Sender: TObject);
                    <b>begin</b>
                    Close
                    <b>end</b>;

                    <font color="#003399"><i>{----------------------------------------------------------}</i></font>
                    <font color="#003399"><i>{ Private Funktionen }</i></font>
                    <font color="#003399"><i>{----------------------------------------------------------}</i></font>

                    <b>procedure</b> TFormMain.FindFUSINWnd;
                    <b>var</b>
                    szTitel : <b>array</b>[0..254] <b>of</b> Char;
                    <b>begin</b>
                    <font color="#003399"><i>// Consolen-Fensterzeilenbeschriftung auslesen</i></font>
                    GetConsoleTitle(szTitel, SizeOf(szTitel));
                    StatBar.Panels[0].Text := szTitel;
                    <font color="#003399"><i>// Fensterhandle des FUSIN-Fensters suchen</i></font>
                    hWndFUSIN := FindWindow(<b>nil</b>, szTitel);
                    <b>if</b> (hWndFUSIN = 0)
                    <b>then</b> MessageBeep(1);
                    <b>end</b>;

                    <b>end</b>.
                    </pre&gt

                    Comment

                    Working...
                    X