All pastes #498249 Raw Edit

Anonymous

public text v1 · immutable
#498249 ·published 2007-05-20 08:43 UTC
rendered paste body
#include <A3LPipes.au3>
Opt("MustDeclareVars", 1)

; ====================================================================================================
===========================
; Description ...: This is the server side of the pipe demo
; Author ........: Paul Campbell (PaulIA)
; Notes .........:
; ====================================================================================================
===========================

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

Global Const $DEBUGGING = False
Global Const $BUFSIZE   = 4096
Global Const $PIPE_NAME = "\\.\\pipe\\Auto3Lib"
Global Const $TIMEOUT   = 5000

; ====================================================================================================
===========================
; Global variables
; ====================================================================================================
===========================

Global $hEvent, $iMemo, $pOverlap, $tOverlap, $hPipe, $hReadPipe, $iState, $iToWrite

; ====================================================================================================
===========================
; Main
; ====================================================================================================
===========================

CreateGUI()
InitPipe()
MsgLoop()

; ====================================================================================================
===========================
; Creates a GUI for the server
; ====================================================================================================
===========================
Func CreateGUI()
  Local $hGUI

  $hGUI  = GUICreate("Pipe Server", 500, 400, -1, -1, $WS_SIZEBOX)
  $iMemo = GUICtrlCreateEdit("", 0, 0, _API_GetClientWidth($hGUI), _API_GetClientHeight($hGUI))
  GUICtrlSetFont($iMemo, 9, 400, 0, "Courier New")
  GUISetState()
EndFunc

; ====================================================================================================
===========================
; This function creates an instance of a named pipe
; ====================================================================================================
===========================
Func InitPipe()
  ; Create an event object for the instance
  $tOverlap = DllStructCreate($tagOVERLAPPED)
  $pOverlap = DllStructGetPtr($tOverlap)
  $hEvent   = _API_CreateEvent()
  if $hEvent = 0 then
    LogError("InitPipe ..........: API_CreateEvent failed")
    Return
  endif
  DllStructSetData($tOverlap, "hEvent", $hEvent)

  ; Create a named pipe
  $hPipe = _Pipe_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 $hPipe = -1 then
    LogError("InitPipe ..........: _Pipe_CreateNamedPipe failed")
  else
    ; Connect pipe instance to client
    ConnectClient()
  endif
EndFunc

; ====================================================================================================
===========================
; This function loops waiting for a connection event or the GUI to close
; ====================================================================================================
===========================
Func MsgLoop()
  Local $iEvent

  do
    $iEvent = _API_WaitForSingleObject($hEvent, 0)
    if $iEvent < 0 then
      LogError("MsgLoop ...........: _API_WaitForSingleObject failed")
      Exit
    endif
    if $iEvent = $WAIT_TIMEOUT then ContinueLoop
    Debug("MsgLoop ...........: Instance signaled")

    Switch $iState
      case 0
        CheckConnect()
      case 1
        ReadRequest()
      case 2
        CheckPending()
      case 3
        RelayOutput()
    EndSwitch
  until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc

; ====================================================================================================
===========================
; Checks to see if the pending client connection has finished
; ====================================================================================================
===========================
Func CheckConnect()
  Local $iBytes

  ; Was the operation successful?
  if not _API_GetOverlappedResult($hPipe, $pOverlap, $iBytes, False) then
    LogError("CheckConnect ......: Connection failed")
    ReconnectClient()
  else
    LogMsg("CheckConnect ......: Connected")
    $iState = 1
  endif
EndFunc

; ====================================================================================================
===========================
; This function reads a request message from the client
; ====================================================================================================
===========================
Func ReadRequest()
  Local $pBuffer, $tBuffer, $iRead, $bSuccess, $iToWrite, $temp

  $tBuffer = DllStructCreate("char Text[" & $BUFSIZE & "]")
  $pBuffer = DllStructGetPtr($tBuffer)
  $bSuccess = _API_ReadFile($hPipe, $pBuffer, $BUFSIZE, $iRead, $pOverlap)

  if $bSuccess and ($iRead <> 0) then
    ; The read operation completed successfully
    Debug("ReadRequest .......: Read success")
  else
    ; Wait for read Buffer to complete
    if not _API_GetOverlappedResult($hPipe, $pOverlap, $iRead, True) then
      LogError("ReadRequest .......: _API_GetOverlappedResult failed")
      ReconnectClient()
      Return
    else
      ; Read the command from the pipe
      $bSuccess = _API_ReadFile($hPipe, $pBuffer, $BUFSIZE, $iRead, $pOverlap)
      if not $bSuccess or ($iRead = 0) then
        LogError("ReadRequest .......: _API_ReadFile failed")
        ReconnectClient()
        Return
      endif
    endif
  endif

    $temp = DllStructGetData($tBuffer, "Text")
  ; Execute the console command
  if not ExecuteCmd($temp) then
    ReconnectClient()
    Return
  endif

  ; Relay console output back to the client
  $iState = 3
EndFunc

