How to determine, if process' window was previously hidden? And list hidden windows?

已答覆 How to determine, if process' window was previously hidden? And list hidden windows?

  • Friday, May 11, 2012 9:26 AM
     
     

    Hi.

    I used this code for listing (in listBox) running windows and hide/show some of them.

    I am adding to the listBox only those processes, which have any MainWindowTitle or have MainWindowHandle != IntPtr.Zero (I mean - I've tried first and second option, not both at a time) - it looks like it's the quite same way.

    Everything works great until I hide some window and then close and reopen app. Of course the hidden window doesn't show in the listBox - it can't, because it's hidden, it has zero-handle.
    But the process exists and if I knew the previous MainWindowHandle I could retrieve (show) it's window - I checked that by simply copying the handle before hiding and after reopen, showing the specific window.

    I just don't know, how to determine, which process has the hidden window and/or how to get it's handle. Is it possible?

    My goal is portability, so I don't want to save hidden window's handle anywhere. Maybe I can "check" somehow the process, give it an attribute or something?

All Replies

  • Friday, May 11, 2012 12:34 PM
    Moderator
     
     

    The previous window handle is irrelevant.  There is no guarantees that when you "hide" a window that the visibility is just toggled.  There are many apps where hiding a window destroys it so when the window is shown again you get a new handle.  AFAIK there is no way to know whether a window was previously hidden because there is no persistent state available.  Even more complicated is the fact that initially a window may be hidden.  In this case the handle hasn't even been created yet.  A window handle doesn't get created until the window is getting ready to be displayed.  So given an arbitrary process determining all hidden windows is pretty much undoable.

    What you can do is enumerate the top level windows (or the windows of a process) and determine their current visibility state.  But hidden windows may or may not be in that list (depends upon whether they are destroyed when hidden).  There is no way to know for sure unless you have complete control over the processes.

    Michael Taylor - 5/11/2012
    http://msmvps.com/blogs/p3net

  • Friday, May 11, 2012 1:26 PM
     
     

    The previous window handle is irrelevant.  There is no guarantees that when you "hide" a window that the visibility is just toggled.  There are many apps where hiding a window destroys it so when the window is shown again you get a new handle.

    Well, you're right, but I only want to minimize the damage, not to prevent it in 100%. So I assume the window's handle do not change, when I use ShowWindow(handle, 0) to hide it.

    With that assumption, is it possible to retrieve the handle from the process itself, or "save" the handle in process' properties anywhere?

  • Friday, May 11, 2012 1:38 PM
    Moderator
     
     

    If:

    • You assume the window is only ever hidden and not destroyed
    • The main window is the only window you care about (even if there are several top level windows)
    • The main window is initially shown and then hidden (vs. initially hidden)
    • No splashscreens are involved

    then the MainWindowHandle gives you the handle to the main window.  When that handle goes away the process is probably going to go away.  What the MainWindowHandle returns is the first window that was created in the process.  Windows assumes that this is the main window but often that is not the case anymore.  For example most apps display a splash screen which would normally be the first window.  In the case of WinForms (where the same assumption is made) apps often have to create the main window and then hide it before showing the splash screen.  It is frustratingly difficult.

    An alternative approach may be to query the top level windows and then match them back to the owning process.  Certainly slower but it would get all top level windows of a process irrelevant of creation order.  Additionally if you wanted all the top windows of a process this is the only solution.

    Michael Taylor - 5/11/2012
    http://msmvps.com/blogs/p3net

  • Friday, May 11, 2012 2:48 PM
     
     

    If:

    • You assume the window is only ever hidden and not destroyed
    • The main window is the only window you care about (even if there are several top level windows)
    • The main window is initially shown and then hidden (vs. initially hidden)
    • No splashscreens are involved

    then the MainWindowHandle gives you the handle to the main window.  When that handle goes away the process is probably going to go away. 

    Yesterday I've made a simple test just to check it. I added a TextBox to enter MainWindowHandle manually and listed all the processes with their ProcessName and MainWindowHandle. What I achieved:

    1. At first run, I see a notepad.exe process listed with MainWindowHandle greater than zero and with a not-null title.
    2. I copy it's MainWindowHandle.
    3. I hide the window.
    4. Close and reopen the app - Notepad is not listed on the windows list. But the process notepad.exe is still listed as present in memory. With one problem - it has no MainWindowTitle and its MainWindowHandle is zero.
    5. Worth a try - I paste the previously copied MainWindowHandle to the TextBox and then run ShowWindow with that handle.
    6. Notepad Window magically appears...

    Based on that (tried a couple of times with different apps) I assumed the MainWindowHandle can be used even if it can't be read from process' properties and the problem is how to retrieve that handle, if it is hidden, when the window is hidden.

  • Friday, May 11, 2012 3:49 PM
    Moderator
     
     Answered

    MainWindowHandle isn't reliable for what you're trying to do.  It's mainly just designed for getting access to a process'es handle so you can send it a message (such as close).  Taking a quick look at the impl it relies on EnumWindows which won't pull hidden windows.  Hence you won't get any value if the window is hidden.  You can verify this by opening Notepad, running your app so you can see the handle, hiding Notepad (however you are doing that) and then call Refresh on the Notepad process instance.  You'll find the handle is now gone. 

    I believe the FindWindow Win32 function can find hidden windows.  If you want to accomplish what you're trying to do then you're probably going to have to use it to find all windows.  For each window you'll have to get its process via GetWindowThreadProcessId.  Given the process ID you can get back to the .NET process.  This will be slow but it should work.

    Michael Taylor - 5/11/2012
    http://msmvps.com/blogs/p3net