Подскажите пожалуйста верно ли копаю.
Идея следующая.
Нужен некий сервис, к нему подключаются плагины (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>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
D>И иеще протрассируй создалось ли окно в методе Execute
Сделал как ты написал. Окно создаеться хендл принимает значение, но месадж все равно не приходит.
Но вопрос мне кажеться еще в следующем: даже если я делал просто цикл в конце Execute, то ДЛЛ перестает работать (на ней как я уже писал есть Beep на таймере). Т.е. может быть в принципе такая идея не работоспособна?
И по ходу вопрос:
по условию задачи (но это худший вариант) я могу писать для каждого свой сервис, вместо плагина к сервису. Но... что лучше? или они одинаковы по затратам машинного времени и загрузкам процессора? или все же один сервис с десятком плагинов работающих в потоке лучше чем десяток сервисов?
З.Ы.: М-да — не выходит каменный цветок.
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Danchik, Вы писали: D>>Можно сделать ее самым банальным способом — создать в потоке окно и посылать к нему сообщения с помощью функций SendMessage (дождаться результата) и PostMessage (поставить сообщение в очередь и продолдать работать)
D>>Создать окно AllocateHWnd и уничтожить DeallocateHWnd (юнит Forms.pas) S>Совершенно необязательно. Можно пользоваться PostThreadMessage и не думать, в какой оконной станции создается окно.
Так то оно так, только вот SendThreadMessage нету . Необходимо как то синхронизироваться.
Здравствуйте, Strannic, Вы писали:
D>>И иеще протрассируй создалось ли окно в методе Execute
S>Сделал как ты написал. Окно создаеться хендл принимает значение, но месадж все равно не приходит.
Странненько... Проверь попадает ли в WndProc метод.
S>Но вопрос мне кажеться еще в следующем: даже если я делал просто цикл в конце Execute, то ДЛЛ перестает работать (на ней как я уже писал есть Beep на таймере). Т.е. может быть в принципе такая идея не работоспособна?
Кажется я таки понял в чем твоя проблема. Timer — это те же Windows сообщения, соответственно их нужно обрабатывать, и причем в том же потоке где Timer был создан. Так как предложенный мною поток имеет реализацию обработки сообщений — то тебе абсолютно ничего не надо дописывать. Но одно но — создавать все Модули и стартовать плагины нужно именно в Execute. Конструктор Create потока для этих целей не подходит.
S>И по ходу вопрос: S>по условию задачи (но это худший вариант) я могу писать для каждого свой сервис, вместо плагина к сервису. Но... что лучше? или они одинаковы по затратам машинного времени и загрузкам процессора? или все же один сервис с десятком плагинов работающих в потоке лучше чем десяток сервисов? S>З.Ы.: М-да — не выходит каменный цветок.
Думаю что все таки один сервис лучше Не будеш же ты из-за каждого плагина регистрить новый сервис
D>Странненько... Проверь попадает ли в WndProc метод.
Да попадает.
D>Кажется я таки понял в чем твоя проблема. Timer — это те же Windows сообщения, соответственно их нужно обрабатывать, и причем в том же потоке где Timer был создан. Так как предложенный мною поток имеет реализацию обработки сообщений — то тебе абсолютно ничего не надо дописывать. Но одно но — создавать все Модули и стартовать плагины нужно именно в Execute. Конструктор Create потока для этих целей не подходит.
Т.е. мне необходимо иметь клас плагина, коий нужно экспортировать из DLL, причем незнаю как, и который создавать на Execute потока, а уже реализацию создания этого класса можно(нужно) делать в самой DLL плагина. Верно я понял? Или может лучше в этом случае плагины писать как потоки, но каждый плагин это один поток. Т.е. реализацию DLL делать как поток? А по событию останова сервиса вызывать функцию DLL, которая будет глушить этот поток.
Еще. А нужнен ли TDllThread.MyMessage2, ведь как только Execute отработает автматом будет вызван TDllThread.DoTerminate, может более коректно на нем производить остановку и выгрузку DLL, т.е. вместо
procedure TDllThread.MyMessage2(var Message: TMessage);
begin
if HandleDLL <> 0 then StopPluggin;
Terminate;
FreeLibrary(HandleDLL);
end;
procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
if DllThread <> nil then
SendMessage (DllThread.WndHandle, MY_MESSAGE2, 0, 0);
Stopped := True;
end;
сделать просто
procedure TDllThread.DoTerminate;
begin
if HandleDLL <> 0 then StopPluggin;
FreeLibrary(HandleDLL);
end;
что скажешь?
D>Думаю что все таки один сервис лучше Не будеш же ты из-за каждого плагина регистрить новый сервис
Поэтому и хотел смотреть в сторону плагинов к сервису. А что касаеться производительности там, загрузки проца и прочее, я понимаю, что щас это не критично, но все же? Так — что называеться для в общеобразовательных целях?
Любая проблема проектирования может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев.
Здравствуйте, Strannic, Вы писали:
D>>Странненько... Проверь попадает ли в WndProc метод.
S>Да попадает.
D>>Кажется я таки понял в чем твоя проблема. Timer — это те же Windows сообщения, соответственно их нужно обрабатывать, и причем в том же потоке где Timer был создан. Так как предложенный мною поток имеет реализацию обработки сообщений — то тебе абсолютно ничего не надо дописывать. Но одно но — создавать все Модули и стартовать плагины нужно именно в Execute. Конструктор Create потока для этих целей не подходит.
S>Т.е. мне необходимо иметь клас плагина, коий нужно экспортировать из DLL, причем незнаю как, и который создавать на Execute потока, а уже реализацию создания этого класса можно(нужно) делать в самой DLL плагина. Верно я понял?
Я бы тебе советовал сделать плагины COM in-proс серверами. Правда это нужно долго обьяснять
Можна также сделать конструкцию типа:
S>Или может лучше в этом случае плагины писать как потоки, но каждый плагин это один поток. Т.е. реализацию DLL делать как поток? А по событию останова сервиса вызывать функцию DLL, которая будет глушить этот поток.
Думаю не стоит писать полагины потоками, но тоже вариант, иногда это необходимо
S>Еще. А нужнен ли TDllThread.MyMessage2, ведь как только Execute отработает автоматом будет вызван TDllThread.DoTerminate, может более коректно на нем производить остановку и выгрузку DLL, т.е. вместо
S>
S>procedure TDllThread.MyMessage2(var Message: TMessage);
S>begin
S> if HandleDLL <> 0 then StopPluggin;
S> Terminate;
S> FreeLibrary(HandleDLL);
S>end;
S>procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
S>begin
S> if DllThread <> nil then
S> SendMessage (DllThread.WndHandle, MY_MESSAGE2, 0, 0);
S> Stopped := True;
S>end;
S>
S>сделать просто S>
S>procedure TDllThread.DoTerminate;
S>begin
S> if HandleDLL <> 0 then StopPluggin;
S> FreeLibrary(HandleDLL);
S>end;
S>
S>что скажешь?
DoTerminate вызывается в главном потоке приложения — это невсегда корректно, да и может подвесить всю программу если StopPlugin зависнет.
Первый вариант более предпочтительней.
D>>Думаю что все таки один сервис лучше Не будеш же ты из-за каждого плагина регистрить новый сервис
S>Поэтому и хотел смотреть в сторону плагинов к сервису. А что касаеться производительности там, загрузки проца и прочее, я понимаю, что щас это не критично, но все же? Так — что называеться для в общеобразовательных целях?
Советую тебе сделать тестовую программу с двумя кнопками Start (like ServiceStart) и Stop (like ServiceStop).
На ней ты сможеш протестить как все работает в дебаге (это проще чем дебажить сервис).
А потом код перенеси на сервис. Если не будет работать можна проанализировать что у тебя с Permission и другой функциональностью, которая некорректно работает в сервисе.