WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

DOS Console UDFs

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Redirecting the Output of a Child Process - DOS Redirection to WB Dialog UDF

Keywords: 	 stdin DOS redirection pipe guiguy gui guy

See Also: Get results from STDOUT - UDF

UDFLIB.REDIRECTION.WBT

User Defined Functions for Redirecting the Output of a Child Process:
;=============================================================================================
;= udflib.redirection.wbt 
;= WinBatch Library of User Defined Functions for Redirecting the Output of a Child Process
;=
;= Translated to WinBatch by GUI Guy, August 2002  (http://guiguy.wminds.com)
;=
;= The following references were used as a guide:
;=     http://msdn.microsoft.com/library/en-us/dllproc/prothred_4uus.asp
;=     http://community.borland.com/article/0,1410,10387,00.html
;=     http://support.microsoft.com/default.aspx?scid=KB;EN-US;q190351&
;=     http://doc.ddart.net/msdn/header/include/winbase.h.html 
;=     http://forum.winbatch.com
;=============================================================================================

;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#DefineFunction udfRunRedirected(app, params)  ;<<<<<< udfRunRedirected >>>>>>>>>>>>>>>>>>>>>>
;/////////////////////////////////////////////////////////////////////////////////////////////
;  Runs an executable file with redirected STDOUT & STDERR (I may add support for STDIN soon)
;  Returns an array containing the following elements:
;     [0] handle to pipe which receives the redirected output (or -1 if the function fails)
;     [1] PROCID (process ID) of the child process
;
;   app = path of program to execute as child
;   params = command-line parameters to pass to child process

;API Constants
; uncomment the ones you use if you modify the code

;STD_INPUT_HANDLE  =     -10
STD_OUTPUT_HANDLE =     -11
STD_ERROR_HANDLE  =     -12
DUPLICATE_SAME_ACCESS =   2
CREATE_NEW_CONSOLE =     16
STARTF_USESTDHANDLES = 256
STARTF_USESHOWWINDOW = 1
SECURITY_DESCRIPTOR_REVISION = 1
;constants for SHOWWINDOW options
SW_HIDE =               0
;SW_SHOWNORMAL =        1 
;SW_NORMAL =            1 
;SW_SHOWMINIMIZED =     2 
;SW_SHOWMAXIMIZED =     3 
;SW_MAXIMIZE =          3 
;SW_SHOWNOACTIVATE =    4 
;SW_SHOW =              5 
;SW_MINIMIZE =          6 
;SW_SHOWMINNOACTIVATE = 7 
;SW_SHOWNA =            8 
;SW_RESTORE =           9 
;SW_SHOWDEFAULT =      10 
;SW_MAX =              10 

ReturnInfo=ArrDimension(2) ;Initialize array to hold info returned by this function

; Save the handle to the current STDOUT & STDERR. (For restoration after child process is created.)  Win95/98/ME only
If WinVersion(4)==5 ;If running on Win95/98/ME
	hSaveStdout = DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"GetStdHandle",long:STD_OUTPUT_HANDLE)
	If !hSaveStdout ;if API call failed, set error and return function
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("GetStdHandle for STDOUT failed. Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
	hSaveStderr = DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"GetStdHandle",long:STD_ERROR_HANDLE)
	If !hSaveStderr
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("GetStdHandle for STDERR failed. Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
endif


; Create a pipe for the child process's STDOUT & STDERR.  (one pipe for both - future versions may handle STDERR and STDOUT separately)

bbChildStdoutRd=BinaryAlloc(4) ;allocate buffer to hold read handle for STDOUT & STDERR
bbChildStdoutWr=BinaryAlloc(4) ;allocate buffer to hold write handle for STDOUT & STDERR
;Define SECURITY_ATTRIBUTES structure for CreatePipe API call so that handles are inheritable by the child
bbSEC_ATTR = BinaryAlloc(12) ; allocate buffer to hold structure
BinaryPoke4(bbSEC_ATTR,0,12) ; size of SECURITY_ATTRIBUTES structure (DWORD nLength;)
If WinVersion(4)==4 ;If running on WinNT/2000/XP initialize security descriptor
	bbSEC_DESC = BinaryAlloc(20)
	if !DllCall(StrCat(DirWindows(1),"advapi32.dll"),long:"InitializeSecurityDescriptor",lpbinary:bbSEC_DESC,long:SECURITY_DESCRIPTOR_REVISION)
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("InitializeSecurityDescriptor failed. Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
	if !DllCall(StrCat(DirWindows(1),"advapi32.dll"),long:"SetSecurityDescriptorDacl",lpbinary:bbSEC_DESC,long:1,lpnull,long:0)
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("SetSecurityDescriptorDacl failed. Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
	BinaryPoke4(bbSEC_ATTR,4,IntControl (42, bbSEC_DESC, 0, 0, 0)) ; pointer to security descriptor
else
	BinaryPoke4(bbSEC_ATTR,4,0) ; null pointer for security descriptor  (LPVOID lpSecurityDescriptor;)
endif
BinaryPoke4(bbSEC_ATTR,8,@TRUE) ;inheritable attribute of SECURITY_ATTRIBUTES structure (BOOL bInheritHandle;)
;Create the pipe:
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"CreatePipe",lpbinary:bbChildStdoutRd,lpbinary:bbChildStdoutWr,lpbinary:bbSEC_ATTR,long:0)
	ReturnInfo[0]=-1
	ReturnInfo[1]=StrCat("CreatePipe failed. Errorcode = ",DllLastError())
	return(ReturnInfo)
endif

BinaryFree(bbSEC_ATTR) ; Free buffer
BinaryFree(bbSEC_DESC) ; Free buffer
BinaryEodSet(bbChildStdoutWr, 4) ;Set EOD so handle can be accessed with BinaryPeek
hChildStdoutWr=BinaryPeek4(bbChildStdoutWr,0) ; write handle for pipe to redirect child's output
BinaryFree(bbChildStdoutWr) ;free buffer
BinaryEodSet(bbChildStdoutRd, 4) ;Set EOD so handle can be accessed with BinaryPeek
hChildStdoutRd=BinaryPeek4(bbChildStdoutRd,0) ; read handle for pipe to redirect child's output
BinaryFree(bbChildStdoutRd) ;free buffer

; set child's STDOUT & STDERR handle to the write end of the pipe
If !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"SetStdHandle",long:STD_OUTPUT_HANDLE,long:hChildStdoutWr) 
	ReturnInfo[0]=-1
	ReturnInfo[1]=StrCat("SetStdHandle failed while setting child STDOUT to write pipe. Errorcode = ",DllLastError())
	return(ReturnInfo)
endif
If !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"SetStdHandle",long:STD_ERROR_HANDLE,long:hChildStdoutWr) 
	ReturnInfo[0]=-1
	ReturnInfo[1]=StrCat("SetStdHandle failed while setting child STDERR to write pipe. Errorcode = ",DllLastError())
	return(ReturnInfo)
