![]() |
CopyFileEx
So, ich habe gerade ein Beispiel für das Kopieren einer Datei mit Fortschrittsanzeige mit Hilfe von
![]()
Delphi-Quellcode:
Nur ein Problem habe ich: Das Abbrechen funktioniert nicht. Er geht zwar in den if-Zweig rein, aber er ruft die Callback Routine immer wieder auf, obwohl ich PROGRESS_CANCEL zurückgebe.
var
Form1: TForm1; CancelCopy: Boolean; implementation {$R *.dfm} function CopyFileProgress(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason, hSourceFile, hDestinationFile, lpData: DWORD): DWORD; stdcall; begin Application.ProcessMessages; if CancelCopy = True then begin ShowMessage('Abbruch'); result := PROGRESS_CANCEL; end; case dwCallbackReason of CALLBACK_CHUNK_FINISHED: begin Form1.ProgressBar1.Position := TotalBytesTransferred.QuadPart; result := PROGRESS_CONTINUE; end; CALLBACK_STREAM_SWITCH: begin Form1.ProgressBar1.Max := TotalFileSize.QuadPart; result := PROGRESS_CONTINUE; end; end; end; procedure TForm1.Button1Click(Sender: TObject); var Cancel: PBOOL; begin CancelCopy := False; Cancel := nil; CopyFileEx('g:\Brennen\Madonna - Erotica.mpg', 'g:\Madonna - Erotica.mpg', @CopyFileProgress, nil, Cancel, 0); end; procedure TForm1.Button2Click(Sender: TObject); begin CancelCopy := True;; end; |
Re: CopyFileEx
Versuchs mit
Delphi-Quellcode:
BTW, Application.ProcessMessages führt eine Ansychronität ein, die Du vermutlich nicht haben willst. Und Du solltest bei Abbruch die Funktion verlassen, sonst wird Dein Result wieder überschrieben. Zudem ist auf den ersten Blick der Rückgabewert nicht immer definiert (noch nicht ganz wach?).
if CancelCopy = True then
begin ShowMessage('Abbruch'); Result := PROGRESS_CANCEL; Exit; end else Application.ProcessMessages; Gruss Nico |
Re: CopyFileEx
^hochhol.
danke für den code. wenn Application.ProcessMessages nicht empfehlenswert ist, was gibt es als alternative? ich will ja nicht daß mein programm nicht mehr reagiert. kann ich die priorität des kopierprozesses durch die priorität meines programmes beeinflussen? ich habe den code so abgeändert, daß statt PROGRESS_CANCEL ein PROGRESS_STOP zurückgegeben wird, zusätzlich setze ich als flag COPY_FILE_RESTARTABLE. wenn ich nun die aktion stoppe und nochmal starte sollte er doch fortsetzen, tut es aber nicht. wieso? |
Re: CopyFileEx
Threads wären besser:
Delphi-Quellcode:
Ungefähr so.
type
TForm1 = class(TForm) ProgressBar1: TProgressBar; Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure WndProc(var Msg: TMessage); override; end; var Form1 : TForm1; implementation {$R *.dfm} type TCopyEx = packed record Source: String[255]; Dest: String[255]; Handle: THandle; end; PCopyEx = ^TCopyEx; const CEXM_CANCEL = WM_USER + 1; CEXM_CONTINUE = WM_USER + 2; // wParam: lopart, lParam: hipart CEXM_MAXBYTES = WM_USER + 3; // wParam: lopart; lParam: hipart var CancelCopy : Boolean = False; function CopyFileProgress(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason, hSourceFile, hDestinationFile: DWORD; lpData: Pointer): DWORD; stdcall; begin if CancelCopy = True then begin SendMessage(THandle(lpData), CEXM_CANCEL, 0, 0); result := PROGRESS_CANCEL; exit; end; case dwCallbackReason of CALLBACK_CHUNK_FINISHED: begin SendMessage(THandle(lpData), CEXM_CONTINUE, TotalBytesTransferred.LowPart, TotalBytesTransferred.HighPart); result := PROGRESS_CONTINUE; end; CALLBACK_STREAM_SWITCH: begin SendMessage(THandle(lpData), CEXM_MAXBYTES, TotalFileSize.LowPart, TotalFileSize.HighPart); result := PROGRESS_CONTINUE; end; else result := PROGRESS_CONTINUE; end; end; procedure TForm1.WndProc(var Msg: TMessage); begin inherited; case Msg.Msg of CEXM_MAXBYTES: begin ProgressBar1.Max := Msg.WParam + Msg.LParam; end; CEXM_CONTINUE: begin Progressbar1.Position := Msg.WParam + Msg.LParam; Caption := IntToStr(Msg.WParam + Msg.LParam); end; CEXM_CANCEL: begin Progressbar1.Position := 0; Caption := '0'; end; end; end; function CopyExThread(p: PCopyEx): Integer; var Source: String; Dest: String; Handle: THandle; Cancel : PBool; begin Source := p.Source; Dest := p.Dest; Handle := p.Handle; Cancel := PBOOL(False); CopyFileEx(PChar(Source), PChar(Dest), @CopyFileProgress, Pointer(Handle), Cancel, 0); Dispose(p); result := 0; end; procedure TForm1.Button1Click(Sender: TObject); var Params: PCopyEx; ThreadID: Cardinal; begin cancelCopy := False; New(Params); Params.Source := 'H:\Videos ungebrannt\Gwen Stefani - rich girl.mpeg'; Params.Dest := 'H:\test.mpeg'; Params.Handle := Handle; CloseHandle(BeginThread(nil, 0, @CopyExThread, Params, 0, ThreadID)); end; procedure TForm1.Button2Click(Sender: TObject); begin CancelCopy := True; end; |
Re: CopyFileEx
auch noch so spät unterwegs? :-D
wie, threads? also einen thread erstellen, der die kopieraktion dann macht? habe mich noch nicht wirklich mit threadprogrammierung beschäftigt, kannst du mir ein grobes gerüst zusammenschustern? ich möchte sehr "performant" viele dateien kopieren/verschieben und kann auf 9x verzichten, habe mir deshalb CopyFileEx/MoveFileEx herausgesucht. vielleicht mache ichs aber doch mit blockread/write, weil ich dann bei netzwerkkopieraktionen den durchsatz limitieren kann. |
Re: CopyFileEx
Zitat:
Zitat:
|
Re: CopyFileEx
danke!
nachdem du deinen beitrag editiert hast schaut es jetzt so aus als hätte ich um 4 uhr morgens nur nicht gesehen daß du ja schon ein beispiel gepostet hast! :) kann ich die priorität des kopierprozesses durch die priorität meines threads beeinflussen? |
Re: CopyFileEx
Sollte möglich sein. Probier es aus. Aber generell würde ich an den Prioritäten nichts ändern, ins besondere, wenn es um das Anheben der Priorität geht. In der Zuteilung von Rechenzeit findet Windows meist schon selber das richtige Maß. Man kann durch Anheben fast mehr kaputt machen, als verbessern.
|
Re: CopyFileEx
ich möchte die priorität nicht anheben, sondern senken. :) ich probiers mal, danke.
|
Re: CopyFileEx
hi
ich wollt mich zunächst für das tolle beispiel bedanken aber ich habe ein problem denn sobald ich datein die größer als ca 2gb sind kopieren will stimmt die progressbar nicht mehr da der progrssbar.max wert ja ein integer ist und msg.lparam und msg.wparam ja auch "nur" integer sind ... steh ich jetz nur auf der leitung oder ist was wirklich schwierig? also hat wer ne ahnung wie man das abändern kann das es auch mit größeren datein funzt? |
Re: CopyFileEx
Zitat:
Delphi-Quellcode:
// wParam: lopart, lParam: hipart
|
Re: CopyFileEx
Die Formel von Luckie ist allerdings nicht richtig, er addiert einfach beide Teile. Der richtige Wert errechnet sich so:
Delphi-Quellcode:
bytes ist natürlich als Int64 zu deklarieren.
bytes := (Int64(Msg.LParam) shl 32) + Msg.WParam;
Gruß Hawkeye |
Re: CopyFileEx
Dann mußt du halt noch einen Divisor mit einbauen, welche die Werte vor der Übergabe an die ProgressBar anpaßt diesen kannst du ja setzen, sobald du die Dateigröße bekommst, also in CEXM_MAXBYTES.
Etwa so:
Delphi-Quellcode:
CEXM_MAXBYTES:
begin if Int64(Msg.WParam) shl 32 + Msg.LParam <= $7FFFFFFF then Divisor := 1 else Divisor := (Int64(Msg.WParam) shl 32 + Msg.LParam) div $7FFFFFFF; ProgressBar1.Max := Msg.WParam + Msg.LParam;
Delphi-Quellcode:
(Int64(Msg.WParam) shl 32 + Msg.LParam) div Divisor
PS: Lackie, muß in WndProc nicht
Delphi-Quellcode:
so sein?
Msg.WParam + Msg.LParam
Delphi-Quellcode:
Mist zu langsam -.-''
Int64(Msg.WParam) shl 32 + Msg.LParam
|
Re: CopyFileEx
Zitat:
|
Re: CopyFileEx
danke nochmal für die antworten ... ich habs jetz einfach in prozent umgerechnet
jetz hab ich dadurch eine ordenliche progressbar |
Re: CopyFileEx
Zitat:
|
Re: CopyFileEx
Tipps noch mal richtig, dann kopiere ich das in meinen Code-Schnippsel rein. ;)
|
Re: CopyFileEx
Das Problem ist: Die Progressbar kommt nur mit Integer klar und nicht mit Int64. Will man eine Progressbar benutzen muss man sowieso in Prozent umrechnen. Ich habe den Code auf meiner Homepage korrigiert:
![]() |
Re: CopyFileEx
Zitat:
Nein, in Prozent muß es nicht sein ... der Wert muß halt "nur" in den Integer-Bereich gebracht (verkleinert) werden, aber Prozent geht och ... is ja auch im entsprechendem Bereich. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz