Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2013-10

SimpleIPC and TWinMsgServerComm.PeekMessage

8 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Juha Manninen

I am testing SimpleIPC with components/chmhelp/lhelp and
components/chmhelp/democontrol/lhelpconnectiondemo1

The latter works as a master application, sending a file name to lhelp and starting it if not running already.
On Linux this works perfectly. The return message status is always "Success". On Windows there is a bug when lhelp is not yet running and it must be started.

In TWinMsgServerComm.PeekMessage() (part of SimpleIPC), if Windows.PeekMessage() failed, the idea is to wait a given TimeOut and then try again:

  R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
  B:=(RWAIT_TIMEOUT);

The caller gives 50 ms as timeout but also uses a loop for 5 seconds total timeout.
It should be enough for even slowly starting processes. However, when the process does not exist yet,
MsgWaitForMultipleObjects returns WAIT_FAILED instead of WAIT_TIMEOUT, and it does NOT wait. It returns immediately.

I was able to fix it like this:
  R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
  if R=WAIT_FAILED then
    Sleep(TimeOut);
  B:=(RWAIT_TIMEOUT) and (RWAIT_FAILED);

The fix can be tested with lhelpconnectiondemo1.
Currently the first reply status is NoAnswer, after the fix it is Success. If you think the fix is OK, I can make a patch.

Regards,
Juha

Reply by email

Michael Van Canneyt
to Juha Manninen: I am testing SimpleIPC with components/chmhelp/lhelp and…
Juha Manninen wrote 32 lines
I am testing SimpleIPC with components/chmhelp/lhelp and components/chmhelp/democontrol/lhelpconnectiondemo1 The latter works as a master application, sending a file name to lhelp and starting it if not running already. On Linux this works perfectly. The return message status is always "Success". On Windows there is a bug when lhelp is not yet running and it must be started. In TWinMsgServerComm.PeekMessage() (part of SimpleIPC), if Windows.PeekMessage() failed, the idea is to wait a given TimeOut and then try again: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); B:=(RWAIT_TIMEOUT); The caller gives 50 ms as timeout but also uses a loop for 5 seconds total timeout. It should be enough for even slowly starting processes. However, when the process does not exist yet, MsgWaitForMultipleObjects returns WAIT_FAILED instead of WAIT_TIMEOUT, and it does NOT wait. It returns immediately. I was able to fix it like this: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); if R=WAIT_FAILED then Sleep(TimeOut); B:=(RWAIT_TIMEOUT) and (RWAIT_FAILED); The fix can be tested with lhelpconnectiondemo1. Currently the first reply status is NoAnswer, after the fix it is Success. If you think the fix is OK, I can make a patch.

Please do.

Michael.

Reply by email

Sven Barth
to Juha Manninen: I am testing SimpleIPC with components/chmhelp/lhelp and…
Juha Manninen wrote 32 lines
I am testing SimpleIPC with components/chmhelp/lhelp and components/chmhelp/democontrol/lhelpconnectiondemo1 The latter works as a master application, sending a file name to lhelp and starting it if not running already. On Linux this works perfectly. The return message status is always "Success". On Windows there is a bug when lhelp is not yet running and it must be started. In TWinMsgServerComm.PeekMessage() (part of SimpleIPC), if Windows.PeekMessage() failed, the idea is to wait a given TimeOut and then try again: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); B:=(RWAIT_TIMEOUT); The caller gives 50 ms as timeout but also uses a loop for 5 seconds total timeout. It should be enough for even slowly starting processes. However, when the process does not exist yet, MsgWaitForMultipleObjects returns WAIT_FAILED instead of WAIT_TIMEOUT, and it does NOT wait. It returns immediately. I was able to fix it like this: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); if R=WAIT_FAILED then Sleep(TimeOut); B:=(RWAIT_TIMEOUT) and (RWAIT_FAILED); The fix can be tested with lhelpconnectiondemo1. Currently the first reply status is NoAnswer, after the fix it is Success. If you think the fix is OK, I can make a patch.

You might want to take a entry:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687022%28v=vs.85%29.aspx Informative blog entry:
http://blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx

In my opinion you should use this in TLHelpConnection.StartHelpServer. Though you could add it in TWinMsgServerComm as well, as we rely on messages anyway...

Regards,
Sven

Reply by email

Juha Manninen
to Sven Barth
Sven Barth wrote 10 lines
You might want to take a look at WaitForInputIdle. MSDN entry: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687022%28v=vs.85%29.aspx Informative blog entry: http://blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx In my opinion you should use this in TLHelpConnection.StartHelpServer. Though you could add it in TWinMsgServerComm as well, as we rely on messages anyway...

No, TLHelpConnection demonstrates cross-platform IPC a cross-platform application. It cannot use Windows API directly.
SimpleIPC is the component that hides platform specific code. I am a little uncomfortable with WinAPI myself.

Another feature :
This code always starts a new instance of lhelp, even if I have already opened one manually.
Sometimes it would be desirable to attach to a running instance. Maybe it is already possible using SimpleIPC, I don't know.

Juha

Reply by email

Sven Barth
to Juha Manninen: I am testing SimpleIPC with components/chmhelp/lhelp and…
Juha Manninen wrote 32 lines
I am testing SimpleIPC with components/chmhelp/lhelp and components/chmhelp/democontrol/lhelpconnectiondemo1 The latter works as a master application, sending a file name to lhelp and starting it if not running already. On Linux this works perfectly. The return message status is always "Success". On Windows there is a bug when lhelp is not yet running and it must be started. In TWinMsgServerComm.PeekMessage() (part of SimpleIPC), if Windows.PeekMessage() failed, the idea is to wait a given TimeOut and then try again: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); B:=(RWAIT_TIMEOUT); The caller gives 50 ms as timeout but also uses a loop for 5 seconds total timeout. It should be enough for even slowly starting processes. However, when the process does not exist yet, MsgWaitForMultipleObjects returns WAIT_FAILED instead of WAIT_TIMEOUT, and it does NOT wait. It returns immediately. I was able to fix it like this: R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE); if R=WAIT_FAILED then Sleep(TimeOut); B:=(RWAIT_TIMEOUT) and (RWAIT_FAILED); The fix can be tested with lhelpconnectiondemo1. Currently the first reply status is NoAnswer, after the fix it is Success. If you think the fix is OK, I can make a patch.

I've looked at the code a bit more and the problem must be something else. MsgWaitForMultipleObjects waits on a FHWND which it created itself and additionally waits for the reception of a message through SendMessage. So this should not fail except maybe the creation of the window failed. Could you print the error message returned by "SysErrorMessage(GetLastOSError)" if put at the then-part of "if R=WAIT_FAILED"?

Regards,
Sven

Reply by email

Juha Manninen
to Sven Barth
Sven Barth wrote 6 lines
I've looked at the code a bit more and the problem must be something else. MsgWaitForMultipleObjects waits on a FHWND which it created itself and additionally waits for the reception of a message through SendMessage. So this should not fail except maybe the creation of the window failed. Could you print the error message returned by "SysErrorMessage(GetLastOSError)" if put at the then-part of "if R=WAIT_FAILED"?

Funny, it gives the error in Finnish language. Translated meaning is "Invalid handle".

Can you reproduce it? You must use the latest Lazarus trunk for testing. Yesterday I fixed TForm1.GetLHelpFilename in unit HelpConnectionUnit1. Apparently it was not tested on Windows until yesterday.

This my my patch after preventing a potential INFINITE sleep :

--- a/packages/fcl-process/src/win/simpleipc.inc
+++ b/packages/fcl-process/src/win/simpleipc.inc
@@ -146,7 +146,9 @@ begin
     if (TimeOut=0) then
       TimeOut:=Integer(INFINITE);
     R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
-    B:=(RWAIT_TIMEOUT);
+    if (R=WAIT_FAILED) and (TimeOutINFINITE) then
+      Sleep(TimeOut);
+    B:=(RWAIT_TIMEOUT) and (RWAIT_FAILED);
     end;
   If B then
     Repeat

Regards,
Juha

Reply by email