danls Posted January 15, 2012 Share Posted January 15, 2012 (edited) First post and first Autoit script. Gotta say I love this scripting language so far. I am modifying the Named Pipes server & client examples that come with the latest AutoIt to run from the console rather than Gui. So far so good. But when I try sending a command from the client to the server that takes followup interaction, the command exits after it sends its first batch of output. As a simple example, I am trying to get the named pipe server to run "cmd.exe dir /k". I want the command prompt to then continue running and taking input after it outputs the first results from "dir", hence using the /k flag instead of /c. However, it sends the output of "dir" back to the client and then the cmd.exe process exits. I cannot figure out why! I'm not going to give the code for the entire server script since it's quite long, but here are the relevant functions for server.au3: expandcollapse popup#include <Timers.au3> #include <Inet.au3> #include <FTPEx.au3> #include <ScreenCapture.au3> #include <NamedPipes.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <GuiConstantsEx.au3> ; =============================================================================================================================== ; Global constants ; =============================================================================================================================== Global Const $DEBUGGING = True Global Const $BUFSIZE = 4096 Global Const $PIPE_NAME = ".pipeAutoIt3" Global Const $TIMEOUT = 5000 Global Const $WAIT_TIMEOUT = 258 Global Const $ERROR_IO_PENDING = 997 Global Const $ERROR_PIPE_CONNECTED = 535 ; =============================================================================================================================== ; Global variables ; =============================================================================================================================== Global $hEvent, $iMemo, $pOverlap, $tOverlap, $hPipe, $hReadPipe, $iState, $iToWrite, $hProcess, $ProcessID ; =============================================================================================================================== ; This function loops waiting for a connection event or the GUI to close ; =============================================================================================================================== Func MsgLoop() Local $iEvent Do $iEvent = _WinAPI_WaitForSingleObject($hEvent, 0) If $iEvent < 0 Then LogError("MsgLoop ...........: _WinAPI_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 ;==>MsgLoop ; =============================================================================================================================== ; This function reads a request message from the client ; =============================================================================================================================== Func ReadRequest() Local $pBuffer, $tBuffer, $iRead, $bSuccess $tBuffer = DllStructCreate("char Text[" & $BUFSIZE & "]") $pBuffer = DllStructGetPtr($tBuffer) $bSuccess = _WinAPI_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 _WinAPI_GetOverlappedResult($hPipe, $pOverlap, $iRead, True) Then LogError("ReadRequest .......: _WinAPI_GetOverlappedResult failed") ReconnectClient() Return Else ; Read the command from the pipe $bSuccess = _WinAPI_ReadFile($hPipe, $pBuffer, $BUFSIZE, $iRead, $pOverlap) If Not $bSuccess Or ($iRead = 0) Then LogError("ReadRequest .......: _WinAPI_ReadFile failed") ReconnectClient() Return EndIf EndIf EndIf ; Execute the console command If Not ExecuteCmd(DllStructGetData($tBuffer, "Text")) Then ReconnectClient() Return EndIf ; Relay console output back to the client $iState = 3 EndFunc ;==>ReadRequest ; =============================================================================================================================== ; 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 _WinAPI_ReadFile($hReadPipe, $pBuffer, $BUFSIZE, $iRead) ;No output read from process If $iRead = 0 Then ; First check if process still exists If ProcessExists($ProcessID) Then LogMsg("Process still exists") ; 1) continue interacting with command Else ; 2) close hReadPipe and request new command LogMsg("RelayOutput .......: Process " & $ProcessID & " !exists..Write done") _WinAPI_CloseHandle($hReadPipe) _WinAPI_FlushFileBuffers($hPipe) ReconnectClient() Return EndIf 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 = _WinAPI_WriteFile($hPipe, $pBuffer, $iToWrite, $iWritten, $pOverlap) If $bSuccess And ($iWritten = $iToWrite) Then Debug("RelayOutput .......: Write success") Else If Not $bSuccess And (_WinAPI_GetLastError() = $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 ;==>RelayOutput ; =============================================================================================================================== ; Executes a command and returns the results ; =============================================================================================================================== Func ExecuteCmd($sCmd) Local $tProcess, $tSecurity, $tStartup, $hWritePipe, $iSuccess ; 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($hReadPipe, $hWritePipe, $tSecurity) Then LogError("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) $iSuccess = _WinAPI_CreateProcess("", $sCmd, 0, 0, True, 0, 0, "", DllStructGetPtr($tStartup), DllStructGetPtr($tProcess)) If Not $iSuccess Then LogError("ExecuteCmd ........: _WinAPI_CreateProcess failed") _WinAPI_CloseHandle($hReadPipe) _WinAPI_CloseHandle($hWritePipe) Return False EndIf _WinAPI_CloseHandle(DllStructGetData($tProcess, 'hThread')) $hProcess = DllStructGetData($tProcess, 'hProcess') $ProcessID = DllStructGetData($tProcess, 'ProcessID') LogMsg("PID: " & $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 Edited January 15, 2012 by danls Link to comment Share on other sites More sharing options...
danls Posted January 16, 2012 Author Share Posted January 16, 2012 So I'm starting to think maybe I should use the Run command instead of _WinAPI_CreateProcess, which the named pipes example uses. I could then use StdoutRead and StdInWrite to send and receive data from the process, and then send this into the named pipe. But I still can't figure out why the cmd /k process exits when using _WinAPI_CreateProcess as above. Any ideas? Link to comment Share on other sites More sharing options...
danls Posted January 18, 2012 Author Share Posted January 18, 2012 No one has any clue about why a created process just exits like this? This is driving me crazy... Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now