Recent

Author Topic: Program not terminating on Windows 10  (Read 13229 times)

scamb09

  • New Member
  • *
  • Posts: 10
Program not terminating on Windows 10
« on: June 04, 2016, 09:34:34 pm »
Hi, I am currently in the process of writing a database application that will start at Windows start up and reside in the system tray with all forms hidden until the user selects from the system tray icons popup menu or double clicks the desktop icon, at which time a form (currently the main form is shown).

The application will be used on a large network of computers with various operating systems ranging from Windows XP to Windows 10 and thus needs to be adaptable.

When the application is run a mutex is created using the applications GUID.

When the user double clicks on the desktop icon a second instance of the application is created which again tries to create a mutex using the same GUID, this being unsuccessful, the second instance of the application broadcasts a message to all top level windows and then terminates. On receiving the message the first instance of the application then shows it main form.

The code located in the project file for creating the mutex and determining if another instance of the program running is as follows.

Code: Pascal  [Select][+][-]
  1. var
  2.    vmutex : THandle;
  3.  
  4. begin
  5.   // Register GUID as windows message.
  6.   AppMessage := RegisterWindowMessage(AppGUID);
  7.   // Create application mutex with GUID
  8.   vmutex := CreateMutex(nil, True, AppGUID);
  9.   // If mutex already exists then broardcast windows message.
  10.   if GetLastError = ERROR_ALREADY_EXISTS then
  11.   begin
  12.        Windows.SendMessage(HWND_BROADCAST, AppMessage, 0, 0);
  13.        Exit;
  14.   end;
  15. end;


And the handler within the main form is a override of the 'WndProc' routine.

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.WndProc(var Msg: TMessage);
  2. begin
  3.         if Msg.msg = AppMessage then
  4.         begin
  5.                MainForm.Show;
  6.                MainForm.ShowInTaskBar:= stDefault;
  7.         end;
  8.         inherited WndProc(Msg);
  9. end;

I have tested the application on all major versions of Windows and it works fine, up to and including Windows 8.1, however on Windows 10, running the second instance of the application triggers the first's to show it's form as expected but does not terminate, it instead continues to run as a background task.

I have tried the alternatives, PostMessage and PostThreadMessage but these are ignored by the message handler, presumable because of ownership issues.

Please could anyone help with this problem as I cannot see what could be wrong and why it would only affect running on one of the 5 operating systems tested on.

Many thanks

scamb09

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: Program not terminating on Windows 10
« Reply #1 on: June 05, 2016, 01:16:59 am »
Quote
..as I cannot see what could be wrong and why it would only affect running on one of the 5 operating systems tested on.
Because that one is Windows 10 :P  :D... What about Defender and other security-like programs or services ??
Obviously in Windows 10 they installed a lot of "useful" features...

I've never used a mutex... normally I use two functions "EnumWindowsProc" and "FindAllWindows" (EnumWindows).
For me that works well enough..  but I've never written a real world program...

But maybe you can test some alternatives with W10: a semaphore or something like that.. or TCriticalSections...

Good Luck...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

rvk

  • Hero Member
  • *****
  • Posts: 6169
Re: Program not terminating on Windows 10
« Reply #2 on: June 05, 2016, 12:41:44 pm »
Code: Pascal  [Select][+][-]
  1.   if GetLastError = ERROR_ALREADY_EXISTS then
  2.   begin
  3.        Windows.SendMessage(HWND_BROADCAST, AppMessage, 0, 0);
  4.        Exit; // <--- Exit right before end....? What's the use ???
  5.   end;
  6. end;
I don't understand your Mutex-procedure. You have a Exit right before end. This does nothing. So if your Sendmessage succeeds the control is just brought back to the main procedure. I don't believe this function is your main procedure... so where are you really exiting your program ??

If this is not your complete code.... please provide more.

scamb09

  • New Member
  • *
  • Posts: 10
Re: Program not terminating on Windows 10
« Reply #3 on: June 05, 2016, 03:57:48 pm »
Quote
rvk -
I don't understand your Mutex-procedure. You have a Exit right before end. This does nothing. So if your Sendmessage succeeds the control is just brought back to the main procedure. I don't believe this function is your main procedure... so where are you really exiting your program ??

If this is not your complete code.... please provide more.

As mentioned in my initial message, this section of code is located in the program  information file(*.lpr).

I have also tried using 'Application.Terminate' in place of 'Exit' but this has no affect on the function of the application.

The full code for the lpr file is as follows.

