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
How to use PIPES for messages 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
29-May-03
Category
Win API
Language
Delphi 3.x
Views
171
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Daniel Wischnewski 

A pipe is a section of shared memory that processes use for communication. The 
process that creates a pipe is the pipe server. A process that connects to a pipe 
is a pipe client. One process writes information to the pipe, then the other 
process reads the information from the pipe. (MSDN)

Answer:

WHAT PIPES ARE 

Pipes are used by independent processes to communicate with each other. For every 
pipe there must be a server that creates and manages the pipe and one or more 
clients that use the pipe to interchange messages between each other. 

Pipes can be used for communication of processes residing on the same computer as 
well as processes residing on different machines within a network. 

WHEN CAN YOU USE PIPES 

Basically all Windows NT 3.51 and up, as well as Win95 and up support named pipes. 
You will use named pipes only to transfer information between applications or 
similar. I would not use them for use within a single application or when the 
SendMessage/PostMessage routines will suffice. 

Named Pipes will ensure the data transport between to processes - therefore you 
will use them when data transport is essential. Mailslots, similar to named pipes, 
will not ensure data transport between processes, are, however much more efficient. 

BLOCKING AND NON-BLOCKING MODES 

Pipes can be created supporting blocking and non-blocking modes. This is essential 
for three routines: ReadFile, WriteFile, and ConnectNamedPipe. These routines will 
not return during blocking-mode until data are read/sent. MS recommends the use of 
the blocking-mode. 

THEORIE OF THIS SAMPLE 

Your Pipe-Server will create a named pipe and wait for clients to access the pipe 
in order to send data. Once a Pipe-Client sends data, the Pipe-Server will open the 
Pipe to the Client, process the data, send the "answer", and closes the Pipe to the 
Client. 

The server will close the pipe after every message processed. 

NOTE 

This is a simple sample for the use of Pipes only, as samples are hard to find 
anyway. I am working on a more complex one, this may, however take quite some time 
- depending on my spare time. :) 

THE UNIT UPIPES.PAS 

In this sample, the Pipe-Server will reverse the data send by the Pipe-Client as 
Response. No Range Checking is done! 

