Sign in to follow this  
Followers 0
DanSut

Problems scripting automation for an MDI

10 posts in this topic

My first post here - only recently discovered AutoIt and I must say I'm impressed - thanks to all involved in the tools and their community.

Not sure if I'm going to be able to get much help here as I'm trying to script a proprietary internal DB access application that I can't give you access to and is an MDI with some custom controls :whistle: The purpose of the scripting is to perform QA tests - functional, regression and eventually performance testing... if anyone can even point me in vaguely the right direction it would be most appreciated.

The child windows of this MDI app seem to be identified as Controls (not Windows) - they share all the same ClassNameNN with a unique dynamic numeric suffix added and their ControlID's are generated on the fly, so they can only really be identified by their Text (child window title). The weird thing (to me) is that the child windows will switch ClassNameNNs as focus is switched between them - the child window with the focus seems to always have a suffix of 1.

Many of the child Windows contain a toolbar which is custom control that is essentially the same for each window (although its actions are just for that child window) - this toolbar has the same ControlID, no Text, and the same ClassNameNN with a unique dynamic numeric suffix for each child windows toolbar. As above, the ClassNameNN seems to switch dependent of the focus.

I have 3 main questions:

  • How should I identify a specific one of these child windows to give it the focus?
  • Once given focus I can close a child window using the Ctrl+f4 shortcut but I can't work out a good way to activate its menu or tools minimize, maximize, etc. Will there be a shortcut - if there is what is a good way to find it?
  • Do I have to just have to do a ControlGetPos() on the custom control toolbar and then use pixel mouse positioning and clicking to activate? Or is there a better way?
Searching in the docs and here made me think I could set Opt(WindowSearchChildren,1) and treat each child window as an individual Window but that doesn't seem to work at all for my app - at least my script never finds the child windows given their titles. ;)

Any pointers, clues, or commiserations are welcome.

/dan

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Well, normally I'd say post your code, but that sounds troublesome. Why don't you run this against it, and see if it doesn't list all of your MDI app's child window handles and titles.

#include <Process.au3>
Opt("WinSearchChildren", 1)     ;0=no, 1=search children also

$exe = "YourAppName.exe"

$var = WinList()
For $i = 1 to $var[0][0]
    If $var[$i][0] <> "" AND IsVisible($var[$i][1]) Then
        $pid = WinGetProcess($var[$i][1])
        if _ProcessGetName ( $pid ) = $exe then
            Consolewrite("Handle: " & $var[$i][1] & ", Title: " & $var[$i][0]& @crlf)
        EndIf
    EndIf
Next

Func IsVisible($handle)
  If BitAnd( WinGetState($handle), 2 ) Then 
    Return 1
  Else
    Return 0
  EndIf
EndFunc

ClassNames are tricky. For MDI child windows, they are useless, don't use them. Use the window handle instead. For the controls inside those windows, they can be confusing because of how AutoIt enumerates them. If you have two Edits, one on each MDI child, AutoIt will nonetheless refer to them as Edit1 and Edit2, but the method by which it decides to number them is beyond me at the moment. You can use WinGetClass list to get their actual ClassNames, but that's not really useful.

What you'd be better off doing is WinActivating the child window, and then use SmOke_N's _WinGetCtrlInfo() to enumerate that window's controls. Then after you've found the target control, you can mess with it all you like - but in your situation, I reccomend doing so through the handles, not the names as the handles shouldn't change.

Good luck!

Edited by lod3n

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites

Thanks for the response ;)

Ran your script and got some very interesting results: the child windows of the MDI didn't show up but a whole host of other windows that weren't visible (or useful to me) did :whistle:

I have taken your advice and am using handles though to keep track of things - what I've ended up doing is cycling through my child MDI windows using Ctrl+F6 and using the fact that the ClassNameNN of the MDI child in focus is reliable and the Text tells me which window it is ... having done this and saved the handles I can then get the child window I want in focus easily. Once I have a known in focus I just treat it as if it is the main window and ignore the others.

Oh for reference - the shortcut for opening a child MDI's (document's) control menu is Alt+-

this turned out to not be much use for me at this point but maybe useful yet.

The custom toolbar looks just like legwork of knowing what buttons are on it, how big they are and their order... Now I just need to work out how I'm going to deal with this wacking great custom control of a table that is in many of my child windows - looks like it is impossible to extract text out of it which I'd really like to do.

Thanks again for the advice.

Share this post


Link to post
Share on other sites

I'm having very similar problems so I used the code that was suggested to get the window handle, but I am still unable to get at the controls. The WinActive/WinActivate functions won't work with the handle either.