endif
; Create noninheritable read handle and close the inheritable read handle. 
hCurProcess=DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"GetCurrentProcess") ;handle for current process is needed for DuplicateHandle API call
bbChildStdoutRdDup=BinaryAlloc(4) ;allocate buffer to hold duplicate handle
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"DuplicateHandle",long:hCurProcess,long:hChildStdoutRd,long:hCurProcess,lpbinary:bbChildStdoutRdDup,long:0,long:0,long:DUPLICATE_SAME_ACCESS)
	ReturnInfo[0]=-1
	ReturnInfo[1]=StrCat("DuplicateHandle failed. Errorcode = ",DllLastError())
	return(ReturnInfo)
endif
hChildStdoutRdDup=BinaryPeek4(bbChildStdoutRdDup,0)
BinaryFree(bbChildStdoutRdDup) ;free buffer

DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"CloseHandle",long:hChildStdoutRd) ;close the inheritable read handle

; Create Process

; Set up members of the PROCESS_INFORMATION structure. 
bbPROC_INFO=BinaryAlloc(16)  ; allocate buffer to hold structure
BinaryPoke4(bbPROC_INFO,0,0) ;    HANDLE hProcess
BinaryPoke4(bbPROC_INFO,4,0) ;    HANDLE hThread
BinaryPoke4(bbPROC_INFO,8,0) ;    DWORD dwProcessId
BinaryPoke4(bbPROC_INFO,12,0);    DWORD dwThreadId
; Set up members of the STARTUPINFO structure. 
bbSTARTINFO=BinaryAlloc(68)
BinaryPoke4(bbSTARTINFO,0,68);    DWORD   cb                  size of structure
BinaryPoke4(bbSTARTINFO,4,0) ;    LPTSTR  lpReserved
BinaryPoke4(bbSTARTINFO,8,0) ;    LPTSTR  lpDesktop
BinaryPoke4(bbSTARTINFO,12,0);    LPTSTR  lpTitle
BinaryPoke4(bbSTARTINFO,16,0);    DWORD   dwX
BinaryPoke4(bbSTARTINFO,20,0);    DWORD   dwY
BinaryPoke4(bbSTARTINFO,24,0);    DWORD   dwXSize
BinaryPoke4(bbSTARTINFO,28,0);    DWORD   dwYSize
BinaryPoke4(bbSTARTINFO,32,0);    DWORD   dwXCountChars
BinaryPoke4(bbSTARTINFO,36,0);    DWORD   dwYCountChars
BinaryPoke4(bbSTARTINFO,40,0);    DWORD   dwFillAttribute
BinaryPoke4(bbSTARTINFO,44,STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES);    DWORD   dwFlags
BinaryPoke2(bbSTARTINFO,48,SW_HIDE);    WORD    wShowWindow  (dwFlags must have STARTF_USESHOWWINDOW bitwise OR'd else this setting is ignored)
BinaryPoke2(bbSTARTINFO,50,0);    WORD    cbReserved2
BinaryPoke4(bbSTARTINFO,52,0);    LPBYTE  lpReserved2
BinaryPoke4(bbSTARTINFO,56,0);    HANDLE  hStdInput
BinaryPoke4(bbSTARTINFO,60,hChildStdoutWr);    HANDLE  hStdOutput
BinaryPoke4(bbSTARTINFO,64,hChildStdoutWr);    HANDLE  hStdError
 
; Create the child process. 
;   return CreateProcess(
;      &app,          // application to execute
;      ¶ms,       // command-line parameters 
;      NULL,          // process security attributes 
;      NULL,          // primary thread security attributes 
;      TRUE,          // handles are inherited 
;      0,             // creation flags 
;      NULL,          // use parent's environment 
;      NULL,          // use parent's current directory 
;      &siStartInfo,  // STARTUPINFO pointer 
;      &piProcInfo);  // receives PROCESS_INFORMATION 

if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"CreateProcessA",lpnull,lpstr:StrCat('"',app,'" ',params),lpnull,lpnull,long:1,long:0,lpnull,lpnull,lpbinary:bbSTARTINFO,lpbinary:bbPROC_INFO)
	ReturnInfo[0]=-1
	ReturnInfo[1]=StrCat("CreateProcess failed. Errorcode = ",DllLastError())
	return(ReturnInfo)
