unit AppInstDemoMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, JclAppInst, ComCtrls, StdCtrls; type TForm1 = class(TForm) InstancesListView: TListView; Label1: TLabel; SwitchBtn: TButton; MsgBtn: TButton; ColorDialog1: TColorDialog; Memo1: TMemo; SendBtn: TButton; AutoUpdateCheckBox: TCheckBox; procedure FormCreate(Sender: TObject); procedure SwitchBtnClick(Sender: TObject); procedure MsgBtnClick(Sender: TObject); procedure SendBtnClick(Sender: TObject); procedure Memo1Change(Sender: TObject); private procedure BuildInstancesList; procedure ApplicationEvents1Message(var Msg: TMsg; var Handled: Boolean); public procedure WndProc(var Message: TMessage); override; end; var Form1: TForm1; implementation {$R *.DFM} const MaxAllowedInstances = 3; MyDataKind = 1; { TForm1 } procedure TForm1.BuildInstancesList; var I, CurrIndex: Integer; begin with InstancesListView, JclAppInstances do begin Items.BeginUpdate; Items.Clear; for I := 0 to InstanceCount -1 do with Items.Add do begin Caption := IntToStr(I + 1); SubItems.Add(Format('%.8x', [ProcessIDs[I]])); SubItems.Add(Format('%.8x', [AppWnds[I]])); end; CurrIndex := InstanceIndex[GetCurrentProcessId]; Selected := Items[CurrIndex]; Items.EndUpdate; end; Label1.Caption := IntToStr(CurrIndex + 1); end; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := ApplicationEvents1Message; BuildInstancesList; end; procedure TForm1.ApplicationEvents1Message(var Msg: TMsg; var Handled: Boolean); begin // AI_* messages handler. These messages are automatically send to all instances // of the application. with Msg do if (hwnd = 0) and (message = JclAppInstances.MessageID) then begin case wParam of AI_INSTANCECREATED, AI_INSTANCEDESTROYED: BuildInstancesList; AI_USERMSG: Label1.Font.Color := TColor(lParam); end; Handled := True; end; end; procedure TForm1.SwitchBtnClick(Sender: TObject); begin JclAppInstances.SwitchTo(InstancesListView.Selected.Index); end; procedure TForm1.MsgBtnClick(Sender: TObject); begin with ColorDialog1 do begin Color := Label1.Font.Color; if Execute then JclAppInstances.UserNotify(Color); end; end; procedure TForm1.SendBtnClick(Sender: TObject); begin // TForm.ClassName matches window class name. It sends the data to all windows // belonging instances of this application. The last parameter identifies the // 'TForm1' (ClassName) window of this instance. JclAppInstances.SendStrings(ClassName, MyDataKind, Memo1.Lines, Handle); end; var MemoChanging: Boolean; procedure TForm1.WndProc(var Message: TMessage); begin // Interprocess communication handler. // First check whether we can safely read TForm.Handle property ... if HandleAllocated and not (csDestroying in ComponentState) then begin // ... then whether it is our message. The last paramter tells to ignore the // message sent from window of this instance case ReadMessageCheck(Message, Handle) of MyDataKind: // It is our data begin MemoChanging := True; // prevent deadlock, TMemo.OnChange is also fired now Memo1.Lines.BeginUpdate; try // Read TStrings from the message ReadMessageStrings(Message, Memo1.Lines) finally Memo1.Lines.EndUpdate; MemoChanging := False; end; end; else inherited; end; end else inherited; end; procedure TForm1.Memo1Change(Sender: TObject); begin if not MemoChanging and AutoUpdateCheckBox.Checked then SendBtnClick(nil); end; initialization with JclAppInstances do // CheckInstance returns False if current instance number is greater than // MaxAllowedInstances constant if not CheckInstance(MaxAllowedInstances) then begin // Switch to the first instance of the application SwitchTo(0); // Close this instance KillInstance; end; // Note: For preventing more than one instance of the application you can put // simple JclAppInstances.CheckSingleInstance line to initialization section // instead of code above end.