Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Doskonsole nutzen und Rückgabewerte einlesen (https://www.delphipraxis.net/164364-doskonsole-nutzen-und-rueckgabewerte-einlesen.html)

daywalker9 10. Nov 2011 09:22

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Hast Du TStrings.Create aufgerufen vorher?

TStrings ist nur die Basisklasse, dann kannst Du auch sowas wie DeddyH bereits gepostet hat zB Memo1.Lines übergeben.

Erzeugen musst Du aber TStringList.

Uwe Raabe 10. Nov 2011 09:30

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Dies
Delphi-Quellcode:
    for I := 0 to SLOut.Count - 1 do
    begin
      Memo1.Lines.Add(SLOut.Strings[I]);
    end;
kann man auch einfach so schreiben

Delphi-Quellcode:
Memo1.Lines := SLOut;

DeddyH 10. Nov 2011 09:37

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Ich habe meinen Code aus #9 genauso ausprobiert, wie er da steht (mit direkter Übergabe der Memo.Lines). Das hat nach Änderung auf TStrings-Parameter ohne Probleme funktioniert, damit kann man sich doch temporäre Listen sparen. Wieso das bei fuchsle nicht klappen soll, ist mir nicht ganz klar :gruebel:

fuchsle 14. Nov 2011 08:02

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1135466)
Dies
Delphi-Quellcode:
    for I := 0 to SLOut.Count - 1 do
    begin
      Memo1.Lines.Add(SLOut.Strings[I]);
    end;
kann man auch einfach so schreiben

Delphi-Quellcode:
Memo1.Lines := SLOut;

Danke. Sieht gleich besser aus.

fuchsle 14. Nov 2011 08:31

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Zitat:

Zitat von DeddyH (Beitrag 1135467)
Ich habe meinen Code aus #9 genauso ausprobiert, wie er da steht (mit direkter Übergabe der Memo.Lines). Das hat nach Änderung auf TStrings-Parameter ohne Probleme funktioniert, damit kann man sich doch temporäre Listen sparen. Wieso das bei fuchsle nicht klappen soll, ist mir nicht ganz klar :gruebel:

Habe es nochmals probiert.
Geht einwandfrei.
Vielen Dank.

himitsu 14. Nov 2011 08:44

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1135466)
Dies
Delphi-Quellcode:
    for I := 0 to SLOut.Count - 1 do
    begin
      Memo1.Lines.Add(SLOut.Strings[I]);
    end;
kann man auch einfach so schreiben

Delphi-Quellcode:
Memo1.Lines := SLOut;

Das ist aber keine korrekte Übersetzung.

Delphi-Quellcode:
Memo1.Lines.AddStrings(SLOut);
wäre richtig.
Das andere stimmt nur überein, wenn das Memo vorher leer ist, bzw. wenn es vorher geleert wird,
denn AddString hängt die Strings an den vorhandenen Inhalt an, wärend die Zuweisung über .Text den Inhalt ersetzt.

fuchsle 14. Nov 2011 10:00

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Ich gehe davon aus, dass hiermit
Delphi-Quellcode:
Memo1.Lines := SLOut;
der Inhalt von Memo1 mit den Daten von SLOut überschrieben wird und dadurch immer "geleert" wird.

In meinem speziellen Fall ist es gewünscht, dass immer nur der aktuelle Inhalt geladen wird.
Daher ist es mir nicht negativ aufgefallen.

MaBuSE 28. Jul 2021 12:31

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Hallo,
sorry wenn ich diesen alten Beitrag wieder rauskrame, aber mein Problem ist hier wohl am besten aufgehoben, da ich den hier veröffentlichen Quelltext verwende. ;)

Mein Problem (Aufgabenstellung):
Ich möchte die Aufrufe von dcc32 protokollieren, um zu sehen, in welcher Reihenfolge und mit welchen Parametern dcc32 aufgerufen wird.

Umsetzung:
Ich habe einen kleinen Wrapper um dcc32 geschrieben.
Der loggt die Aufrufe und wenn eine dcc32_org.exe (Kopie der originalen dcc32.exe) vorhanden ist, wird diese auch aufgerufen und die Ausgabe geloggt.
(Dazu habe ich die GetConsoleOutput von hier verwendet.)

-> Das funktioniert auch meistens, aber manchmal auch nicht :evil:

Mein Problem (der Fehler):
Im Log steht für jeden Eintrag:
Code:
40705308-0001: rem cd /d C:\Temp\DevExpress\VCL\Library\RS27
40705308-0002: "C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\dcc32.exe" "C:\Temp\DevExpress\VCL\Library\RS27\dxCoreRS27.dpk" -B -U"C:\Temp\DevExpress\VCL\Library\RS27" -I"C:\Temp\DevExpress\VCL\Library\RS27" -R"C:\Program Files (x86)\Embarcadero\Studio\21.0\lib\win32\release;C:\Temp\DevExpress\VCL\Library\RS27" -NU"C:\Temp\DevExpress\VCL\Library\RS27" -LE"C:\Temp\DevExpress\VCL\Library\RS27" -LN"C:\Temp\DevExpress\VCL\Library\RS27"   -NS"WinApi;Vcl;System;System.Win;Vcl.Imaging;Data;Data.Win;Bde;Xml;Xml.Win;Vcl.Shell;VclTee;Datasnap;IBX" -DSHAREPACKAGES -NB"C:\Temp\DevExpress\VCL\Library\RS27" -NH"C:\Temp\DevExpress\VCL\Library\RS27" -JL -W-UNSUPPORTED_CONSTRUCT
40705308-0003:  rem Embarcadero Delphi for Win32 compiler version 34.0
40705308-0004:  rem Copyright (c) 1983,2021 Embarcadero Technologies, Inc.
40705308-0005:  rem Fatal: F1026 File not found: 'Files.dpr'
Alle Aufrufe geben den Fehler
Code:
Fatal: F1026 File not found: 'Files.dpr'
aus, aber die Packages werden erzeugt.

Der Aufruf ohne Wrapper funktioniert und auch der Aufruf von dcc32_org.exe funktioniert ohne Fehler.
Code:
 C:\Temp\DevExpress\VCL\Library\RS27>"C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\dcc32_org.exe" "C:\Temp\DevExpress\VCL\Library\RS27\dxCoreRS27.dpk" -B -U"C:\Temp\DevExpress\VCL\Library\RS27" -I"C:\Temp\DevExpress\VCL\Library\RS27" -R"C:\Program Files (x86)\Embarcadero\Studio\21.0\lib\win32\release;C:\Temp\DevExpress\VCL\Library\RS27" -NU"C:\Temp\DevExpress\VCL\Library\RS27" -LE"C:\Temp\DevExpress\VCL\Library\RS27" -LN"C:\Temp\DevExpress\VCL\Library\RS27"   -NS"WinApi;Vcl;System;System.Win;Vcl.Imaging;Data;Data.Win;Bde;Xml;Xml.Win;Vcl.Shell;VclTee;Datasnap;IBX" -DSHAREPACKAGES -NB"C:\Temp\DevExpress\VCL\Library\RS27" -NH"C:\Temp\DevExpress\VCL\Library\RS27" -JL -W-UNSUPPORTED_CONSTRUCT
Embarcadero Delphi for Win32 compiler version 34.0
Copyright (c) 1983,2021 Embarcadero Technologies, Inc.
dxCoreRS27.dpk(67)
68 lines, 0.48 seconds, 1273428 bytes code, 209496 bytes data.

Frage:
Hat jemand eine Ahnung woran das liegen könnte?

Danke im Voraus.


Der Quelltext (auf das wesentliche reduziert):
Delphi-Quellcode:
program DCC32_Dummy;

{$APPTYPE CONSOLE}

// Ersatz für DCC32.exe in Delphi Installation um BuildSkripts zu analysieren
// z.B. DevExpress
// Diese Version ruft (falls vorhanden) *_org.exe mit den übergebenen Parametern auf.

uses
  SysUtils, Windows, Classes;

const
  Filename = 'C:\TEMP\DCC32.LOG';
var
  Programmstart: Integer;
  Zeile: integer = 0;

function GetConsoleOutput(const Command : string;
                          Output, Errors : TStringList) : Boolean;
var
  Buffer : array[0..255] of Char;
  CreationFlags : DWORD;
  NumberOfBytesRead : DWORD;
  PipeErrorsRead : THandle;
  PipeErrorsWrite : THandle;
  PipeOutputRead : THandle;
  PipeOutputWrite : THandle;
  ProcessInfo : TProcessInformation;
  SecurityAttr : TSecurityAttributes;
  StartupInfo : TStartupInfo;
  Stream : TMemoryStream;
  sCmd : string;
