Jump to content
Digisoul

Unable to read/write through Pipe for Aspell.exe

Recommended Posts

Hello,

I am trying to create a Spell Checker with help of Aspell.exe, my intention is to communicate with Aspell.exe through _NamedPipes_CreatePipe , after reading the following articles & discussions:

http://aspell.net/man-html/Through-A-Pipe.html

https://www.autoitscript.com/forum/topic/120575-createprocess-with-stdio-solved/

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx

I wrote this script:

#include <AutoItConstants.au3>
#include <WinAPI.au3>
#include <NamedPipes.au3>
Global $hOutRead, $hOutWrite, $hInRead, $hInWrite

Global $hSTD_OUT_ReadPipe, $hSTD_OUT_WritePipe
Global $hSTD_IN_ReadPipe, $hSTD_IN_WritePipe
$iPID = _Run("C:\Program Files (x86)\Aspell\bin\aspell.exe", " -a", "C:\Program Files (x86)\Aspell\bin")

ConsoleWrite("pid:" & $iPID & @LF)

;read 1st msg
_ReadMsg()

; try to check spell
Local $iData,$nBytes,$tBuffer
$iData = "Thq Quick Brown Fox Jumps ovzr tha lezy dog."
$tBuffer = DllStructCreate("byte["&StringLen($iData)&"]")
$res = _WinAPI_WriteFile($hSTD_IN_WritePipe, DllStructGetPtr($tBuffer), StringLen($iData), $nBytes)
ConsoleWrite(">WriteResult:"&$res&":"&$nBytes&@LF)

; totally stuck
_ReadMsg()


_WinAPI_CloseHandle($hSTD_OUT_ReadPipe)
Exit


Func _ReadMsg()
    Local $tBuffer,$nBytes,$rData,$return


    While True
        ToolTip("i am stuck")
        $tBuffer = DllStructCreate("byte[4096]")
        $sOutput = _WinAPI_ReadFile($hSTD_OUT_ReadPipe, DllStructGetPtr($tBuffer), 4096, $nBytes,0)
        If $nBytes > 0 Then ; Exit the loop if the process closes or StdoutRead returns an error.
            $rData = BinaryToString(DllStructGetData($tBuffer, 1))
            ConsoleWrite($rData)

            If StringInStr($rData, @LF) Then
                ConsoleWrite("msg complete" & @LF)
                ToolTip("")
                ExitLoop
            Else
                $return = $rData
            EndIf

            $tBuffer = 0
            $nBytes = 0
        Else
            ExitLoop
        EndIf
    WEnd
    ;--------------
    Return $return
EndFunc   ;==>_ReadMsg


Func _Run($location, $sCmd, $sWorkingDir = "", $state = @SW_SHOW)
    Local $tProcess, $tSecurity, $tStartup
    Local Const $STARTF_USESHOWWINDOW = 0x1
    Local Const $STARTF_USESTDHANDLES = 0x100

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

    ; Create a pipe for the child process's STDOUT

    ;**************
    _NamedPipes_CreatePipe($hSTD_OUT_ReadPipe, $hSTD_OUT_WritePipe,DllStructGetPtr($tSecurity))
    _WinAPI_SetHandleInformation($hSTD_OUT_ReadPipe, 1, 0) ; dont inherte it
;~  _WinAPI_SetHandleInformation($hSTD_OUT_WritePipe, 1, 1)

    _NamedPipes_CreatePipe($hSTD_IN_ReadPipe, $hSTD_IN_WritePipe,DllStructGetPtr($tSecurity))
    _WinAPI_SetHandleInformation($hSTD_IN_WritePipe, 1, 0) ; here is the problem
;~  _WinAPI_SetHandleInformation($hSTD_IN_ReadPipe, 1, 1)
    ;**************

    ; 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", $hSTD_OUT_WritePipe)
    DllStructSetData($tStartup, "StdError", $hSTD_OUT_WritePipe)
    DllStructSetData($tStartup, "StdInput", $hSTD_IN_ReadPipe)

    DllStructSetData($tStartup, "ShowWindow", $state)
    _WinAPI_CreateProcess($location, $sCmd, 0, 0, True, 0, 0, $sWorkingDir, DllStructGetPtr($tStartup), DllStructGetPtr($tProcess))

    Return DllStructGetData($tProcess, "ProcessID")
EndFunc   ;==>_Run

but I am only able to read the 1st introduction line of the Aspell.exe:

 

