我有一个正在开发的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。我错过了什么?
注意:该代码只有两个线程在运行,其中一个是使用不同消息编号的计时器,发生这种情况时不会发送任何消息。
在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
:的文档
用于定义专用窗口类使用的专用消息,通常格式为WM_USER+x,其中x是一个整数值。
通常,这将用于发送到窗口的消息,并且消息的含义将是特定于类的。在阅读TService
代码时,设计人员认为他们完全可以控制消息队列,并有权确定其私有消息的含义。这样做的最终结果是,不能使用WM_USER
范围内的线程消息,因为它们已被TService
类保留。
您的主要选择:
- 将消息发送到窗口
- 使用
RegisterWindowMessage
确保消息id的唯一性 - 停止使用windows消息(不是专门用于服务),并使用其他机制进行通信