Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi DEC onProgress-Ereignis bei mehreren Threads (https://www.delphipraxis.net/7337-dec-onprogress-ereignis-bei-mehreren-threads.html)

Luckie 9. Aug 2003 17:36


DEC onProgress-Ereignis bei mehreren Threads
 
Folgendes: In einer Liste habe ich verschiedene Dateien zum Verschlüsseln. Für jede Datei wird jetzt ein Thread mit BeginThread gestartet. In diesem Thread wird jetzt dynamisch die Cipher-Komponente erzeugt und dem OnProgress Ereignis eine Prozedur zugewiesen. In einer zweiten Spalte eines Listview soll nur der Fortschrit separat für jede Datei angezeigt werden. Wie teile ich OnProgress jetzt mit welche Spalte er aktualisieren soll?

Ich habe kein TTHread-Object, sondern arneite mit der Windows-API.

Schema:
Code:
procedure MyProgress;
begin
  Listview1.Items[x],Subitems[0].Text := y%;
end;

function Thread
begin
  TCipher.OnProgress := myProgress;
end;
Das "X" ist jetzt das Problem.

Luckie 9. Aug 2003 18:08

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Mein Lösungsversuch:

Ich vergebe beim Erstellen im Thread die Tag-Eigenschaft. In OnProgress ist sie aber immer 0.

Luckie 9. Aug 2003 21:29

Re: DEC onProgress-Ereignis bei mehreren Threads
 
So ich habe es jetzt geschaft, aber nicht so richtig. Ich benutze jetzt ein TThread-Objekt.
Delphi-Quellcode:
procedure BlowFishThread.EncryptBlowFish;
var
  BlowFish: TCipherManager;
begin
  BlowFish := TCiphermanager.Create(nil);
  with BlowFish do
  begin
    try
      Algorithm := 'Blowfish';
      InitKey(FPW, nil);
      OnProgress := Progress;
      EncodeFile(FFilename, FFilename + '.encoded');
    except
      BlowFish.Free;
      FPosition := -1;
      exit;
    end;
  end;
  BlowFish.Free;
end;

procedure BlowFishThread.Progress;
begin
  FPosition := Trunc(100 / Maximal * Current);
  Synchronize(UpLV);
end;

procedure BlowFishThread.Execute;
var
  Header: TFileHeader;
begin
  EncryptBlowFish;
  with Header do
  begin
    HeaderSize := sizeof(TFileHeader);
    sVersion := VER;
    sAlgo := ALGO_BLOWFISH;
    KeySize := 0;
  end;
  Addheader(Header, Filename + '.encoded');
end;

procedure BlowFishThread.UPLV;
begin
  Form1.UpLV(FIndex, FPosition);
end;
Allerdings zählt er nur die letzte Datei hoch. :?

Luckie 9. Aug 2003 23:15

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Liste der Anhänge anzeigen (Anzahl: 1)
So eine Konstruktion hilft auch nicht:
Delphi-Quellcode:
procedure BlowFishThread.Execute;
var
  Header: TFileHeader;
begin
  setlength(FIndexArray, length(FIndexArray)+1);
  FIndexArray[length(FIndexArray)-1] := FIndex;
  setlength(FPositionArray, length(FPositionArray)+1);
  EncryptBlowFish;
Delphi-Quellcode:
procedure BlowFishThread.Progress;
var
  i: Integer;
begin
  for i := 0 to length(FPositionArray)-1 do
  begin
     FPositionArray[i] := Trunc(100 / Maximal * Current);
  end;
  Synchronize(UpLV);
end;
Delphi-Quellcode:
procedure BlowFishThread.UPLV;
var
  i: Integer;
begin
  for i := 0 to length(FIndexArray)-1 do
  begin
    Form1.UpLV(FIndexArray[i], FPositionArray[i]);
    writeln(IntToStr(FIndexArray[i])+' / '+IntToStr(FPositionArray[i]));
    break;
  end;
end;
Ich habe jetzt mal das Projekt angehangen. Ob das sicher ist sei erst mal dahingestellt. benötigt wird das DEC von Hagen Reddmann.

Luckie 10. Aug 2003 10:55

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Liste der Anhänge anzeigen (Anzahl: 1)
So Code etwas überarbeitet. Es geht aber immer noch nicht, so wie ich will.

negaH 10. Aug 2003 11:09

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Hi Luckie,

sorry für die späte Antwort, aber es gibt auch mal einen Geburtstag zu feiern.

Also, es ist schon erschreckend wie du so schnell die Schwachstellen im DEC findest. OnProgress() ist ein globales Event das 1. nicht threadsafe ist und 2. global immer nur einen Verschlüsselungsprozess unterstützt.

D.h. mit OnProgress() wirst du das was du willst nie hinbekommen. Vergiss es also. Verzichte auf TCipherManager/THashManager, beides sind Komponenten die ich für die DAU's coden musste, es sind Drag&Design Hilfsmittel.


Nachfolgend zeige ich wie man jeden Stream mit Progress Funktionalität ausbauen kann. D.h. deine Progressbar sollte individuell zum Streaming sein, dann ist sie auch threadsafe. Desweiteren zeige ich wie man Verschlüsselt ohne TCipherManager, die Entschlüsselung bekommste damit selber hin.

Delphi-Quellcode:
type
  TStreamProgressAdapter = class(TStream)
  private
    FStream: TStream;
  protected
    procedure SetSize(NewSize: Longint); override;
  public
    constructor Create(AStream: TStream);
    destructor Destroy; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
    function Seek(Offset: Longint; Origin: Word): Longint; override;

    procedure DoProgress(Writing: Boolean); virtual;
  end;

procedure TStreamProgressAdapter.SetSize(NewSize: Longint);
begin
  TStreamProgressAdapter(FStream).SetSize(NewSize);
end;

constructor TStreamProgressAdapter.Create(AStream: TStream);
begin
  inherited Create;
  FStream := AStream;
end;

destructor TStreamProgressAdapter.Destroy;
begin
  inherited Destroy;
  FStream.Free;
end;

function TStreamProgressAdapter.Read(var Buffer; Count: Longint): Longint;
begin
  Result := FStream.Read(Buffer, Count);
  DoProgress(False);
end;

function TStreamProgressAdapter.Write(const Buffer; Count: Longint): Longint;
begin
  Result := FStream.Write(Buffer, Count);
  DoProgress(False);
end;

function TStreamProgressAdapter.Seek(Offset: Longint; Origin: Word): Longint;
begin
  Result := FStream.Seek(Offset, Origin);
end;

procedure TStreamProgressAdapter.DoProgress(Writing: Boolean);
begin
  // hier deine Progress Funktionen einbauen
end;

procedure Encrypt(Stream: TStream; const Password: String; CipherClass: TCipherClass = nil); overload;
begin
  if CipherClass = nil then
    CipherClass := TCipher_Blowfish;
  with CipherClass.Create('', nil) do
  try
    Mode := cmCTS;
    InitKey(Password, nil);
    EncodeStream(Stream, Stream, -1);
  finally
    Free;
  end;
end;

procedure Encrypt(const FileName, Password: String; CipherClass: TCipherClass = nil); overload;
var
  Stream: TStream;
begin
  Stream := TStreamProgressAdapter.Create(TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive));
  try
    Encrypt(Stream, Password, CipherClass);
  finally
    Stream.Free;
  end;
