Reputation: 241
I know using os.startfile('....') or os.system('....') can run a file, for example, *.pdf, *.mp4 and so on, but it can't get the hwnd of that file. (I have to know the hwnd to control the window, for instance, move, resize, or close it)
Of course, I can get the hwnd by win32gui.FindWindow(None,"file name"), however, it can't get hwnd separately if there are two windows which have the same name.
Is there a function can run a file and get its hwnd in win32?
Like this:
hwnd=win32.function("file dir/file name") // run a file like os.startfile(...)
//hwnd=-1 if failed
//hwnd=1234567 if successful
and then I can run multiple files and get their hwnd without any problem.
Thanks in advance.
Upvotes: 0
Views: 8643
Reputation: 365945
First, "the hwnd" is an ambiguous concept. A process can have no windows, or 3000 windows.
But let's assume you happen to be running a program that always has exactly 1 window, and you need to know which windows belongs to the process you actually launched rather than, say, another instance of the same process already running. (Otherwise you could just search by title and class.)
So, you need some way to refer the process. If you're using os.system
or os.startfile
, you have no way to do that, so you're stuck. This is just one of the many, many reasons to use the subprocess
module instead:
p = subprocess.Popen(args)
pid = p.pid
Now, you just enumerate all top-level windows, then get the PID for each, and check which one matches.
Assuming you have pywin32
installed, and you're using Python 3.x, it looks like this:
def find_window_for_pid(pid):
result = None
def callback(hwnd, _):
nonlocal result
ctid, cpid = win32process.GetWindowThreadProcessId(hwnd)
if cpid == pid:
result = hwnd
return False
return True
win32gui.EnumWindows(callback, None)
return result
In Python 2.x, there's no nonlocal
, so you need some other way to get the value from your callback to the outer function, like a closure around a mutable dummy variable (like result = [None]
, then set result[0]
instead of result
).
But note that this can easily fail, because when you first launch the process, it probably doesn't have a window until a few milliseconds later. Without some means of synchronizing between the parent and child, there's really no way around this. (You can hack it by, say, sleeping for a second, but that has the same problem as any attempt to sleep instead of synchronizing—most of the time, it'll be way too long, reducing the responsiveness/performance of your code for no reason, and occasionally, when the computer is busy, it'll be too short and fail.)
The only way to really solve this is to use pywin32
to create the process instead of using standard Python code. Then you have a handle to the process. This means you can wait for the child to start its window loop, then enumerate just that process's windows.
Upvotes: 5