Jump to content

Checking boxes in SysTreeView32 not working as expected


 Share

Recommended Posts

Let me preface this with the fact that I am completely new to AutoIt, and I'm sure my methods here are very naive.

I'm trying to automate the use of the GUI of Autodesk's uninstall tool executable (which has no commandline support). The GUI looks like this:

image.png.5d481d303c7da3507a85e6e23a7717e8.png image.thumb.png.fc092cf9b31922beef5e047b59fcac8b.png

I'm trying something very simple, running the exe, grabbing the window handle, focusing it, and sending "Down" and "Space" keystrokes to check all the boxes. I haven't worked out all the logic yet, so for now I'm just sending a static number of keystrokes, and haven't even gotten to clicking the "Uninstall" button. Here is my code so far:

#RequireAdmin

Run("C:\Program Files (x86)\Common Files\Autodesk Shared\Uninstall Tool\R1\UninstallTool.exe")
Local $handle = WinWait("[CLASS:#32770]", "", 1)
ControlFocus("Autodesk Uninstall Tool", "", "SysTreeView321")

Check()
Check()
Check()
Check()
Check()
Check()
Check()
Check()
Check()

Func Check()
    Delay()
    Send("{Down}")
    Send("{Space}")
EndFunc

Func Delay()
    Sleep(500)
EndFunc

It works... sort of. The boxes get checked, but the exe doesn't seem to realize that the boxes are checked. It doesn't check child boxes when parent boxes are checked (a behavior that happens when checking boxes manually with a mouse), and the "Uninstall" button stays grayed out (it normally becomes available to click once any box is checked).

Again, I'm sure I'm butchering the way this is supposed to work, so any insight and direction are greatly appreciated.

Thanks.

Link to comment
Share on other sites

A SysTreeView is accessible thru GUI TreeView UDF, which will give you more control over the object.  Sending keys like you do is probably the worst approach to create a robust script.  If you doing it for yourself, well good luck.  If you are doing it for you corporation, forget about it.  Now I understand you need some help, but it is going very hard for us to suggest specific code since we dont have access to your application.

Link to comment
Share on other sites

 

28 minutes ago, Nine said:

... it is going very hard for us to suggest specific code since we dont have access to your application.

Yes, it is :( !

1 hour ago, mmseng said:

... Autodesk's uninstall tool executable (which has no commandline support)

You might want to take a look at the following links. Maybe they contain a solution that makes the automation of the uninstall tool superfluous.

How-to-Uninstall-Autodesk-Products-Silently-Using-Batch-Scripts

uninstall-multiple-autodesk-software

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

Try this:

#Include <String.au3>
#Include <GuiTreeView.au3>

Run("C:\Program Files (x86)\Common Files\Autodesk Shared\Uninstall Tool\R1\UninstallTool.exe")
Local $handle = WinWait("[CLASS:#32770]", "", 1)
ControlFocus("Autodesk Uninstall Tool", "", "SysTreeView321")

$hTree = ControlGetHandle("Autodesk Uninstall Tool", "", "SysTreeView321")

$hItem = _GUICtrlTreeView_GetFirstItem($hTree)
While $hItem <> 0
    _GUICtrlTreeView_SetChecked($hTree, $hItem)
    $hItem = _GUICtrlTreeView_GetNextSibling($hTree, $hItem)
WEnd

 

Link to comment
Share on other sites

1 hour ago, Musashi said:

You might want to take a look at the following links. Maybe they contain a solution that makes the automation of the uninstall tool superfluous.

@Musashi Thanks, but trust me, I wouldn't be here at all if I hadn't exhausted those options. I've crawled their spiderweb of articles half a dozen times. Outside of this manual uninstall tool, Autodesk only supports uninstalling their apps through MECM (which we are already doing), but their officially supported methods do not clean up all the garbage their apps leave behind (and this actually breaks some of the apps we're NOT uninstalling). For that matter the uninstall tool doesn't clean up fully either, but it comes much closer. I'm certainly not asking anyone here to try this, but I will just say in my defense that the Autodesk uninstall tool comes with every version of every Autodesk application ever installed anywhere. It's not exactly a niche application, and the desire to automate it is not unique to me and my use case.

