Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > выполнение действия в определенное время


Автор: Romany4 5.6.2009, 17:43
Добрый день. В программировании я полный нуб, и терминологии почти не знаю, так что не ругайтесь из-за возможно глупых вопросов.

Необходимо написать программу, которая будет висеть в трее, и которая в полночь удаляет файл, а в 8 утра копирует его из резервной копии. С копированием и удалением я разобрался, а вот с автоматизацией этого - нет.
Как сделать, чтобы процедуры удаления и копирования выполнялись в определенное время?

Автор: kami 5.6.2009, 18:24
Самое простое (и не самое лучшее) решение - повесить таймер с интервалом около 1 минуты (хотя и это много - можно и пореже).
Это предполагает, что компьютер включен постоянно, либо нужно будет при его включении/выключении загружать/сохранять даты последних действий.

в объявление класса сервиса включить:
Код

  TMyService=class(TService)
  ......
  private
    FLastDelDate:TDateTime;
    FLastCopyDate:TDateTime;
  .....
  end;


В OnTimer написать примерно так:

Код

if not IsToday(FLastDelDate) then // эта штука сработает в полночь, или чуть позже - смотря 
  // какой интервал задать таймеру, так как дата меняется в полночь
  begin
    DoDeleteFile;
    FLastDelDate:=Now;
  end
else // если убрать else, то удаление и копирование сработают за один вызов таймера.
if not IsToday(FLastCopyDate, Now) and (Time>=EncodeTime(8, 0, 0, 0)) then
  begin
    DoCopyFile;
    FLastCopyDate:=Now;
  end;
end;


У этого кода есть недостаток: первое срабатывание будет сразу же, как только сработает таймер (удаление - при первом срабатывании, копирование - при втором).

Автор: Romany4 5.6.2009, 20:48
а если не использовать дату а брать только hh и mm?

Автор: kami 5.6.2009, 21:06
Цитата(Romany4 @  5.6.2009,  20:48 Найти цитируемый пост)
а если не использовать дату а брать только hh и mm?

Тогда с таймером в общем случае задача, скорее всего невыполнима.
Потому что таймер - объект не точный. Т.е. если выставить у него в интервал секунду, то это далеко не означает, что следующее срабатывание его будет ровно через секунду.
Таким образом, нельзя сказать, что он в обязательном порядке сработает в 00:00:00, может - чуть раньше, может - чуть позже.

Хотя...

можно попробовать так:

вместо  FLastDelDate и FLastCopyDate объявить

Код

FIsDeleted:boolean;


В OnTimer прописать:

Код

if (Time>=EncodeTime(0, 0, 0, 0)) and (Time<=EncodeTime(0, 1, 0, 0)) then
  if not FIsDeleted then
    begin
      DoDeleteFile;
      FIsDeleted:=True;
    end;

if (Time>=EncodeTime(8, 0, 0, 0)) and (Time<=EncodeTime(8, 1, 0, 0)) then
  if FIsDeleted then
    begin
      DoCopyFile;
      FIsDeleted:=False;
    end;

Автор: Romany4 5.6.2009, 21:52
Спасибо, буду пробовать.
Если честно мало что понимаю, пробую и так и эдак, используя листинги различных примеров.
Хреново получается, но думаю, что-нибудь, да будет smile

Автор: kami 5.6.2009, 22:11
Цитата(Romany4 @  5.6.2009,  21:52 Найти цитируемый пост)
Если честно мало что понимаю,

Ну так ты же вроде именно затем задал вопрос, чтобы что-то понять?
Тогда не вижу причин, чтобы не задавать уточняющих вопросов.
Спрашивай.
Иначе дальше постоянно будет  "дайте готовый код"

Автор: Romany4 5.6.2009, 23:00
 smile У меня столько вопросов, что вы предпочтете дать готовый код, нежели на них отвечать.
Мне просто неудобно всё спрашивать. Буду стараться и своей головой думать. Не зря ж на программиста решил учиться smile

Автор: kami 6.6.2009, 10:15
Цитата(Romany4 @  5.6.2009,  23:00 Найти цитируемый пост)
предпочтете дать готовый код, нежели на них отвечать

Это если решение настолько очевидно, что каким-то образом его пояснять - ... (дальше подставить нужную фразу).

Поправка - в таком случае проще отправить RTFM smile 

Автор: Romany4 6.6.2009, 16:15
smile С проверкой времени я справился, спасибо вам. Продолжаю усложнять программу. Теперь нужно, чтобы программа убивала процесс в определенное время и тут же его создавала.

Автор: Proxin 6.6.2009, 16:23
http://www.delphirus.com/modules.php?name=News&file=article&sid=32
Тут, возможно, найдёшь полезное.

Автор: kami 6.6.2009, 16:26
Цитата(Romany4 @  6.6.2009,  16:15 Найти цитируемый пост)
нужно, чтобы программа убивала процесс в определенное время и тут же его создавала.

Зачем его убивать? Это жестоко. А нормально завершить не судьба?
Чей процесс - свой или чужой? И это сервис или простое приложение?

Автор: Romany4 6.6.2009, 16:35
Нашел такой код:

Код

function KillTask(ExeFileName: string): integer;
const
  PROCESS_TERMINATE=$0001;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  result := 0;

  FSnapshotHandle := CreateToolhelp32Snapshot
  (TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle,
  FProcessEntry32);

  while integer(ContinueLoop) <> 0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
    UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
    UpperCase(ExeFileName))) then
      Result := Integer(TerminateProcess(OpenProcess(
      PROCESS_TERMINATE, BOOL(0), FProcessEntry32.th32ProcessID), 0));
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  end;
procedure TForm1.Button1Click(Sender: TObject);
begin
 killtask ('hfs2b.exe')
