Solved

# Mailslots and Terminal Server

Posted on 2001-07-02
351 Views
Hello there,

I have developed a system consisting of a series of applications, which uses mailslots to communicate changes in data among each other, both locally on a machine and over the network. This practice has proven solid and very practical for my purposes, but...

Now I have had to install the system on a network where we use a Terminal Server (Win2000), from which some of the users run the applications. When the first user logs on to the terminal server and starts an application, the mailslot is created and everything works fine. When the second user logs on to the same terminal server, and starts the same application, I get an error saying that the "file" already exists, and the communication over the mailslot won't work.

So, now I'm looking for another way (or a more advanced way of using mailslots) to communicate among the applications. It has to be in the broadcasting form, meaning that I have to be able to send a "messages" (in my case a string will do) out on the network, and the applications how "cares" must all be able to read it.

Any ideas ?

Best regards
NetGeek
0
Question by:NetGeek
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• Learn & ask questions
• 4
• 4
• 2
• +3

LVL 3

Expert Comment

ID: 6244192
NetGeek

I have found mailslots to be a pain. Why not use TCP? There are some great components out there like Indy and errmm the french one :) (cant remember the name off by heart).
You could make a server app that monitors on one port number e.g. 200 for login in then you could keep a string list of who is logged on so when you need to make a broadcast you could just write a loop to go through them. Or if you want to you can send it on ip address 255.255.255.255 which is supposed to be the broadcast ip for TCP but Ive never tried it.

I do have some examples of some client / server apps with TCP if you want them.
just a thought.
regards
Smurff
0

LVL 13

Expert Comment

ID: 6244216
Use Named Pipes (NT only). Start both client and server from a DOS window.

Modyfied version of: http://www.jgsoftware.com/files/pipes.zip

======= PipeClnt.dpr =========

program PipeClnt;

{$APPTYPE CONSOLE} uses Windows, SysUtils, PipeObjs; var Pipe: TPipeClient; BrokenPipe: Boolean; buf: AnsiString; begin Pipe:= TPipeClient.Create('\\.\pipe\TestServer'); repeat Readln(buf); if buf <> '' then begin Pipe.WriteStr(buf + #13#10); Pipe.ReadStr(buf); write('From server: ', buf); end; until buf = ''; Pipe.Free; end. ======= PipeSrv.dpr ========= program PipeSrv; {$APPTYPE CONSOLE}

uses
Windows, SysUtils, PipeObjs;

const
CR = #13;
LF = #10;
CRLF = CR + LF;

var
Pipe: TPipeServer;
BrokenPipe: Boolean;
buf: AnsiString;
sa: TSecurityAttributes;

begin
writeln('Halt with ^C');
// Set NIL security
sa.nLength:= sizeOf(sa);
sa.bInheritHandle:= false;
sa.lpSecurityDescriptor:= nil;
while true do begin
try
Pipe:= TPipeServer.Create('\\.\pipe\TestServer', sa);
except
on E: Exception do begin
writeln(E.Message);
halt(1);
end;
end;
{ Wait for client to connect }
if not Pipe.Connect then begin
Writeln('Connect failed');
Pipe.Destroy;
halt(2);
end;
{ Client is connected, process input }
writeln('Client has connected!');
BrokenPipe:= false;
repeat
try
except
BrokenPipe:= true;
end;
if not BrokenPipe then
Pipe.WriteStr(UpperCase(buf));
until BrokenPipe;
{ Clean up }
Pipe.Free;
end; // while
end.

======= PipeObjs.pas=========

unit PipeObjs;

interface

uses
Windows, Classes, SysUtils;

type
EPipe = class(Exception);

TPipe = class(TObject)
pipeHandle: THandle;
rc        : Boolean;

destructor  Destroy; override;

procedure Read(var buf; bufsize: Integer; var BytesRead: Cardinal);
procedure Write(var buf; bufsize: Integer; var BytesWritten: Cardinal);
procedure ReadStr(var buf: AnsiString);
procedure WriteStr(ToSend: AnsiString);
end;

TPipeServer = class(TPipe)
constructor Create(AName: AnsiString; var sa: TSecurityAttributes); virtual;

function Connect: Boolean;
end;

TPipeClient = class(TPipe)
constructor Create(AName: AnsiString); virtual;
end;

implementation

procedure TPipe.Read(var buf; bufsize: Integer; var BytesRead: Cardinal);
begin
if not rc then
raise EPipe.Create('TPipe.Read : Broken pipe, error = ' + IntToStr(GetLastError));
end;

procedure TPipe.Write(var buf; bufsize: Integer; var BytesWritten: Cardinal);
begin
rc:= WriteFile(pipeHandle, buf, bufsize, BytesWritten, nil);
if not rc then
raise EPipe.Create('TPipe.Write : Broken pipe, error = ' + IntToStr(GetLastError));
end;

procedure TPipe.ReadStr(var buf: AnsiString);
var
begin
SetLength(buf, 255);
end;

procedure TPipe.WriteStr(ToSend: AnsiString);
var
buf: AnsiString;
BytesWritten: Cardinal;
begin
buf:= ToSend;
Write(buf[1], length(buf), BytesWritten);
end;

destructor TPipe.Destroy;
begin
if pipeHandle <> 0 then CloseHandle(pipeHandle);
Inherited Destroy;
end;

constructor TPipeServer.Create(AName: AnsiString; var sa: TSecurityAttributes);
begin
Inherited Create;
pipeHandle:= CreateNamedPipe(PChar(AName), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE +
PIPE_WAIT, 1, 0, 0, 150, @sa);
if pipeHandle = INVALID_HANDLE_VALUE then
raise EPipe.Create('TPipeServer.Create, error = ' + IntToStr(GetLastError));
end;

function TPipeServer.Connect: Boolean;
begin
Result:= ConnectNamedPipe(pipeHandle, nil);
end;

constructor TPipeClient.Create(AName: AnsiString);
begin
Inherited Create;
pipeHandle:= CreateFile(PChar(AName), GENERIC_READ + GENERIC_WRITE,
FILE_ATTRIBUTE_NORMAL, 0);
if pipeHandle = INVALID_HANDLE_VALUE then
raise EPipe.Create('TPipeClient.Create, error = ' + IntToStr(GetLastError));
end;

end.
0

LVL 14

Expert Comment

ID: 6244393
NetGeek, as quick fix, you could use an identifier unique to the logged on user as Mailslot identifier, so that different users in different sessions on the same server will work correctly.
0

LVL 14

Expert Comment

ID: 6244409
I found what you need as identifier: when TS is running, a global environment variable SESSIONNAME is set with the session identifier unique to the system. If SESSIONNAME is empty (does not exist), you're app is running on the console.
0

Author Comment

ID: 6244621
smurff, I agree completely that mailslots are a real pain, but I have a component that makes it very easy to use them, so.. ;-). I've also thought about using TCP/IP sockets with a service application controlling it all, but I really would prefer the appliocations to control it all themselves. I'm quite familiar with the use of TCP/IP sockets (I've written a nice little thing that allows sharing clipboards on the entire network), but thanks for you offer anyway :-)

epsylon, that looks very interessting at first glance, and I'll look over as soon as I can. I'm somewhat worried about the createfile call, but I hope it will work :-)