endif

BinaryFree(bbSTARTINFO)
;restore saved STDOUT & STDERR (Win95/98/ME only)
If WinVersion(4)==5 ;If running on Win95/98/ME
	if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"SetStdHandle",long:STD_OUTPUT_HANDLE,long:hSaveStdout)
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("SetStdHandle failed (STDOUT). Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
	if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"SetStdHandle",long:STD_ERROR_HANDLE,long:hSaveStderr)
		ReturnInfo[0]=-1
		ReturnInfo[1]=StrCat("SetStdHandle failed (STDERR). Errorcode = ",DllLastError())
		return(ReturnInfo)
	endif
endif
ReturnInfo[0]=hChildStdoutRdDup			  ;handle to pipe
ReturnInfo[1]=BinaryPeek4(bbPROC_INFO,8) ;ProcessID
BinaryFree(bbPROC_INFO)

Return(ReturnInfo)

#EndFunction ;<<<<< udfRunRedirected >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#DefineFunction udfPipeDataWaiting(handle) ;<<<<< udfPipeDataWaiting >>>>>>>>>>>>>>>>>>>>>>>>>
;/////////////////////////////////////////////////////////////////////////////////////////////
;
;  Checks a pipe to see if there is DATA waiting to be read
;  Returns number of unread bytes in pipe or -1 if function failed (use DllLastError to determine the error)
;
;   handle = handle of pipe to check

