Get a handle to a particular window when multiple windows have same name

Started by cssyphus, October 18, 2021, 08:20:34 AM

Previous topic - Next topic

cssyphus

Ever since apps written in electron (Zoom, Slack, Teams) started appearing life has become more difficult. It appears that electron apps do not follow the (formerly) sacrosanct rule that all windows must have unique window titles.

I am attempting to manipulate the Zoom launch ("Join" / "Schedule" / "Share Screen") window, and part of that process is to get the position of the window on screen. However, there are multiple windows (3) that are named exactly "Zoom" - including the one I need to target. Using the old staple of _winPos = winPosition("Zoom~") does not work because it gets the first window with that name, not the one I need to target.

Does anyone have any thoughts on how to handle this?

For example, how could I loop through all three windows with the same window title, and get unique handles for each that would allow me to interrogate/manipulate each?


td

There are many ways to get a window handle when multiple windows have the same or no name. Start with the Roboscripter WinBatch utility that is on your start menu. That is only the start. This is an often-discussed problem so there is much to be found on this form and in the Tech Database, including several WIL CLR hosting (dotNet) approaches.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

cssyphus

Thanks Tony. Yeah, RoboScripter doesn't detect it at all... I'll snoop around.  If there are one or two threads in particular you suggest I review, I'd appreciate it.

Update:
Found this one, it looks to have what I need. (Funny, I searched for this very thing several times in the recent past and didn't stumble across this post - and yet here it is. From 2016. Meh. Probably just Tony's assurance that such a post could be found guided my disbelieving fingers to a happy result.)
https://forum.winbatch.com/index.php?topic=1650.msg8148#msg8148

cssyphus

From the above-mentioned topic, this code gets a list of all shell windows...


objShell = ObjectCreate("Shell.Application")
objWindows = objShell.Windows
cnt = objWindows.Count -1
_out = ``
For item = 0 To cnt
   objWin = objWindows.Item(item);
   if StrIndexNc(objWin.FullName,'Zoom', 1, @FWDSCAN)
      _out := `[` : objWin.FullName : `]` : @CRLF
   endif
next
terminate(1, `Windows found:`, _out)


Which displays nothing in my case, because I am looking for normal windows.  What must I change to search through the Windows-app windows?

cssyphus

Okay, I'm stumped.

I've searched and searched both within this Forum and in the TechSupport Database, and I haven't found a code example that allows one to distinguish between multiple windows applications with the same window title. I found a great one about shell windows, some about file system windows, but these are electron quasi-Windows windows. Clearly, I haven't stumbled across the right search terms.

I understand that winIdGet() is the WIL function that provides a usable window handle - but it requires a unique partial-window-name as input.  This basic script loops through the window titles and tries to assign unique window IDs to each successive Zoom window - but clearly it is inadequate (returning the winPosition from the first Zoom window 3x).


_x = winItemize()
_o = ``
_p = ``
For _n = 1 to itemCount(_x, @TAB)
_z = itemExtract(_n, _x, @TAB)
if strIndex(_z, `Zoom`, 0, @FWDSCAN)
_o := _z : @CRLF
_a = winIdGet(_z)
_p := winPosition(_a) : @CRLF
endif
Next
message(`All Zoom Windows:`, _o) ;Zoom || Zoom Meeting || Zoom || Zoom || Zoom Cloud Meetings
message(`All Zoom Positions:`, _p) ;870,129,986,246 || -694,62,-52,737 || 870,129,986,246 || 870,129,986,246 || 343,300,677,745


The window in which I'm interested has a window position like [215,105,785,865]  (I masked it with a Notepad window and got the size of the Notepad window), so I'm sure I don't have the right window anywhere in there.

I could use another tip...

td

I believe you are missing an important point. Not all "windows" that appear on the Windows desktop are created equal. Some application frameworks like Java or nodejs or whatever have their own windowing system. Generally, these frameworks only have one desktop window and that window may not even be visible. I have no idea which framework Zoom is using nor do I even want to know but you need to take a different approach. 

One suggestion would be to look at the .Net framework's "System.Diagnostics.Process" class which works well with WLL CLR hosting. Not saying that it will work but it is worth checking out. Again there are examples using this class on this forum and I believe the Tech Database.  The MSFT documentation can be found here:

https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=netframework-4.8

It duplicates a lot of the functionality of the WIL process extender but has some additional features that may or may not be useful to complete your task.

FWIW, when I used the search term "Windows Name" sans quotes in the forums Search menu page I got about 100 hits. Didn't try any more creative search terms to get better targeted results.

You can use the Windows Task Manager to get a better look at the process or processes and threads created for your Zoom session. That may tell you if the .Net class is a possible answer.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

cssyphus

I was missing that point, thank you Tony. (And my search fu has never been as good as my jujit su, about which I know nothing).

I appreciate the (very helpful) tips and the additional places to look.

td

Another possibility is that Zoom is created with MSFT's WinRT (Windows Store App) API. If it is, it lives in the WinRT "app ghetto" and your options are limited.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

A simple example that may be a starting point or not...

Code (winbatch) Select
ObjectClrOption("useany","System")
objProcess = ObjectClrNew("System.Diagnostics.Process")

strProcName = "zoom" 
aProcs = objProcess.GetProcessesByName(strProcName)
nProcMax =  ArrInfo(aProcs, 1) - 1
for  i = 0 to  nProcMax
   Pause(strProcName: " Title and Handle", aProcs[i].MainWindowTitle:' ':aProcs[i].MainWindowHandle)
next
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

cssyphus