Main Logo
Articles   Members Online:
-Article/Tip Search
-News Group Search over 800,000 Borland news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
Delphi: Walkie-talkie or How to communicate between two Delphi applications
Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
Walkie-talkie or How to communicate between two Delphi applications Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Using SendMessage function to communicate between two applic 25-Oct-04
Category
Communication
Language
Delphi All Versions
Views
1180
User Rating
8
# Votes
4
Replies
0
Publisher:
Perevoznyk, Serhiy
Reference URL:
			Recently I've been researching different ways of communication between two 
applications. There are many ways to reach an application from another one. The 
challenge is to find the best one for your situation and one of the possible 
solutions is to use a call to the Windows API function SendMessage. 

Windows is built around messages. You can create and send messages to windows (or 
controls) within a Delphi application. In addition, applications send messages to 
each other, and applications even send messages to themselves. 

The SendMessage API function requires 4 arguments. The first argument is the handle 
of the window to which the message is addressed; the second argument-usually a 
symbolic constant-is the numeric value of the message; the third and fourth 
arguments, traditionally named wParam and lParam, carry any additional information 
needed by the message-in this case, which margin should be set and its new width, 
respectively. When more than two values are needed, they are usually gathered in a 
structure and its address is sent in the lParam argument. 

The first task here is to establish the communication. To do this the client needs 
to find the servers window (it needs its window handle). The best way for that is 
the FindWindow API function. The FindWindow function retrieves the handle to the 
top-level window whose class name and window name match the specified strings. As a 
target window we will use Application's window. Why? because the global variable 
Application, of type TApplication, is in every Delphi Windows application. 
Application encapsulates your application as well as providing many functions that 
occur in the background of the program. In this case we already know that the value 
of the first parameter of FindWindow will be 'TApplication'. The secons is a 
window's title and it equal to Application.Title. Simple, isn't ? 

My first solution was to use OnMessage event of TApplication class to trap the 
messages. However, this solution has a problem. The OnMessage event occurs when an 
application receives a Windows message. An OnMessage event handler allows an 
application to respond to messages other than those declared in the events for 
TApplication. Unfortunately, OnMessage only receives messages that are posted to 
the message queue, not those sent directly with the Windows API SendMessage 
function, so we need another way for it. 

To solve this problem we can use one of the special methods of the TApplication 
class usually used internally for displaying Windows common dialogs. TApplication 
class has a special method called HookMainWindow that enables a non-VCL dialog box 
to receive messages sent to the application's main window (the window of 
TApplication, not main form of the application). 


To encapsulate the complexities of messages handling I wrote a small component 
TpsvApplicationHook. 

