Sign in to follow this  
Followers 0
Fur

Listbox Madness

10 posts in this topic

I need my script to peer into the listbox of another window, and loop over the contents to decide which one to select. This seemingly simple task is making me bonkers. Hopefully I'm just missing something stupid!! Heeelllp!

The help pages (if I'm reading them right) say you can use either the hwnd, or the controlid, or controlref for calling these commands, but that doesn't seem to be the case. Also, all these control commands take a second argument called "text" but I can't for the life of me understand what its used for. All of the examples just pass in an empty string.

Example code for window I'm trying to peer into:

#include <GUIConstants.au3>

GUICreate("Select An Object", 300, 300) 
Local $list_box = GUICtrlCreateList("", 30, 10)
Local $close_button = GUICtrlCreateButton("&Close", 70,250, 60)
GUICtrlSetData($list_box, "red|blue|green")
GUISetState(@SW_SHOW)
While 1
   Local $msg = GUIGetMsg()

  Select
    Case $msg = $close_button
      ExitLoop
      
    Case $msg = $GUI_EVENT_CLOSE
      ExitLoop
  EndSelect
   
WEnd

Here's me trying everything possible I can think of. I can get ControlCommand() to work, but it can't loop over the elements. No matter how I try to use ControlListView() it never works..

#include <GuiConstants.au3>

Local $title = "Select An Object"
Local $win_hwnd = WinActivate($title)

Local $focus = ControlGetFocus($title)
Local $list = _GuiCtrlGetFocus($title) 
Local $hwnd = ControlGetHandle($title, "", ControlGetFocus($title))

;MsgBox(0, "", ControlListView($title, "", $focus, "GetItemCount") )
;MsgBox(0, "", ControlListView($title, "", $focus, "GetText", 1, 0) )
;MsgBox(0, "", ControlListView($title, "", $list, "GetItemCount") )
;MsgBox(0, "", ControlListView($title, "", $list, "GetText", 1, 0) )
;MsgBox(0, "", ControlListView($title, "", $hwnd, "GetItemCount") )
;MsgBox(0, "", ControlListView($title, "", $hwnd, "GetText", 1, 0) )


MsgBox(0, "", ControlCommand($title, "", $focus, "GetCurrentSelection") )
;MsgBox(0, "", ControlListView($title, "", $focus, "GetSelected") )
;ControlCommand($title, "", $list, "AddString", "Foopy")
; works ControlCommand($title, "", $focus, "AddString", "Foopy")
ControlCommand($title, "", $focus, "SelectString", "red")
;ControlCommand($title, "", $hwnd, "AddString", "Foopy")

Exit
 
 Func _GuiCtrlGetFocus($GuiRef)
    Local $hwnd = ControlGetHandle($GuiRef, "", ControlGetFocus($GuiRef))
    Local $result = DllCall("user32.dll", "int", "GetDlgCtrlID", "hwnd", $hwnd)
    Return $result[0]
 EndFunc

Share this post


Link to post
Share on other sites



- It appears that ControlGetFocus doesn't return the right value....

- ControlListView is not designed for ListBoxes.

- ControlCommands for ListBoxes are limited; there is no direct command to read all the items in the list.... When ControlCommand was designed, it was assumed you would know what is already in the list....

You can select each item and read the text using the following:

Local $title = "Select An Object"
Local $control = "ListBox1"

$i = 0

While 1
    ControlCommand($title,"", $control, "SetCurrentSelection", $i)
    If @error Then ExitLoop
    $item = ControlCommand($title,"", $control, "GetCurrentSelection")
    MsgBox(4096, $i, $item)
    $i = $i + 1
WEnd

Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!

Share this post


Link to post
Share on other sites

ok, so i'm not as crazy as i thought i was then.

powers that be: is it too late to sneak something to get all the elements out of a listbox? even if its just a pipe delimited list of them all?

what about the mysterious 'text' argument? any clues?

Share this post


Link to post
Share on other sites

what about the mysterious 'text' argument? any clues?

<{POST_SNAPBACK}>

It is used to tell the difference between windows that have the same title.

For example, you might have a program that displays a message box that either has the text "Success" or "Error." If the title/size/etc. are the same, you need can use the text parameter to tell the difference.

$title = "Sample Info Dialog"

WinWait($title)

If WinExists($title, "Success!") Then

; good

ElseIf WinExists($title, "Error: Could not copy files.")

; bad

ElseIf WinExists($title, "Error: Unknown error.")

; really bad

Else

; whatever

EndIf


Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!

Share this post


Link to post
Share on other sites

I made a C function to put the pipe delimited contents into a string that I can grab via a DLLCall. This is using a static memory space, so it would not be thread/process safe. If anyone has any advice on how to have AutoIt allocate a string buffer that could be passed into this, I would appreciate hearing how.

// given the hwnd for a listbox, put the contents into a pipe delimited string
// TODO: NOT thread/process safe
// TODO: NOT checking for buffer overruns
const char *ExtractListContents(HWND hwnd)
{
    static char results[4096];

    *results = '\0';

    long count = SendMessage(hwnd, LB_GETCOUNT, 0, 0);

    for (long i = 0; i < count; ++i)
    {
        char item[256] = "";
        SendMessage(hwnd, LB_GETTEXT, i, (long) item);
        if (i == 0)
            strcpy(results, item);
        else
        {
            strcat(results, "|");
            strcat(results, item);
        }
    }
    return results;
}

Share this post


Link to post
Share on other sites

Just to let you know, you can already SendMessage(hwnd, LB_GETCOUNT, 0, 0) using plain dllcall...


Who else would I be?

Share this post


Link to post
Share on other sites

Yes, but can you call LB_GETTEXT in that same manner? That's the tricky part.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Not tricky at all:

Local $aCount = DllCall("user32.dll", "int", "SendMessage", "hwnd", $hWnd, "int", $LB_GETCOUNT, "int", 0, "int" 0)
Local $sResult = ""
For $i = 0 To $aCount[0]-1
    Local $aTmp = DllCall("user32.dll", "int", "SendMessage", "hwnd", $hWnd, "int", $LB_GETTEXT', "int", $i, "str", "")
    $sResult = $sResult & "|" & $aTmp[4]
Next
$sResult = StringTrimLeft($sResult, 1); Trim a leading pipe

Thats off the top of my head and if its not working, it should be close enough to give you an idea how it should be.

Edit: Fixed mistake.

Edited by Valik

Share this post


Link to post
Share on other sites

How/where is the memory for that last str argument allocated? You're just passing in "" which by itself is not going to be long enough to hold the result. Does AutoIt do some kind of padding behind the scenes? By how much?

Share this post


Link to post
Share on other sites

65535 bytes. And yes, when you tell it that the function expects a "str", then it allocates that buffer.

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