【问题标题】:how do i send a custom message to a windows service?如何将自定义消息发送到 Windows 服务?
【发布时间】:2011-04-22 19:43:44
【问题描述】:

我已经实现了一个启动几个工作线程的 windows xp 服务应用程序。 我需要从其中一个线程将自定义消息发送回服务。 我该怎么做?

【问题讨论】:

  • 您的工作线程是您的服务应用程序的一部分,因此不清楚您要做什么。我的印象是您需要在线程之间传递一些数据,这可以通过简单地保留对数据结构的引用并锁定线程安全来完成。根据您的意图,主服务线程可能更容易轮询工作线程的状态。你能提供更多细节吗?
  • 我会尽力解释得更好。我的服务应用程序在其 OnStart 事件中创建了两个线程。它还创建一个对象列表(对象有自己的功能和属性)。现在,两个线程之一轮询串行端口以获取新数据,并且需要将此数据(或超时)发送到对象列表中的一个对象,但我需要在不中断其执行的情况下执行此操作。因此,当串行端口上有数据可用时,我想向主服务线程发布一条消息。这个主服务线程可以将数据发送到对象。
  • 我知道一个可能的解决方案是在服务类中创建一个仅消息窗口,但我不知道该怎么做。

标签: windows multithreading delphi service message


【解决方案1】:

感谢您的帮助。以下是我解决问题的方法:

在服务类定义中:

  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);

它工作得很好。

【讨论】:

    【解决方案2】:

    创建仅消息窗口:

    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() 处理程序将负责调用该函数。

    【讨论】:

    • AlloocateHWnd() 不是线程安全的,不应在主线程之外调用。 TService 在它自己的工作线程中运行。
    【解决方案3】:

    我同意 TOndrej 的观点,即共享对象就足够了。

    另一方面,您可以使用我的 IPC (Cromis IPC),它在服务中运行良好。它易于使用,面向消息,因此您无需了解命名管道的工作原理并且速度非常快。服务器部分也使用线程池,因此无需等待处理。您可以使用“一劳永逸”的场景。

    或者,如果您认为稍微重新设计就可以了,您可以尝试 OmniThreadLibrary,它已经内置了所有消息传递,并且专为此类任务而设计。

    编辑

    好吧,可能最干净的方法是使用一个受关键部分保护的公共对象列表,无需任何重新设计。工作线程正在列表中添加需要处理的对象。当添加对象时,工作线程会发出一个事件信号。然后你有一个对象处理线程正在等待 WaitForSingleObject 这个事件。一旦将某些内容添加到列表中,就会发出事件信号,并且处理线程只会处理它在列表中找到的所有对象。然后它再次等待。您需要做的就是保护对公共列表的访问。

    简化后的代码如下所示:

    工作线程

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

    处理线程

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

    【讨论】:

    • 我没有时间重新设计。整个应用程序工作得很好,除了那部分。我只需要从主服务线程运行内部对象函数,而不是从工作线程。
    • 然后使用我的 IPC 解决方案或实施我在 EDIT 中的建议。
    • 使用这种方法,我最好创建另一个线程来查看消息,并将它们分派到正确的对象。
    • 我也去看看IPC
    【解决方案4】:

    一种选择是使用OmniThreadLibrary(例如阅读this blog post)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多