views:

140

answers:

4

I have implemented a windows xp service application that starts a couple of working threads. From one of the threads i need to send custom messages back to the service. How do i do that?

+1  A: 

One option is to use OmniThreadLibrary (read this blog post for an example).

glob
A: 

I agree with TOndrej that shared objects should be sufficient.

On the other hand you can use my IPC (Cromis IPC) which works just fine inside services. It is easy to use, message oriented, so you don't need to know how named pipes work and very fast. The server part also uses a thread pool, so there is no waiting for something to be processed. You can use the fire and forget scenario.

Or if you think a little redesign is ok, you can try OmniThreadLibrary which has all the messaging already build in and is made for tasks like this.

EDIT:

Ok probably the cleanest way to go, without any redesing is to have a common object list which is protected by a critical section. The working thread is adding objects that need to be processed in the list. When and object is added the working thread signals an event. Then you have an object processing thread which is waiting with WaitForSingleObject for this event. As soon as something is added to the list the event is signaled and the processing thread just processes all the objects it finds in the list. Then it waits again. All you need to do is to protect the access to the common list.

Simplified the code would look like this:

WORKER THREAD

ObjectList.Add(MessageObject);
SetEvent(FEvent);

PROCESSING THREAD

while not Terminated do
begin
  WaitForSingleObjest(FEvent, INFINITE);
  // process all the objects
end;
Runner
I don't have time for redesign. The entire application works just fine except that part. I just need to run the internal objects functions from the main service thread, not from the working thread.
zoomz
Then just use my IPC solution or implement what I suggested in my EDIT.
Runner
With this approach, I'd better create another thread who peek for the messages, and dispatches them to the right object.
zoomz
I'll take a look at the IPC too
zoomz
A: 

Creating message-only window:

procedure TMyService.MessageQueueDispatch(var Message: TMessage);
begin
  Dispatch(Message); //Delphi default dispatcher for TMyService
end;

procedure TMyService.SomeKindOfOnCreate;
begin
  MessageQueue := AllocateHWnd(MessageQueueDispatch);
end;

Destroying:

procedure TMyService.SomeKindOfDestroy;
begin
  CloseHandle(MessageQueue);
end;

Now you can handle messages like you would do with form messages:

TMyService = class(TService)
...
protected
  procedure HandleMyMessage(var msg: TMsg); message WM_MY_MESSAGE;
end;

Delphi Dispatch() handler will take care of calling the function.

himself
AlloocateHWnd() is not thread-safe, and should not be called outside of the main thread. TService runs in its own worker thread instead.
Remy Lebeau - TeamB
+1  A: 

Thanks for your help. Here is how I solved the problem:

In the Service class definition:

...

WHandle: HWND;

protected

procedure HandleServiceMessage(var Msg: TMessage); virtual;

...

In the ServiceExecute method:

...

WHandle := AllocateHWnd(HandleServiceMessage);

MyThread := TMyThread.Create(true);

MyThread.HndMain := WHandle;

MyThread.Resume;

while not Terminated do ServiceThread.ProcessRequests(True);

DeallocateHWnd(WHandle);

end;

In ServiceStop method:

...

MyThread.Terminate;

...

And the method for handling messages:

procedure TMessageService.HandleServiceMessage(var Msg : TMessage);

var

Handled: Boolean;

begin

Handled := True;

if Msg.Msg = WM_MYMESSAGE

then

 Beep;

else

 Handled := False;

end;

if Handled then

Msg.Result := 0

else

Msg.Result := DefWindowProc(WHandle, Msg.Msg, Msg.WParam, Msg.LParam);

end;

In MyThread.Execute method:

...

PostMessage(HndMain,WM_MYMESSAGE,0,0);

...

Its working just fine.

zoomz