I have tried using ControlGetHandle with the control NN and instance (it's a SysTabControl32) and AutoLib3's _API_GetDlgItem using the item ID 3020 which I obtained form spy++ (I also tried 14880 in case 3020 is hex). None of these work.

I also tried changing the style of the window but that just caused the program to crash!

Do you have any other ideas?

Thanks

Sam

Share this post


Link to post
Share on other sites

I've determined part of the problem - the actual window containing the controls tow levels below the window in the MDI. I can retrieve the correct window handle but the GetControlHandle command still can't get the control. The command I am using is:

$hCtl = ControlGetHandle($hDlg, "", "[CLASSNN:SysTabControl32]") having obtained $hDlg from _API_GetWindow($GW_CHILD).

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I've determined part of the problem - the actual window containing the controls tow levels below the window in the MDI. I can retrieve the correct window handle but the GetControlHandle command still can't get the control. The command I am using is:

$hCtl = ControlGetHandle($hDlg, "", "[CLASSNN:SysTabControl32]") having obtained $hDlg from _API_GetWindow($GW_CHILD).

Do you get it with:
$hCtl = ControlGetHandle($hDlg, "", "[CLASS:SysTabControl32; INSTANCE:1]");Assuming that au3 info tool gave you instance 1, change if you need to.oÝ÷ ØGb´êî²)àrZ,zÚ0«r¢çbu«­¢+ØÀÌØí¡
Ñ°ô
½¹Ñɽ±Ñ!¹± ÀÌØí¡±°ÅÕ½ÐìÅÕ½Ðì°ÅÕ½Ðím
1MM98éMåÍQ
½¹Ñɽ°ÌÈÅtÅÕ½Ðì¤
Note the 1 after 32. Edited by SmOke_N

[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Do you get it with:

$hCtl = ControlGetHandle($hDlg, "", "[CLASS:SysTabControl32; INSTANCE:1]");Assuming that au3 info tool gave you instance 1, change if you need to.oÝ÷ ØGb´êî²)àrZ,zÚ0«r¢çbu«­¢+ØÀÌØí¡
Ñ°ô
½¹Ñɽ±Ñ!¹± ÀÌØí¡±°ÅÕ½ÐìÅÕ½Ðì°ÅÕ½Ðím
1MM98éMåÍQ
½¹Ñɽ°ÌÈÅtÅÕ½Ðì¤
Note the 1 after 32.
I thought I had tried the first form you give as well as what I wrote, but as it now works using that I guess that I may not have done!. Thanks.

Share this post


Link to post
Share on other sites

I have come up with an additional problem around testing whether the MDI window is really active. My current code simply loops until the window is detected in the window list. However, although this gets the handle the window doesn't necessarily seem to be truly active. On some, where it is populating a spreadsheet control, if I immediately try to access the controls on the returned window, I get controls elsewhere in the program. However, if I run the script again, with the MDI window already open, everything is hunky dory.

If I add a Sleep(1000) command after my call to MDIWinGetHandle then everything works fine. However Sleep(500) seems to be too short so I would really like to find a way to detect if the window is really active.

Thanks

Sam

; Gets a MDI window handle given the handle to the main window

; This is required for FracPro because some of the MDI windows

; aren't detected by AutoIt

Func MDIWinGetHandle($hMainWnd, $title)

Dim $pid = WinGetProcess($hMainWnd)

Dim $winArray = WinList()

Dim $hWnd = ""

For $i = 1 to $winArray[0][0]

local $p = WinGetProcess($winArray[$i][1])

If StringInStr($winArray[$i][0], $title) <> 0 AND $winArray[$i][1] <> "" Then

if $pid = WinGetProcess($winArray[$i][1]) Then

$hWnd = $winArray[$i][1]

ExitLoop

EndIf

EndIf

Next

return $hWnd

EndFunc

; loops until a MDI window is detected

; note there is no timeout

Func MDIWinWaitActive($hMainWnd, $title)

Local $hWnd = ""

Do

$hWnd = MDIWinGetHandle($hMainWnd, $title)

Until $hWnd <> ""

return $hWnd

EndFunc

Share this post


Link to post
Share on other sites

"; This is required for FracPro because some of the MDI windows

; aren't detected by AutoIt"

Try this:

Opt("WinSearchChildren", 1) ;0=no, 1=search children also

"I would really like to find a way to detect if the window is really active."

Try this:

If WinActive($hwnd) then...


[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

"; This is required for FracPro because some of the MDI windows

; aren't detected by AutoIt"

Try this:

Opt("WinSearchChildren", 1) ;0=no, 1=search children also

"I would really like to find a way to detect if the window is really active."

Try this:

If WinActive($hwnd) then...

I've been using both of those - and it doesn't help. WinActive never sees the MDI window as being active - maybe it isn't truly active asa I can't find it as being active using the API calls either.

EDITED TO ADMIT STUPIDITY

Turns out that there was another window (actually an entry in a navigation tree) that had the same name as the MDI window I was looking for. So, some of the time, searching WinList based upon the pid returned that handle instead of the one I wanted. I've recoded the methods using GetWindow to search children based upon class and name and this has solved the immediate problem.

Thanks to everyone who made suggestions.

Sam

Edited by AmISam

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0