메뉴 여닫기
개인 메뉴 토글
로그인하지 않음
만약 지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.

Carlet 읽기 -uiawrappers이용

데브카페

Carlet 읽기 -uiawrappers이용


#include <Misc.au3>

HotKeySet("^+r", "ReadCurrentCaretControl")
HotKeySet("^+x", "_Exit")

ConsoleWrite("텍스트 입력 위치에서 Ctrl+Shift+R을 눌러주세요." & @CRLF)
ConsoleWrite("종료: Ctrl+Shift+X" & @CRLF)

While 1
    Sleep(100)
WEnd

Func _Exit()
    Exit
EndFunc

Func ReadCurrentCaretControl()
    Local $aInfo = _GetCurrentCaretInfo()

    If @error Or Not IsArray($aInfo) Then
        ConsoleWrite("[오류] 현재 포커스/캐럿 정보를 가져오지 못했습니다." & @CRLF)
        Return
    EndIf

    Local $hActive = $aInfo[0]
    Local $hFocus  = $aInfo[1]
    Local $hCaret  = $aInfo[2]

    ; 캐럿 HWND가 있으면 우선 사용하고, 없으면 포커스 HWND 사용
    Local $hTarget = $hCaret
    If $hTarget = 0 Then $hTarget = $hFocus
    If $hTarget = 0 Then $hTarget = $hActive

    If $hTarget = 0 Then
        ConsoleWrite("[오류] 대상 컨트롤 핸들이 없습니다." & @CRLF)
        Return
    EndIf

    ; 대상이 속한 최상위 프로그램 창
    Local $hRoot = _GetRootWindow($hTarget)
    If $hRoot = 0 Then $hRoot = $hActive

    Local $iPID = _GetWindowPID($hTarget)
    Local $sTitle = WinGetTitle($hRoot)
    Local $sClass = _GetWindowClassName($hTarget)

    ConsoleWrite(@CRLF)
    ConsoleWrite("========================================" & @CRLF)
    ConsoleWrite("활성 창 HWND   : " & $hActive & @CRLF)
    ConsoleWrite("포커스 HWND    : " & $hFocus & @CRLF)
    ConsoleWrite("캐럿 HWND      : " & $hCaret & @CRLF)
    ConsoleWrite("읽기 대상 HWND : " & $hTarget & @CRLF)
    ConsoleWrite("최상위 HWND    : " & $hRoot & @CRLF)
    ConsoleWrite("PID            : " & $iPID & @CRLF)
    ConsoleWrite("창 제목        : " & $sTitle & @CRLF)
    ConsoleWrite("컨트롤 클래스  : " & $sClass & @CRLF)
    ConsoleWrite("캐럿 좌표      : X=" & $aInfo[3] & ", Y=" & $aInfo[4] & @CRLF)

    ; 표준 Edit/RichEdit 컨트롤의 선택 텍스트 확인
    Local $sSelected = ""

    If $hRoot <> 0 Then
        $sSelected = ControlCommand( _
                $hRoot, _
                "", _
                $hTarget, _
                "GetSelected", _
                "")
    EndIf

    If $sSelected <> "" Then
        ConsoleWrite("=== 선택된 텍스트 ===" & @CRLF)
        ConsoleWrite($sSelected & @CRLF)

        ToolTip( _
                "선택된 텍스트: " & $sSelected, _
                MouseGetPos(0), _
                MouseGetPos(1) - 60)

        Sleep(2000)
        ToolTip("")
        Return
    EndIf

    ; 선택 영역이 없거나 GetSelected를 지원하지 않는 경우 전체 텍스트
    Local $sText = _GetWindowTextSafe($hTarget)

    ; 대상 자식 컨트롤에서 실패하면 AutoIt ControlGetText도 시도
    If $sText = "" And $hRoot <> 0 Then
        $sText = ControlGetText($hRoot, "", $hTarget)
    EndIf

    If $sText <> "" Then
        ConsoleWrite("=== 컨트롤 전체 텍스트 ===" & @CRLF)
        ConsoleWrite(StringLeft($sText, 1000) & @CRLF)

        Local $sPreview = StringLeft($sText, 200)
        If StringLen($sText) > 200 Then $sPreview &= "..."

        ToolTip( _
                "현재 컨트롤 텍스트:" & @CRLF & $sPreview, _
                MouseGetPos(0), _
                MouseGetPos(1) - 60)

        Sleep(2000)
        ToolTip("")
    Else
        ConsoleWrite("[경고] 핸들은 확인했지만 텍스트를 읽을 수 없습니다." & @CRLF)
        ConsoleWrite("브라우저, Electron, Java, UWP 등의 컨트롤은 UIA가 필요할 수 있습니다." & @CRLF)

        ToolTip( _
                "대상 HWND: " & $hTarget & @CRLF & _
                "Class: " & $sClass & @CRLF & _
                "텍스트 읽기 실패", _
                MouseGetPos(0), _
                MouseGetPos(1) - 60)

        Sleep(2000)
        ToolTip("")
    EndIf
EndFunc

