///Event dispatching component. Part of the OmniThreadLibrary project.
///Primoz Gabrijelcic
///
///This software is distributed under the BSD license.
///
///Copyright (c) 2009, Primoz Gabrijelcic
///All rights reserved.
///
///Redistribution and use in source and binary forms, with or without modification,
///are permitted provided that the following conditions are met:
///- Redistributions of source code must retain the above copyright notice, this
/// list of conditions and the following disclaimer.
///- Redistributions in binary form must reproduce the above copyright notice,
/// this list of conditions and the following disclaimer in the documentation
/// and/or other materials provided with the distribution.
///- The name of the Primoz Gabrijelcic may not be used to endorse or promote
/// products derived from this software without specific prior written permission.
///
///THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
///ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
///WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
///DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
///ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
///(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
///LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
///ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
///(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
///SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
///
/// Home : http://otl.17slon.com
/// Support : http://otl.17slon.com/forum/
/// Author : Primoz Gabrijelcic
/// E-Mail : primoz@gabrijelcic.org
/// Blog : http://thedelphigeek.com
/// Web : http://gp.17slon.com
/// Contributors : GJ, Lee_Nover
///
/// Creation date : 2008-06-12
/// Last modification : 2009-01-26
/// Version : 1.0a
///
/// History:
/// 1.0a: 2009-01-26
/// - Pass correct task ID to the OnPoolWorkItemCompleted handler.
/// 1.0: 2008-08-26
/// - First official release.
///
{$WARN SYMBOL_PLATFORM OFF}
unit OtlEventMonitor;
interface
uses
Messages,
Classes,
GpStuff,
GpLists,
OtlCommon,
OtlTaskControl,
OtlThreadPool;
type
TOmniTaskEvent = procedure(const task: IOmniTaskControl) of object;
TOmniPoolThreadEvent = procedure(const pool: IOmniThreadPool; threadID: integer) of object;
TOmniPoolWorkItemEvent = procedure(const pool: IOmniThreadPool; taskID: int64) of object;
TOmniEventMonitor = class(TComponent, IOmniTaskControlMonitor, IOmniThreadPoolMonitor)
strict private
tedMessageWindow : THandle;
tedMonitoredPools : IInterfaceDictionary;
tedMonitoredTasks : IInterfaceDictionary;
tedOnPoolThreadCreated : TOmniPoolThreadEvent;
tedOnPoolThreadDestroying: TOmniPoolThreadEvent;
tedOnPoolThreadKilled : TOmniPoolThreadEvent;
tedOnPoolWorkItemEvent : TOmniPoolWorkItemEvent;
tedOnTaskMessage : TOmniTaskEvent;
tedOnTaskTerminated : TOmniTaskEvent;
strict protected
procedure WndProc(var msg: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Detach(const task: IOmniTaskControl): IOmniTaskControl; overload;
function Detach(const pool: IOmniThreadPool): IOmniThreadPool; overload;
function Monitor(const task: IOmniTaskControl): IOmniTaskControl; overload;
function Monitor(const pool: IOmniThreadPool): IOmniThreadPool; overload;
published
property OnPoolThreadCreated: TOmniPoolThreadEvent read tedOnPoolThreadCreated
write tedOnPoolThreadCreated;
property OnPoolThreadDestroying: TOmniPoolThreadEvent read tedOnPoolThreadDestroying
write tedOnPoolThreadDestroying;
property OnPoolThreadKilled: TOmniPoolThreadEvent read tedOnPoolThreadKilled
write tedOnPoolThreadKilled;
property OnPoolWorkItemCompleted: TOmniPoolWorkItemEvent read tedOnPoolWorkItemEvent
write tedOnPoolWorkItemEvent;
property OnTaskMessage: TOmniTaskEvent read tedOnTaskMessage write tedOnTaskMessage;
property OnTaskTerminated: TOmniTaskEvent read tedOnTaskTerminated write
tedOnTaskTerminated;
end; { TOmniEventMonitor }
var
COmniTaskMsg_NewMessage: cardinal;
COmniTaskMsg_Terminated: cardinal;
COmniPoolMsg : cardinal;
implementation
uses
Windows,
SysUtils,
DSiWin32;
{ TOmniEventMonitor }
constructor TOmniEventMonitor.Create(AOwner: TComponent);
begin
inherited;
tedMessageWindow := DSiAllocateHWnd(WndProc);
Win32Check(tedMessageWindow <> 0);
tedMonitoredTasks := CreateInterfaceDictionary;
tedMonitoredPools := CreateInterfaceDictionary;
end; { TOmniEventMonitor.Create }
destructor TOmniEventMonitor.Destroy;
var
intfKV: TInterfaceDictionaryPair;
begin
for intfKV in tedMonitoredTasks do
(intfKV.Value as IOmniTaskControl).RemoveMonitor;
tedMonitoredTasks.Clear;
for intfKV in tedMonitoredPools do
(intfKV.Value as IOmniThreadPool).RemoveMonitor;
tedMonitoredPools.Clear;
if tedMessageWindow <> 0 then begin
DSiDeallocateHWnd(tedMessageWindow);
tedMessageWindow := 0;
end;
inherited;
end; { TOmniEventMonitor.Destroy }
function TOmniEventMonitor.Detach(const task: IOmniTaskControl): IOmniTaskControl;
begin
Result := task.RemoveMonitor;
tedMonitoredTasks.Remove(task.UniqueID);
end; { TOmniEventMonitor.Detach }
function TOmniEventMonitor.Detach(const pool: IOmniThreadPool): IOmniThreadPool;
begin
Result := pool.RemoveMonitor;
tedMonitoredPools.Remove(pool.UniqueID);
end; { TOmniEventMonitor.Detach }
function TOmniEventMonitor.Monitor(const task: IOmniTaskControl): IOmniTaskControl;
begin
tedMonitoredTasks.Add(task.UniqueID, task);
Result := task.SetMonitor(tedMessageWindow);
end; { TOmniEventMonitor.Monitor }
function TOmniEventMonitor.Monitor(const pool: IOmniThreadPool): IOmniThreadPool;
begin
tedMonitoredPools.Add(pool.UniqueID, pool);
Result := pool.SetMonitor(tedMessageWindow);
end; { TOmniEventMonitor.Monitor }
procedure TOmniEventMonitor.WndProc(var msg: TMessage);
var
pool : IOmniThreadPool;
task : IOmniTaskControl;
taskID : int64;
tpMonitorInfo: TOmniThreadPoolMonitorInfo;
begin
if msg.Msg = COmniTaskMsg_NewMessage then begin
if assigned(OnTaskMessage) then begin
Int64Rec(taskID).Lo := cardinal(msg.WParam);
Int64Rec(taskID).Hi := cardinal(msg.LParam);
task := tedMonitoredTasks.ValueOf(taskID) as IOmniTaskControl;
if assigned(task) then
OnTaskMessage(task);
end;
msg.Result := 0;
end
else if msg.Msg = COmniTaskMsg_Terminated then begin
if assigned(OnTaskTerminated) then begin
Int64Rec(taskID).Lo := cardinal(msg.WParam);
Int64Rec(taskID).Hi := cardinal(msg.LParam);
task := tedMonitoredTasks.ValueOf(taskID) as IOmniTaskControl;
if assigned(task) then begin
OnTaskTerminated(task);
Detach(task);
end;
end;
msg.Result := 0;
end
else if msg.Msg = COmniPoolMsg then begin
tpMonitorInfo := TOmniThreadPoolMonitorInfo(msg.LParam);
try
pool := tedMonitoredPools.ValueOf(tpMonitorInfo.UniqueID) as IOmniThreadPool;
if assigned(pool) then begin
if tpMonitorInfo.ThreadPoolOperation = tpoCreateThread then begin
if assigned(OnPoolThreadCreated) then
OnPoolThreadCreated(pool, tpMonitorInfo.ThreadID);
end
else if tpMonitorInfo.ThreadPoolOperation = tpoDestroyThread then begin
if assigned(OnPoolThreadDestroying) then
OnPoolThreadDestroying(pool, tpMonitorInfo.ThreadID);
end
else if tpMonitorInfo.ThreadPoolOperation = tpoKillThread then begin
if assigned(OnPoolThreadKilled) then
OnPoolThreadKilled(pool, tpMonitorInfo.ThreadID);
end
else if tpMonitorInfo.ThreadPoolOperation = tpoWorkItemCompleted then begin
if assigned(OnPoolWorkItemCompleted) then
OnPoolWorkItemCompleted(pool, tpMonitorInfo.TaskID);
end;
end;
finally FreeAndNil(tpMonitorInfo); end;
end
else
msg.Result := DefWindowProc(tedMessageWindow, msg.Msg, msg.WParam, msg.LParam);
end; { TOmniEventMonitor.WndProc }
initialization
COmniTaskMsg_NewMessage := RegisterWindowMessage('Gp/OtlTaskEvents/NewMessage');
Win32Check(COmniTaskMsg_NewMessage <> 0);
COmniTaskMsg_Terminated := RegisterWindowMessage('Gp/OtlTaskEvents/Terminated');
Win32Check(COmniTaskMsg_Terminated <> 0);
COmniPoolMsg := RegisterWindowMessage('Gp/OtlThreadPool');
Win32CHeck(COmniPoolMsg <> 0);
end.