@Nine I appreciate the lead. I didn't find (or understand) anything directly useful in the examples for _GUITreeViewEx, but it at least gave me somewhere to start. I've done a lot of playing around with various functions now, but am still banging my head.

Problem #1: there appears to be no way to reference individual list items in a SysTreeView32 object. Similar to the issues discussed in this thread, AU3Info simply doesn't recognize any item more granular than the TreeView itself. I've tried both the x86 and x64 versions. So that apparently precludes me from using things like _GUICtrlListView_ClickItem and _GUICtrlListView_GetItemPosition, because they both rely on references to individual list items.

Problem #2: I've tried several variations on the theme of ControlTreeView. As noted in the OP, these do not actually cause the app to register that a "check" or "click" is happening. Same problem with ControlClick. I've confirmed this is a default behavior of the app. If I simply open the app and manually use the keyboard down arrow and spacebar to check the boxes, the app will never recognize that anything has been checked until I physically click the mouse on a checkbox. What's worse, even once I do that, the other keyboard-checked checkboxes are still not recognized as being checked, because unchecking the mouse-checked checkbox will cause the "Uninstall" button to gray itself out again. So that bodes terribly. I'm amazed at how garbage this app is, and I've been in IT for 13 years so that's saying something.

Edit: @Zedna Thanks for your suggestion. You posted as I was typing and I'll look into it. In the meantime...

