Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.07.2011, 03:09   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию TService после запуска, должен запустить TThread но он этого не делает.

Доброго времени суток!

Задачка:
Создать приложение-сервис.

Что делает приложение?
У приложения есть таймер. Таймер по умолчанию включен, разве что интервал работы таймера, вводит пользователь через файл ini.
Когда таймер отстучал свой интервал, запускается поток TThread.

Проблема в том, что я немогу толково написать этот TService

Ну просто не запускает поток.. ну почему??
Заодно, можно указать мне на ошибки, которые я допустил?

Вот код:
Код:
unit MainUnit;

interface

uses
    {вырезано}
    Miscunit, WorkThreadUnit, DataModuleUnit;

type
  TSFU = class(TService)
    Timer: TTimer;
  private
 {вырезано}
    { Private declarations }
  publiс
  {вырезано}
    { Public declarations }
    procedure OnTermThread(Sender: TObject);
  end;

var
  SFU: TSFU;
  Thr: TWorkThread; //поток

implementation

{$R *.DFM}

// параметры
procedure LoadServiceSettings;
var
  Ini: TiniFile;
begin
  Ini := TiniFile.Create(GetDataPath + ConfigFile);
  try
    SFU.DisplayName := Ini.ReadString('Service', 'DisplayName', 'FUS');
    SFU.Interactive := Ini.ReadBool('Service', 'Interactive', False);
    SFU.AllowPause := Ini.ReadBool('Service', 'UserAllowPause', False);
    SFU.AllowStop := Ini.ReadBool('Service', 'UserAllowStop', False);
  finally
    FreeAndNil(Ini);
  end;
end;
//

// управление потоком//

procedure StopThread;
begin
  If not(Thr = nil) then
  begin
    Thr.Terminate;
  end;
end;

procedure RunThread;
begin
  If (Thr = nil) then
  begin
    // thread
    Thr := TWorkThread.Create(True);
    Thr.FreeOnTerminate := True;
    Thr.OnTerminate := SFU.OnTermThread;
    Thr.Priority := tpNormal;
    Thr.Resume;
  end;
end;

procedure PauseThread;
begin
  If not(Thr = nil) then
  begin
    Thr.Suspend;
  end;
end;

procedure ResumeThread;
begin
  If not(Thr = nil) then
  begin
    Thr.Resume;
  end;
end;

procedure TSFU.OnTermThread(Sender: TObject);
begin
  If not(Thr = nil) then
  begin
    log('Thread terminated.');
    log('------------------------------------');
    Thr := nil;
  end;
end;

// управление потоком\\

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  SFU.Controller(CtrlCode);
end;

function TSFU.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TSFU.ServiceBeforeInstall(Sender: TService);
begin
  LoadServiceSettings;
end;

procedure TSFU.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
  ResumeThread;
  Continued := True;
end;

procedure TSFU.ServicePause(Sender: TService; var Paused: Boolean);
begin
  PauseThread;
  Paused := True;
end;

procedure TSFU.ServiceShutdown(Sender: TService);
begin
  StopThread;
  Timer.Enabled := False;
end;

procedure TSFU.ServiceStart(Sender: TService; var Started: Boolean);
begin
  Timer.Interval:=TimerInterval;
  Timer.Enabled := True;
  Started := True;
end;

procedure TSFU.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  StopThread;
  Timer.Enabled := False;
  Stopped := True;
end;

procedure TSFU.TimerTimer(Sender: TObject);
begin
  RunThread;
end;

end.
Чтение настроек в таймер происходит в DataModule.

Очень прошу помощи у тех, кто разбирается, и уже писал подобного рода приложения.

Последний раз редактировалось Человек_Борща; 04.07.2011 в 03:13.
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2011, 12:57   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

1) неплохо бы выводить в лог состояние сервиса - запущен, остановлен, и т.д., а то может дело до таймера вобще не доходит.

2) TimerInterval вывести в лог, может там на несколько часов интервальчик

3) в лог выводим, что RunThread() отработал, возможно, до него дело и не доходит.

