我正在开发一个Delphi XE4服务应用程序。该服务启动一些长时间运行的任务的线程,并且这些线程通过PostThreadMessage调用将状态传递回去。

主ServiceExecute循环如下所示:

procedure TScanService.ServiceExecute(Sender: TService);
var
  CurrentMessage: TMsg;
begin
  LogServerEvent('ServiceExecute', 'Starting');
  while not Terminated do
  begin
    if not PeekMessage(CurrentMessage, 0, WM_NULL, msgHigh, PM_NOREMOVE) then
    begin
      Sleep(1000);
      Continue;
    end;

    GetMessage(CurrentMessage, 0, WM_NULL, msgHigh);

    LogServerEvent('ServiceExecute', 'CurrentMessage.message', IntToStr(CurrentMessage.message));
    LogServerEvent('ServiceExecute', 'CurrentMessage.wParam', IntToStr(CurrentMessage.wParam));
    LogServerEvent('ServiceExecute', 'CurrentMessage.lParam', IntToStr(CurrentMessage.lParam));

在线程中,消息发送看起来像这样:
    gThreadNumber: Integer;

    LogThreadEvent('Execute', 'Found Notice, Thread number: ' + IntToStr(gThreadNumber));
    PostThreadMessage(ParentThreadID, msgFound, gThreadNumber, 6);

消息到达正常,消息号正确(msgFound = WM_USER +1);但是,我为wParam,lParam发送了0、6,而我收到的是4、0。我缺少什么?

注意:该代码仅运行2个线程,一个是使用不同消息号的计时器,并且在发生这种情况时不发送任何内容。

最佳答案

TService代码中,您可以找到以下代码:

const
  CM_SERVICE_CONTROL_CODE = WM_USER + 1;
....
procedure TService.Controller(CtrlCode: DWord);
begin
  PostThreadMessage(ServiceThread.ThreadID, CM_SERVICE_CONTROL_CODE, CtrlCode, 0);
  if ServiceThread.Suspended then ServiceThread.Resume;
end;

因此,TService发送的消息号与您的消息相同。你怎么区分他们?好吧,你不能。

WM_USER的文档中:



通常,这将用于发送到窗口的消息,并且消息的含义是特定于类的。当我阅读TService代码时,设计人员认为他们完全控制消息队列,并有权确定其私有(private)消息的含义。最终结果是,您不能使用WM_USER范围内的线程消息,因为它们已被TService类保留。

您的主要选择:
  • 将您的消息发送到窗口。
  • 使用RegisterWindowMessage可确保消息ID唯一。
  • 停止使用Windows消息(不是专门用于服务),并使用其他某种机制进行通信。
  • 关于multithreading - GetMessage中的wparam值不是我所期望的(Delphi XE4),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28772011/

    10-11 18:32