Как отправить пользовательское сообщение в службу Windows? - PullRequest
0 голосов
/ 08 октября 2010

Я реализовал приложение службы Windows XP, которое запускает несколько рабочих потоков. Из одного из потоков мне нужно отправить пользовательские сообщения обратно в сервис. Как мне это сделать?

Ответы [ 4 ]

1 голос
/ 08 октября 2010

Спасибо за вашу помощь. Вот как я решил проблему:

В определении класса обслуживания:

  WHandle: HWND;
protected
  procedure HandleServiceMessage(var Msg: TMessage); virtual;

В методе ServiceExecute:

  WHandle := AllocateHWnd(HandleServiceMessage);
  MyThread := TMyThread.Create(true);
  MyThread.HndMain := WHandle;
  MyThread.Resume;
  while not Terminated do ServiceThread.ProcessRequests(True);
  DeallocateHWnd(WHandle);
end;

В методе ServiceStop:

  MyThread.Terminate;

И метод обработки сообщений:

procedure TMessageService.HandleServiceMessage(var Msg : TMessage);
var
  Handled: Boolean;
begin
  Handled := True;
  if Msg.Msg = WM_MYMESSAGE then
    Beep
  else
    Handled := False;
  if Handled then
    Msg.Result := 0
  else
    Msg.Result := DefWindowProc(WHandle, Msg.Msg, Msg.WParam, Msg.LParam);
end;

В методе MyThread.Execute:

  PostMessage(HndMain,WM_MYMESSAGE,0,0);

Работает просто отлично.

1 голос
/ 08 октября 2010

Один из вариантов - использовать OmniThreadLibrary (для примера прочитайте в этом блоге ).

0 голосов
/ 08 октября 2010

Создание окна только для сообщений:

procedure TMyService.MessageQueueDispatch(var Message: TMessage);
begin
  Dispatch(Message); //Delphi default dispatcher for TMyService
end;

procedure TMyService.SomeKindOfOnCreate;
begin
  MessageQueue := AllocateHWnd(MessageQueueDispatch);
end;

Уничтожение:

procedure TMyService.SomeKindOfDestroy;
begin
  CloseHandle(MessageQueue);
end;

Теперь вы можете обрабатывать сообщения, как если бы вы работали с сообщениями в форме:

TMyService = class(TService)
...
protected
  procedure HandleMyMessage(var msg: TMsg); message WM_MY_MESSAGE;
end;

Обработчик Delphi Dispatch () позаботится о вызове функции.

0 голосов
/ 08 октября 2010

Я согласен с TOndrej, что общих объектов должно быть достаточно.

С другой стороны, вы можете использовать мой IPC ( Cromis IPC ), который прекрасно работает внутри сервисов.Он прост в использовании, ориентирован на сообщения, поэтому вам не нужно знать, как работают именованные каналы, и очень быстро.Серверная часть также использует пул потоков, поэтому не нужно ждать обработки чего-либо.Вы можете использовать сценарий «забей и забудь».

Или, если вы считаете, что небольшая редизайн в порядке, вы можете попробовать OmniThreadLibrary, в котором уже встроен весь обмен сообщениями и который предназначен для подобных задач.

РЕДАКТИРОВАТЬ :

Хорошо, возможно, самый чистый путь, без каких-либо изменений, - это иметь общий список объектов, который защищен критической секцией.Рабочий поток добавляет объекты, которые должны быть обработаны в списке.Когда и объект добавлен, рабочий поток сигнализирует о событии.Затем у вас есть поток обработки объекта, который ожидает с помощью WaitForSingleObject этого события.Как только что-то добавляется в список, событие сигнализируется, и поток обработки просто обрабатывает все объекты, которые он находит в списке.Тогда это ждет снова.Все, что вам нужно сделать, это защитить доступ к общему списку.

Упрощенный код будет выглядеть следующим образом:

РАБОЧАЯ РЕЗЬБА

ObjectList.Add(MessageObject);
SetEvent(FEvent);

ОБРАБОТКА РЕЗЬБЫ

while not Terminated do
begin
  WaitForSingleObjest(FEvent, INFINITE);
  // process all the objects
end;
...