views:

1523

answers:

6

How can a desktop application communicate with a Windows service under Vista/Windows2008/Windows7? The application needs to send small strings to the service and receive string responses back. Both are written in Delphi 2009. (Please provide sample code also)

+2  A: 

I haven't tried it, but I think you could use named pipes.

dangph
+3  A: 

Have a look at the answers in Exchange Data between two apps across PC on LAN which is pretty much the same question nowadays. Local comms via TCP is standard. As I said in my response there, solutions that use "Remote Procedure Call" type interfaces work well. I use RemObjects SDK for this sort of thing, and it makes it easy to expand to control across the network if you wish to later.

Both of these allow you to create a connection that for most of your code is "transparent", and you just call an interface which sends the data over the wire and gets results back. You can then program how you usually do, and forget the details of sockets etc.

mj2008
Doesn't a service have to have special permissions in order to use the network, even if it's only listening locally?
Rob Kennedy
@Rob, it depends on what account the service is running as.
Iceman
I've had no problems using RemObjects using either the system account or a user account. The issue relates more to domain user rights than TCP/IP socket access which is independent.
mj2008
A service can use TCP sockets (other than RAW sockets) without regard to user accounts.
Remy Lebeau - TeamB
+2  A: 

Using Indy you can relatively easy create a TCP connection between your apps. Especially if you only need to send string messages. For the client (in your case the desktop application) it's basically

var
  Client : TIdTCPClient;
...
Client.Host := 'localhost';
Client.Port := AnyFreePortNumber;
Client.Connect;
Client.IOHandler.Writeln (SomeString);
Response := Client.Readln;
...
Client.Disconnect;

For the server (would be the service in your case)

var
  Server  : TIdTCPServer;
  Binding : TIdSocketHandle;
...
Server.DefaultPort := SameFreePortNumberAsInClient;
Binding := Server.Bindings.Add;
Binding.IP := '127.0.0.1';    
Binding.Port := Server.DefaultPort;
Server.OnConnect := HandleConnection;
Server.OnDisconnect := HandleDisconnection;
Server.OnExecute := HandleCommunication;
Server.Active := True;

Just implement the HandleCommunication method. It is called whenever the client decides to send something. Example:

procedure MyClass.HandleCommunication (AContext : TIdContext);
var
  Request : String;
begin
  Request := AContext.Connection.IOHandler.Readln;
  if (Request = Command1) then
    HandleCommand1
  else if (Request = Command2) then
    HandleCommand2
  ...
end;

IIRC a service is only allowed to have a graphical user interface OR have network access, so this might be a problem if your service needs a GUI (which you should avoid anyway, see this question). I don't know how this is handled in Windwos Vista and later though.

Smasher
+4  A: 

The way to go is named pipes, you'll probably have to take a look at the communication across different Integrity levels.

This article explores how to do this in vista. Although it's written in c++ it's just basic Windows API calls, so it should translate fast enough to Delphi.

If you want to search for more on this subject, this communication is called Inter Process Communication, but a better search term is IPC.

Davy Landman
Is this absolute true? I've done a several windows services acting as both TCP server and TCP client. They have all run fine as "local system". I have always believed that the restriction is on network resources (//machine/resource/...).
mliesen
The first assertion is completely bogus. Every Windows service I've ever written has been a networking daemon of some sort. The only time it's needed funky permissions was one that needed to be able to display UI as well.
Steve Gilham
Yes, I remembered wrong, it's not allowed to create network connection to outside resources, or you have to run as NetworkService. I deleted the first assertion. But still, named pipes are a better way to communicate with your service (have problem locating the vista compatibility article about IPC)
Davy Landman
+3  A: 

You have to change the service user from localsystem to networkservice and then the service can use TCPIP fine. I have several services which use TCPIP for an external control hook. Just make sure your service port is configurable so you can handle any collisions.

A few of my control interfaces are based on XML pages served from an internal HTTP server. This allows me to remotely check on status of the service using any web browser which can reach the port on that machine. The advantage of using HTTP over other methods is that it works well when you need to work over existing network hardware.

If your ONLY going to be communicating locally, then named pipes, mail slots or a memory mapped file might be the best method.

skamradt
You don't need to use the NetworkService account just to use TCP. It works just fine with LocalSystem and LocalService accounts as well.
Remy Lebeau - TeamB
+1  A: 

I use in my service applications a component set, freeware with sourcecode called Simple IPC.

Search torry.net. It has worked very well in all of my service apps when communicating with a desktop app.

John