; ====================================================================================================
===========================
; This function relays the console output back to the client
; ====================================================================================================
===========================
Func CheckPending()
  Local $bSuccess, $iWritten

  $bSuccess = _API_GetOverlappedResult($hPipe, $pOverlap, $iWritten, False)
  if not $bSuccess or ($iWritten <> $iToWrite) then
    Debug("CheckPending ......: Write reconnecting")
    ReconnectClient()
  else
    Debug("CheckPending ......: Write complete")
    $iState = 3
  endif
EndFunc

; ====================================================================================================
===========================
; This function relays the console output back to the client
; ====================================================================================================
===========================
Func RelayOutput()
  Local $pBuffer, $tBuffer, $sLine, $iRead, $bSuccess, $iWritten

  $tBuffer = DllStructCreate("char Text[" & $BUFSIZE & "]")
  $pBuffer = DllStructGetPtr($tBuffer)
  ; Read data from console pipe
  _API_ReadFile($hReadPipe, $pBuffer, $BUFSIZE, $iRead)
  if $iRead = 0 then
    LogMsg("RelayOutput .......: Write done")
    _API_CloseHandle($hReadPipe)
    _API_FlushFileBuffers($hPipe)
    ReconnectClient()
    Return
  endif

  ; Get the data and strip out the extra carriage returns
  $sLine    = StringLeft(DllStructGetData($tBuffer, "Text"), $iRead)
  $sLine    = StringReplace($sLine, @CR & @CR, @CR)
  $iToWrite = StringLen($sLine)
  DllStructSetData($tBuffer, "Text", $sLine)
  ; Relay the data back to the client
  $bSuccess = _API_WriteFile($hPipe, $pBuffer, $iToWrite, $iWritten, $pOverlap)
  if $bSuccess and ($iWritten = $iToWrite) then
    Debug("RelayOutput .......: Write success")
  else
    if not $bSuccess and (@Error = $ERROR_IO_PENDING) then
      Debug("RelayOutput .......: Write pending")
      $iState = 2
    else
      ; An error occurred, disconnect from the client
      LogError("RelayOutput .......: Write failed")
      ReconnectClient()
    endif
  endif
EndFunc

; ====================================================================================================
===========================
; This function is called to start an overlapped connection operation
; ====================================================================================================
===========================
Func ConnectClient()
  $iState = 0
  ; Start an overlapped connection
  if _Pipe_ConnectNamedPipe($hPipe, $pOverlap) then
    LogError("ConnectClient .....: ConnectNamedPipe 1 failed")
  else
    Switch @Error
      ; The overlapped connection is in progress
      case $ERROR_IO_PENDING
        Debug("ConnectClient .....: Pending")
      ; Client is already connected, so signal an event
      case $ERROR_PIPE_CONNECTED
        LogMsg("ConnectClient .....: Connected")
        $iState = 1
        if not _API_SetEvent($tOverlap.hEvent) then
          LogError("ConnectClient .....: SetEvent failed")
        endif
      ; Error occurred during the connection event
      case else
        LogError("ConnectClient .....: ConnectNamedPipe 2 failed")
    EndSwitch
  endif
EndFunc

; ====================================================================================================
===========================
; Dumps debug information to the screen
; ====================================================================================================
===========================
Func Debug($sMessage)
  if $DEBUGGING then LogMsg($sMessage)
EndFunc

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

  ; 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 _Pipe_CreatePipe($hReadPipe, $hWritePipe, $tSecurity) then
    LogError("ExecuteCmd ........: _Pipe_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 _API_CreateProcess("", $sCmd, 0, 0, True, 0, 0, "", DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) then
    LogError("ExecuteCmd ........: _API_CreateProcess failed")
    _API_CloseHandle($hReadPipe )
    _API_CloseHandle($hWritePipe)
    Return False
    endif

$temp2 = DllStructGetData($tProcess, "hProcess")
$temp3 = DllStructGetData($tProcess, "hThread")
  _API_CloseHandle($temp2)
  _API_CloseHandle($temp3)

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

  LogMsg("ExecuteCommand ....: " & $sCmd)
  Return True
EndFunc

; ====================================================================================================
===========================
; Logs an error message to the display
; ====================================================================================================
===========================
Func LogError($sMessage)
  $sMessage &= " (" & _API_GetLastErrorMessage() & ")"
  _Lib_ConsoleWrite($sMessage)
EndFunc

; ====================================================================================================
===========================
; Logs a message to the display
; ====================================================================================================
===========================
Func LogMsg($sMessage)
  GUICtrlSetData($iMemo, $sMessage & @CRLF, 1)
EndFunc

; ====================================================================================================
===========================
; This function is called when an error occurs or when the client closes its handle to the pipe
; ====================================================================================================
===========================
Func ReconnectClient()
  ; Disconnect the pipe instance
  if not _Pipe_DisconnectNamedPipe($hPipe) then
    LogError("ReconnectClient ...: DisonnectNamedPipe failed")
    Return
  endif

  ; Connect to a new client
  ConnectClient()
EndFunc