end;

Проверил - работает, но как именно он работает - я не понял.
Кто-нибудь может прокомментировать?
Для чего объявляется переменные   
ContinueLoop: BOOL;
FSnapshotHandle: THandle;

Что за result:=0? Она ведь нигде не объявляется? А дальше вообще дебри. Ничего не понял smile

Автор: Romany4 6.6.2009, 16:51
Цитата(kami @ 6.6.2009,  16:26)
Цитата(Romany4 @  6.6.2009,  16:15 Найти цитируемый пост)
нужно, чтобы программа убивала процесс в определенное время и тут же его создавала.

Зачем его убивать? Это жестоко. А нормально завершить не судьба?
Чей процесс - свой или чужой? И это сервис или простое приложение?

kami, сейчас расскажу в чем вообще суть программы.
Программа нужна для того, чтобы менять IP-фильтры приложения FlyLink DC++.
У нас в регионе проблема с тарификацией трафика в зависимости от времени суток.
Ночью фильтры не используются, так как трафик становится бесплатным, поэтому после полуночи я удаляю файл фильтра.
А с утра, в 8 часов, вновь его создаю или копирую из резерва.
Чтобы фильтры имели силу после смены, требуется перезапустить клиент DC++. Для этого мне и нужно завершить его процесс, и вновь запустить.
На данный момент я не знаю всех методов выполнения конкретной задачи, поэтому использую что могу. 
Не знаю, как правильно завершить процесс FlyLinkDC.exe, поэтому предложил известный мне вариант. Если знаете как корректно завершить работу программы - подскажите.
Программа обычно свернута в трей и не имеет открытого окна (видел способы закрывать окна программы, что в данном случае сработало бы).
И еще, если завершить работу программы как следует, то программа выгружается не сразу, а спустя короткое время. Мне же необходимо после закрытия клиента вновь его запустить, но если клиент не успел выгрузиться -  в диалоговом окне предложится запустить копию, что нежелательно и к тому прервет автоматизацию процесса перезапуска.
Вот такие пироги smile Может быть я выбрал не совсем правильный путь решения, но делаю себе снисхождение как новичку. В дальнейшем, набравшись опыта, возможно и найду более рациональное решение.

Автор: kami 6.6.2009, 20:52
Цитата(Romany4 @  6.6.2009,  16:51 Найти цитируемый пост)
Программа обычно свернута в трей и не имеет открытого окна (видел способы закрывать окна программы, что в данном случае сработало бы).

Если окно не "висит" на экране, это не значит, что его нет (как и суслика в ДМБ smile ).
Завершение процесса через TerminateProcess - это жестокая вещь, означающая, что процесс перестает существовать даже не успев мявкнуть. Не говоря уже о том, чтобы корректно завершить свою работу и деинициализировать все, что использует. И делать так нужно в крайних, не терпящих отлагательства случаях.
Поэтому если есть возможность - лучше завершить правильно. И подождать завершения используя WaitForSingleObject.

ContinueLoop: BOOL;
Эта переменная содержит результат выполнения функций Process32XXX. Потому что если хоть одна не выполнена, то дальнейшее выполнение кода теряет смысл.

FSnapshotHandle: THandle; - это идентификатор снимка списка процессов.
Сперва создается снимок (CreatexxxSnapshot), а потом из него получаем информацию о первом процессе (Process32First) и последующих (Process32Next).

Result - это то, что вернется после вызова этой функции. Любая ф-я неявно имеет эту переменную.
И она более чем используется (нужно только код нормально отформатировать, все станет видно).
Result:=0; - мы же заранее не знаем, выполнятся ли Create...Snapshot и Process32XXX? Значит, в случае их не-отработки нужно вернуть результат "все плохо", т.е. 0. 
А дальше проходя по списку процессов и найдя нужный:

Цитата(Romany4 @  6.6.2009,  16:35 Найти цитируемый пост)
Код

Result := Integer(TerminateProcess(OpenProcess(PROCESS_TERMINATE, BOOL(0), FProcessEntry32.th32ProcessID), 0));

И результатом будет уже то, отработало ли TerminateProcess или нет.

Автор: Romany4 6.6.2009, 21:07
Это ладно. Потом разберусь. Я что-то с формой намудрил. Теперь при запуске появляется такое:
user posted image
Копался только в Properties Формы (и только)
Не подскажете где искать решение?

Добавлено через 3 минуты и 14 секунд
Здесь свои посты нельзя удалять? Поторопился, вместо того, чтобы пораскинуть мозгами. Поменял
FormStyle на Child получил ошибку.

Автор: Romany4 6.6.2009, 22:32
kami, Большое спасибо за помощь. Худо-бедно программу реализовал, основные функции выполняются. Процесс завершаю всё-таки через TerminateProcess. Осталось ждать предложений от сотоварищей по хабу, и вносить изменений. Думаю работы будет много.

Перво-наперво хочу поместить иконку в трей, чтобы программа не отображала окно вообще.
Вы согласитесь помочь в случае чего? Чтобы не засорять форум буду писать в этой теме.

Автор: THandle 7.6.2009, 09:50
Цитата(Romany4 @  6.6.2009,  23:32 Найти цитируемый пост)
Перво-наперво хочу поместить иконку в трей, чтобы программа не отображала окно вообще.
Вы согласитесь помочь в случае чего? Чтобы не засорять форум буду писать в этой теме. 



 ! 
THandle
Правила форума: http://forum.vingrad.ru/index.php?act=boardrules

Пункт №10


Вот ссылка по трею:
http://forum.vingrad.ru/index.php?showtopic=197999&view=findpost&p=1425160

Остальные вопросы задавайте в новых темах.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)