end;

procedure TestC;
begin
  Encrypt('d:\test.bin', 'Test');
  Encrypt('d:\test.bin', 'Test', TCipher_Rijndael);
  Encrypt('d:\test.bin', 'Test', TCipherClass(DECClassByName('IDEA', TCipher)));
end;
Gruß Hagen

Luckie 10. Aug 2003 11:24

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Danke. Dann habe ich es ja gerade im richtigen Moment wieder hervor geholt.

Wie komme ich in OnProgress an die Werte dran und wie weise ich das Ereignis einer Ver- / Entschlüsselung zu?

negaH 10. Aug 2003 11:38

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Du redest jetzt von obigem TStreamProgressAdapter ?
Diese Klasse muß natürlich erweitert werden. Im .DoProgress kann man über FStream.Size und FStream.Position das Verhältniss ermittelt werden.
In meinem eigene Source habe ich dies allerdings über eigene Variablen gemacht. Also im Contructor FStream.Size zwischen gespeichert. Im .Seek() .Read() und .Write() zähle ich eine eigene FPosition mit. Im .DoProgress() kann ich nun die berechnete FSize und FPosition von TStreamProgressAdapter auswerten. Dies verhindert unnötige Repositionierungen wenn man mit FStream.Position und FStream.Size arbeitet. Intern wird nämlich über Seek() die Größe des Stream ermittelt.

