home *** CD-ROM | disk | FTP | other *** search
- unit MonForm;
-
- { Interprocess Communication Demo
-
- This program along with the Client.dpr project, demonstrate a number
- of topics in Win32 programming. Threads, Events, Mutexes, and Shared
- memory are all used to provide communication between this monitor and
- it's clients, see IPCThrd.pas.
-
- To Run, compile this project and the Client.dpr project. Run one
- instance of the monitor and then run several instances of the client.
- You can switch between clients by clicking on the Client's window or
- by selecting it from the Client menu in the monitor.
-
- Topics Covered:
-
- Interprocess Communication
- Threads
- Events
- Mutexes
- Shared Memory
- Single instance EXE.
-
- }
-
- interface
-
- uses
- SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, Typinfo, IPCThrd, Buttons, ComCtrls, ExtCtrls, Menus;
-
- const
- WM_SETTRACEDATA = WM_USER + 1;
- WM_UPDATESTATUS = WM_USER + 2;
- WM_UPDATEMENU = WM_USER + 3;
-
- type
- TWMTraceData = record
- Msg: Cardinal;
- X: Smallint;
- Y: Smallint;
- Flag: TClientFlag;
- Result: Longint;
- end;
-
- TLabelRec = record
- XLabel: TLabel;
- YLabel: TLabel;
- end;
-
- TMonitorForm = class(TForm)
- DownX: TLabel;
- DownY: TLabel;
- SizeX: TLabel;
- SizeY: TLabel;
- MoveX: TLabel;
- MoveY: TLabel;
- Bevel1: TBevel;
- Panel1: TPanel;
- PauseButton: TSpeedButton;
- StatusBar: TStatusBar;
- MouseMove: TCheckBox;
- MouseDown: TCheckBox;
- WindowSize: TCheckBox;
- MainMenu: TMainMenu;
- Options1: TMenuItem;
- AutoClientSwitch1: TMenuItem;
- PlaceHolder21: TMenuItem;
- File1: TMenuItem;
- miFileExit: TMenuItem;
- miClients: TMenuItem;
- PlaceHolder1: TMenuItem;
- Help1: TMenuItem;
- About1: TMenuItem;
- ShowTraceButton: TSpeedButton;
- ClearButton: TSpeedButton;
- ExitButton: TSpeedButton;
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure ClientMenuClick(Sender: TObject);
- procedure miClientsClick(Sender: TObject);
- procedure SetTraceFlags(Sender: TObject);
- procedure AutoClientSwitch1Click(Sender: TObject);
- procedure miFileExitClick(Sender: TObject);
- procedure ShowTraceButtonClick(Sender: TObject);
- procedure PauseButtonClick(Sender: TObject);
- procedure ClearButtonClick(Sender: TObject);
- procedure ExitButtonClick(Sender: TObject);
- procedure About1Click(Sender: TObject);
- private
- FTraceMsg: TWMTraceData;
- IPCMonitor: TIPCMonitor;
- TraceLabels: array[TClientFlag] of TLabelRec;
- FClientData: TEventData;
- FStatusText: string;
- procedure ClearLabels;
- procedure OnConnect(Sender: TIPCThread; Connecting: Boolean);
- procedure OnDirectoryUpdate(Sender: TIPCThread);
- procedure OnSignal(Sender: TIPCThread; Data: TEventData);
- procedure SignalClientStatus;
- procedure UpdateTraceData(var Msg: TWMTraceData); message WM_SETTRACEDATA;
- procedure UpdateStatusBar(var Msg: TMessage); message WM_UPDATESTATUS;
- procedure UpdateClientMenu(var Msg: TMessage); message WM_UPDATEMENU;
- end;
-
-
- var
- MonitorForm: TMonitorForm;
-
- implementation
-
- uses TrcView, About;
-
- {$R *.DFM}
-
- { Private Routines }
-
- procedure TMonitorForm.ClearLabels;
- var
- Index: TClientFlag;
- begin
- for Index := Low(TClientFlag) to High(TClientFlag) do
- begin
- TraceLabels[Index].YLabel.Caption := '0';
- TraceLabels[Index].XLabel.Caption := '0';
- end;
- end;
-
- procedure TMonitorForm.OnConnect(Sender: TIPCThread; Connecting: Boolean);
- begin
- if Connecting then
- begin
- FStatusText := IPCMonitor.ClientName;
- SignalClientStatus;
- end
- else
- FStatusText := 'No Client';
- PostMessage(Handle, WM_UPDATESTATUS, 0, 0);
- end;
-
- { When a client starts or stops we need to update the client menu.
- We do this by posting a message to the Monitor Form, which in turn causes
- the UpdateClientMenu method to be invoked. We use this approach, rather than
- calling UpdateClientMenu directly because this code is not being executed
- by the main thread, but rather by the thread used in the TMonitorThread
- class. We could also have used the TThread.Synchonize method, but since
- there is no need for the IPC thread to wait for the monitor to update
- the menu, this approach is more effecient. }
-
- procedure TMonitorForm.OnDirectoryUpdate(Sender: TIPCThread);
- begin
- PostMessage(Handle, WM_UPDATEMENU, 0, 0);
- end;
-
- { This event is triggered when the client has new data for us. As with
- the OnDirectoryUpdate event above, we use PostMessage to get the main
- thread to update the display. }
-
- procedure TMonitorForm.OnSignal(Sender: TIPCThread; Data: TEventData);
- begin
- FTraceMsg.X := Data.X;
- FTraceMsg.Y := Data.Y;
- FTraceMsg.Flag := Data.Flag;
- PostMessage(Handle, WM_SETTRACEDATA, TMessage(FTraceMsg).WPARAM,
- TMessage(FTraceMsg).LPARAM);
- end;
-
- procedure TMonitorForm.SignalClientStatus;
- begin
- if PauseButton.Down then
- IPCMonitor.SignalClient([]) else
- IPCMonitor.SignalClient(FClientData.Flags);
- end;
-
- procedure TMonitorForm.UpdateTraceData(var Msg: TWMTraceData);
- begin
- with Msg do
- if Flag in FClientData.Flags then
- begin
- TraceLabels[Flag].XLabel.Caption := IntToStr(X);
- TraceLabels[Flag].YLabel.Caption := IntToStr(Y);
- end
- end;
-
- procedure TMonitorForm.UpdateStatusBar(var Msg: TMessage);
- begin
- StatusBar.SimpleText := FStatusText;
- ClearLabels;
- end;
-
- procedure TMonitorForm.UpdateClientMenu(var Msg: TMessage);
- var
- I, ID: Integer;
- List: TStringList;
- mi: TMenuItem;
- begin
- List := TStringList.Create;
- try
- IPCMonitor.GetClientNames(List);
- while miClients.Count > 0 do miClients.Delete(0);
- if List.Count < 1 then
- miClients.Add(NewItem('(None)', 0, False, False, nil, 0, ''))
- else
- for I := 0 to List.Count - 1 do
- begin
- ID := Integer(List.Objects[I]);
- mi := NewItem(List[I], 0, False, True, ClientMenuClick, 0, '');
- mi.Tag := ID;
- mi.RadioItem := True;
- mi.GroupIndex := 1;
- miClients.Add(MI);
- end;
- finally
- List.Free;
- end;
- end;
-
- { Event Handlers }
-
- procedure TMonitorForm.FormCreate(Sender: TObject);
-
- procedure SetupLabelArray;
- begin
- TraceLabels[cfMouseMove].XLabel := MoveX;
- TraceLabels[cfMouseMove].YLabel := MoveY;
- TraceLabels[cfMouseDown].XLabel := DownX;
- TraceLabels[cfMouseDown].YLabel := DownY;
- TraceLabels[cfResize].XLabel := SizeX;
- TraceLabels[cfResize].YLabel := SizeY;
- end;
-
- begin
- IPCMonitor := TIPCMonitor.Create(Application.Handle, 'Monitor');
- IPCMonitor.OnSignal := OnSignal;
- IPCMonitor.OnConnect := OnConnect;
- IPCMonitor.OnDirectoryUpdate := OnDirectoryUpdate;
- IPCMonitor.Activate;
- OnDirectoryUpdate(nil);
- OnConnect(nil, False);
- FClientData.Flags := [cfMouseMove, cfMouseDown, cfReSize];
- SetupLabelArray;
- end;
-
- procedure TMonitorForm.FormDestroy(Sender: TObject);
- begin
- IPCMonitor.Free;
- end;
-
- procedure TMonitorForm.ClientMenuClick(Sender: TObject);
- var
- NewID: Integer;
- begin
- NewID := (Sender as TMenuItem).Tag;
- if NewID <> IPCMonitor.ClientID then
- IPCMonitor.ClientID := NewID;
- end;
-
- procedure TMonitorForm.miClientsClick(Sender: TObject);
- var
- I: Integer;
- begin
- if IPCMonitor.ClientID <> 0 then
- for I := 0 to miClients.Count - 1 do
- with miClients.Items[I] do
- if Tag = IPCMonitor.ClientID then
- begin
- Checked := True;
- System.Break;
- end;
- end;
-
- procedure TMonitorForm.SetTraceFlags(Sender: TObject);
- var
- F: TClientFlag;
- begin
- with (Sender as TCheckBox) do
- begin
- F := TClientFlag(Tag);
- if Checked then
- Include(FClientData.Flags, F) else
- Exclude(FClientData.Flags, F);
- end;
- SignalClientStatus;
- end;
-
- procedure TMonitorForm.AutoClientSwitch1Click(Sender: TObject);
- begin
- with (Sender as TMenuItem) do
- begin
- Checked := not Checked;
- IPCMonitor.AutoSwitch := Checked;
- end;
- end;
-
- procedure TMonitorForm.miFileExitClick(Sender: TObject);
- begin
- Close;
- end;
-
- procedure TMonitorForm.ShowTraceButtonClick(Sender: TObject);
- begin
- IPCMonitor.GetDebugInfo(TraceForm.TraceData.Items);
- TraceForm.ShowModal;
- end;
-
- procedure TMonitorForm.PauseButtonClick(Sender: TObject);
- begin
- SignalClientStatus;
- end;
-
- procedure TMonitorForm.ClearButtonClick(Sender: TObject);
- begin
- IPCMonitor.ClearDebugInfo;
- end;
-
- procedure TMonitorForm.ExitButtonClick(Sender: TObject);
- begin
- Close;
- end;
-
- procedure TMonitorForm.About1Click(Sender: TObject);
- begin
- ShowAboutBox;
- end;
-
- end.
-