1   unit uPipes;
2   
3   interface
4   
5   uses
6     Classes, Windows;
7   
8   const
9     cShutDownMsg = 'shutdown pipe ';
10    cPipeFormat = '\\%s\pipe\%s';
11  
12  type
13    RPIPEMessage = record
14      Size: DWORD;
15      Kind: Byte;
16      Count: DWORD;
17      Data: array[0..8095] of Char;
18    end;
19  
20    TPipeServer = class(TThread)
21    private
22      FHandle: THandle;
23      FPipeName: string;
24  
25    protected
26    public
27      constructor CreatePipeServer(aServer, aPipe: string; StartServer: Boolean);
28      destructor Destroy; override;
29  
30      procedure StartUpServer;
31      procedure ShutDownServer;
32      procedure Execute; override;
33    end;
34  
35    TPipeClient = class
36    private
37      FPipeName: string;
38      function ProcessMsg(aMsg: RPIPEMessage): RPIPEMessage;
39    protected
40    public
41      constructor Create(aServer, aPipe: string);
42  
43      function SendString(aStr: string): string;
44    end;
45  
46  implementation
47  
48  uses
49    SysUtils;
50  
51  procedure CalcMsgSize(var Msg: RPIPEMessage);
52  begin
53    Msg.Size :=
54      SizeOf(Msg.Size) +
55      SizeOf(Msg.Kind) +
56      SizeOf(Msg.Count) +
57      Msg.Count +
58      3;
59  end;
60  
61  { TPipeServer }
62  
63  constructor TPipeServer.CreatePipeServer(
64    aServer, aPipe: string; StartServer: Boolean
65    );
66  begin
67    if aServer = '' then
68      FPipeName := Format(cPipeFormat, ['.', aPipe])
69    else
70      FPipeName := Format(cPipeFormat, [aServer, aPipe]);
71    // clear server handle
72    FHandle := INVALID_HANDLE_VALUE;
73    if StartServer then
74      StartUpServer;
75    // create the class
76    Create(not StartServer);
77  end;
78  
79  destructor TPipeServer.Destroy;
80  begin
81    if FHandle <> INVALID_HANDLE_VALUE then
82      // must shut down the server first
83      ShutDownServer;
84    inherited Destroy;
85  end;
86  
87  procedure TPipeServer.Execute;
88  var
89    I, Written: Cardinal;
90    InMsg, OutMsg: RPIPEMessage;
91  begin
92    while not Terminated do
93    begin
94      if FHandle = INVALID_HANDLE_VALUE then
95      begin
96        // suspend thread for 250 milliseconds and try again
97        Sleep(250);
98      end
99      else
100     begin
101       if ConnectNamedPipe(FHandle, nil) then
102       try
103         // read data from pipe
104         InMsg.Size := SizeOf(InMsg);
105         ReadFile(FHandle, InMsg, InMsg.Size, InMsg.Size, nil);
106         if
107           (InMsg.Kind = 0) and
108           (StrPas(InMsg.Data) = cShutDownMsg + FPipeName) then
109         begin
110           // process shut down
111           OutMsg.Kind := 0;
112           OutMsg.Count := 3;
113           OutMsg.Data := 'OK'#0;
114           Terminate;
115         end
116         else
117         begin
118           // data send to pipe should be processed here
119           OutMsg := InMsg;
120           // we'll just reverse the data sent, byte-by-byte
121           for I := 0 to Pred(InMsg.Count) do
122             OutMsg.Data[Pred(InMsg.Count) - I] := InMsg.Data[I];
123         end;
124         CalcMsgSize(OutMsg);
125         WriteFile(FHandle, OutMsg, OutMsg.Size, Written, nil);
126       finally
127         DisconnectNamedPipe(FHandle);
128       end;
129     end;
130   end;
131 end;
132 
133 procedure TPipeServer.ShutDownServer;
134 var
135   BytesRead: Cardinal;
136   OutMsg, InMsg: RPIPEMessage;
137   ShutDownMsg: string;
138 begin
139   if FHandle <> INVALID_HANDLE_VALUE then
140   begin
141     // server still has pipe opened
142     OutMsg.Size := SizeOf(OutMsg);
143     // prepare shut down message
144     with InMsg do
145     begin
146       Kind := 0;
147       ShutDownMsg := cShutDownMsg + FPipeName;
148       Count := Succ(Length(ShutDownMsg));
149       StrPCopy(Data, ShutDownMsg);
150     end;
151     CalcMsgSize(InMsg);
152     // send shut down message
153     CallNamedPipe(
154       PChar(FPipeName), @InMsg, InMsg.Size, @OutMsg, OutMsg.Size, BytesRead, 100
155       );
156     // close pipe on server
157     CloseHandle(FHandle);
158     // clear handle
159     FHandle := INVALID_HANDLE_VALUE;
160   end;
161 end;
162 
163 procedure TPipeServer.StartUpServer;
164 begin
165   // check whether pipe does exist
166   if WaitNamedPipe(PChar(FPipeName), 100 {ms}) then
167     raise Exception.Create('Requested PIPE exists already.');
168   // create the pipe
169   FHandle := CreateNamedPipe(
170     PChar(FPipeName), PIPE_ACCESS_DUPLEX,
171     PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
172     PIPE_UNLIMITED_INSTANCES, SizeOf(RPIPEMessage), SizeOf(RPIPEMessage),
173     NMPWAIT_USE_DEFAULT_WAIT, nil
174     );
175   // check if pipe was created
176   if FHandle = INVALID_HANDLE_VALUE then
177     raise Exception.Create('Could not create PIPE.');
178 end;
179 
180 { TPipeClient }
181 
182 constructor TPipeClient.Create(aServer, aPipe: string);
183 begin
184   inherited Create;
185   if aServer = '' then
186     FPipeName := Format(cPipeFormat, ['.', aPipe])
187   else
188     FPipeName := Format(cPipeFormat, [aServer, aPipe]);
189 end;
190 
191 function TPipeClient.ProcessMsg(aMsg: RPIPEMessage): RPIPEMessage;
192 begin
193   CalcMsgSize(aMsg);
194   Result.Size := SizeOf(Result);
195   if WaitNamedPipe(PChar(FPipeName), 10) then
196     if not CallNamedPipe(
197       PChar(FPipeName), @aMsg, aMsg.Size, @Result, Result.Size, Result.Size, 500
198       ) then
199       raise Exception.Create('PIPE did not respond.')
200     else
201   else
202     raise Exception.Create('PIPE does not exist.');
203 end;
204 
205 function TPipeClient.SendString(aStr: string): string;
206 var
207   Msg: RPIPEMessage;
208 begin
209   // prepare outgoing message
210   Msg.Kind := 1;
211   Msg.Count := Length(aStr);
212   StrPCopy(Msg.Data, aStr);
213   // send message
214   Msg := ProcessMsg(Msg);
215   // return data send from server
216   Result := Copy(Msg.Data, 1, Msg.Count);
217 end;
218 
219 end.


A SAMPLE USING UPIPES.PAS 

Create a new application and add the unit uPipes.pas to the uses clause. 
Add the following Controls to the Main Form


Checkbox: (Name: chkRunServer; Caption: Run Server) 

Edit: (Name: edtServer) 

Edit: (Name:edtTextToSend) 

Button: (Name: btnSend) 

Edit: (Name: edtResponse) 



Add the private variable: 

FServer: TPipeServer;

For the OnClick Event of the chkRunServer add the following code: 

220 procedure TForm1.chkRunServerClick(Sender: TObject);
221 begin
222   if chkRunServer.Checked then
223   try
224     FServer := TPipeServer.CreatePipeServer('', 'testit', True);
225   except
226     on E: Exception do
227     begin
228       ShowMessage(E.message);
229       chkRunServer.Checked := False;
230     end;
231   end
232   else
233   begin
234     FServer.Destroy;
235   end;
236 end;
237 
238 //For the OnClick Event of the btnSend add the following code: 
239 
240 procedure TForm1.btnSendClick(Sender: TObject);
241 begin
242   with TPipeClient.Create(edtServer.Text, 'testit') do
243   try
244     edtResponse.Text := SendString(edtTextToSend.Text);
245   finally
246     Free;
247   end;
248 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