UnZip; // on ZipForge1Password I get error: EInvalidOperation with message 'Canvas does not allow drawing'. The Form is not frozen while archive is being extracted.
Это связано с тем, что вы запускаете небезопасный для потока код (1) из своего потока. Весь небезопасный для потоков код (1) (как и большинство подпрограмм VCL и WinAPI) должен выполняться в основном потоке. Подпрограмма UnZip ссылается на form2, который является компонентом VCL, поэтому вы должны (1) использовать Synchronize, чтобы временно передать выполнение основному потоку.
Synchronize(UnZip); // No EInvalidOperation error on ZipForge1Password, but the Form is frozen while archive is being extracted.
Как объяснялось, с помощью Synchronize вы намеренно выполняете код в основном потоке, поэтому он кажется замороженным во время процесса извлечения.
Итак, теперь у вас есть небольшая дилемма курицы и яйца. Тот, который можно устранить, создав компонент ZipForge @runtime в вашем потоке. В этом случае единственное взаимодействие с пользователем, которое остается синхронизированным, — это предоставление пароля. Недостатком является то, что Synchronize принимает только метод без параметров, поэтому вам придется немного поработать над реализацией обработчика событий OnPassword. Это может выглядеть следующим образом:
type
TUnZip = class(TThread)
private
FFileName: String;
FPassword: AnsiString;
FSkipFile: Boolean;
procedure DoPassword;
procedure ZipForgePassword(Sender: TObject; FileName: string;
var NewPassword: AnsiString; var SkipFile: Boolean);
protected
procedure Execute; override;
public
property PassSkip ...
property ItemToExtract ...
end;
{ TUnZip }
procedure TUnZip.DoPassword;
var
S: String;
begin
if PassSkip then
FSkipFile := True
else if InputQuery('Pass', FFileName, S) then
FPassword := AnsiString(S)
else
begin
PassSkip := True;
FSkipFile := True;
Terminate;
end;
end;
procedure TUnZip.Execute;
var
ZipForge: TZipForge;
begin
ZipForge := TZipForge.Create(...);
try
ZipForge.OnPassword := ZipForgePassword;
ZipForge.FileName := ItemToExtract;
ZipForge.OpenArchive;
if not Terminated then {Assuming OpenArchive triggers the OnPassword event}
begin
ZipForge.BaseDir := XXX;
ZipForge.ExtractFiles('*.*');
ZipForge.CloseArchive;
end;
finally
ZipForge.Free;
end;
end;
procedure TUnZip.ZipForgePassword(Sender: TObject; FileName: String;
var NewPassword: AnsiString; var SkipFile: Boolean);
begin
FFileName := FileName;
FPassword := NewPassword;
FSkipFile := SkipFile;
Synchronize(DoPassword);
FileName := FFileName;
NewPassword := FPassword;
SkipFile := FSkipFile;
end;
Отказ от ответственности: я не знаком с компонентом ZipForge, поэтому этот код может быть неполным. Вы должны реализовать все настройки, созданные во время разработки, в TUnZip.Execute. Я даже не знаю, есть ли вообще у TZipForge событие OnPassword, но я сделал это из вашего кода.
Изменить:
(1) Не весь код VCL является небезопасным для потоков, и не говорится, что каждый вызов из вторичного потока элемента управления, компонента или переменной основного потока опасен, но это хорошая практика. предотвратить это. На мой взгляд, термин потокобезопасность является удобным предостережением. Но фактическая причина этой небезопасности заключается в том, что все элементы управления пользовательского интерфейса (т. е. все объекты GDI Windows) могут иметь привязку только к одному потоку; основной поток.
person
NGLN
schedule
13.06.2011