I'm still up for trying new things though, so I'll post what I currently have (which demonstrates some of the things I've tried). Again, any input or suggestions are appreciated.

#RequireAdmin

#include <GuiListView.au3>

Run("C:\Program Files (x86)\Common Files\Autodesk Shared\Uninstall Tool\R1\UninstallTool.exe")
Sleep(1000)
$hWnd = WinGetHandle("Autodesk Uninstall Tool")
ControlFocus($hWnd, "", "SysTreeView321")

$hTreeView = ControlGetHandle($hWnd, "", "[CLASS:SysTreeView32; INSTANCE:1]")

$count = ControlTreeView($hWnd, "", $hTreeView, "GetItemCount")
ConsoleWrite("There are " & $count & " (parent) checkboxes." & @CRLF)

; Expando boxes are 11 pixels in
$xExpando = 11

; Parent checkboxes are 30 pixels in
$xCheckbox = 30

; First expando/checkbox is 11 pixels down
$y = 11

; Each line is very close to, if not exactly 17 pixels
$spacing = 17

For $i = 0 To ($count - 1) Step 1
    $num = "#" & $i

    ; Get this checkbox text
    $text = ControlTreeView($hWnd, "", $hTreeView, "GetText", $num)
    ConsoleWrite("Checkbox #" & $i & ": " & $text & @CRLF)

    ; Trying to directly check the box
    ; https://www.autoitscript.com/autoit3/docs/functions/ControlTreeView.htm
    ; For some reason this uninstall tool only seems to respond to actual mouse clicks... wow.
    ;ControlTreeView($hWnd, "", $hTreeView, "Check", $num)

    ; Can't seem to get item IDs of individual list/tree items from a SysTreeView32
    ; https://www.autoitscript.com/forum/topic/177397-accessing-individual-elements-within-a-systreeview32-control/?tab=comments#comment-1272879
    ; https://www.autoitscript.com/forum/topic/187587-clicking-syslistview32-check-box-problem/
    ; https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlListView_ClickItem.htm
    ;_GUICtrlListView_ClickItem($hWnd, $i, "left", False, 1)

    ; I was hoping this would give me a controlID for an individual item, so I could use it with
    ; the below functions, but it just returns the 0-based index again
    ;ControlTreeView($hWnd, "", $hTreeView, "Select", $num)
    ;$ref = ControlTreeView($hWnd, "", $hTreeView, "GetSelected")
    ;ConsoleWrite("Checkbox #" & $i & ": " & $ref & @CRLF)
    ;$refIndex = ControlTreeView($hWnd, "", $hTreeView, "GetSelected", 1)
    ;ConsoleWrite("Checkbox #" & $i & ": " & $refIndex & @CRLF)

    ; Not even sure how this works, but probably also depends on individual item IDs
    ; https://www.autoitscript.com/forum/topic/133367-how-click-on-an-item-of-a-listview/
    ; https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlListView_GetItemPosition.htm
    ;$pos = _GUICtrlListView_GetItemPosition($hTreeView, 0)
    ;ConsoleWrite("Checkbox #" & $i & ": " & $pos[0] & "," & $pos[1] & @CRLF)

    ; This uses coords that are relative to the to the global screen (i.e. not helpful)
    ; https://www.autoitscript.com/autoit3/docs/functions/MouseClick.htm
    ;MouseClick("primary", 30, 11, 1)

    ; This uses coords that are relative to the TreeView item
    ; https://www.autoitscript.com/autoit3/docs/functions/ControlClick.htm
    ; Still doesn't trigger the app to respond properly
    ControlClick($hWnd, "", $hTreeView, "primary", 1, $xExpando, $y)
    Delay()
    ControlClick($hWnd, "", $hTreeView, "primary", 1, $xCheckbox, $y)
    $y = $y + $spacing

    ; Things to try/look into
    ; Manpulating checkbox state images?
    ;     https://www.autoitscript.com/forum/topic/198343-solved-controlling-a-syslistview32-instance/?tab=comments#comment-1422916
    ;     https://www.autoitscript.com/forum/topic/86470-checking-the-state-of-a-check-box/
    ;     https://www.autoitscript.com/forum/topic/179394-checkboxes-overlay-icons-and-state-images-in-listviews/
    ; https://www.autoitscript.com/forum/topic/158996-get-text-from-systreeview32/
    ; https://www.autoitscript.com/wiki/ControlCommand
    ; https://www.autoitscript.com/forum/topic/166594-guitreeviewex-new-release-11-jan-15/

    Delay()
Next

Func Delay()
    Sleep(250)
EndFunc

 

Thanks and regards.

Link to comment
Share on other sites

@Zedna Your code does work, but it unfortunately has the same problem as several of my other attempts, where the checkboxes are visually checked, but not recognized as being checked by the application. However your code also let me finally wrap my head around the differences between handles for the window vs. treeview vs. specific item, and also made me realize that I've been mix/matching _GUICtrlListView and _GUICtrlTreeView calls. So some of my testing has been invalid.

While your _GUICtrlTreeView_SetChecked call still isn't working for this particular app, I've had some success using _GUICtrlTreeView_ClickItem. _GUICtrlTreeView_ClickItem unfortunately only clicks on the very left edge of the text of each row, which does nothing but select the text. However, from there I can grab the mouse position and do some dirty pixel math to move/click just far enough left check the checkbox. This action is actually recognized by the app, and checks each parent checkbox's child boxes and un-grays the "Uninstall" button, as expected. I'm wondering if there's a better way though.

My working code is below. Unfortunately I'm guessing that using the mouse like this probably limits the portability of this solution (even more than it already is by virtue of needing to interact with the GUI), due to potential differences in endpoint screen resolutions. But it's a step in the right direction. It's just a shame that the app only properly recognizes mouse clicks.

#RequireAdmin

#Include <GuiTreeView.au3>

; Run app
Run("C:\Program Files (x86)\Common Files\Autodesk Shared\Uninstall Tool\R1\UninstallTool.exe")

; Get handles for window and treeview
Sleep(1000)
$hWnd = WinGetHandle("Autodesk Uninstall Tool")
$hTree = ControlGetHandle($hWnd, "", "SysTreeView321")
;$hTree = ControlGetHandle($hWnd, "", "[CLASS:SysTreeView32; INSTANCE:1]")

; Make sure window is focused
ControlFocus($hWnd, "", $hTree)

;$count = ControlTreeView($hWnd, "", $hTree, "GetItemCount")
;ConsoleWrite("There are " & $count & " (parent) checkboxes." & @CRLF)

; Thanks to Zedna
; Get first item
$hItem = _GUICtrlTreeView_GetFirstItem($hTree)
While $hItem <> 0
    ;ConsoleWrite("Item: " & $hItem & @CRLF)

    ; This unfortunately is still not properly recognized by the app
    ;_GUICtrlTreeView_SetChecked($hTree, $hItem)

    ; Click on this item instead
    _GUICtrlTreeView_ClickItem($hTree, $hItem, "primary", True, 1)

    ; Grab mouse position
    $itemX = MouseGetPos(0)
    $itemY = MouseGetPos(1)
    ;ConsoleWrite($itemX  & "," & $itemY & @CRLF)

    ; Adjust mouse position
    $checkX = $itemX - 27
    $checkY = $itemY + 8

    ; Click at adjusted position
    Delay()
    MouseClick("primary", $checkX, $checkY, 1, 0)

    ; Move to next item
    $hItem = _GUICtrlTreeView_GetNextSibling($hTree, $hItem)
    Delay()
WEnd

; TODO: Click on "Uninstall" button

Func Delay()
    ;Sleep(250)
EndFunc

To be continued...

Link to comment
Share on other sites

here an idea, replace with :

$hItem = _GUICtrlTreeView_GetFirstItem($hTree)
Local $aPos
While $hItem <> 0
  ; get the display rectangle of the item
  $aPos = _GUICtrlTreeView_DisplayRect($hTree, $hItem, False) ; you may want to try True also, to see if that is helping
  _ArrayDisplay ($aPos)
  ; based on the array calculate more precisely the coordinates
  $hItem = _GUICtrlTreeView_GetNextSibling($hTree, $hItem)
  Sleep (250)
WEnd

or maybe this :

$hItem = _GUICtrlTreeView_GetFirstItem($hTree)
Local $aPos
While $hItem <> 0
  ; get the display rectangle of the item
  _GUICtrlTreeView_SelectItem ($hTree, $hItem, $TVGN_CARET)
  ControlSend ($hWnd, "", $hTree, "{SPACE}")

  $hItem = _GUICtrlTreeView_GetNextSibling($hTree, $hItem)
  Sleep (250)
WEnd

Have tried ControlTreeView with "check", "item"  ?

 

Edited by Nine
Link to comment
Share on other sites

Thank you both for the additional suggestions. I'll give them a try.

Yes, I have tried this:

ControlTreeView($hWnd, "", $hTreeView, "Check", $num)

(it was one of the first things I tried which only visually checked the boxes)

However I might want to try it again in combination with _GUICtrlTreeView_SelectItem, similar to your second suggestion. Perhaps checking the boxes might work properly if they are selected first.

Cheers.

Link to comment
Share on other sites

I haven't looked into @Zedna's link yet, but I've ruled out @Nine's suggestions (for now).

Firstly,  _GUICtrlTreeView_SelectItem did not help anything. Following it with ControlSend($hWnd, "", $hTree, "{SPACE}"), or ControlTreeView($hWnd, "", $hTree, "Check", $num), or _GUICtrlTreeView_SetChecked($hTree, $hItem) all had the same result, where the checkboxes were only checked visually. So that's a bummer.

Also, unfortunately it seems _GUICtrlTreeView_DisplayRect only returns the position of items RELATIVE to the item's parent tree, so this is no more accurate than using _GUICtrlTreeView_ClickItem + MouseGetPos + some dirty math + MouseClick. The only way I can see this methodology could be more accurate is if there were some way to return the ABSOLUTE coordinates of the actual checkbox. Otherwise, I'm always going to be guessing at how many pixels big the checkbox is and doing dirty math to find the rough center of it to click. The closer I can get absolute coordinates before making that guess, the more accurate this will be, and currently the closest I can get is with _GUICtrlTreeView_ClickItem + MouseGetPos.

Next I'll look into the  Winspector/WM_COMMAND stuff.

Thanks again for the suggestions.

Edited by mmseng
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...