Hi Bernd
Bernd Holzmüller wrote:
> Hi all,
>
> I am developing a test management GUI where processes are started and
> their output (on stdout and stderr) are shown on corresponding console
> windows. The process management worked quite OK with version 0.9.4 but
> does no longer work in version 0.10.3 (using ghc 6.8.3 on Windows XP).
>
> The attached small example application shows what happens: with
> processExecAsync only garbage is shown on both the stdout and the stderr
> console window, with processExecAsyncTimed the stdout console works
> fine, but the stderr console shows nothing. Main.hs is the wxHaskell GUI
> with two buttons, both calling the application compiled from
> Testproc.hs, one using processExecAsync, one using the Timed variant.
> The attached makefile builds everything.
>
> If someone with understanding of the internals of wxHaskell could have a
> look on this topic, I would be very grateful. Perhaps the (soon?) coming
> new wxHaskell version 0.11 will do correctly?
>
> Thanks,
> Bernd
>
Your processExecAsyncTimed example works on Linux. But of cause that do
not help you much. The processExecAsync example do not work on Linux
either.
A while ago I got tired of the hard-to-get-to-work nature of
processExecAsyncTimed and therefore wrote my own process executor. I
have attached my own process executor and an adapted version of your
code, which works for me (on Linux). You will have to adapt it a little
bit to work on windows (properly just changing "./testproc.exe" to
"testproc" should do).
I would love to hear if it works on your machine.
Greetings,
Mads Lindstrøm
module Main where
import Graphics.UI.WX
import Graphics.UI.WXCore
import WxProcess
main = start $ do
f <- frame [ text := "Test Process Handling in wxHaskell" ]
p <- panel f []
stdoutConsole <- textCtrlRich p [ font := fontFixed {_fontSize = 8} ]
stderrConsole <- textCtrlRich p [ font := fontFixed {_fontSize = 8} ]
let write console txt = textCtrlAppendText console txt
clear c = set c [text := ""]
clearAll = do clear stdoutConsole; clear stderrConsole
onEndProcess exitcode = write stdoutConsole $ "\nprocess terminated with exitcode " ++ show exitcode
onStdout txt _ = write stdoutConsole $ "Stdout: " ++ txt
onStderr txt _ = write stderrConsole $ "Stderr: " ++ txt
spawnTimed = processExecAsyncTimed p "./testproc.exe" True onEndProcess onStdout onStderr
spawnThreaded = processExecAsync p "./testproc.exe" 100 onEndProcess onStdout onStderr
--
onStdout' txt = write stdoutConsole $ "Stdout: " ++ txt
onStderr' txt = write stderrConsole $ "Stderr: " ++ txt
spawnWxExecProcess = wxExecProcess p "./testproc.exe" 100 onEndProcess onStdout' onStderr'
startThreadedButton <- button p [ text := "processExecAsync"
, on command := do clearAll; spawnThreaded; return ()]
startTimedButton <- button p [ text := "processExecAsyncTimed"
, on command := do clearAll; spawnTimed; return ()]
startWxProcessButton <- button p [ text := "wxExecProcess"
, on command := do clearAll; spawnWxExecProcess; return ()]
-- stopProcessButton <- button p []
set p [ layout := column 5
[ row 5 [widget startThreadedButton, hglue]
, row 5 [widget startTimedButton, hglue]
, row 5 [widget startWxProcessButton, hglue]
, row 5 [ column 5 [hfill $ label "stdout", fill $ widget stdoutConsole]
, column 5 [hfill $ label "stderr", fill $ widget stderrConsole ]]]
]
set f [ layout := margin 5 $ hfill $ widget p
, clientSize := sz 860 550
]
{-# LANGUAGE MultiParamTypeClasses, PatternSignatures, RecursiveDo #-}
module WxProcess
( wxExecProcess
, ExitCode(..)
)
where
import Control.Concurrent
import System.Exit
import System.Process
import System.IO
import Foreign.Marshal.Array
import Foreign.Marshal.Alloc
import Data.Word
import qualified Graphics.UI.WX as WX
import Graphics.UI.WX (Prop(..), on)
type OnReceive = String -> IO()
wxExecProcess :: WX.Window a -> String -> Int -> (ExitCode -> IO()) -> OnReceive -> OnReceive
-> IO ()
-- if the user needs to give input to the created process, we could return IO (String -> IO StreamStatus) in stead
wxExecProcess parent cmd bufferSize onEndProcess onOutput onErrOutput =
do (inh,outh,errh,pid) <- runInteractiveCommand cmd
mapM_ (\hdl -> hSetBuffering hdl NoBuffering) [inh, outh, errh]
-- fork off a thread to start consuming the output
stdOutMVar <- newEmptyMVar
stdErrMVar <- newEmptyMVar
stdOutIsFinished <- newEmptyMVar
stdErrIsFinished <- newEmptyMVar
processFinished <- newEmptyMVar
let consume handle isFinished outputMVar =
do buf <- mallocArray bufferSize
consume' handle isFinished outputMVar buf
free buf
consume' handle isFinished outputMVar buf =
do outIsEOF <- hIsEOF handle
if outIsEOF
then putMVar isFinished ()
else do hWaitForInput handle 1000 -- 1000 = one second
count <- hGetBufNonBlocking handle buf bufferSize
(x :: [Word8]) <- peekArray count buf
putMVar outputMVar (map (toEnum . fromIntegral) x)
consume' handle isFinished outputMVar buf
forkIO $ consume outh stdOutIsFinished stdOutMVar
forkIO $ consume errh stdErrIsFinished stdErrMVar
let handleAllInput = do handleAnyInput stdOutMVar onOutput
handleAnyInput stdErrMVar onErrOutput
mdo t <- WX.timer parent [ WX.interval := 100 -- 10 times a second
, on WX.command := do handleAllInput
exitCode <- tryTakeMVar processFinished
case exitCode of
Nothing -> return ()
Just code -> do handleAllInput -- handle remaining input
onEndProcess code
WX.objectDelete t
]
return ()
forkIO (do takeMVar stdOutIsFinished
takeMVar stdErrIsFinished
waitForProcess pid >>= putMVar processFinished
hClose outh
hClose errh
)
return ()
where
handleAnyInput mvar withOutput =
do val <- tryTakeMVar mvar
case val of
Nothing -> return ()
Just xs -> withOutput xs
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
wxhaskell-devel mailing list
wxhaskell-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wxhaskell-devel