Code: Pascal  [Select][+][-]
  1. program BenchCheck;
  2.  
  3. //{$mode objfpc}{$H+}
  4. {$MODE DELPHI}{$H+}
  5.  
  6. uses
  7.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  8.   cthreads,
  9.   {$ENDIF}{$ENDIF}
  10.   Interfaces, // this includes the LCL widgetset
  11.   Forms, StringVar, lazcontrols, runtimetypeinfocontrols, treelistviewpackage,
  12.   bcmain, bcoptions, RunElevatedSupport, sysutils, windows, messages, bcsplash,
  13.   AppRoutines, bcgplviewer, bcelevatedtasks, bcconstants,
  14.   bcfilecopythread;
  15.  
  16. {$R *.res}
  17.  
  18. var
  19.    vmutex : THandle;
  20.  
  21. begin
  22.   // Register GUID as windows message.
  23.   AppMessage := RegisterWindowMessage(AppGUID);
  24.   // Create application mutex with GUID
  25.   vmutex := CreateMutex(nil, True, AppGUID);
  26.   // If mutex already exists then broardcast windows message and exit.
  27.   if GetLastError = ERROR_ALREADY_EXISTS then
  28.   begin
  29.        Windows.SendMessage(HWND_BROADCAST, AppMessage, 0, 0);
  30.        Exit;
  31.   end;
  32.  
  33.   try
  34.      RequireDerivedFormResource := True;
  35.      Application.Initialize;
  36.      Application.ShowMainForm:= false;
  37.      Application.CreateForm(TMainForm, MainForm);
  38.      Application.Run;
  39.   finally
  40.          CloseHandle(vmutex);
  41.   end;
  42. end.

I have now tested the application on Windows 10 Home and Professional versions with the same results.

Seems as if that under Windows 10, 'SendMessage' is not receiving a reply and therefore the 'Exit' command is never executed and hence the second instance of the application is not terminating.

Any help please?

scamb09
« Last Edit: June 05, 2016, 04:17:21 pm by scamb09 »

rvk

  • Hero Member
  • *****
  • Posts: 6169
Re: Program not terminating on Windows 10
« Reply #4 on: June 05, 2016, 04:25:34 pm »
Can you put dialogs in the uses and put a Showmessage('Broadcast done and returned'); directly after the SendMessage. If it shows the Showmessage on second run there must be something else wrong. (Exit should end the program in this case) If the message does not show your SendMessage does not return and we can look at that more specifically.

I tested this with a small sample here on Windows 10 Pro 64b and it works fine.

Did you try disabling you virusscanner etc.?
If you start the program multiple times, do you also get multiple instances (i.e. >2 times)?


ezlage

  • Guest
Re: Program not terminating on Windows 10
« Reply #5 on: June 05, 2016, 05:14:51 pm »
Main form needs to be closed if you want to get out from Application.Run loop and enter on "finally" statement.
Where and how users can tell the app to close? Where and how app closes itself?

Sorry by my poor english.

rvk

  • Hero Member
  • *****
  • Posts: 6169
Re: Program not terminating on Windows 10
« Reply #6 on: June 05, 2016, 05:20:40 pm »
Main form needs to be closed if you want to get out from Application.Run loop and enter on "finally" statement.
When the second instance is run it should even reach Application.Initialize;. So there is no mainform to close. There isn't even an Application to close (it doesn't come that far). So Exit after Sendmessage should just do the trick.

Where and how users can tell the app to close? Where and how app closes itself?
If a second instance on the same computer is run it should "activate" the first instance and exit directly. There is no "how many users". Also... there is no instruction to close the first application. The second run instance should detect the first instance (with the mutex) and activate the first after which the second should quit immediately.

And that's also what happens for me. So my guess is still a troubled virusscanner or that SendMessage doesn't return for some reason.

scamb09

  • New Member
  • *
  • Posts: 10
Re: Program not terminating on Windows 10
« Reply #7 on: June 05, 2016, 05:27:26 pm »
Quote
rvk -
Can you put dialogs in the uses and put a Showmessage('Broadcast done and returned'); directly after the SendMessage. If it shows the Showmessage on second run there must be something else wrong. (Exit should end the program in this case) If the message does not show your SendMessage does not return and we can look at that more specifically.

Ok, as you suggested, I put a showmessage instruction directly after the SendMessage command, this has no effect, so my initial assumption that the second instance of the application is not receiving a return value from the first.

Quote
rvk -
Did you try disabling you virusscanner etc.?

Windows Defender and AVG have been disabled.

Quote
rvk -
If you start the program multiple times, do you also get multiple instances (i.e. >2 times)?

A new instance of the application can be found as a background process after every attempt to run.

This is puzzling %).

scamb09



ezlage

  • Guest
Re: Program not terminating on Windows 10
« Reply #8 on: June 05, 2016, 05:31:58 pm »
Many times the McAfee causes unexpected things on my apps.

But see, this code never shows me the message:

Code: Pascal  [Select][+][-]
  1.   try
  2.     RequireDerivedFormResource:=True;
  3.     Application.Initialize;
  4.     Application.ShowMainForm:=False;
  5.     Application.CreateForm(TForm1, Form1);
  6.     Application.Run;
  7.   finally
  8.     ShowMessage('ok');
  9.   end;

Something in other piece of code needs to terminate the app or close the main form. This doesn't fit to your case?

rvk

  • Hero Member
  • *****
  • Posts: 6169
Re: Program not terminating on Windows 10
« Reply #9 on: June 05, 2016, 05:33:48 pm »
Ok, so the SendMessage does not return and that's the one that hangs. (So actually it hangs in your first instance because that should just return a result).

Could you try the following:
Code: Pascal  [Select][+][-]
  1. procedure TMainform.WndProc(var Msg: TMessage);
  2. begin
  3.   if Msg.msg = AppMessage then
  4.   begin
  5.     Mainform.Show;
  6.     Mainform.ShowInTaskBar := stDefault;
  7.   end
  8.   else // <-------- ADD THE ELSE
  9.     inherited WndProc(Msg);
  10. end;

You don't need to call inherited if your Msg.msg is AppMessage.

Does it work now? If not you could add a showmessage right after Mainform.Show to see if it doesn't hang in Show.
« Last Edit: June 05, 2016, 05:36:41 pm by rvk »

ezlage

  • Guest
Re: Program not terminating on Windows 10
« Reply #10 on: June 05, 2016, 05:52:40 pm »
You also can try the LPK UniqueInstance, from Luipack.


scamb09

  • New Member
  • *
  • Posts: 10
Re: Program not terminating on Windows 10
« Reply #11 on: June 05, 2016, 05:57:09 pm »
Ok, so the SendMessage does not return and that's the one that hangs. (So actually it hangs in your first instance because that should just return a result).

Could you try the following:
Code: Pascal  [Select][+][-]
  1. procedure TMainform.WndProc(var Msg: TMessage);
  2. begin
  3.   if Msg.msg = AppMessage then
  4.   begin
  5.     Mainform.Show;
  6.     Mainform.ShowInTaskBar := stDefault;
  7.   end
  8.   else // <-------- ADD THE ELSE
  9.     inherited WndProc(Msg);
  10. end;

You don't need to call inherited if your Msg.msg is AppMessage.

Does it work now? If not you could add a showmessage right after Mainform.Show to see if it doesn't hang in Show.

Ok, the else state was originally  in the 'WndProc' procedure, I removed it prior to starting this thread in a hope that calling inherited would cause a response, I have now replaced it.

As suggested, I have added a sendmessage statement immediately after the 'Mainform.Show' command,  this fires and shows he message when the second application instance is run, as expected.

scamb09

scamb09

  • New Member
  • *
  • Posts: 10
Re: Program not terminating on Windows 10
« Reply #12 on: June 05, 2016, 06:00:38 pm »
You also can try the LPK UniqueInstance, from Luipack.

Thanks for the hint, downloading now, but the routine I am tring to use, I have used many times before on Delphi, will give your suggestion a try.

scamb09

ezlage

  • Guest
Re: Program not terminating on Windows 10
« Reply #13 on: June 05, 2016, 06:13:45 pm »
I understand.

I'm creating a LPK similar to UniqueInstance, with more options, like instances counting and limit them to a license, stop the first and continue the job from next instances, and some more useful things for me.

If your problem persists, maybe I can finish my package including a solution for your case.

Please, sorry by my poor english.

rvk

  • Hero Member
  • *****
  • Posts: 6169
Re: Program not terminating on Windows 10
« Reply #14 on: June 05, 2016, 06:19:15 pm »
Ok, I think I have a (partial possible) reason.
Quote
For backward compatibility with Windows 3.0, SendMessage will not return until all of the top level windows in the system have responded to your broadcast.
http://stackoverflow.com/a/1956702/1037511

So there might be a top-level window without GetMessage or PeekMessage. I can't imagine what kind of window that would be.

The only window I could think of is that Lazarus itself creates a thread/window which doesn't implement that GetMessage yet until Application.Run is run. But I'm also puzzled why it runs fine for me then.

You could try using SendMessageTimeout().
Code: Pascal  [Select][+][-]
  1. var
  2.   Dummy: DWORD;
  3. //...
  4.   if GetLastError = ERROR_ALREADY_EXISTS then
  5.   begin
  6.     //Windows.SendMessageTimeout(HWND_BROADCAST, AppMessage, 0, 0);
  7.     Windows.SendMessageTimeout(HWND_BROADCAST, AppMessage, 0, 0, SMTO_NORMAL or SMTO_ABORTIFHUNG, 1000, Dummy);
  8.     Exit;
  9.   end;
But that would always mean a delay of 1000ms. Although... that might not be a problem because it's in the background... :)

You could try to find out what kind of window is not responding to that broadcast.

(Does Lazarus create a hidden window/thread before Application.Initialize is run??)
« Last Edit: June 05, 2016, 06:23:42 pm by rvk »

 

TinyPortal © 2005-2018