2

I'm currently automating a process that involves running Hapfacs 3.0, a C# program designed to construct facial images. I'm using python to open the program, to set some parameters, and then to save the resulting image. The automation will do this process 1000s of times. The saving process involves opening File Explorer (I'm on Windows 7), typing in the file name, and then saving.

One issue I'm running into is that File Explorer occasionally takes a while to open, which messes up with the automation since the program begins typing in the file name before the File Explorer window is open.

I'd like to have the program wait for File Explorer to open before it begins typing. Thus, I need to be able to tell if File Explorer is open. I found this page here:

Python check if a process is running or not

which suggests to use the psutil module:

import psutil    
"someProgram" in (p.name() for p in psutil.process_iter())

However the list

[p.name() for p in psutil.process_iter()]

is not different if File Explorer is open compared to when it is closed, suggesting File Explorer isn't ever added to the list. Can I still check whether File Explorer is open with psutil, or is there a different way to accomplish my goal? Thanks for your help.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • File Explorer is almost always open. When you ask Windows to, e.g., `explore C:\Spam`, the `explore.exe` program starts up, finds your existing File Explorer process, tells it to open a window for `C:\Spam`, then exits. So, after that's done, the set of running processes will usually be exactly the same as it was before. – abarnert Aug 20 '18 at 23:08
  • So how do I tell if a window of File Explorer is open? The code "explorer.exe" in [p.name() for p in psutil.process_iter()] evalauates True regardless of whether a window of File Explorer is open or not. – Spencer Reschke Aug 20 '18 at 23:30
  • If _any_ window is open? Or any window that's navigated to some particular directory? Or some specific window that you can identify in some way that you haven't explained yet? – abarnert Aug 20 '18 at 23:31
  • Yes, of course it's true. As I said, File Explorer is almost always open, so it's almost always going to be found in `process_iter`. – abarnert Aug 20 '18 at 23:31
  • If I could tell if a File Explorer window that is navigated to a specific directory is open, that would work. – Spencer Reschke Aug 20 '18 at 23:35
  • Not just any window, is your desktop open? `explorer` is the process which displays your desktop - when it crashes your taskbar, icons, and other items on your desktop typically disappear (and that's just the most noticeable change). – LinkBerest Aug 20 '18 at 23:36
  • Please don't "tag" your question title with the programming language - that's what the actual tags are for. editing. – xaxxon Aug 20 '18 at 23:37
  • I think what you actually want to do is one of the following (from most ideal downward): (1) don't use explorer; (2) use explorer via Win32COM instead of subprocess; (3) use explorer with some flag that forces it to open a new process; (4) enumerate all windows with PyWin32 and look for one that has the owner, class, and name that you want. (There is, or at least used to be, a tool called something like WinSpy that comes with the free version of Visual Studio that lets you inspect existing windows and see what the values should look like.) – abarnert Aug 21 '18 at 00:19

2 Answers2

0

Unfortunately for you the reason you can't find anything changing is that on windows "explorer.exe" which is responsible for pretty much all file operations (file explorer, desktop management, etc...) is always open, and runs from a single instance. I'm not aware of any way you can do this from python but I do have a solution that you can incorporate, even if it's not ideal.

Using PIL, found here http://www.pythonware.com/products/pil/, you can grab an image of the screen and check pixel colors at specific points, which should allow what you're currently after. If you need to grab pixel colors from the screen the best tool I can think of for quick mockups would be autohotkeys window spy.

Hopefully this helps, I know how annoying automation can be sometimes when you have to do hacks like this so let me know if you have any other questions.

Edit: I was messing around with the idea that when file explorer is open the amount of handles open by explorer will increase by a decent margin, and if you aren't doing anything except running automated scripts the behavior is fairly predictable but would require a little experimentation on your end.

This is what I have:

import psutil
for proc in psutil.process_iter():
    if 'explorer' in proc.name():
        print(proc.name() + " handles:" + str(proc.num_handles()))

When I run this with my file explorer closed vs file explorer open I get a random increase of about 100 handles or more, so you might be able to store the previous amount and poll the current amount assuming you do not open anything else when the handles increase by X amount you know that file explorer has been opened and can begin typing, then after it drops near X amount you know its closed and you resave the new handle count and wait for your X increase again.

While this is not a perfect solution you should be able to make it work quite well for what you want.

Edit2:

This works for me, you may need to change the usualIncrease amount since it might be a larger or smaller amount of handles created.

import psutil
import time


handlesPrevious = 0
usualIncrease = 100

for proc in psutil.process_iter():
    if 'explorer' in proc.name():
        handlesPrevious = proc.num_handles()

while 1:
    time.sleep(5)
    for proc in psutil.process_iter():
        if 'explorer' in proc.name():
            handlesCurrent = proc.num_handles()
            if (handlesPrevious + usualIncrease) <= handlesCurrent:
                print("File explorer open! - handles:" + str(handlesCurrent) + " previous handles:" + str(handlesPrevious))
                handlesPrevious = handlesCurrent
            elif (handlesPrevious - usualIncrease) > handlesCurrent:
                print("File explorer not open! - handles:" + str(handlesCurrent))
                handlesPrevious = handlesCurrent
vividpk21
  • 384
  • 1
  • 11
  • How is knowing the pixel color at a specific point going to tell you whether some Explorer window has been opened (even if the OP could figure out how to define which window he's looking for in the first place)? – abarnert Aug 20 '18 at 23:56
  • It's just basic automation, assume you have a file explorer screen and a menu screen for your program, when you open the file explorer the pixel at many of the locations on the screen will change because a new window is being placed over the old one and you just choose an arbitrary location. But regardless I have updated my post with a somewhat better (faster) solution. – vividpk21 Aug 20 '18 at 23:59
  • @vividpk21 I like this better than using PIL, since PIL doesn't currently support python 3+ (I'm running python 3.6). I'll give your second suggestion a try and let you know how it works. – Spencer Reschke Aug 21 '18 at 00:14
  • @SpencerReschke Pillow is the modern version of PIL, and it definitely does support Python 3 (in fact, it's moving Python 2 to legacy support in the next version). – abarnert Aug 21 '18 at 00:18
  • I wrote up a small test and it works, I edited the above again with my simple mockup if you want to test it. – vividpk21 Aug 21 '18 at 00:20
  • Looking at a bunch of random pixels to see if any of them have changed can easily have both false negatives (it's easily possible that the new window doesn't overlap any of those pxiels) and false positives (e.g,, the clock changes every second, some of your windows might be doing a live tail or an animation, …). – abarnert Aug 21 '18 at 00:27
  • Like I said it's not ideal but it gets the job done, I've wrote complex game botting programs all in autohotkey that use that technique and it's all a matter of trial and error. Obviously there are extreme cases that would not permit it but for his uses it should be easy to implement. I'll leave it at that since my second solution posted works on my end quite well. – vividpk21 Aug 21 '18 at 00:31
  • @SpencerReschke if the solution works for you I'd appreciate if you would mark it as the answer, if you need any more help let me know. – vividpk21 Aug 21 '18 at 00:32
  • @vividpk21 it seemed to work just fine on my computer. I won't have access to the computer I'll implement the changes on till tomorrow. If it works then, I'll mark it as the answer. Thanks for your help! – Spencer Reschke Aug 21 '18 at 00:45
  • @vivdpk21 I ended up checking pixel colors and that worked just fine. The second solution you suggested using the number of handles ended up being a little too unpredictable to be used in the implementation. Thanks again for your help. – Spencer Reschke Aug 23 '18 at 22:36
-1

EDIT: I feel this is a XY problem (http://xyproblem.info/ ) where the author is launching File Explorer and selecting Hapfacs files via keyboard, because they doesn't know how to use command-line arguments, "for each file, launch Hapfacs.exe $file".


Maybe you should call Hapfacs via Python, instead of trying to automate File Explorer?

Builtin subprocess.Popen is flexible for piping.

subprocess.call and the plumbum library are easier to use, if you want to call a program and waiting for it to terminate.

nyanpasu64
  • 2,805
  • 2
  • 23
  • 31
  • Calling a program and waiting for it to terminate is not useful here, because explorer.exe immediately exits after telling the real Explorer process to open a new window, which is the entire problem the OP is trying to solve, and not what the OP wanted anyway even if that weren't true, because they need to interact with the window before it closes. – abarnert Aug 21 '18 at 03:49
  • I feel this is a XY problem where the author is launching File Explorer and selecting Hapfacs files via keyboard, because they doesn't know how that double-clicking a file is actually launching `webbrowser.open(file)` or `Hapfacs.exe $file` which can be done directly via Python. – nyanpasu64 Aug 21 '18 at 04:57