3 Answers
3

Services don't generally receive window messages. They don't necessarily have window handles at all. Even if they do, they run in a separate desktop. Programs cannot send messages from one desktop to another, so a service can only receive messages from another service, or from a program started by a service.

Before Windows Vista, you could have configured your service to interact with the desktop. That makes the service run on the same desktop as a logged-in user, so a program running as that user could send messages to your service's windows. Windows Vista isolates services, though; they can't interact with any user's desktop anymore.

There are many other ways to communicate with services. They include named pipes, mailslots, memory-mapped files, semaphores, events, and sockets.

With a socket, for instance, your service could listen on an open port, and programs that need to communicate with it could connect to that port. This could open the door to remote administration, but you can also restrict the service to listen only for local connections.

All the above is trying to tell you that you're taking the wrong approach. But there's also the matter of the problem at hand. Your program behaves one way in the debugger and another way outside it. How are you debugging the service in the first place, if it's not installed? What user account is your service running as? Your debugger? What debugging techniques have you tried that don't involve the debugger (e.g. writeln to a log file to track your program's actions)?

Services in Delphi DO have the ability receive window messages without creating a message pump. To prove this, create a service in Delphi, and you will notice something that creates a form (e.g. a 'hidden' window like a normal VCL app): Application.CreateForm(TMyService1, MyService1);
–
MickDec 10 '08 at 17:09

1

Nonetheless, it can't receive messages from a program running in another desktop.
–
Rob KennedyDec 10 '08 at 17:36

Yes, that is true in Windows Vista. That is because the service is running with SYSTEM privileges, and its process has a higher IL (Integrity Level) than an application run by the user. Its possible to elevate the IL of an app and send WM's to a service. But this isn't feasible with a production app
–
MickDec 10 '08 at 17:58

What do you mean when you say it "uses" Windows Messaging System? Are you consuming or sending Windows Messages?

If you send a Windows message, you need ensure you are doing it correctly. I'd suggest writing a message loop to ensure your messages are being dispatched properly. I'd also suggest reading up on message loops and how they work.

The message loop calls GetMessage(),
which looks in your message queue.
If the message queue is empty your
program basically stops and waits
for one (it Blocks).

When an event occures causing a
message to be added to the queue
(for example the system registers a
mouse click) GetMessages() returns a
positive value indicating there is a
message to be processed, and that it
has filled in the members of the MSG
structure we passed it. It returns 0
if it hits WM_QUIT, and a negative
value if an error occured.

We take the message (in the Msg
variable) and pass it to
TranslateMessage(), this does a bit
of additional processing,
translating virtual key messages
into character messages. This step
is actually optional, but certain
things won't work if it's not there.

Once that's done we pass the message
to DispatchMessage(). What
DispatchMessage() does is take the
message, checks which window it is
for and then looks up the Window
Procedure for the window. It then
calls that procedure, sending as
parameters the handle of the window,
the message, and wParam and lParam.

In your window procedure you check
the message and it's parameters, and
do whatever you want with them! If
you aren't handling the specific
message, you almost always call
DefWindowProc() which will perform
the default actions for you (which
often means it does nothing).

Once you have finished processing
the message, your windows procedure
returns, DispatchMessage() returns,
and we go back to the beginning of
the loop.

While this is great general information on message processing in Windows, it doesn't apply directly to Delphi where the message loop and even the actual message object are typically hidden from the developer.
–
Scott WDec 11 '08 at 15:24

What do you mean "hidden"? I can translate this exact code to Delphi (and I've done this in production projects), and WHAM, I have a message loop. They are simply apart of the API, which Delphi can fully access and use just like in C/C++
–
MickDec 12 '08 at 19:20

True, you can do this, but I meant that you don't have to. For example, I can create a new project with a form and set up a handler for a particular message type. Then, without any attempt at building a message processing loop, my handler will receive those messages.
–
Scott WDec 13 '08 at 5:09

You are correct. If you create a VCL application, this is not necessary. However, if you create a console application and you want to send Window Messages from it, then you would need a message loop.
–
MickDec 15 '08 at 13:34