4) если RunThread() отрабатывает, давайте исходник TWorkThread.

5) и желательно глобальную переменную Thr сделать полем класса TSFU, т.к. один модуль может содержать несколько сервисов.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 04.07.2011 в 13:05.
veniside вне форума Ответить с цитированием
Старый 04.07.2011, 13:18   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
2) TimerInterval вывести в лог, может там на несколько часов интервальчик
Нет. Таймер на 5 секунд.

Цитата:
Сообщение от veniside Посмотреть сообщение
4) если RunThread() отрабатывает, давайте исходник TWorkThread.
TworkThread работает стабильно и 100%. Перед созданием сервиса, я издевался на VCL приложением.

С сервисом чуть сложнее.

Вообще всё должно быть так:
Запускается сервис, запускается таймер.
По окончанию интервала запускается поток TThread.

Какие события сервиса вообще использовать мне?
так же к сервису подключен DataModule.
В его OnCreate создаются и загружаются все списки.
А так же параметры для работы потока WorkThread.

Какое событие генерируется первым? DataModule.OnCreate или TSerrvice.OnCreate?


И последнее.. как производить отладку сервиса?
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2011, 13:45   #4
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> Нет. Таймер на 5 секунд.

без лога я бы с такой уверенностью это не утверждал.

> Запускается сервис, запускается таймер.

кстати, таймер-то работает через виндовые сообщения, а кто их выгребает? Я бы не советовал без крайней необходимости юзать контролы, основанные на сообщениях, в сервисах. В общем случае сервис не должен содержать окон и прочего кода, основанного на рассылке сообщений. Если так уж нужны окна, то лучше, если сервис будет запускать обычное гуевое приложение, которое будет тихонько сидеть в трее и делать что нужно. А если просто нужен таймер, то полно таймеров, не основанных на оконных сообщениях.

> как производить отладку сервиса?

логи рулят.

Для себя я обычно отлаживаю весь код вне сервиса, а потом просто оборачиваю его в сервис. Интерактивно отлаживать сервис в Дельфи нельзя (без танцев с бубном).
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 04.07.2011, 14:45   #5
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Цитата:
без лога я бы с такой уверенностью это не утверждал.
Утверждает мой код=) Явно в datamodule указывается:
TimerInterval:=1000; А по другому где-те ещё приплюсовать и не может.

Но логировать абсолютно все это вариант.
Цитата:
кстати, таймер-то работает через виндовые сообщения, а кто их выгребает? Я бы не советовал без крайней необходимости юзать контролы, основанные на сообщениях, в сервисах. В общем случае сервис не должен содержать окон и прочего кода, основанного на рассылке сообщений. Если так уж нужны окна, то лучше, если сервис будет запускать обычное гуевое приложение, которое будет тихонько сидеть в трее и делать что нужно. А если просто нужен таймер, то полно таймеров, не основанных на оконных сообщениях.
Мой сервис не имеет ни окон ни чего-либо подобного. Один DataModule подключен.

Можно показать пример такого таймера?

Я использую стандартный TTimer(При servce application он дотупен на вкладке System).

Цитата:
Для себя я обычно отлаживаю весь код вне сервиса, а потом просто оборачиваю его в сервис. Интерактивно отлаживать сервис в Дельфи нельзя (без танцев с бубном).
Я так и сделал. Создал Demo приложение, и там отлаживал работу потока.

Осталось прикрутить поток и таймер к сервису. Но я не знаю как заставить их работать. В сервисе....

Какие Свойства Tservice мне выставлять, и какими событиями пользоваться?
Что создаётся первым TService или DataModule?

И где наконец можно почитать нормальную документацию о обьекту TService?
Читал DRKB, читал справку Delphi 7,2010 и XE.

Последний раз редактировалось Человек_Борща; 04.07.2011 в 14:47.
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2011, 15:05   #6
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> логировать абсолютно все это вариант

