Jump to content
Sign in to follow this  
PhilHibbs

AttachConsole and CreateFile DLL calls

Recommended Posts

PhilHibbs

I'm trying to convert this (scroll down to n-l-i-d's post) to AutoIt.

This is my not-working AutoIt code:

#include <WinAPI.au3>

$pCmd = Run( "cmd.exe" )
$hCmd = _CmdGetWindow( $pCmd )
$hCon = _CmdAttachConsole( $pCmd )
msgbox( 0, "cmd", "Window = "& $hCmd & ", console = "& $hCon & ", error = " & @error )

Func _CmdGetWindow( $pCmd )
    Local $WinList, $i
    While True
        $WinList = WinList()
        For $i = 1 to $WinList[0][0]
            If $WinList[$i][0] <> "" And WinGetProcess( $WinList[$i][1] ) = $pCmd Then
                Return $WinList[$i][1]
            EndIf
        Next
    WEnd
EndFunc   ;==>_CmdGetWindow

Func _CmdAttachConsole( $pCmd )
    Local $hConsole
    DllCall( "Kernel32.dll", "int", "AttachConsole", "int", $pCmd )
    If @error Then Return SetError(1, 0, -1)
    $hConsole = DllCall( "Kernel32.dll", "hwnd", "CreateFile","str","CONOUT$", "int", 0xC0000000 _
                       , "int", 7, "int", 0, "int", 3, "int", 0, "int", 0 )
    If $hConsole = -1 Then Return SetError( 2, 0, -1 )
    Return $hConsole
EndFunc   ;==>_CmdAttachConsole

I'm getting nothing in the $hCon handle. The root of the problem is I don't really understand what the AttachConsole and CreateFile DLL calls do, or what the syntax should be to call them. For instance, what is that "CONOUT$" in the CreateFile call?

*Update*: Just found Valik's Screen_Scrape.au3, I should be able to use that as a starting point instead of the <cough>AutoHotKey script.

Edited by PhilHibbs

Share this post


Link to post
Share on other sites
PhilHibbs

OK I've had a go at cannibalising Screen_Scrape.au3. The original script won't compile since WinAPI.au3 no longer has a _WinAPI_MakeDWord function, and also I don't have 7Zip so I can't use it anyway. Here's my full script, which returns "0" instead of the screen contents.

#include <WinAPI.au3>
#include "VarDump.au3"

Global Const $STD_INPUT_HANDLE = -10
Global Const $STD_OUTPUT_HANDLE = -11
Global Const $STD_ERROR_HANDLE = -12
Global Const $_CONSOLE_SCREEN_BUFFER_INFO = "short dwSizeX; short dwSizeY;" & _
    "short dwCursorPositionX; short dwCursorPositionY; short wAttributes;" & _
    "short Left; short Top; short Right; short Bottom; short dwMaximumWindowSizeX; short dwMaximumWindowSizeY"
Global Const $_COORD = "short X; short Y"
Global Const $_CHAR_INFO = "wchar UnicodeChar; short Attributes"
Global Const $_SMALL_RECT = "short Left; short Top; short Right; short Bottom"


$pCmd = Run( "cmd.exe" )
$hCmd = _CmdGetWindow( $pCmd )
$hCon = _CmdAttachConsole( $pCmd )
$cmdtext = _CmdGetText( $hCmd, $hCon )
MsgBox( 0, "text", $cmdtext )

Func _CmdGetWindow( $pCmd )
    Local $WinList, $i
    While True
        $WinList = WinList()
        For $i = 1 to $WinList[0][0]
            If $WinList[$i][0] <> "" And WinGetProcess( $WinList[$i][1] ) = $pCmd Then
                Return $WinList[$i][1]
            EndIf
        Next
    WEnd
EndFunc   ;==>_CmdGetWindow

Func _CmdAttachConsole( $pCmd )
    Local $aRet = DllCall("kernel32.dll", "int", "AttachConsole", "dword", $pCmd)
    If @error Then Return SetError(@error, @extended, False)
    ; Return the handle on success.
    Return _CmdGetStdHandle($STD_OUTPUT_HANDLE) ; STDOUT Handle
EndFunc ; _CmdAttachConsole()

Func _CmdGetStdHandle($nHandle)
    Local $aRet = DllCall("kernel32.dll", "hwnd", "GetStdHandle", "dword", $nHandle)
    If @error Then Return SetError(@error, @extended, $INVALID_HANDLE_VALUE)
    Return $aRet[0]
EndFunc ; _GetStdHandle()