bbNumBytesInBuffer=BinaryAlloc(4)
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"PeekNamedPipe",long:handle, lpnull, long:0, lpnull, lpbinary:bbNumBytesInBuffer, lpnull) then  Return(-1) 
BinaryEodSet(bbNumBytesInBuffer, 4)
BytesInPipe= BinaryPeek4(bbNumBytesInBuffer,0)
BinaryFree(bbNumBytesInBuffer)
Return (BytesInPipe)
#EndFunction ;<<<<< udfPipeDataWaiting >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#DefineFunction udfPipeReadLine(handle) ;<<<<< udfPipeReadLine >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;/////////////////////////////////////////////////////////////////////////////////////////////
;
;  Read a line from child's stdout
;  Returns one line of data from pipe if CR or LF found, else returns remaining data in pipe (or -1 on failure)
;
;   handle = handle of pipe to check

readLine=""

;Get number of bytes in Pipe
bbNumBytesInPipe=BinaryAlloc(4)
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"PeekNamedPipe",long:handle, lpnull, long:0, lpnull, lpbinary:bbNumBytesInPipe, lpnull)
	return(-1)
endif
BinaryEodSet(bbNumBytesInPipe, 4)
BytesInPipe= BinaryPeek4(bbNumBytesInPipe,0)
BinaryFree(bbNumBytesInPipe)

;Copy contents of pipe into binary buffer
bb=BinaryAlloc(BytesInPipe)
bbRead=BinaryAlloc(4)
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"PeekNamedPipe",long:handle, lpbinary:bb, long:BytesInPipe, lpbinary:bbRead, lpnull, lpnull)
	return(-1)
endif
BinaryEodSet(bbRead, 4)
BytesRead= BinaryPeek4(bbRead,0)
BinaryEodSet(bb, BytesRead)
BinaryFree(bbRead)

;find EOL (end of line)
eol=BinaryIndexEx(bb, 0, @CR, @FWDSCAN, 0) 
if eol==-1
	eol=BinaryIndexEx(bb, 0, @LF, @FWDSCAN, 0)
   if eol==-1
		eol=BytesRead ;if no EOL character, get ALL remaining data in pipe
	else
		eol=eol+1 ;since BinaryIndexEx returns 0 based index
	endif 
else
	if BinaryIndexEx(bb, eol, @LF, @FWDSCAN, 0)==1 then eol=eol+1 ;if linefeed after carraige return, we want to remove it from pipe too
	eol=eol+1 ;since BinaryIndexEx returns 0 based index
endif
BinaryFree(bb)

;Read one line of data from Pipe
bbReadLine=BinaryAlloc(BytesRead)
bbBytesRead=BinaryAlloc(4)
if !DllCall(StrCat(DirWindows(1),"kernel32.dll"),long:"ReadFile",long:handle, lpbinary:bbReadLine, long:eol, lpbinary:bbBytesRead, long:0) then return(-1)
BinaryEodSet(bbBytesRead, 4)
length=BinaryPeek4(bbBytesRead,0)
BinaryEodSet(bbReadLine, length)
readLine=BinaryPeekStr(bbReadLine, 0, length)
BinaryFree(bbReadLine)
BinaryFree(bbBytesRead)

;Standardize all EOL characters
readLine=StrReplace(readline, @CR, "")
readline=StrReplace(readline, @LF, "")
readLine=StrCat(readLine,@CRLF)

return(readline)

#EndFunction ;<<<<< udfPipeReadLine >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


RedirectionExample.wbt

