Jump to content

CMD Pipe demo


Dan_555
 Share

Recommended Posts

Hi, 

this is not my script. I have used the Autoit Examples\GUI\Advanced\_NamedPipes_Server.au3 script and stripped down everything unneeded.

Now it functions like what both Client and Server script did, just in one file:

It captures the command-line output directly, using the pipe, and puts it into its own edit field. 

#include <GuiStatusBar.au3>
#include <GuiEdit.au3>
#include <GuiConstantsEx.au3>
#include <NamedPipes.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

; ===============================================================================================================================
; Description ...: This was the server side of the pipe demo
; Author ........: Paul Campbell (PaulIA)
; Notes .........: CMD-Mod by dan_555
; ===============================================================================================================================

; ===============================================================================================================================
; Global constants
; ===============================================================================================================================

Global Const $BUFSIZE = 1024 * 4
Global Const $PIPE_NAME = "\\.\\pipe\\AutoIt3PipeTest"
Global Const $TIMEOUT = 5000
Global Const $WAIT_TIMEOUT = 250
Global Const $ERROR_IO_PENDING = 997
Global Const $ERROR_PIPE_CONNECTED = 535
Global $locktimer = 0, $lockexit = 0, $inp1Txt
Global $h_PID = 0

Global $closingdelay = 1000, $closecounter = 0, $TimeHandle = TimerInit(), $TimeDiff = TimerDiff($TimeHandle)          ;Used for CloseGuiOnDoubleClick()
Global $formTitle = "Pipe CMD Test"
; ===============================================================================================================================
; Global variables
; ===============================================================================================================================

Global $g_hEvent, $g_idMemo, $g_pOverlap, $g_tOverlap, $g_hPipe, $g_hReadPipe, $g_iState, $g_iToWrite

; ===============================================================================================================================
; Main
; ===============================================================================================================================
GUIRegisterMsg($WM_SIZE, "WM_SIZE")

CreateGUI()
InitPipe()
MsgLoop()

; ===============================================================================================================================
; Creates a GUI
; ===============================================================================================================================
Func CreateGUI()

    Global $hGUI = GUICreate($formTitle, 500, 400, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX, $WS_THICKFRAME))
    Global $Button1 = GUICtrlCreateButton("Go", 2, 1, 37, 29)
    GUICtrlSetTip(-1, "Execute the command from the input box")
    Global $StatusBar1 = _GUICtrlStatusBar_Create($hGUI)
    Global $g_idMemo = GUICtrlCreateEdit("", 0, 31, 499, 349)
    Global $Input1 = GUICtrlCreateInput("", 40, 4, 380, 24)
    GUICtrlSetTip(-1, "Command to execute. Enter to start!" & @CRLF & "Needs user input to accept enter key!")
    Global $Button2 = GUICtrlCreateButton("CLS", 421, 1, 30, 29)
    GUICtrlSetTip(-1, "Clear the output")
    Global $Button3 = GUICtrlCreateButton("STOP", 461, 1, 35, 29)
    GUICtrlSetTip(-1, "Emergency stop, works only if a command is running." & @CRLF & "This will close the running Proccess !!!")
    GUICtrlSetFont($g_idMemo, 9, 400, 0, "Courier New")
    GUISetState()
    GUICtrlSetLimit($g_idMemo, 555555555)
    GuiCtrlSetState ($Button3,$GUI_DISABLE)
EndFunc   ;==>CreateGUI

; ===============================================================================================================================
; This function creates an instance of a named pipe
; ===============================================================================================================================
Func InitPipe()
    ; Create an event object for the instance
    $g_tOverlap = DllStructCreate($tagOVERLAPPED)
    $g_pOverlap = DllStructGetPtr($g_tOverlap)
    $g_hEvent = _WinAPI_CreateEvent()
    If $g_hEvent = 0 Then
        LogMSG("ERR:InitPipe ..........: API_CreateEvent failed")
        Return
    EndIf
    DllStructSetData($g_tOverlap, "hEvent", $g_hEvent)

    ; Create a named pipe
    $g_hPipe = _NamedPipes_CreateNamedPipe($PIPE_NAME, _ ; Pipe name
            2, _ ; The pipe is bi-directional
            2, _ ; Overlapped mode is enabled
            0, _ ; No security ACL flags
            1, _ ; Data is written to the pipe as a stream of messages
            1, _ ; Data is read from the pipe as a stream of messages
            0, _ ; Blocking mode is enabled
            1, _ ; Maximum number of instances
            $BUFSIZE, _ ; Output buffer size
            $BUFSIZE, _ ; Input buffer size
            $TIMEOUT, _ ; Client time out
            0) ; Default security attributes
    If $g_hPipe = -1 Then
        LogMSG("ERR:InitPipe ..........: _NamedPipes_CreateNamedPipe failed")
    EndIf
EndFunc   ;==>InitPipe

; ===============================================================================================================================
; This function loops, waiting for user input or the GUI to close
; ===============================================================================================================================
Func MsgLoop()
GUICtrlSetData ($Input1,"cmd.exe /c dir C:\ /oN")
    While 1
        CloseGuiOnDoubleClick("loop")
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                CloseGuiOnDoubleClick("button")
            Case $Input1
                Go()
            Case $Button1                                    ;Execute the command from the edit field
                Go()
            Case $Button2                ;Clear the Edit field
                MemoWrite("", 1)
        EndSwitch
    WEnd

EndFunc   ;==>MsgLoop

