Search code examples
autohotkey

Am I referencing hwnd's incorrectly? Unable to get text out of a simple notepad window using AutoHotkey


When I run this script, I have a notepad window open with "test.txt - Notepad" as the text. The id variable gets properly filled with the hwnd array from the subfunction ControlListHwnd. Then it loops through all of the control items it found for notepad (there are very few).

Script:

!t::  ;To retrieve the formatted text and paste:
{
    DetectHiddenText, On
    DetectHiddenWindows, On

    MsgBox, Starting

    WinGet, id, ControlListHwnd, test.txt - Notepad, , Program Manager
    Loop, Parse, id, `n
    {
         this_id := %A_LoopField%
         ;this_id := id%id_Index%
         ;this_id := id
         ;WinActivate, ahk_id %this_id%
         WinGetClass, this_class, ahk_id %this_id%
         WinGetTitle, this_title, ahk_id %this_id%
         ;MsgBox, 4, , Visiting All Windows`n%A_Index% of %id%`nahk_id %this_id%`nahk_class %this_class%`n%this_title%`n`nContinue?


         ControlHwnd := %A_LoopField%
         ControlGetText, outputText, , ahk_id %ControlHwnd%
         MsgBox, 4, , All Controls`n id - %A_LoopField% `n Control Text - %outputText%`n Class - %this_class% `n Title - %this_title% `n `n Continue?

         IfMsgBox, NO, break
    }

    MsgBox, Finished - %id% - end

    return
}

When it loops through, it should display a messagebox that contains the text, class, and title from the control queried.

Does it look like I am passing the hwnd incorrectly? Or else is there a better way to do this?

In the past I used direct Dll calls to User32\GetWindow, hoping I can do this with AutoHotkey with it's existing functions.


Solution

  • This is a classic mistake of confusing legacy syntax with the new expression syntax.
    These two lines specifically:
    this_id := %A_LoopField%
    ControlHwnd := %A_LoopField%

    In legacy assignment (=) you'd indeed reference a variable by wrapping it in % %, but in an expression (which you what you get when you use :=) you reference variables by just typing it in:

    this_id := A_LoopField
    ControlHwnd := A_LoopField
    

    No %s.

    Misc stuff:
    Hotkey labels do not need to be wrapped in { }s, in case you didn't know.
    And there's no need to set

    DetectHiddenText, On
    DetectHiddenWindows, On 
    

    every time you run your hotkey. You can just set them once at the top of your script.


    Here's your full script using expression syntax.
    Overall, I'd recommend to stop using legacy syntax, it's not 2008 anymore.
    You can get started on learning the difference between legacy and expression syntaxes here

    DetectHiddenText, On
    DetectHiddenWindows, On
    
    !t::
         MsgBox, Starting
    
         ;parameters that are started with a % followed up by a space
         ;are automatically evaluated as expressions
         ;using it to just be able to quate straight text parameters
         ;could be considered overkill, but I'll just convert everything
         ;to expression syntax for the sake of the demonstration
         
         ;also, I'd change "test.txt - Notepad" to "ahk_exe notepad.exe"
         WinGet, id, ControlListHwnd, % "test.txt - Notepad", , % "Program Manager"
         Loop, Parse, id, `n
         {
              this_id := A_LoopField
              WinGetClass, this_class, % "ahk_id " this_id
              WinGetTitle, this_title, % "ahk_id " this_id
              
              ControlHwnd := A_LoopField
              ControlGetText, outputText, , % "ahk_id " ControlHwnd
              MsgBox, 4, , % "All Controls`n id - " A_LoopField "`n Control Text - " outputText "`n Class - " this_class "`n Title - " this_title "`n `n Continue?"
    
              IfMsgBox, No
                   break
         }
         MsgBox, % "Finished - " id " - end"
    return