AvonWyss, giving the mailslots unique identifiers wont work, because one messages has to get to all other mailslots currently running (created).

I'll be back with more as soon as I have tried out the named pipes solution

Best regards
NetGeek
0

LVL 14

Expert Comment

ID: 6244650
NetGeek, you'll very probably encounter the very same problem when using named pipes since there also the file will already be open when one app is running. And even if you use sockets, you'll run into basically the same problem: only one socket can listen on a specific port...

A possibility would be to make some sort of proxy per machine (as application, service, COM-object or whatever) which opens the one mailslot instance and allows multiple apps with unique ID's to subscribe to the mailslot data distribution (this can again be using mailslots or any other IPC like memory mapped file, named pipes, sockets etc.). By this, you will have one mailslot per machine and several applications connecting to this single mailslot instance.
0

Author Comment

ID: 6245511
Yeah, the Pipes solution has the same problem :-(

So far I've solved the problem by keeping track of what machines are running on the TS and then using those machine names as additional aliases, but that slows it down some.

I'll try the TCP/IP solution tomorrow, cause I dont think I'll have the same problem there, becasuse the service will only run in one instance,and it keeps track of the connected clients with their handles, not their IP numbers (i hope).

Please keep those ideas coming :-)

Best regards
NetGeek
0

LVL 13

Expert Comment

ID: 6245550
How about impersonating another user before creating pipes or mailslots?
0

Author Comment

ID: 6247629
Sorry, Epsylon, but even if I where able to program something like that, I wouldn't feel comfortable using that. I'm installing the system on a clients network, and I have no real control over their network setup.

I've actually started looking into the Terminal Server settings, hoping there's a way to completely separate the individual sessions on the TS.

Best regards
NetGeek
0

LVL 14

Expert Comment

ID: 6426427
NetGeek, has any solution come up?
0

Author Comment

ID: 6431328
Not really AvonWyss, I've installed a system where I keep track of what connections are using the terminal server, then assign them a unique alias. The problem with this of course thatI have to send everything out to all the assigned aliases :-(

0

LVL 26

Expert Comment

ID: 8701403
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

To be PAQ/Refund

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Thank you,
Russell

EE Cleanup Volunteer
0

Accepted Solution

PashaMod earned 0 total points
ID: 8816820
Per recommendation,

PashaMod
Community Support Moderator @Experts Exchange
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
###### Suggested Courses
Course of the Month5 days, 9 hours left to enroll

#### 705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.