1   unit psvApplicationHook;
2   
3   interface
4   
5   uses
6     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
7   
8   type
9   
10    TOnHookMessage = procedure (Sender : TObject; var message : TMessage; var Handled 
11  : boolean) of object;
12  
13    THookItem = class(TCollectionItem)
14    private
15      FHook : TWindowHook;
16      FOnMessage : TOnHookMessage;
17    protected
18      function HookProc(var message : TMessage) : boolean;
19    public
20      constructor Create(Collection : TCollection); override;
21    published
22      property OnMessage : TOnHookMessage read FOnMessage write FonMessage;
23    end;
24  
25    THookItems = class(TCollection)
26    private
27      FOwner : TPersistent;
28    protected
29      function GetItem(Index : integer) : THookItem;
30      procedure SetItem(Index : integer; Value : THookItem);
31      function GetOwner : TPersistent; override;
32    public
33      constructor Create(AOwner : TPersistent; ItemClass : TCollectionItemClass);
34      function Add : THookItem;
35      property Items[Index : integer] : THookItem read GetItem write SetItem; default;
36    end;
37  
38    TpsvApplicationHook = class(TComponent)
39    private
40      FItems : THookItems;
41      procedure SetItems(const Value: THookItems);
42    protected
43    public
44      constructor Create(AOwner : TComponent); override;
45      destructor Destroy; override;
46      procedure Activate;
47      procedure Deactivate;
48    published
49      property Items : THookItems read FItems write SetItems;
50    end;
51  
52  procedure register;
53  
54  implementation
55  
56  procedure register;
57  begin
58    RegisterComponents('Additional', [TpsvApplicationHook]);
59  end;
60  
61  { THookItem }
62  
63  constructor THookItem.Create(Collection: TCollection);
64  begin
65    inherited;
66    FHook := HookProc;
67  end;
68  
69  function THookItem.HookProc(var message: TMessage): boolean;
70  begin
71    Result := false;
72    if Assigned(FOnMessage) then
73       FOnMessage(THookItems(Collection).FOwner, message, Result);
74  end;
75  
76  { TpsvApplicationHook }
77  
78  procedure TpsvApplicationHook.Activate;
79  var
80   cnt : integer;
81  begin
82    if Assigned(Application) then
83    for cnt := 0 to FItems.Count - 1 do
84     begin
85       Application.HookMainWindow(FItems[cnt].FHook);
86     end;
87  end;
88  
89  constructor TpsvApplicationHook.Create(AOwner: TComponent);
90  begin
91    inherited;
92    FItems := THookItems.Create(Self, THookItem);
93  end;
94  
95  procedure TpsvApplicationHook.Deactivate;
96  var
97   cnt : integer;
98  begin
99    if Assigned(Application) then
100   for cnt := 0 to FItems.Count - 1 do
101    begin
102      Application.UnHookMainWindow(FItems[cnt].FHook);
103    end;
104 end;
105 
106 destructor TpsvApplicationHook.Destroy;
107 begin
108   if (not (csDesigning in ComponentState) ) then
109    Deactivate;
110   FItems.Free;
111   inherited;
112 end;
113 
114 procedure TpsvApplicationHook.SetItems(const Value: THookItems);
115 begin
116   FItems.Assign(Value);
117 end;
118 
119 { THookItems }
120 
121 function THookItems.Add: THookItem;
122 begin
123   Result := THookItem(inherited Add);
124 end;
125 
126 constructor THookItems.Create(AOwner: TPersistent;
127   ItemClass: TCollectionItemClass);
128 begin
129   inherited Create(ItemClass);
130   FOwner := AOwner;
131 end;
132 
133 function THookItems.GetItem(Index: integer): THookItem;
134 begin
135   Result := THookItem(inherited GetItem(Index));
136 end;
137 
138 function THookItems.GetOwner: TPersistent;
139 begin
140   Result := FOwner;
141 end;
142 
143 procedure THookItems.SetItem(Index: integer; Value: THookItem);
144 begin
145   inherited SetItem(Index, Value);
146 end;
147 
148 end.
149 {Okay, down to business. Sometimes would be very useful to centralize processing of 
150 the events that apply to the application as a whole. I will show how we can use 
151 TpsvApplicationHook in standalone Delphi application to create own "processing 
152 center". }
153 unit StandaloneExample;
154 
155 interface
156 
157 uses
158   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
159   StdCtrls, psvApplicationHook;
160 
161 type
162   TfrmHookTest = class(TForm)
163     psvApplicationHook: TpsvApplicationHook;
164     btnSendMessage: TButton;
165     btnActivateHook: TButton;
166     btnDeactivateHook: TButton;
167     procedure ProcessHookMessage(Sender: TObject;
168       var message: TMessage; var Handled: Boolean);
169     procedure btnSendMessageClick(Sender: TObject);
170     procedure btnActivateHookClick(Sender: TObject);
171     procedure btnDeactivateHookClick(Sender: TObject);
172   private
173     { Private declarations }
174   public
175     { Public declarations }
176   end;
177 
178 var
179   frmHookTest: TfrmHookTest;
180 
181 implementation
182 
183 {$R *.DFM}
184 
185 const
186   WM_MY_MESSAGE = WM_USER +1;
187 
188 procedure TfrmHookTest.ProcessHookMessage(Sender: TObject;
189   var message: TMessage; var Handled: Boolean);
190 begin
191   if message.Msg = WM_MY_MESSAGE then
192    begin
193      ShowMessage('I received a message!');
194    end;
195 end;
196 
197 procedure TfrmHookTest.btnSendMessageClick(Sender: TObject);
198 begin
199   SendMessage(Application.Handle, WM_MY_MESSAGE, 0, 0);
200 end;
201 
202 procedure TfrmHookTest.btnActivateHookClick(Sender: TObject);
203 begin
204   psvApplicationHook.Activate;
205 end;
206 
207 procedure TfrmHookTest.btnDeactivateHookClick(Sender: TObject);
208 begin
209    psvApplicationHook.Deactivate;
210 end;
211 
212 end.
213 
214 {Next example shows communication between two applications. Client application will 
215 send custom message messages to server and Server will receive and process it using 
216 TpsvApplicationHook component. Here is the code of the server application: }
217 unit Unit1;
218 
219 interface
220 
221 uses
222   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
223   psvApplicationHook, StdCtrls;
224 
225 type
226   TfrmTestServer = class(TForm)
227     psvApplicationHook: TpsvApplicationHook;
228     LogMemo: TMemo;
229     procedure ProcessCustomMessage(Sender: TObject; var message: TMessage;
230       var Handled: Boolean);
231     procedure FormCreate(Sender: TObject);
232   private
233     { Private declarations }
234   public
235     { Public declarations }
236     MyMsg : UINT;
237   end;
238 
239 var
240   frmTestServer: TfrmTestServer;
241 
242 implementation
243 
244 {$R *.DFM}
245 
246 procedure TfrmTestServer.ProcessCustomMessage(Sender: TObject;
247   var message: TMessage; var Handled: Boolean);
248 begin
249   if message.Msg = MyMsg then
250    begin
251      LogMemo.Lines.Add(Format('%s : new message was received', 
252 [DateTimeToStr(Now)]));
253      Handled := true;
254    end;
255 end;
256 
257 
258 procedure TfrmTestServer.FormCreate(Sender: TObject);
259 var
260  NewHook : THookItem;
261 begin
262   MyMsg := RegisterWindowMessage('MyMessage');
263   NewHook := psvApplicationHook.Items.Add;
264   NewHook.OnMessage := ProcessCustomMessage;
265   psvApplicationHook.Activate;
266 end;
267 
268 end.
269 
270 {As a last step we have to create a client application that will send custom 
271 messages to the server application. }
272 unit ClientMainForm;
273 
274 interface
275 
276 uses
277   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
278   StdCtrls;
279 
280 type
281   TfrmClient = class(TForm)
282     btnSendMessage: TButton;
283     procedure FormCreate(Sender: TObject);
284     procedure btnSendMessageClick(Sender: TObject);
285   private
286     { Private declarations }
287   public
288     { Public declarations }
289     MyMsg : UINT;
290     ServerApplicationHandle : THandle;
291   end;
292 
293 var
294   frmClient: TfrmClient;
295 
296 implementation
297 
298 {$R *.DFM}
299 
300 procedure TfrmClient.FormCreate(Sender: TObject);
301 begin
302   MyMsg := RegisterWindowMessage('MyMessage');
303   ServerApplicationHandle := FindWindow('TApplication', 'Project1');
304 end;
305 
306 procedure TfrmClient.btnSendMessageClick(Sender: TObject);
307 begin
308   SendMessage(ServerApplicationHandle, MyMsg, 0, 0);
309 end;
310 
311 end.



			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC
Advertisement


Share this page
Advertisement
Copyright © 2024 by No Limit Solutions LLC