@(#) International Ispell Version 3.1.20 (but really Aspell 0.50.3)
 

 after that autoit process just stop responding, I am not sure where is the issue or what is the issue. Please help me here.

 

Thanks in Advance.

Edited by Digisoul
Changed Title

73 108 111 118 101 65 117 116 111 105 116

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

  • Similar Content

    • By TheDcoder
      Hi, I thought I would never post a C/WinAPI related question in this forum ever, but here we are after a few years and me having learnt enough of C to write a basic console program
      My issue is that I am trying to read my child process's stdout output but ReadFile never returns if the child exits or if it is killed... very strange , I have been trying to work my way around this. The options I can think of are:
      Create a new thread and check for existance of the process constantly while reading Somehow make the pipe asynchronous (overlapped) so that I can read it in a non-blocking manner Fix ReadFile to return when the process ends Obviously I would prefer No. 3, I just want to make my program work. Here is my code if you guys want to take a look:
      // No text highlighting for C/C++ but we have it for C#? Blasphemy! bool allium_start(struct TorInstance *instance, char *config, allium_pipe *output_pipes) { char *cmd; // Figure out the command string for execution if (config) { char *parameters = " -f -"; cmd = malloc(strlen(instance->tor_path) + strlen(parameters) + 1); if (!cmd) return false; strcpy(cmd, instance->tor_path); strcat(cmd, parameters); } else cmd = instance->tor_path; // Prepare startup info with appropriate information SecureZeroMemory(&instance->startup_info, sizeof instance->startup_info); instance->startup_info.dwFlags = STARTF_USESTDHANDLES; SECURITY_ATTRIBUTES pipe_secu_attribs = {sizeof(SECURITY_ATTRIBUTES), NULL, true}; HANDLE pipes[2]; if (output_pipes == NULL) { CreatePipe(&pipes[0], &pipes[1], &pipe_secu_attribs, 0); output_pipes = pipes; } instance->startup_info.hStdOutput = output_pipes[1]; instance->startup_info.hStdError = output_pipes[1]; instance->stdout_pipe = output_pipes[0]; // Stored for internal reference if (config) { // Reuse the pipes array to store standard input pipes CreatePipe(&pipes[0], &pipes[1], &pipe_secu_attribs, 0); instance->startup_info.hStdInput = pipes[0]; } // Create the process bool success = CreateProcessA( NULL, cmd, NULL, NULL, config ? true : false, 0, NULL, NULL, &instance->startup_info, SecureZeroMemory(&instance->process, sizeof instance->process) ); // Free command string if needed if (config) free(cmd); // Write config to Tor's standard input unsigned long bytes_written; if (success) { WriteFile(pipes[1], config, strlen(config), &bytes_written, NULL); // Work around for simulating Ctrl + Z which sends the substitution character (ASCII 26), // this is needed in order for Tor to detect EOT/EOF while reading the config WriteFile(pipes[1], &(char){26}, 1, &bytes_written, NULL); } CloseHandle(pipes[1]); // Return on failure if (!success) return false; } char *allium_read_stdout_line(struct TorInstance *instance) { char *buffer = instance->buffer.data; // Check for valid buffer and allocate if needed if (instance->buffer.size == 0 || !buffer) { buffer = instance->buffer.data = malloc(instance->buffer.size = 80 + 1); if (!buffer) return NULL; } // Process the input unsigned int read_len = 0; while (true) { // Read data unsigned long bytes_read; if (ReadFile(instance->stdout_pipe, buffer, 1, &bytes_read, NULL) == false || bytes_read == 0) return NULL; // Check if we have reached end of line if (buffer[0] == '\n') break; // Proceed to the next character ++buffer; ++read_len; // Resize buffer if it is full if (read_len == instance->buffer.size) { char *new_buffer = malloc(instance->buffer.size += 50); if (new_buffer) memcpy(new_buffer, instance->buffer.data, read_len); free(instance->buffer.data); if (!new_buffer) return NULL; instance->buffer.data = new_buffer; buffer = instance->buffer.data + read_len; } } // Terminate the new line with null character and return // Special handling for Windows, terminate at CR if present buffer[read_len >= 2 && buffer[-1] == '\r' ? -1 : 0] = '\0'; } The allium_start function creates the redirection pipes and the child process, the other allium_read_stdout_line function reads from the stdout pipe created by the first function, ReadFile in this function does not return when the child ends or gets killed.

      I appriciate the help of the WinAPI gurus here, thanks in advance!
×
×
  • Create New...