всё не всё, но полезно выводить в лог ключевые значения и точки прохождения программы. И не забыть в релизе всё это логирование отключить (через {$IFDEF DEBUG } ).

> показать пример такого таймера?

Мультимедийный таймер, например. Работает в своём потоке, сообщения не использует.

> Что создаётся первым TService или DataModule?

ну так это в исходниках проекта надо глянуть. Скорей всего, DataModule. Кстати, кода для создания переменной SFU я вобще не вижу.

> И где наконец можно почитать нормальную документацию о обьекту TService?

Да это просто обёртка вокруг сервисного API, чё там документировать.

Вобще, мне кажется проще руками сервис поднимать, без Дельфовых обёрток. Больше контроля. Хотя, для простенького сервиса, вероятно, путь через File -> New -> Service Application будет достаточен.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 04.07.2011, 15:42   #7
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

окей.. потоптал форум. Нашёл полезное сообщение.

последовал вашему совету, логировать абсолютно все.

Создал тестовое Service Application с DataModule.

Project1.dpr
Код:
program Project1;

uses
  SvcMgr,
  Unit1 in 'Unit1.pas' {Service1: TService},
  Unit2 in 'Unit2.pas' {DataModule2: TDataModule};

{$R *.RES}

begin
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TService1, Service1);
  Application.CreateForm(TDataModule2, DataModule2);
  Application.Run;
end.
Unit1
Код:
type
  TService1 = class(TService)
    procedure ServiceAfterInstall(Sender: TService);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceBeforeInstall(Sender: TService);
    procedure ServiceBeforeUninstall(Sender: TService);
    procedure ServiceContinue(Sender: TService; var Continued: Boolean);
    procedure ServiceCreate(Sender: TObject);
    procedure ServiceDestroy(Sender: TObject);
    procedure ServiceExecute(Sender: TService);
    procedure ServicePause(Sender: TService; var Paused: Boolean);
    procedure ServiceShutdown(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
    procedure log(aStr: string);
  end;

var
  Service1: TService1;

implementation

{$R *.DFM}

procedure TService1.log(aStr: string);
var
  Ts: TstringList;
begin
  Ts := TstringList.Create;
  try
    If FileExists(ExtractFilePath(ParamStr(0)) + 'Log.txt') then
      Ts.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'Log.txt');
    Ts.Add(aStr);
    Ts.SaveToFile(ExtractFilePath(ParamStr(0)) + 'Log.txt');
  finally
    FreeAndNil(Ts);
  end;
end;

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;

function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TService1.ServiceAfterInstall(Sender: TService);
begin
  log('Service event: AfterInstall');
end;

procedure TService1.ServiceAfterUninstall(Sender: TService);
begin
  log('Service event: AfterUnistall');
end;

procedure TService1.ServiceBeforeInstall(Sender: TService);
begin
  log('Service event: BeforeInstall');
end;

procedure TService1.ServiceBeforeUninstall(Sender: TService);
begin
  log('Service event: BeforeUnistall');
  ServiceThread.ProcessRequests(True);
end;

procedure TService1.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
  log('Service event: OnContinue');
  Continued := True;
end;

procedure TService1.ServiceCreate(Sender: TObject);
begin
  log('Service event: OnCreate');
end;

procedure TService1.ServiceDestroy(Sender: TObject);
begin
  log('Service event: OnDestroy');
end;

procedure TService1.ServiceExecute(Sender: TService);
begin
  log('Service event: OnExecute');
end;

procedure TService1.ServicePause(Sender: TService; var Paused: Boolean);
begin
  log('Service event: OnPause');
  Paused := True;
end;

procedure TService1.ServiceShutdown(Sender: TService);
begin
  log('Service event: OnShutdown');
end;

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  log('Service event: OnStart');
  Started := True;
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  log('Service event: OnStop');
  Stopped := True;
end;

end.
Unit2
Код:
unit Unit2;

interface

uses
  SysUtils, Classes, Unit1;

type
  TDataModule2 = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DataModule2: TDataModule2;

implementation

{$R *.dfm}