Gruß Hagen

Luckie 10. Aug 2003 12:30

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Liste der Anhänge anzeigen (Anzahl: 1)
So. Ich habe das jetzt mal eingebaut noch ohne Threads nur zum Testen. Leider bin ich da auf ein paar Probleme gestossen.

Erst mal habe ich den von dir gepostet Code in eine Unit gesteckt und entsprechend erweitert. Du findest sie im Anhang.

Dann habe ich versucht den Code anzuwenden. Habe da aber wohl noch ein paar Verständnisschwierigkeiten.

Delphi-Quellcode:
procedure TForm1.btnOKClick(Sender: TObject);
var
  i: Integer;
  Filename: string;
  ProgressAdapter: TStreamProgressAdapter;
  FileStream: TFileStream;
begin
  for i := 0 to lvFiles.Items.Count - 1 do
  begin
    Filename := lvFiles.Items.Item[i].Caption;
    if lvFiles.Items.Item[i].SubItems[0] = 'unverschlüsselt' then
    begin
      FileStream := TFileStream.Create(Filename, fmOpenReadWrite);
      try
        ProgressAdapter := TStreamProgressAdapter.Create(FileStream);
        try
          Encrypt(FileStream, edtPW1.Text, TCipher_Rijndael); // 156
          lvFiles.Items.Item[i].SubItems[0] := FloatToStr(ProgressAdapter.Progress);
        finally
          {???}
        end;
      finally
        FreeAndNil(FileStream);
      end;
    end;
  end;
end;
Frage: Kann es so überhaupt funktionieren? Weil wenn ich in der Schleife den ProgressAdapter gleich wieder freigebe, dann war es das ja gewesen, deswegen die drei Dedektive (???) an dieser Stelle.

Probleme:
Zitat:

[Fehler] Unit1.pas(156): Undefinierter Bezeichner: 'TCipher_Rijndael'
Zitat:

[Fehler] Unit1.pas(156): Es gibt keine überladene Version von 'Encrypt', die man mit diesen Argumenten aufrufen kann

negaH 10. Aug 2003 16:16

Re: DEC onProgress-Ereignis bei mehreren Threads
 
Einfacher, TProgressAdapter gibt den Stream den er kapselt selber frei. D.h. FileStream.Free ist in jedem Falle falsch.

Delphi-Quellcode:
ProgressAdapter := TStreamProgressAdapter.Create(TFileStream.Create(FileName, Mode));
try
  ProgressAdapter.Read();
  ProgressAdapter.Write();
finally
  ProgressAdapter.Free;
end;
D.h. der Stream den man einem TStreamProgressAdapter übergibt ist irrelevant und muß nicht mehr als variable gespeichert werden. Alle Stream-Funktionen laufen nur über den ProgressAdapter, er kapselt sozusagen vollständig ein anderes Stream Object. Der Vorteil: statt ihn nur für Progressbars zu nutzen kann er auch beim Lesen/Schreiben Prüfsummen berechnen, zusätzlich komprimieren und vwerschlüsseln. Dazu müssen nur die .Write() .Read() Methoden angepasst werden.

Gruß Hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:03 Uhr.
Seite 1 von 2  1 2      

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