Func _CmdGetText( $hWin, $hConsole )
    Local $bScrInfo = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure
    ; Try to get the screen buffer information.
    If _GetConsoleScreenBufferInfo($hConsole, $bScrInfo) Then
        ; Set up the coordinate structures.
        Local $coordBufferSize = _WinAPI_MakeDWord(4, 1)
        Local $coordBufferCoord = _WinAPI_MakeDWord(0, 0)
        Local $bRect = DllStructCreate($_SMALL_RECT)

        ; Load the SMALL_RECT with the projected text position.
        DllStructSetData($bRect, "Left", DllStructGetData($bScrInfo, "Left"))
        DllStructSetData($bRect, "Top", DllStructGetData($bScrInfo, "Top"))
        DllStructSetData($bRect, "Right", DllStructGetData($bScrInfo, "Right"))
        DllStructSetData($bRect, "Bottom", DllStructGetData($bScrInfo, "Bottom"))

        Local $iWidth = DllStructGetData( $bRect, "Right") - DllStructGetData( $bRect, "Left") + 1
        Local $iHeight = DllStructGetData( $bRect, "Bottom") - DllStructGetData( $bRect, "Top") + 1

        Local $bScrContent = DllStructCreate("dword[" & ($iWidth * $iHeight) & "]")

        ; Read the console output.
        ; We lie about the types for the COORD structures.  Since they are the size of an int we expect a packed
        ; int.  Otherwise we may crash or just pass garbage.
        Local $aRet = DllCall("kernel32.dll", "int", "ReadConsoleOutputW", _
                              "ptr", $hConsole, _
                              "ptr", _CmdSafeGetPtr($bScrContent), _
                              "int", $coordBufferSize, _
                              "int", $coordBufferCoord, _
                              "ptr", _CmdSafeGetPtr($bRect) )
        If @error Then SetError(@error, @extended, False)
        If $aRet[0] Then
            ; This variable holds the output string.
            Local $sScreen = ""

            ; We iterate over 3 characters because that's all we read.
            For $i = 0 To $iHeight - 1
                Local $sLine = ""
                For $j = 0 To $iWidth - 1
                    ; We offset the buffer each iteration by 4 bytes because that is the size of the CHAR_INFO
                    ; structure.  We do this so we can read each individual character.
                    Local $pCharInfo = DllStructCreate($_CHAR_INFO, DllStructGetPtr($bScrContent) + ($i * 4))

                    ; Append the character.
                    $sLine &= DllStructGetData($pCharInfo, "UnicodeChar")
                Next
                $sScreen &= StringStripWS( $sLine, 2 ) & @CRLF
            Next
            $sScreen = StringStripWS( $sScreen, 2 )
        EndIf
    EndIf
EndFunc   ;==>_CmdGetText

Func _GetConsoleScreenBufferInfo($hConsoleOutput, $pConsoleScreenBufferInfo)
    Local $aRet = DllCall("kernel32.dll", "int", "GetConsoleScreenBufferInfo", "hwnd", $hConsoleOutput, _
        "ptr", _CmdSafeGetPtr($pConsoleScreenBufferInfo))
    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc ; _GetConsoleScreenBufferInfo()

Func _CmdSafeGetPtr(Const ByRef $ptr)
    Local $_ptr = DllStructGetPtr($ptr)
    If @error Then $_ptr = $ptr
    Return $_ptr
EndFunc ; _SafeGetPtr()

Func _WinAPI_MakeDWord($LoWORD, $HiWORD)
    Local $tDWord = DllStructCreate("uint34")
    Local $tWords = DllStructCreate("word;word", DllStructGetPtr($tDWord))
    DllStructSetData($tWords, 1, $LoWORD)
    DllStructSetData($tWords, 2, $HiWORD)
    Return DllStructGetData($tDWord, 1)
EndFunc   ;==>_WinAPI_MakeQWord

It's failing in the _ReadConsoleOutput call, the ReadConsoleOutputW API returns 0 as the first array element, but it looks like Screen_Scrape.au3 does the same for me. Any ideas?

Full output of the ReadConsoleOutputW call:

[0] => Integer(0)

[1] => Pointer(0x00000007)

[2] => Pointer(0x015695C0)

[3] => Integer(0)

[4] => Integer(0)

[5] => Pointer(0x0156A6E8)

p.s. Yes I am compiling it.

*Update:* I've installed 7Zip and tried ScreenScrape.au3 again and it isn't picking up the %, the progress bar doesn't appear until it's finished when it jumps to 100%.

Edited by PhilHibbs

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  

×