procedure TDataModule2.DataModuleCreate(Sender: TObject);
begin
  Service1.Log('Data Module Event: OnCreate');
end;

procedure TDataModule2.DataModuleDestroy(Sender: TObject);
begin
  Service1.Log('Data Module Event: OnDestroy');
end;

end.
согласно полезному сообщению, должны логироваться события OnBeforeInstall/Uninstall, OnAfterInstall/Uninstall. И события Start,stop,pause,continue,execute,shutdown. Они тоже не логируются.

В лог заностися только создание/уничтожение DataModule.

Почему? Что я не так делаю?

голый сервис ведь..

Последний раз редактировалось Человек_Борща; 04.07.2011 в 15:44.
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2011, 15:51   #8
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> Почему? Что я не так делаю?

дык сервис надо сначала установить в систему, и запускать уже через SCM. Это ж не обычное приложение. Если не ошибаюсь, дельфовая обёртка умеет сама себя устанавливать, если запустить ваш сервис (как обычное приложения) с параметром -install.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 04.07.2011, 16:06   #9
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Вы меня за идиота держите?

Компилирую(Без запуска).
Устанавливаю сервис в систему. Иду в службы. Запускаю, приостанавливаю, продолжаю, перезапускаю, останавливаю.
Деинсталирую сервис из системы.

Результат:
Цитата:
Data Module Event: OnCreate
Data Module Event: OnDestroy
Data Module Event: OnCreate
Data Module Event: OnDestroy
Data Module Event: OnCreate
Data Module Event: OnDestroy
Data Module Event: OnCreate
Data Module Event: OnDestroy
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2011, 16:48   #10
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

В общем разобрался я:
Код:
procedure TService1.ServiceExecute(Sender: TService);
begin
  log('Service event: OnExecute');
  while not terminated do
  begin
    ServiceThread.ProcessRequests(True);
  end;
end;
Лог:
Цитата:
//instaling service
Service event: OnCreate
Data Module Event: OnCreate
Service event: BeforeInstall
Service event: AfterInstall
Data Module Event: OnDestroy
Service event: OnDestroy
//
//Запуск сервиса
Service event: OnCreate
Data Module Event: OnCreate
Service event: OnStart
Service event: OnExecute
//
//Паузка
Service event: OnPause
//
//Продолжить
Service event: OnContinue
//
//перезапустить
Service event: OnStop
Data Module Event: OnDestroy
Service event: OnDestroy
Service event: OnCreate
Data Module Event: OnCreate
Service event: OnStart
Service event: OnExecute
//
//Остановка сервиса
Service event: OnStop
Data Module Event: OnDestroy
Service event: OnDestroy
//
//Деинсталяция сервиса
Service event: OnCreate
Data Module Event: OnCreate
Service event: BeforeUnistall
Service event: AfterUnistall
Data Module Event: OnDestroy
Service event: OnDestroy
__ADDED__
Почему при коде:
Код:
procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
     Started := True;
  log('//Service start');
  log('Service event: OnStart');
  Timer.Interval := 2000;
  log('Timer interval:=' + IntToStr(Timer.Interval));
  Timer.Enabled := True;
  log('Timer status: Enabled!');
end;
SCM сообщает что сервису нечего делать?
Если убрать Timer.Enabled:=True; то все работает..

Последний раз редактировалось Человек_Борща; 04.07.2011 в 17:26.
Человек_Борща вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
После сохранения в файл *.xls при открытии этого файла выдается предупреждение. Как от этого избавиться? A-IX-2 Общие вопросы Delphi 1 13.11.2011 20:33
После пятой цифры макрос должен ставить дефис Manonia Microsoft Office Excel 4 22.03.2010 10:15
Удаление кнопки после первого запуска программы keet Помощь студентам 5 09.01.2010 23:35
Вот и верь СМИ после этого Роман Радер Свободное общение 13 29.10.2009 17:40
После запуска Торрента - загрузка проца 100% ??? spamer Компьютерное железо 11 29.04.2009 09:00