Multithreading GetMessage中的wparam值不是我所期望的(Delphi XE4)

Multithreading GetMessage中的wparam值不是我所期望的(Delphi XE4),multithreading,delphi,delphi-xe4,getmessage,Multithreading,Delphi,Delphi Xe4,Getmessage,我正在开发一个DelphiXe4服务应用程序。该服务为一些长时间运行的任务启动线程,线程通过PostThreadMessage调用返回状态 主ServiceExecute循环如下所示: procedure TScanService.ServiceExecute(Sender: TService); var CurrentMessage: TMsg; begin LogServerEvent('ServiceExecute', 'Starting'); while not Termin

我正在开发一个DelphiXe4服务应用程序。该服务为一些长时间运行的任务启动线程,线程通过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);
在线程中,消息发送如下所示:

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个线程在运行,其中一个是使用不同消息编号的计时器,并且在发生这种情况时不会发送任何内容。

t服务
代码中,您可以找到以下代码:

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;
因此,
t服务
正在发送与您的邮件编号相同的邮件。你怎么能把他们分开?嗯,你不能

来自
WM用户的文档

用于定义私有窗口类使用的私有消息,通常采用WM_USER+x的形式,其中x是一个整数值

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

您的主要选择:

  • 将您的消息发送到窗口
  • 使用
    RegisterWindowMessage
    确保消息id的唯一性
  • 停止使用windows消息(并非专门用于服务)并使用其他机制进行通信
奇怪的消息循环,您可以单独使用GetMessage来阻止,直到发布消息。我在您发布的代码中没有看到问题,这意味着问题可能不在您发布的代码中。你能不能把它简化成一个小样本来演示我们可以编译并运行以重现它的问题?你对你的
HWND
。。。RTL使用
WM_USER+x
范围内的一些消息;如果没有更多的代码,很难说,但也有可能是您接收到了散乱的消息。如果将
-1
用于
PeekMessage
GetMessage
HWND
参数,您将限制仅拾取使用
NULL
HWND发布的消息(否则也会获取窗口消息)-前者只包括使用带有空句柄的
PostMessage
发送的消息,以及使用
posthreadmessage
@J.发送的消息。我错过了。我通常使用PostThreadMessage在线程和GUI之间进行通信,并在收到消息时始终检查
Msg.hwnd=0
;我没有想过从服务中这样做。CM_服务控制代码是WM_USER+1,wparam as 4是服务控制查询。TService.Controller可能正在发布它。如果是这样的话,检查hwnd将没有帮助。如果我们遵守文档,也没有好处。“仅当多个应用程序…”时使用RegisterWindowMessage。我认为WM_USER+没有任何真正的危险,当您使用“PostThreadMessage”时,它永远不会被发送到窗口。那么它的意思就是你想要它的意思。WM_APP+可能会更好。@Sertac ok,如果用户检查hwnd,则不会出现混淆。然而,我认为WM_用户是用于窗口类的。如果是我,我会创建一个窗口,永远不会调用PostThreadMessage。-1“这意味着您不能将此范围内的消息与PostThreadMessage一起使用”-消息ID的
WM\u用户
范围与
PostThreadMessage()
(如果没有,
TService
本身不会运行,因为它使用
PostThreadMessage)(WM_USER+1)
在内部将SCM请求发布到
t服务
消息队列)。对
PostThreadMessage()的消息ID没有限制
接受。它所关心的只是一个附加了消息队列的有效线程ID。其他参数按原样发布到该线程的消息队列中。OP只需选择一个已被
TService
使用的消息ID,并将其消息发布到
TService
发布其权限的同一线程消息队列中将消息发送给。仅此而已。这是使用
WM_USER
的真正危险,而不是它根本不能与
PostThreadMessage()
一起使用。好的,我能够确认我收到的消息不是来自我的线程,因此作为临时解决方案,我将消息编号移到了更高的位置。