Func Go()
    $inp1Txt = GUICtrlRead($Input1)
    If $inp1Txt <> "" Then
        If ExecuteCmd($inp1Txt) Then
            GuiCtrlSetState ($Button3,$GUI_ENABLE)
            While $lockexit = 0                 ;Exits the loop when the ReadOutput() stops receiving data.
                If GUIGetMsg() = $Button3 Then ProcessClose($h_PID)               ;Stop Button, closes the proccess id - in case it is stuck
                _GUICtrlEdit_BeginUpdate($g_idMemo)                 ;This allows the edit field to be scrolled via scrollbars, while getting data.
                ReadOutput()                                        ;Read the pipe and set the output into the edit field
                _GUICtrlEdit_EndUpdate($g_idMemo)
            WEnd
            $lockexit = 0
            GuiCtrlSetState ($Button3,$GUI_DISABLE)
            LogMsg("done")
        EndIf
    EndIf
EndFunc   ;==>Go

Func ReadOutput()
    Local $pBuffer, $tBuffer, $sLine, $iRead, $bSuccess, $iWritten

    $tBuffer = DllStructCreate("char Text[" & $BUFSIZE & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    ; Read data from console pipe
    _WinAPI_ReadFile($g_hReadPipe, $pBuffer, $BUFSIZE, $iRead)
    If $iRead = 0 Then
        _WinAPI_CloseHandle($g_hReadPipe)
        _WinAPI_FlushFileBuffers($g_hPipe)
        $lockexit = 1
        $h_PID = 0
        Return
    EndIf

    ; Get the data and strip out the extra carriage returns
    $sLine = StringLeft(DllStructGetData($tBuffer, "Text"), $iRead)
    $sLine = StringReplace($sLine, @CR & @CR, @CR)
    If $sLine <> "" Then MemoWrite($sLine)
EndFunc   ;==>ReadOutput


; ===============================================================================================================================
; Executes a command and returns the results
; ===============================================================================================================================
Func ExecuteCmd($sCmd)
    Local $tProcess, $tSecurity, $tStartup, $hWritePipe

    ; Set up security attributes
    $tSecurity = DllStructCreate($tagSECURITY_ATTRIBUTES)
    DllStructSetData($tSecurity, "Length", DllStructGetSize($tSecurity))
    DllStructSetData($tSecurity, "InheritHandle", True)

    ; Create a pipe for the child process's STDOUT
    If Not _NamedPipes_CreatePipe($g_hReadPipe, $hWritePipe, $tSecurity) Then
        LogMSG("ERR: ExecuteCmd ........: _NamedPipes_CreatePipe failed")
        Return False
    EndIf

    ; Create child process
    $tProcess = DllStructCreate($tagPROCESS_INFORMATION)
    $tStartup = DllStructCreate($tagSTARTUPINFO)
    DllStructSetData($tStartup, "Size", DllStructGetSize($tStartup))
    DllStructSetData($tStartup, "Flags", BitOR($STARTF_USESTDHANDLES, $STARTF_USESHOWWINDOW))
    DllStructSetData($tStartup, "StdOutput", $hWritePipe)
    DllStructSetData($tStartup, "StdError", $hWritePipe)
    If Not _WinAPI_CreateProcess("", $sCmd, 0, 0, True, 0, 0, "", DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) Then
        LogMSG("ERR: ExecuteCmd ........: _WinAPI_CreateProcess failed")
        _WinAPI_CloseHandle($g_hReadPipe)
        _WinAPI_CloseHandle($hWritePipe)
        Return False
    EndIf
    $h_PID = DllStructGetData($tProcess, "ProcessID")
    _WinAPI_CloseHandle(DllStructGetData($tProcess, "hProcess"))
    _WinAPI_CloseHandle(DllStructGetData($tProcess, "hThread"))

    ; Close the write end of the pipe so that we can read from the read end
    _WinAPI_CloseHandle($hWritePipe)

    LogMsg("ExecuteCommand ....: " & $sCmd)
    Return True
EndFunc   ;==>ExecuteCmd

Func MemoWrite($sMessage = "", $clr = 0)
    local $CRLF=""

    If $clr = 1 Then
        GUICtrlSetData($g_idMemo, "")
    Else
        $CRLF=@CRLF
    EndIf

    GUICtrlSetData($g_idMemo, $sMessage & $CRLF, 0)
EndFunc   ;==>MemoWrite

Func LogMsg($msg)
    _GUICtrlStatusBar_SetText($StatusBar1, $msg)
EndFunc   ;==>LogMsg

; Resize the status bar when GUI size changes
Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    _GUICtrlStatusBar_Resize($StatusBar1)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE


Func CloseGuiOnDoubleClick($typ)
    $typ = StringLower($typ)
    Select
        Case $typ = "button"
            If $closecounter = 1 And TimerDiff($TimeHandle) <= $closingdelay Then
                GUIDelete()
                Exit
            EndIf
            If $closecounter = 0 Then
                $closecounter = 1
                $TimeHandle = TimerInit()
                WinSetTitle($hGUI, "", "To close, use Slow doubleclick on the X ! Or (2* Alt F4) or (2*Esc)")
            EndIf
        Case $typ = "loop"
            If $closecounter = 1 And TimerDiff($TimeHandle) > $closingdelay Then
                $closecounter = 0
                WinSetTitle($hGUI, "", $formTitle)
            EndIf
    EndSelect
EndFunc   ;==>CloseGuiOnDoubleClick

 

Edit: The script may freeze, if the executed command waits for input.

Edited by Dan_555

Some of my script sourcecode

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...