; ------------------------------------------------------------
; 현재 활성 스레드의 활성 창, 포커스 창, 캐럿 창과 좌표를 가져온다.
;
; 반환 배열:
; [0] 활성 창 HWND
; [1] 포커스 HWND
; [2] 캐럿 HWND
; [3] 캐럿 화면 X
; [4] 캐럿 화면 Y
; ------------------------------------------------------------
Func _GetCurrentCaretInfo()
    Local $tGUI = DllStructCreate( _
            "dword cbSize;" & _
            "dword flags;" & _
            "hwnd hwndActive;" & _
            "hwnd hwndFocus;" & _
            "hwnd hwndCapture;" & _
            "hwnd hwndMenuOwner;" & _
            "hwnd hwndMoveSize;" & _
            "hwnd hwndCaret;" & _
            "long rcLeft;" & _
            "long rcTop;" & _
            "long rcRight;" & _
            "long rcBottom")

    DllStructSetData($tGUI, "cbSize", DllStructGetSize($tGUI))

    ; dwThreadId=0이면 현재 전경 스레드의 GUI 정보를 얻는다.
    Local $aCall = DllCall( _
            "user32.dll", _
            "bool", "GetGUIThreadInfo", _
            "dword", 0, _
            "struct*", $tGUI)

    If @error Or Not IsArray($aCall) Or Not $aCall[0] Then
        Return SetError(1, 0, 0)
    EndIf

    Local $hActive = DllStructGetData($tGUI, "hwndActive")
    Local $hFocus  = DllStructGetData($tGUI, "hwndFocus")
    Local $hCaret  = DllStructGetData($tGUI, "hwndCaret")

    Local $iX = DllStructGetData($tGUI, "rcLeft")
    Local $iY = DllStructGetData($tGUI, "rcTop")

    ; 캐럿 좌표는 hwndCaret 기준의 클라이언트 좌표이므로 화면 좌표로 변환
    If $hCaret <> 0 Then
        Local $tPoint = DllStructCreate("long X;long Y")
        DllStructSetData($tPoint, "X", $iX)
        DllStructSetData($tPoint, "Y", $iY)

        Local $aPoint = DllCall( _
                "user32.dll", _
                "bool", "ClientToScreen", _
                "hwnd", $hCaret, _
                "struct*", $tPoint)

        If Not @error And IsArray($aPoint) And $aPoint[0] Then
            $iX = DllStructGetData($tPoint, "X")
            $iY = DllStructGetData($tPoint, "Y")
        EndIf
    EndIf

    Local $aResult[5]
    $aResult[0] = $hActive
    $aResult[1] = $hFocus
    $aResult[2] = $hCaret
    $aResult[3] = $iX
    $aResult[4] = $iY

    Return $aResult
EndFunc

; 대상 HWND가 속한 최상위 창을 반환
Func _GetRootWindow($hWnd)
    If $hWnd = 0 Then Return 0

    ; GA_ROOT = 2
    Local $aCall = DllCall( _
            "user32.dll", _
            "hwnd", "GetAncestor", _
            "hwnd", $hWnd, _
            "uint", 2)

    If @error Or Not IsArray($aCall) Then Return 0
    Return $aCall[0]
EndFunc

; HWND의 프로세스 ID 반환
Func _GetWindowPID($hWnd)
    If $hWnd = 0 Then Return 0

    Local $aCall = DllCall( _
            "user32.dll", _
            "dword", "GetWindowThreadProcessId", _
            "hwnd", $hWnd, _
            "dword*", 0)

    If @error Or Not IsArray($aCall) Then Return 0
    Return $aCall[2]
EndFunc

; HWND의 실제 클래스명 반환
Func _GetWindowClassName($hWnd)
    If $hWnd = 0 Then Return ""

    Local $tBuffer = DllStructCreate("wchar[512]")

    Local $aCall = DllCall( _
            "user32.dll", _
            "int", "GetClassNameW", _
            "hwnd", $hWnd, _
            "struct*", $tBuffer, _
            "int", 512)

    If @error Or Not IsArray($aCall) Or $aCall[0] = 0 Then Return ""
    Return DllStructGetData($tBuffer, 1)
EndFunc

; WM_GETTEXT를 SendMessageTimeout으로 호출한다.
; 응답하지 않는 프로그램 때문에 스크립트가 멈추는 것을 방지한다.
Func _GetWindowTextSafe($hWnd)
    If $hWnd = 0 Then Return SetError(1, 0, "")

    Local Const $WM_GETTEXT = 0x000D
    Local Const $WM_GETTEXTLENGTH = 0x000E
    Local Const $SMTO_ABORTIFHUNG = 0x0002

    ; 텍스트 길이 확인
    Local $aLength = DllCall( _
            "user32.dll", _
            "lresult", "SendMessageTimeoutW", _
            "hwnd", $hWnd, _
            "uint", $WM_GETTEXTLENGTH, _
            "wparam", 0, _
            "lparam", 0, _
            "uint", $SMTO_ABORTIFHUNG, _
            "uint", 1000, _
            "ulong_ptr*", 0)

    If @error Or Not IsArray($aLength) Or Not $aLength[0] Then
        Return SetError(2, 0, "")
    EndIf

    ; DllCall 매개변수: 0=반환값,1=hwnd,2=msg,3=wparam,4=lparam,5=flags,6=timeout,7=result
    Local $iLength = $aLength[7]

    If $iLength <= 0 Then Return ""

    ; 과도하게 큰 버퍼 할당 방지
    If $iLength > 1000000 Then $iLength = 1000000

    Local $tBuffer = DllStructCreate("wchar[" & ($iLength + 1) & "]")

    Local $aText = DllCall( _
            "user32.dll", _
            "lresult", "SendMessageTimeoutW", _
            "hwnd", $hWnd, _
            "uint", $WM_GETTEXT, _
            "wparam", $iLength + 1, _
            "lparam", DllStructGetPtr($tBuffer), _
            "uint", $SMTO_ABORTIFHUNG, _
            "uint", 1000, _
            "ulong_ptr*", 0)

    If @error Or Not IsArray($aText) Or Not $aText[0] Then
        Return SetError(3, 0, "")
    EndIf

    Return DllStructGetData($tBuffer, 1)
EndFunc

Comments