![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Отслеживание исполнения
zdm © (2008-03-27 09:21:00)Добрый день.
Исходные данные.
Нобходимо приложение, которое выполняет функцию копирования файлов, их архивирование и отправку по эл.почте
Копирование выполнено CopyFile, архивирование Winexec ('rar a ...') или ShellExecute (это непринципиально), Отпарвка по эл.почте средствами INDY.
Загвоздка.
При архивации вызывается внешнее приложение (rar) , а код естественно "бежит дальше"и пытается отправить то, что еще находится в процессе архивирования.
Вопрос.
Как выходить из таких ситуаций? т.е. добиться ожидания окончания процесса, чтобы продолжить код дальше
Вызывать ShowMessage, можно, но не красиво, это я могу дожидаться окончания, а юзер точно жмахнет "OK".
Таймер выставлять, тут тоже непонятно. В зависимости от производительности и загружености компа я незнаю на сколько выставлять.
С чем то подобным я сталкивался, очень давно, выход находил как FindWindow // т.е. циклил поиск окна, пока он живо ни чего не делать.. но как-то это криво, может Вы сталкивались с чем-то подобным?
grisme (2008-03-28 17:42:00) [1]
> Palladin © (28.03.08 17:22) [17]
ну, теперь ощущаю, tnx -- будем знать :-) в отмазку(эх...) скажу, что классу TThread со мной не работалось %)
Германн (2008-03-28 17:28:00) [2]
> Для получения дескриптора процесса, его нужно запускать
> с помощью Createprocess
Так у Createprocess туева хуча параметров! Задолбаешься их понять!
:-)
Palladin (2008-03-28 17:22:00) [3]
> grisme (28.03.08 17:18) [16]
ты разницу между дескриптором TThreadArch и дескриптором процесса созданного WinExec ощущаешь? или тебе пофиг, лишь бы дескриптор? любой подставляй и работать будет
grisme (2008-03-28 17:18:00) [4]Оригинал (28.03.08 13:11) [14]
а разве не:
The WaitForSingleObject function can wait for the following objects:
...
ThreadThe CreateProcess, CreateThread, or CreateRemoteThread function returns the handle. A thread object's state is signaled when the thread terminates.
...
Игорь Шевченко (2008-03-28 14:19:00) [5]
> код в Tthread
> procedure TThreadArch.Execute;
> var
> Source:string;
> begin
> WinExec(pchar('rar a c:\1\qqq c:\1'),1);
> end;
>
> В окне где вызовется процесс
> procedure TFormOsn.Button1Click(Sender: TObject);
> var T1 : TThreadArch;
> begin
> T1:= TThreadArch.Create(false);
> T1.Priority:=tpLowest;
> WaitForSingleObject(T1.Handle,0); //тайм на бесконечность
> пока не выполнится
> ShowMessage(''); //пока процесс незакончится и модалка даже
> не выскочит
> end;
Дети Ивана Кулибина
RTFM: ShellExecuteEx
Оригинал (2008-03-28 13:11:00) [6]
> zdm (28.03.08 12:13) [13]
> я чегото вас не всех понял. Вчера уже все решили и получилось,
> Palladin © правильно наталкнул на мысль о WaitForSingleObject.
> Вопрос был в ожидании процесса а не какими средствами его
> исполнять.я нашел с его помощью такое решение, ну например.
> ..
На мысль-то натолкнул, но ты явно неправильно понял.
И непонятно, что у тебя работает.
Для получения дескриптора процесса, его нужно запускать с помощью Createprocess, а не WinExec. WinExec не ожидает завершения процесса.
WaitForSingleObject нужно применять как раз к полченному дескриптору, а ине к дескриптору потока, в котором ты запускаешь свой процесс архивации.
zdm (2008-03-28 12:13:00) [7]я чегото вас не всех понял. Вчера уже все решили и получилось, Palladin © правильно наталкнул на мысль о WaitForSingleObject. Вопрос был в ожидании процесса а не какими средствами его исполнять.
я нашел с его помощью такое решение, ну например...
код в Tthread
procedure TThreadArch.Execute;
var
Source:string;
begin
WinExec(pchar('rar a c:\1\qqq c:\1'),1);
end;
В окне где вызовется процесс
procedure TFormOsn.Button1Click(Sender: TObject);
var T1 : TThreadArch;
begin
T1:= TThreadArch.Create(false);
T1.Priority:=tpLowest;
WaitForSingleObject(T1.Handle,0); //тайм на бесконечность пока не выполнится
ShowMessage(''); //пока процесс незакончится и модалка даже не выскочит
end;
Оригинал (2008-03-27 14:37:00) [8]
> Нет не лень, но расскажи мне. Как заставить в кодеWinExec('notepad.
> exe',sw_shownormal);ShowMessage('Notepad закрыли');сообщение
> 'Note pad закрыли' появится после закрытия запущенного блокнота,
> о мудрейший...
Сорри. Забыл, что WinExec ждет только загрузки приложения, о блистательнейший Мастер.
Palladin (2008-03-27 14:26:00) [9]Нет не лень, но расскажи мне. Как заставить в коде
WinExec('notepad.exe',sw_shownormal);
ShowMessage('Notepad закрыли');
сообщение 'Note pad закрыли' появится после закрытия запущенного блокнота, о мудрейший...
Оригинал (2008-03-27 14:24:00) [10]
> Palladin © (27.03.08 14:21) [9]
> > Оригинал (27.03.08 14:20) [8] нет конечно, ты читал
> вопрос то?
А ты читал? Или лень f1 нажать?
Palladin (2008-03-27 14:21:00) [11]
> Оригинал (27.03.08 14:20) [8]
нет конечно, ты читал вопрос то?
Оригинал (2008-03-27 14:20:00) [12]
> Palladin © (27.03.08 14:17) [6]
> > [4] Оригинал (27.03.08 14:13)И что же там интересного?
>
Полностью удовлетворяет условиям задачи. Не согласен?
Kolan (2008-03-27 14:17:00) [13]> это непринципиально
Видишь, оказывается принципиально. :)
Вот пример:
{************************************************************}
{ }
{ KRunApplication }
{ Copyright © 2007 KSoftWare }
{ }
{ }
{ Разработчик: Товеровский Николай }
{ Модифицирован: 14 декабря 2007 }
{ }
{************************************************************}
unit KRunApplication;
interface
uses
Windows, SysUtils, Forms;
type
{ERunApplicationException предок для всех исключений
генерируемых в этом модуле.}
ERunApplicationException = class(Exception);
{IConsoleViewVisitor интерфейс посетителя,
умеющего отображать данные из консоли.}
IConsoleViewVisitor = interface
['{F37E51D8-7E2A-4AC1-B090-8F38F860B48A}']
procedure ViewConsoleMessage(const Msg: string);
end;
{RunApplicationAndWaitTillFinish функция для запуска процесса
и ожидания его завершения.
Для того, чтобы иметь возможность обработать полученные из консоли данные
в процедуру надо передать объект, поддерживающий интерфейс IConsoleViewVisitor
(паттерн Visitor).
*Не стоит использовать её в доп. потоках.
*Не забывайте, что при реализации интерфейса производится подсчет ссылок
и ваш объект может быть удален автоматически. Для предотвращения такого
поведения можно унаследовать класс от TInterfacedPersistent, или реализовать
нужную функциональность вручную.}
procedure RunApplicationAndWaitTillFinish(RunString: string;
ConsoleViewVisitor: IConsoleViewVisitor = nil);
implementation
procedure RunApplicationAndWaitTillFinish(RunString: string;
ConsoleViewVisitor: IConsoleViewVisitor);
var
StartupInfo: TStartupInfo;
SecurityAttributes: TSecurityAttributes;
ProcessInfo: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
CreateResult: Boolean;
S: string;
BytesReadFromFile: Cardinal;
BytesReadFromPipe: Cardinal;
WaitResult: Cardinal;
begin
with SecurityAttributes do
begin
nLength := SizeOf(SecurityAttributes);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
{Создать пайп для перенаправления стандартного вывода.}
if not CreatePipe(
StdOutPipeRead, // дескриптор чтения.
StdOutPipeWrite, // дескриптор записи.
@SecurityAttributes, // аттрибуты безопасности.
0) // количество байт принятых для пайпа 0 по умолчанию.
then
raise ERunApplicationException.Create(SysErrorMessage(GetLastError));
try
with StartupInfo do
begin
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
cb := SizeOf(StartupInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // стандартный ввод не перенаправляем
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
ZeroMemory(@ProcessInfo, SizeOf(@ProcessInfo));
CreateResult := CreateProcess(nil, PAnsiChar(RunString), nil, nil, True,
0, nil, nil, StartupInfo, ProcessInfo);
if CreateResult then
begin
try
repeat
Application.ProcessMessages;
{Ждать процесс 100 мс.}
WaitResult := WaitForSingleObject(ProcessInfo.hProcess, 100);
Application.ProcessMessages;
{Узнать сколько в пайпе байт}
PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BytesReadFromPipe, nil);
{Есл байт больше 0 }
if BytesReadFromPipe > 0 then
begin
{ выделить память для строки.}
SetLength(S, BytesReadFromPipe);
{Прочесть байты.}
if not ReadFile(StdOutPipeRead, PChar(S)^, BytesReadFromPipe, BytesReadFromFile, nil) then
raise ERunApplicationException.Create(SysErrorMessage(GetLastError));
{Отрезать лишние.}
SetLength(S, BytesReadFromFile);
{Перекодировать из дос кодировки.}
OemToAnsi(PChar(S), PChar(S));
{Отправить полученые из консоли данные посетителю.}
if Assigned(ConsoleViewVisitor) then
ConsoleViewVisitor.ViewConsoleMessage(S);
end;
{Выйти если процесс завершился и нечего читать.}
until (WaitResult WAIT_TIMEOUT) and (BytesReadFromPipe = 0);
finally
{Закрыть хендлы процесса.}
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
end;
end
else
raise ERunApplicationException.Create(SysErrorMessage(GetLastError));
finally
{Закрыть хендлы пайпа.}
CloseHandle(StdOutPipeRead);
CloseHandle(StdOutPipeWrite);
end;
end;
end.
Palladin (2008-03-27 14:17:00) [14]
> [4] Оригинал (27.03.08 14:13)
И что же там интересного?
Оригинал (2008-03-27 14:16:00) [15]
> zdm77 (27.03.08 09:40) [3]
> Накопал инфу. пасиба. Снимаю вопрос.
Обрати внимание на WinExec.
Оригинал (2008-03-27 14:13:00) [16]
> zdm77 (27.03.08 09:40) [3]
> Накопал инфу. пасиба. Снимаю вопрос.
Обрати внимание на WinExec.
zdm77 (2008-03-27 09:40:00) [17]Накопал инфу. пасиба. Снимаю вопрос.
zdm77 (2008-03-27 09:29:00) [18]
> Palladin © (27.03.08 09:24) [1]
Я мало сталкивался с распоралеливанием.. у Вас нет ссылок где об этом можно почитать поподробней. Заранее спасибо.
Palladin (2008-03-27 09:24:00) [19]CreateProcess + WaitForSingleObject