;=============================================================================================
;= RedirectionExample.wbt
;= Example program for demonstrating the use of the udflib.redirection.wbt library
;=
;= Coded in WinBatch by GUI Guy, August 2002  (http://guiguy.wminds.com)
;=============================================================================================

;Change the path below to reflect where you placed the library on your system
#include "Redirection UDF.wbt"

;Dynamic dialog constants
DIALOG_INIT =       0
DIALOG_TIMERTICK =  1
DIALOG_PUSH =       2
DIALOG_RADIO =      3
DIALOG_CHECK =      4
DIALOG_EDIT =       5
DIALOG_FILESEL =    6
DIALOG_ITEMSEL =    7
DIALOG_ITEMCHANGE = 8
DIALOG_DATECHANGE = 9
DIALOG_NUMCHANGE = 10
DIALOG_CLOSE =     11

#DEFINESUBROUTINE procRedirEx(DialogHandle, EventCode, ControlNum, Res4, Res5)

oncancel="exit"
switch(EventCode)

   case DIALOG_INIT
   	DialogProcOptions(DialogHandle, DIALOG_PUSH, 1)
   	DialogProcOptions(DialogHandle, DIALOG_EDIT, 1)
	 	break

   case DIALOG_PUSH
      if  ControlNum == 5 ;Browse
         gosub Browse
			DialogControlSet(DialogHandle,  10, 4, StrCat(edtApp," ",edtParams))
         return -2
      endif
      if ControlNum == 11 ;Run
			gosub RunRedirected
			return -2
      endif
		if ControlNum == 12 ;Exit
			return 99
		endif
		break

   case DIALOG_EDIT
		DialogControlSet(DialogHandle,  10, 4, StrCat(DialogControlGet(DialogHandle,4,3)," ",DialogControlGet(DialogHandle,8,3)))
		break

	case DIALOG_TIMERTICK
		while udfPipeDataWaiting(Pipe_Info[0]) > 0
			ReadLine=udfPipeReadLine(Pipe_Info[0])
			if ReadLine == -1
				Message("Error (udfReadLine):",DLLLastError())
				exit
			endif
			newOutput=StrCat(newOutput,ReadLine)
			DialogControlSet(DialogHandle,1,3, newOutput)
		endwhile
		if !WinExist(title) then DialogProcOptions(DialogHandle, DIALOG_TIMERTICK, 0)  ;if child has exited, then turn off timer event
		return -1
		break

endswitch

return -1

:browse
oncancel="goto bresume"
temp=edtApp
edtApp=AskfileName("Select the DOS program to run redirected...", "", "Executable Files (*.exe,*.com)|*.exe;*.com|All Files (*.*)|*.*|", edtApp, 2)
:bresume
if edtApp=="0" then edtApp = temp
DialogControlSet(DialogHandle,  4, 3, edtApp)
return

:RunRedirected
if DialogControlGet(DialogHandle,4,3) != ""
	if !FileExist(DialogControlGet(DialogHandle,4,3)) 
		message("Oops","Specified program doesn't exist...")
	else	
		params=DialogControlGet(DialogHandle,8,3)
		Pipe_Info=udfRunRedirected(DialogControlGet(DialogHandle,4,3), params)
		DialogProcOptions(DialogHandle, DIALOG_TIMERTICK, 1) ;timer event every 1/4 second
		newoutput=""
		delay(.125)
		title = WinItemProcId(Pipe_Info[1], 2|8, 0) ;get title of DOS window launched above
	endif
endif
return

:cancel ; CANCEL Handler
%oncancel%
exit
#ENDSUBROUTINE

dlgRedirExFormat=`WWWDLGED,6.1`

dlgRedirExCaption=`Redirection Example Dialog`
dlgRedirExX=-01
dlgRedirExY=-01
dlgRedirExWidth=240
dlgRedirExHeight=157
dlgRedirExNumControls=012
dlgRedirExProcedure=`procRedirEx`
dlgRedirExFont=`DEFAULT`
dlgRedirExTextColor=`DEFAULT`
dlgRedirExBackground=`DEFAULT,DEFAULT`

dlgRedirEx001=`006,079,225,067,MULTILINEBOX,medtOutput,DEFAULT,DEFAULT,12,8,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx002=`001,071,233,080,GROUPBOX,DEFAULT,"Redirected output:",DEFAULT,11,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx003=`001,001,233,057,GROUPBOX,DEFAULT,"Command-line program to run with redirected STDOUT && STDERR:",DEFAULT,1,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx004=`031,012,161,011,EDITBOX,edtApp,DEFAULT,DEFAULT,2,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx005=`196,012,035,011,PUSHBUTTON,DEFAULT,"Browse",1,3,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx006=`006,014,023,010,STATICTEXT,DEFAULT,"Program:",DEFAULT,7,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx007=`006,030,063,010,STATICTEXT,DEFAULT,"Parameters:",DEFAULT,8,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx008=`071,028,160,011,EDITBOX,edtParams,DEFAULT,DEFAULT,4,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx009=`001,039,233,019,GROUPBOX,DEFAULT,DEFAULT,DEFAULT,9,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx010=`006,047,225,011,STATICTEXT,DEFAULT,DEFAULT,DEFAULT,10,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx011=`158,062,034,010,PUSHBUTTON,DEFAULT,"Run",2,5,32,DEFAULT,DEFAULT,DEFAULT`
dlgRedirEx012=`196,062,035,010,PUSHBUTTON,DEFAULT,"Exit",0,6,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("dlgRedirEx")


exit

Some Modifications to UDF_Redirection.wbt

I don't presently have a need to continuously monitor a stdout program, which is the real magic of udflib_redirection.wbt (script above).

But I did notice how slickly it packages the output. No pif files, no temp files to hold output text. Really tidy.

So here's my attempt to simplify the RunRedirected idea for when you are willing to simply wait to get all your output at once. One call runs the command and returns the output.

#include "udflib_redirection.wbt"

#definefunction udfSimpleRunRedirected(app, params, maxtime, maxchars)
;      app is executeable program
;   params is parameter string for app
;  maxtime is seconds to spend waiting for completion
; maxchars is maximum chars to accept for return data
;
; return is array:  [0] is status, 1=success, -1=fail inside runredirected, -2=out of time
;                   [1] output data string
;
    arrStat = udfRunRedirected(app, params)
    if arrstat[0] < 0 then return arrStat

    incr = 0.25 ; granularity of delay
    buf = ""
    while 1
      ; grab window (if still there)
      pid = WinItemProcId(arrStat[1],2|8,0)

      ; loop for any data remaining in the pipe
      while strlen(buf)
        gosub piperead
        if bit == "*ERR*" then goto errorret
        if bit == "*EOF*" then break
        buf = strcat(buf, bit)
      endwhile
  
      ; was window gone?
      if pid == "" || pid == 0
        arrStat[0] = 1
        arrStat[1] = buf
        return arrStat
      endif

      ; decrement wait time
      maxtime = maxtime - incr
      if maxtime < 0
        arrStat[0] = -2
        arrStat[1] = buf
        return arrStat
      endif

      ; snooze
      timedelay(incr)
    endwhile  
    x=1/0

  :errorret
      arrStat[0] = -3
      arrStat[1] = DllLastError()
      return arrStat

  :piperead ;--- subroutine ---
      bit = "" ; return data in here
      handle = arrStat[0]
      k32dll = StrCat(DirWindows(1),"kernel32.dll")
      ;Get number of bytes in Pipe
      bbBytesInPipe = BinaryAlloc(4)
      if !DllCall(k32dll,long:"PeekNamedPipe",long:handle, lpnull, long:0, lpnull, lpbinary:bbBytesInPipe, lpnull)
        bit = "*ERR*"
        return 
      endif
      BinaryEodSet(bbBytesInPipe, 4)
      BytesInPipe = BinaryPeek4(bbBytesInPipe, 0)
      BinaryFree(bbBytesInPipe)
      ;nothing? were done
      if BytesInPipe == 0
        bit = "*EOF*"
        return 
      endif
      ;set to read remainder needed
      BytesToRead = Min(BytesInPipe,maxchars-strlen(buf))
      ;Get pipe contents
      bbBit = BinaryAlloc(BytesToRead)
      bbBytesRead = BinaryAlloc(4)
      if !DllCall(k32dll,long:"ReadFile",long:handle, lpbinary:bbBit, long:BytesToRead, lpbinary:bbBytesRead, long:0)
        bit = "*ERR*"
        return 
      endif
      BinaryEodSet(bbBytesRead, 4)
      length = BinaryPeek4(bbBytesRead, 0)
      BinaryEodSet(bbBit, length)
      bit = BinaryPeekStr(bbBit, 0, length)
      BinaryFree(bbBit)
      BinaryFree(bbBytesRead)
      return

#endfunction


a = udfSimpleRunRedirected("command.com","/c dir c:\*.dll /s",5,65535)

a[1] = strreplace(a[1],@crlf,@lf)
askitemlist(a[0],a[1],@lf,@unsorted,@single)

exit

Another User's Note:

a = udfSimpleRunRedirected("command.com","/c dir c:\*.dll /s /-p",5,65535)
... runs a little bit more 'continous' ...
Article ID:   W15729
File Created: 2014:07:18:09:51:40
Last Updated: 2014:07:18:09:51:40