Link to home
Start Free TrialLog in
Avatar of joshuayip
joshuayip

asked on

Send Message from TService to Standard Exe

Hi experts,

I have a Tservice which I would like to send notification of some information to a standard exe. e.g. connection active or not, date of the last update. I havent come to discover many options to do this. If yes, would like to hear from you.

I am thinking about using CreateFileMappnig and use the shared memory to pass data around. However I am stuck at section where the std exe was not able to retrive the map handle after the service has started first. If I start the std exe first, then start the service, the message seems to be sending correctly from the service to the std exe. But if I turn on the service first , then the std app, the message was not received by the std exe.

Joshua

edit: I am sorry guys, I should have posted this to the Delphi language section. I only realize this after I click submit. And I cant seems to find any link to change the channel to delphi
Avatar of cookre
cookre
Flag of United States of America image

A common way of doing that sort of thing is with MSMQ.

If all you want to do is send notifications with no more than a DWORD, just use the windows message queue:

1) Create custom messageID with RegisterWindowMessage()
2) Send messages back and forth with PostMessage(), or, if you want synchrony, SendMessage().

Avatar of joshuayip
joshuayip

ASKER

Hi Cookre, thanks for your response.

That is what I did. I was able to send the message from the service through if I start the std exe first, then start the service. I notice that if I start the service first , my std exe was able to obtain the

In the std exe, at formcreate, I have
  TheMsgVal := RegisterWindowMessage(TheMsgConstant);
  TheMapHnd := ObtainMappingHandle;

Where ObtainMappingHandle is

function ObtainMappingHandle: THandle;
begin
  Result := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,MaxMapLen,TheMappingConstant);
  if Result <> 0 then                                
    if GetLastError = ERROR_ALREADY_EXISTS then      
      begin
        CloseHandle(Result);                      
        Result := OpenFileMapping(FILE_MAP_WRITE,False,TheMappingConstant);
      end;
end;


A sample code I have showed that I should override the WndProc.

procedure TForm1.WndProc(Var TheMsg: TMessage);
Var
  ThePtr : PChar;
  TmpBmp : TBitmap;
begin
  if TheMsg.Msg = TheMsgVal then
    case TheMsg.wParam of
      wpString   : if TheMapHnd <> 0 then
                     begin
                       ThePtr := MapViewOfFile(TheMapHnd,FILE_MAP_WRITE,0,0,0);
                       edtStringRec.Text := ThePtr;
                       UnmapViewOfFile(ThePtr);
                     end;
      wpValue    : edtValueRec.Text := IntToStr(TheMsg.lParam);
      wpBitmap   : begin
                     TmpBmp := TBitmap.Create;
                     try
                       TmpBmp.Handle := TheMsg.lParam;
                       Image2.Picture.Bitmap.Width := TmpBmp.Width;
                       Image2.Picture.Bitmap.Height := TmpBmp.Height;
                       Image2.Picture.Bitmap.Canvas.Draw(0,0,TmpBmp);
                     finally
                       TmpBmp.ReleaseHandle;
                       TmpBmp.Free;
                     end;
                   end;
      wpShutDown : LookForApp(True);
    end;
  Inherited WndProc(TheMsg);
end;

So this actually works, when I start the std exe first, then the service. But it doesnt work the other way round. I notice if I start the service first, then the std exe, the TheMapHnd was showign 0 (on timer, obtainmappinghandle)

-----
 On the service side, I also do the following
  TheMsgVal := RegisterWindowMessage(TheMsgConstant);
  TheMapHnd := ObtainMappingHandle;

On Timer ,

I do the following

if TheHWnd = 0 then
   TheHWnd := FindWindow('TForm1','Test Application #1');


  ThePtr := MapViewOfFile(TheMapHnd,FILE_MAP_WRITE,0,0,0);
  StrPLCopy(ThePtr,IntToStr(DummyCount),MaxMapLen);
  SendMessage(TheHWnd,TheMsgVal,wpString,0);
  UnmapViewOfFile(ThePtr);


Is there anything I am not doing correctly here? Thanks

Joshua




Your second parm to CreateFileMapping() is null, resulting in a default security descriptor.  This means that only processes with rights equal to or higher than the creating process will have access to the map.

Presuming the service is started under the local system account, you'll have to specify user level security descriptor.

See CreateFileMapping():
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfilemapping.asp?frame=true
Thanks Cookre again for the reply.

I am not familiar with user level security descriptor that you have mentioned. I have looked the documentation. All I know is I have to create an object of type PSecurityAttributes , which has 3 properties I am suppose to initialize. (nLength, lpSecurityDescriptor, and bInheritHandle).  

An example of a security descriptor parameter for CreateFileMapping in delphi would be much appreciated. Thanks

Joshua
ASKER CERTIFIED SOLUTION
Avatar of cookre
cookre
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for your reply again. It is madness in there. I have no idea what it is talking about. But I found some articles related to creating mutex
http://www.jrsoftware.org/iskb.php?mutexsessions
I have absolutely no idea what are mutexes before you mentioned it.

From your last reply you mentioned I should be specifying NULL DACL, as oppose to null DACL. I am sorry but I dont get this.

I guess this kind of service is kind of complicated for a new bie in service to write. Thanks again for your guidance.

Joshua