Thread: Best method to (gracefully) quit another application

  1. #1
    Registered User
    Join Date
    Apr 2004
    Posts
    210

    Question Best method to (gracefully) quit another application

    Hi,

    I'm writing a small launcher that is supposed to mount a virtual drive (a TrueCrypt volume), launch a menu application (called PortableApps) on that volume and then wait until this application quits. Once it does, the launcher also asks all processes launched from the volume to quit as well, waits until they do and then unmounts the volume.

    Anyway, I've got this working for the most part. The only thing that doesn't really work very well is the part where it's supposed to quit the other applications. I'm using EnumProcesses/Modules and GetModuleFileNameEx to find all processes launched from the volume. Comparing the results with EnumWindows gives me the window handles of those processes and sending them a WM_CLOSE works for a couple of applications. Others either "ignore" the message or one particular application (FreeCommander) crashes. I'm guessing this is because I send this message to all windows of a process. (Googling for something like a 'mainwindow' didn't yield any helpful results:/)

    I was wondering if anybody might have a better idea on how to do this (short of using TerminateProcess ).

  2. #2
    Registered User
    Join Date
    Jan 2009
    Posts
    31
    WM_CLOSE should work for most situations. It is the equivalent of clicking on the close button (clicking the close button sends the WM_CLOSE message to the window). You should only send WM_CLOSE to non child windows (windows without the WS_CHILD style). EnumWindows gives top level windows only, except in a few circumstances.

    Calling WM_CLOSE on windows should probably be done in the order that the user would normally close the windows. For example, if there's a modal dialog active for an application, WM_CLOSE should be sent to that window first (as the user normally cannot click the close button while a modal dialog is active, so sending WM_CLOSE to it may yield unexpected results). That's not to say that most programs will have issues with it.

    EnumThreadWindows can be used to determine what windows belong to a specific thread (message pump).

    The nice thing about WM_CLOSE is that if you have any unsaved documents, most applications will prompt you to save them, as there should be no difference between using that and the user clicking the close button or using Alt-F4. All other methods will yield undesired side effects (at least ones that do not use WM_CLOSE or something that triggers a WM_CLOSE to be sent).

  3. #3
    Registered User
    Join Date
    Apr 2004
    Posts
    210
    Thanks for your reply, tjb.
    Quote Originally Posted by tjb View Post
    WM_CLOSE should work for most situations. It is the equivalent of clicking on the close button (clicking the close button sends the WM_CLOSE message to the window).
    You should only send WM_CLOSE to non child windows (windows without the WS_CHILD style).
    EnumWindows gives top level windows only, except in a few circumstances.
    For the applications I tested this with, EnumWindows mostly yielded several results, so I'm now doing a GetAncestor(.., GA_ROOT) to get the "mainwindow". At least I think this should be it. (?) I haven't done any Windows programming in the last 4 years or so :/
    This works nicely for foobar2000, but TotalCommander ignores it (maybe I got the wrong "root" window?). Also, what about applications that reside in the system tray and currently do not have a window (i.e. Miranda)?

    Quote Originally Posted by tjb View Post
    Calling WM_CLOSE on windows should probably be done in the order that the user would normally close the windows. For example, if there's a modal dialog active for an application, WM_CLOSE should be sent to that window first
    I'm not quite sure how to find out whether it's a modal window or not. But assuming I did this, wouldn't I risk closing a "Save document first" or similar dialog?

    Quote Originally Posted by tjb View Post
    The nice thing about WM_CLOSE is that if you have any unsaved documents, most applications will prompt you to save them
    Yes, that's exactly the behavior I'd like to achieve. The launcher will be installed on the U3 partition of my usb flashdrive. Basically I want the drive to be in a state where I can safely unplug it when PortableApps quits.
    Last edited by Nyda; 05-11-2009 at 07:30 AM.
    main() { int O[!0<<~-!0]; (!0<<!0)[O]+= ~0 +~(!0|!0<<!0); printf("a function calling "); }

  4. #4
    Registered User
    Join Date
    Jan 2009
    Posts
    31
    I downloaded FreeCommander to play with it, and I noticed that there were several hidden top-level windows associated with it. I don't know if you're using Visual Studio, but there's a program that comes with it called Spy++ which is quite useful for determining what windows are associated with a process, each window style, etc. The main issue though is a window that not technically hidden (but off the screen) that has a class name of "TApplication". It's sending a WM_CLOSE to this window that is causing the issue. Unfortunately, I can't think of any very good way of detecting this case, other than by it's class name (this is a common feature of Delphi and C++ VCL applications, I believe). The other windows can be filtered out by making sure that the WS_VISIBLE style is set before sending it a WM_CLOSE.

  5. #5
    Registered User
    Join Date
    Apr 2004
    Posts
    210
    Quote Originally Posted by tjb View Post
    I downloaded FreeCommander to play with it, and I noticed that there were several hidden top-level windows associated with it. I don't know if you're using Visual Studio, but there's a program that comes with it called Spy++ which is quite useful for determining what windows are associated with a process, each window style, etc.
    Thanks for researching that. I'm using a free IDE called CodeBlocks, but I think I could get a free students license of VS, if only for Spy, which sounds like it would help quite a bit.

    Quote Originally Posted by tjb View Post
    The main issue though is a window that not technically hidden (but off the screen) that has a class name of "TApplication". It's sending a WM_CLOSE to this window that is causing the issue.
    Right, I remember that. I think it's some sort of project container class that 'uses' (=includes) all forms and runs the main loop.

    Quote Originally Posted by tjb View Post
    Unfortunately, I can't think of any very good way of detecting this case, other than by it's class name (this is a common feature of Delphi and C++ VCL applications, I believe). The other windows can be filtered out by making sure that the WS_VISIBLE style is set before sending it a WM_CLOSE.
    I'll try that, thanks tjb.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C# method
    By siten0308 in forum C# Programming
    Replies: 6
    Last Post: 07-15-2008, 07:01 AM
  2. Overriding a method in C
    By DavidDobson in forum C Programming
    Replies: 1
    Last Post: 07-05-2008, 07:51 AM
  3. how to make a windows application
    By crvenkapa in forum C++ Programming
    Replies: 3
    Last Post: 03-26-2007, 09:59 AM
  4. processes not exiting or quit
    By kryptkat in forum Tech Board
    Replies: 8
    Last Post: 11-13-2006, 12:43 PM