begin
  //Initialisierung ProcessInfo
  FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);

  //Initialisierung SecurityAttr
  FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
  SecurityAttr.nLength := SizeOf(TSecurityAttributes);
  SecurityAttr.bInheritHandle := True;
  SecurityAttr.lpSecurityDescriptor := nil;

  //Pipes erzeugen
  CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
  CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);

  //Initialisierung StartupInfo
  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.hStdInput := 0;
  StartupInfo.hStdOutput := PipeOutputWrite;
  StartupInfo.hStdError := PipeErrorsWrite;
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

  CreationFlags := CREATE_DEFAULT_ERROR_MODE or
                   CREATE_NEW_CONSOLE or
                   NORMAL_PRIORITY_CLASS;
  sCmd:=Command;
  UniqueString(sCmd);
  if CreateProcess(nil,
                   (PChar(sCmd)),
                   nil,
                   nil,
                   True,
                   CreationFlags,
                   nil,
                   PChar(GetCurrentDir),
                   StartupInfo,
                   ProcessInfo) then
  begin
    Result := True;
    //Write-Pipes schließen
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsWrite);

    //Ausgabe Read-Pipe auslesen
    Stream := TMemoryStream.Create;
    try
      while ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil) do
      begin
        Stream.Write(Buffer, NumberOfBytesRead);
      end;
      Stream.Position := 0;
      Output.LoadFromStream(Stream);
    finally
      Stream.Free;
    end;
    CloseHandle(PipeOutputRead);

    //Fehler Read-Pipe auslesen
    Stream := TMemoryStream.Create;
    try
      while ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil) do
      begin
        Stream.Write(Buffer, NumberOfBytesRead);
      end;
      Stream.Position := 0;
      Errors.LoadFromStream(Stream);
    finally
      Stream.Free;
    end;
    CloseHandle(PipeErrorsRead);

    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    CloseHandle(ProcessInfo.hProcess);
  end
  else
  begin
    Result := False;
    CloseHandle(PipeOutputRead);
    CloseHandle(PipeOutputWrite);
    CloseHandle(PipeErrorsRead);
    CloseHandle(PipeErrorsWrite);
  end;
end;

{ TMyLog }

type
  TMyLog = class(TObject)
  private
    Log: TextFile;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(const s: string);
  end;

constructor TMyLog.Create;
begin
  inherited;
  ForceDirectories(ExtractFilePath(Filename));
  AssignFile(Log, Filename);
  if FileExists(Filename) then
  begin
    Append(Log);
  end
  else
  begin
    ReWrite(Log);
  end;
end;

destructor TMyLog.Destroy;
begin
  CloseFile(Log);
  inherited;
end;

procedure TMyLog.Add(const s: string);
begin
  Inc(Zeile);
  WriteLn(Log, Format('%.8d-%.4d: %s', [ProgrammStart, Zeile, s]));
  Flush(Log);
end;

var
  i, j: Integer;
  App, Params: string;
  sl1, sl2: TStringList;
  MyLog: TMyLog;
begin
  Programmstart :=  DateTimeToTimeStamp(now).Time;
  try
    MyLog := TMyLog.Create;
    try
      MyLog.Add('rem cd /d '+GetCurrentDir);
      MyLog.Add(CmdLine);
    finally
      MyLog.Free;
    end;

    // Wenn *_org.exe da ist, dann diese mit Parametern starten
    App := ChangeFileExt(ParamStr(0), '_org.exe');
//    WriteLn(App);
    if FileExists(App) then
    begin
      for i := 1 to ParamCount do Params := Params + #32 + ParamStr(i);
//      WriteLn(Params);
      sl1 := TStringList.Create;
      sl2 := TStringList.Create;
      try
        GetconsoleOutPut(App + ' ' + Params, sl1, sl2);
        MyLog := TMyLog.Create;
        try
          for j := 0 to sl1.Count-1 do
          begin
            MyLog.Add(' rem ' + sl1[j]);
            WriteLn(sl1[j]);
          end;
          for j := 0 to sl2.Count-1 do
          begin
            MyLog.Add(' rem ERROR:' + sl2[j]);
            WriteLn(sl1[j]);
          end;
        finally
          MyLog.Free;
        end;
      finally
        sl1.Free;
        sl2.Free;
      end;
    end;
    except
    on E: Exception do
      Writeln('Es ist ein Fehler aufgetreten:',#13#10,E.ClassName, ': ', E.Message);
  end;
end.

generic 28. Jul 2021 13:49

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Ideen beim ersten lesen:
Ich denke die Parameter werden nicht "richtig" übergeben.
Das "Files" kommt bestimmt aus den langen Dateinamen welche in " gefasst sind bzw. welche Leerzeichen enthalten.

MaBuSE 28. Jul 2021 17:26

AW: Doskonsole nutzen und Rückgabewerte einlesen
 
Zitat:

Zitat von generic (Beitrag 1492926)
Ideen beim ersten lesen:
Ich denke die Parameter werden nicht "richtig" übergeben.
Das "Files" kommt bestimmt aus den langen Dateinamen welche in " gefasst sind bzw. welche Leerzeichen enthalten.

Danke, ja das wars.
Manchmal sieht man vor lauter Wald die Bäume nicht. :stupid:

Delphi-Quellcode:
 App := ChangeFileExt(ParamStr(0), '_org.exe');
...
for i := 1 to ParamCount do Params := Params + #32 + ParamStr(i);
...
// -> App + ' ' + Params
Ist natürlich Humbug. Da muss es schon spät gewesen sein :stupid:

Ich mache es nun über ein Suchen und Ersetzen mit
Delphi-Quellcode:
StringReplace
direkt in der
Delphi-Quellcode:
cmdline
. -> funktioniert super.

:dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:02 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz