do anonymous pipes normally work on NT?
Georg Mischler
schorsch at schorsch.com
Sat Jun 12 15:03:11 EDT 1999
'''
Hi all,
I seem to be unable to do anonymous pipes right on NT4sp3.
This may be more of a Windows than a Python related
question, but I'll try it here for a start anyway...
The code below was created with the help of an example
posted here some time ago by Bill Tut, a C++ example by
someone else, and after studying the docs to the win32
extensions by Mark Hammond, as well as the documentation
in VisualStudio for VC++5.
To my uninitiated eyes, everything looks as if it would
make sense, and corresponds to similar code for unix,
using fork() and execv().
The problem is, that in the case here, I can write
to the stdin pipe, but reading from stdout or stderr
will get no results at all. All I see is an exception
eventually, telling me:
'(109, 'ReadFile', 'Die Pipe wurde beendet')
'The pipe was terminated'.
When calling a program from cygwin (b19), instead
of listening to lines of input and answering with
its results, it will just die and nothing else
will happen. This is normally the same if I call a
program from windows, except for example with ftp.exe,
which starts an infinite loop and eats all cpu. I don't
know if this is a related problem or just a ftp.exe
weirdness.
An example invocation would be:
d:\somewhere\> python
>>> import ntprocess
>>> p = ntprocess.Coprocess('c:\\winnt\\system32\\ping.exe -t
localhost')
>>> print p.read()
# nothing happens until I kill ping from the task manager:
Traceback (innermost last):
File "<stdin>", line 1, in ?
File "ntprocess.py", line 111, in read
res, str = win32file.ReadFile(self.hStdout, 0)
pywintypes.api_error: (109, 'ReadFile', 'Die Pipe wurde beendet.')
Now it may be that the nt console programs don't
write to stdout but just directly to the console.
But my cygwin stuff certainly *does* write to stdout
and stderr. Are there any problems known when
combining native NT Python with cygwin binaries?
Am I doing aything else wrong?
Since I have *no* idea where to look, I can't help
but just include the complete source below.
If anyone knowing more about this stuff could
take a short look at it and point me to the blatant
error I made, I'd be extremely happy.
Thanks for any insights!
-schorsch
'''
# ntprocess.py
import types
import os
import sys
import string
import msvcrt
import winnt
import win32api
import win32pipe
import win32file
import win32process
import win32event
import win32security
class Coprocess:
def __init__ (self, cmd, env={}):
self.running = 0
self.exitstatus = None
if type(cmd) == types.StringType:
cmd = string.split(cmd)
executable = cmd[0]
self.args = cmd[1:]
self.executable = os.path.normpath(executable)
# security attributes for created pipes
sAttrs = win32security.SECURITY_ATTRIBUTES()
sAttrs.bInheritHandle = 1
# redirecting child STDOUT:
# XXX redirection should actually be checked before
# cmd is split.
# XXX Right now, the '>' must be framed by whitespace
# in a string.
if '>' in self.args:
redirpos = self.args.index('>')
if len(self.args) < redirpos + 2:
raise IOError, 'Empty Redirect.'
if len(self.args) > redirpos + 2:
raise IOError, 'Ambiguous Redirect.'
outfn = self.args[-1]
outfd = os.open(outfn,
os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0664)
hStdout_w = msvcrt.get_osfhandle(outfd)
self.args = self.args[:-2]
hStdout_r = None
self.hStdout = hStdout_r
elif '>>' in self.args:
redirpos = self.args.index('>>')
if len(self.args) < redirpos + 2:
raise IOError, 'Empty Redirect.'
if len(self.args) > redirpos + 2:
raise IOError, 'Ambiguous Redirect.'
outfn = self.args[-1]
outfd = os.open(outfn,
os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0664)
hStdout_w = msvcrt.get_osfhandle(outfd)
self.args = self.args[:-2]
hStdout_r = None
self.hStdout = hStdout_r
else:
hStdout_r, hStdout_w = win32pipe.CreatePipe(sAttrs, 0)
self.hStdout = hStdout_r
# child STDIN:
hStdin_r, hStdin_w = win32pipe.CreatePipe(sAttrs, 0)
self.hStdin = hStdin_w
# child STDERR:
hStderr_r, hStderr_w = win32pipe.CreatePipe(sAttrs, 0)
self.hStderr = hStderr_r
# create environment for new process.
newenv = os.environ.copy() # use parent environment.
newenv.update(env) # add/override from caller data.
# set up the command line.
sCmdLine = self.executable + ' ' + string.join(self.args)
# set the info structure for the new process.
StartupInfo = win32process.STARTUPINFO()
StartupInfo.hStdInput = hStdin_r
StartupInfo.hStdOutput = hStdout_w
StartupInfo.hStdError = hStderr_w
StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES
# start the process.
hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(
self.executable, sCmdLine, # what to start
None, # process security attributes
None, # thread attributes
1, # inherit handles, or USESTDHANDLES won't work.
# creation flags. Don't access the console.
win32process.DETACHED_PROCESS,
newenv, # new environment
None, # current directory (stay where we are)
StartupInfo)
#print hProcess, hThread, dwPid, dwTid
self.hProcess = hProcess
self.hThread = hThread
self.pid = dwPid
self.tid = dwTid
self.running = 1
def write(self, str):
err, bytes = win32file.WriteFile(self.hStdin, str)
return bytes
def read(self):
if not self.hStdout: raise IOError, 'Error: output redirected.'
res, str = win32file.ReadFile(self.hStdout, 0)
if res == 0: return str
else: return ''
def stderr_read(self):
res, str = win32file.ReadFile(self.hStderr, 0)
if res == 0: return str
else: return ''
#XXX we'd probably need to implement line buffering ourselves
#def readline(self):
# return ''
#def stderr_readline(self):
# return ''
def flush(self):
win32file.FlushFileBuffers(self.hStdin)
def waitpid (self, opt=0):
wres = win32event.WaitForSingleObject(self.hProcess, opt)
# XXX do we want to check the status if we timed out?
status = win32process.GetExitCodeProcess(self.hProcess)
self.exitstatus = status/256
self.running = 0
return (self.pid, status)
def kill (self, signal=9):
self.close()
if self.running:
win32process.TerminateProcess(self.hProcess, -9)
return self.waitpid(0)
else:
return 0
def __del__(self):
'''close all handles when our instance is garbage collected.'''
self.close()
def close(self):
# close handles defensively, in case we fail early...
if hasattr(self, 'self.hStdin'):
win32api.CloseHandle(self.hStdin)
if hasattr(self, 'self.hStdout'):
win32api.CloseHandle(self.hStdout)
if hasattr(self, 'self.hStderr'):
win32api.CloseHandle(self.hStderr)
if hasattr(self, 'self.hProcess'):
win32api.CloseHandle(self.hProcess)
if hasattr(self, 'self.hThread'):
win32api.CloseHandle(self.hThread)
--
Georg Mischler -- simulation developper -- schorsch at schorsch.com
+schorsch.com+ -- lighting design tools -- http://www.schorsch.com/
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
More information about the Python-list
mailing list