Подскажите пожалуйста верно ли копаю.
Идея следующая.
Нужен некий сервис, к нему подключаются плагины (DLL некие). Эти DLL должны отслеживать изменения в БД (эвенты от IB/FB) и посылать письма.
Итого. Мне необходимо создать сервис-приложение. На старт сервиса повесить как то регистрацию плагина, т.е. это я так понимаю некий поток в котором должна работать DLL. Смысл в том, что по большому счету сам сервис ничего не делает, он должен просто управлять плагином — запустить поток и при останове сервиса остановить его. Сама DLL может быть какой угодно, т.е. хоть по таймеру вызывать формы диалога.
Подскажите, или если есть, костяк всего этого. А то общую картину вижу, а по частям как-то не складывается. Т.е. как к примеру запустить в потоке DLL, и верно ли вот это?
procedure TService1.ServiceExecute(Sender: TService);
begin
while not Terminated do begin
ServiceThread.ProcessRequests(false);
end;
end;
Или все же тут должна быть некая обработка?
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
S>Подскажите пожалуйста верно ли копаю. S>Идея следующая. S>Нужен некий сервис, к нему подключаются плагины (DLL некие). Эти DLL должны отслеживать изменения в БД (эвенты от IB/FB) и посылать письма. S>Итого. Мне необходимо создать сервис-приложение. На старт сервиса повесить как то регистрацию плагина, т.е. это я так понимаю некий поток в котором должна работать DLL. Смысл в том, что по большому счету сам сервис ничего не делает, он должен просто управлять плагином — запустить поток и при останове сервиса остановить его. Сама DLL может быть какой угодно, т.е. хоть по таймеру вызывать формы диалога. S>Подскажите, или если есть, костяк всего этого. А то общую картину вижу, а по частям как-то не складывается. Т.е. как к примеру запустить в потоке DLL, и верно ли вот это? S>procedure TService1.ServiceExecute(Sender: TService); S>begin S> while not Terminated do begin S> ServiceThread.ProcessRequests(false); S> end; S>end; S>Или все же тут должна быть некая обработка?
1. Не используй событие ServiceExecute. Обязательно вытри.
2. Повесь свой код на ServiceStart — запусти свой поток(и)
3. ServiceStop — останови поток(и)
Здравствуйте, Danchik, Вы писали: D>1. Не используй событие ServiceExecute. Обязательно вытри. D>2. Повесь свой код на ServiceStart — запусти свой поток(и) D>3. ServiceStop — останови поток(и)
Ясно.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
При попытке запуска службы, в случае если она использует функцию из DLL, происходит вылет по ошибке 1053.
Функция уже упрощена до минимума — выводит месадж_бокс.
Если же повесить вызов функции на крейт сервиса и запустить сервис как приложение, то все работает как надо, но если попробывать ег стартовать, то выдает ошибку и не стартует.
Может быть нельзя использовать функции DLL в сервисах??? Бред. Если можно, то какие особенности их вызова?
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
S>При попытке запуска службы, в случае если она использует функцию из DLL, происходит вылет по ошибке 1053.
1053 — Старт занимает слишком много времени
S>Функция уже упрощена до минимума — выводит месадж_бокс.
Месадж бокс в сервисе выводить нельзя (читай не рекомендуется, трудно), особенно делфовский. Для этого нужно играться с интерактивными сервисами.
Да и если ты месадж бокс выдаш 1053 тебе обеспечен.
S>Если же повесить вызов функции на крейт сервиса и запустить сервис как приложение, то все работает как надо, но если попробывать ег стартовать, то выдает ошибку и не стартует.
Случайно COM не используеш?
S>Может быть нельзя использовать функции DLL в сервисах??? Бред. Если можно, то какие особенности их вызова?
Можна, только есть ограничения на использование, например с GUI (правда и это обходится, но не так просто)
Здравствуйте, Danchik, Вы писали:
D>Месадж бокс в сервисе выводить нельзя (читай не рекомендуется, трудно), особенно делфовский. Для этого нужно играться с интерактивными сервисами. D>Да и если ты месадж бокс выдаш 1053 тебе обеспечен.
Как ни странно, но щас щапустил — все работает, даже при них. Причина была бональна — не находил DLL, так как она была включена в шифрованную папку.
S>>Может быть нельзя использовать функции DLL в сервисах??? Бред. Если можно, то какие особенности их вызова? D>Можна, только есть ограничения на использование, например с GUI (правда и это обходится, но не так просто)
Проблема щас в другом, точнее не проблема а непонятнка. Стартует поток Thread.Execute; но как только Execute выполнилось поток тут же вызывает DoTerminate. В итоге я не сильно соображаю, каким образом не завершать работу потока пока ему явно не придет на это команды??? Ну не делать же в Execute Repeat Until Terminated; — так же все ресурсы можно посадить!
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Т.е. картина проста — мне необходимо, что бы поток запустивший ДЛЛ (в ней находится DataModule, на котором уже может висеть и отправка писем и проверка эвентов из базы и прочее) не закрывался сам по себе. В ДЛЛ я просто пишу
procedure StartPluggin;
begin
dmNSTL := TdmNSTL.Create(nil);
end;
procedure StopPluggin;
begin
dmNSTL.Free;
end;
И ожидаю, что пока не будет вызван StopPluggin; форма будет висеть в памяти.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
"Strannic" <10509@users.rsdn.ru> wrote in message news:1187099@news.rsdn.ru... >Ну не делать же в Execute Repeat Until Terminated; — так же все ресурсы можно посадить!
делать
repeat
sleep(100) (или Sleep(0))
until terminated;
?!?!?
Удевлен. Но однако все равно что-то не так с этой ДЛЛ потоке...
procedure TDllThread.Execute;
Const DLL = 'C:\Work\Service\DLL\NSTL\bNSTL.dll';
begin
HandleDLL := LoadLibrary(DLL);
if HandleDLL <> 0 then
begin
@StartPluggin := GetProcAddress(HandleDLL, 'StartPluggin');
@StopPluggin := GetProcAddress(HandleDLL, 'StopPluggin');
if( (@StartPluggin = nil)or(@StopPluggin = nil) )then begin
MessageDlg('Плагин '+DLL+ ' не соответствует требуемому.',mtInformation,[mbOk],0);
Exit;
end;
StartPluggin;
end
else
MessageDlg('Не найден указанный плагин - '+DLL,mtError,[mbOk],0);
MessageDlg('1',mtInformation,[mbOk],0); -- первый месадж
repeat
sleep(100);
until terminated;
MessageDlg('2',mtInformation,[mbOk],0); -- второй месадж
end;
В DLL на DataModule лежит таймер, и он бипает каждую секунду. Так вот когда вызываеться месадж 1 — он бибает. после его закрытия тишина. причем сервис закрыть не удаеться — очень долго висит в ожидани, после чего я его снимаю ручками. да 2-го месаджа так и не добирается.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
S>Проблема щас в другом, точнее не проблема а непонятнка. Стартует поток Thread.Execute; но как только Execute выполнилось поток тут же вызывает DoTerminate. В итоге я не сильно соображаю, каким образом не завершать работу потока пока ему явно не придет на это команды??? Ну не делать же в Execute Repeat Until Terminated; — так же все ресурсы можно посадить!
Тут тебе необходимо в потоке организовать очередь сообщений.
Можно сделать ее самым банальным способом — создать в потоке окно и посылать к нему сообщения с помощью функций SendMessage (дождаться результата) и PostMessage (поставить сообщение в очередь и продолдать работать)
Создать окно AllocateHWnd и уничтожить DeallocateHWnd (юнит Forms.pas)
Твой поток будет выглядеть так:
const
MY_MESSAGE_BASE = CM_BASE + 1000;
MY_MESSAGE1 = MY_MESSAGE_BASE + 1; // sample message 1
MY_MESSAGE2 = MY_MESSAGE_BASE + 2; // sample message 2type
TPluginThread = class (TThread)
private
FWndHandle: HWND;
protected
procedure WndProc(var Message: TMessage); virtual;
procedure Execute; override;
procedure Idle;
function ProcessMessage(var Msg: TMsg): Boolean;
procedure ProcessMessages;
private
procedure MyMessage1(var Message: TMessage); message MY_MESSAGE1;
procedure MyMessage2(var Message: TMessage); message MY_MESSAGE2;
public
property WndHandle: HWND read FWndHandle;
end;
implementation
procedure TPluginThread.Execute;
begin
try
FWndHandle := AllocateHWND (WndProc);
try
ProcessMessages;
finally
DeallocateHWnd (FWndHandle);
end;
except// kill any exceptionsend;
end;
procedure TPluginThread.ProcessMessages;
var
Msg: TMsg;
begin
while not Terminated and ProcessMessage (Msg) do{loop};
end;
function TPluginThread.ProcessMessage(var Msg: TMsg): Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
if GetMessage (Msg, 0, 0, 0) then begin
Result := True;
if Msg.Message <> WM_QUIT then begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end else
Terminate;
end;
end else
WaitMessage;
Idle;
end;
procedure TPluginThread.Idle;
begin{ do something if you want}end;
procedure TPluginThread.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except// kill exceptions;end;
end;
procedure TPluginThread.MyMessage1(var Message: TMessage);
begin// do somethingend;
procedure TPluginThread.MyMessage2(var Message: TMessage);
begin// do somethingend;
Здравствуйте, Strannic, Вы писали:
S>?!?!? S>Удевлен. Но однако все равно что-то не так с этой ДЛЛ потоке...
Sleep позволяет отдать время твоего потока Windows, что предотвратит перегрузку процессора. Лично я не люблю такой подход к написанию потоков — как
то не чисто выглялит. Есть такое понятие Event — вот это вариант когда необходимо продолжать работать, а не крутится на месте пока какой то флажок не поставят.
S>
S>procedure TDllThread.Execute;
S>Const DLL = 'C:\Work\Service\DLL\NSTL\bNSTL.dll';
S>begin
S> HandleDLL := LoadLibrary(DLL);
S> if HandleDLL <> 0 then
S> begin
S> @StartPluggin := GetProcAddress(HandleDLL, 'StartPluggin');
S> @StopPluggin := GetProcAddress(HandleDLL, 'StopPluggin');
S> if( (@StartPluggin = nil)or(@StopPluggin = nil) )then begin
S> MessageDlg('Плагин '+DLL+ ' не соответствует требуемому.',mtInformation,[mbOk],0);
S> Exit;
S> end;
S> StartPluggin;
S> end
S> else
S> MessageDlg('Не найден указанный плагин - '+DLL,mtError,[mbOk],0);
S>MessageDlg('1',mtInformation,[mbOk],0); -- первый месадж
S> repeat
S> sleep(100);
S> until terminated;
S>MessageDlg('2',mtInformation,[mbOk],0); -- второй месадж
S>end;
S>
S>В DLL на DataModule лежит таймер, и он бипает каждую секунду. Так вот когда вызываеться месадж 1 — он бибает. после его закрытия тишина. причем сервис закрыть не удаеться — очень долго висит в ожидани, после чего я его снимаю ручками. да 2-го месаджа так и не добирается.
Ты на ServiceStop вызывал MyThread.Terminate?
Да и черт побери , перестань вызывать MessageDlg — это может тебе подвесить сервис. VCL не thread-safe. Если тебе уж так необходимо мессадж боксы видеть — вызывай MessageBox из Windows.pas
Не сочтите совсем за деревянного, но что-то в этой жизни я безвозвратно упустил....
Бипы в ДЛЛ, а как я понимаю и выполнение ее, идут лишь в случае если повесить после запуска потока месадж. Т.е. пока висит месадж плагин крутиться, и как бы работает, но как только я его закрою — все — обработка его завершается. Почему??? Т.е. ДЛЛ работает пока явно держать систему на диалоге? Понимаю, что не так, а в чем тогда дело?
Даже если я просто вешал пустой цикл после вызова функции из ДЛЛ, то работа с этой ДЛЛ (бипы по таймеру) прекращалась.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
S>Не сочтите совсем за деревянного, но что-то в этой жизни я безвозвратно упустил.... S>Бипы в ДЛЛ, а как я понимаю и выполнение ее, идут лишь в случае если повесить после запуска потока месадж. Т.е. пока висит месадж плагин крутиться, и как бы работает, но как только я его закрою — все — обработка его завершается. Почему??? Т.е. ДЛЛ работает пока явно держать систему на диалоге? Понимаю, что не так, а в чем тогда дело? S>Даже если я просто вешал пустой цикл после вызова функции из ДЛЛ, то работа с этой ДЛЛ (бипы по таймеру) прекращалась.
Поток заканчивает свою работу после того как выходит из метода Execute — надеюсь это понятно.
Возьми класс который я тебе написал перед этим.
Сделай так:
Здравствуйте, Danchik, Вы писали:
D>Ты на ServiceStop вызывал MyThread.Terminate?
Да.
D>Да и черт побери , перестань вызывать MessageDlg — это может тебе подвесить сервис. VCL не thread-safe. Если тебе уж так необходимо мессадж боксы видеть — вызывай MessageBox из Windows.pas
Да это типа для отладки — не более.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Danchik, Вы писали:
D>Поток заканчивает свою работу после того как выходит из метода Execute — надеюсь это понятно.
Вот это как раз понятно.
D>Возьми класс который я тебе написал перед этим. D>Сделай так:
Все сделал. В итоге не получаю вызова MyMessage1 — проверял бипами.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
S>Все сделал. В итоге не получаю вызова MyMessage1 — проверял бипами.
MyMessage2 — тоже не приходит
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
DllThread := TDllThread.Create(false);
PostMessage (DllThread.WndHandle, MY_MESSAGE1, 0, 0);
Started := True;
end;
procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
if DllThread <> nil then
SendMessage (DllThread.WndHandle, MY_MESSAGE2, 0, 0);
Stopped := True;
end;
Однако месаджы не проходят.
Причем после
DllThread := TDllThread.Create(false);
DllThread.WndHandle = 0
естественно месадж не попадает
PostMessage (DllThread.WndHandle, MY_MESSAGE1, 0, 0);
Однако "0" почему пока не ясно
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
S>Здравствуйте, Danchik, Вы писали:
D>>Ты на ServiceStop вызывал MyThread.Terminate? S>Да.
D>>Да и черт побери , перестань вызывать MessageDlg — это может тебе подвесить сервис. VCL не thread-safe. Если тебе уж так необходимо мессадж боксы видеть — вызывай MessageBox из Windows.pas
S>Да это типа для отладки — не более.
Вот именно эта отладка может тебе все испортить и ты не поймеш в чем дело. Пиши лучше в файл
Здравствуйте, Danchik, Вы писали: D>Можно сделать ее самым банальным способом — создать в потоке окно и посылать к нему сообщения с помощью функций SendMessage (дождаться результата) и PostMessage (поставить сообщение в очередь и продолдать работать)
D>Создать окно AllocateHWnd и уничтожить DeallocateHWnd (юнит Forms.pas)
Совершенно необязательно. Можно пользоваться PostThreadMessage и не думать, в какой оконной станции создается окно.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.