Hi,
Has anyone ever captured the output of a cmd process and put it into a window? Does anyone have any code?
Thanks
Ron
Hi,
Has anyone ever captured the output of a cmd process and put it into a window? Does anyone have any code?
Thanks
Ron
I was trying to paste this thread, but failed. Here’s another try. Using WriteConsoleA from a Clarion application - #8 by mriffey
Also, Capesoft’s Oddjob works well for capturing a commandline output.
Thanks Jeff. I will check it out an see if this will work. I am not trying to capture the output from the command line and just display it. I was thinking of using CreateProcess and running cmd and then read stdout. I just wonder the best way to get the data into a window. Not looking to purchase a solution. Always looking to learn more.
Wow, long time no see.
I’ve been around. Just very busy. A lot of my new work is Laravel (php) and python. Just trying to do some Clarion work and merge Laravel and Clarion hence getting information back from php commands.
Ron, I have an old ClarionMag article that includes a class to do this. I’ll see if I can track down a link.
Also, if you have OddJob from Capesoft there is a method to do what you want.
I think KSS captures Std Out when it runs FindStr.
The source is on GitHub under Devuna.
I have an older one on mine that has the routines converted to a class. It does not have any third party products.
Robert Artigas has it on his GitHub setup to be easy to build.
The article is called ‘Capturing Standard Output From A Console Program’ and is in the ClarionMag cmag-2008-01.pdf and cmag-2008-01.zip (source code) that you can still access on the Jira ClarionMag archive here…
Thanks for tracking that down, @Graham_Dawson
Here is working code. Took it from a lot of sources. Thanks everyone.
Test2 PROCEDURE ! Declare Procedure
szCmdLine CSTRING(261)
laravelPath CSTRING(261)
currentDirectory CSTRING(261)
saAttr LIKE(SECURITY_ATTRIBUTES)
hStdInPipeRead HANDLE
hStdInPipeWrite HANDLE
hStdOutPipeRead HANDLE
hStdOutPipeWrite HANDLE
hStdErrPipeWrite HANDLE
siStartInfo LIKE(STARTUPINFO)
bSuccess BOOL
chBuf CSTRING(128)
dwRead DWORD
Window WINDOW('Caption'),AT(,,260,141),GRAY,FONT('Segoe UI',9),TIMER(10)
TEXT,AT(2,2,255,137),USE(?OutputText)
END
CODE ! Begin processed code
szCmdLine = 'php artisan bulloch:setx-activate 9998'
laravelPath = GETINI('Laravel','Application Path','','.\cmdbox.INI')
IF laravelPath = ''
DO ProcedureReturn
END
saAttr.nLength = SIZE(SECURITY_ATTRIBUTES)
saAttr.lpSecurityDescriptor = 0
saAttr.bInheritHandle = TRUE
IF NOT CreatePipe(hStdOutPipeRead, hStdOutPipeWrite, saAttr, 0)
DO ProcedureReturn
END
IF NOT SetHandleInformation(hStdOutPipeRead, HANDLE_FLAG_INHERIT, 0)
DO ProcedureReturn
END
IF NOT DuplicateHandle(GetCurrentProcess(),hStdOutPipeWrite,GetCurrentProcess(),hStdErrPipeWrite,0,TRUE,DUPLICATE_SAME_ACCESS)
DO ProcedureReturn
END
IF NOT CreatePipe(hStdInPipeRead, hStdInPipeWrite, saAttr, 0)
DO ProcedureReturn
END
IF NOT SetHandleInformation(hStdInPipeWrite, HANDLE_FLAG_INHERIT, 0)
DO ProcedureReturn
END
ZeroMemory(ADDRESS(siStartInfo),SIZE(STARTUPINFO))
siStartInfo.cb = SIZE(STARTUPINFO);
siStartInfo.dwFlags = BOR(siStartInfo.dwFlags,STARTF_USESTDHANDLES)
siStartInfo.hStdError = hStdErrPipeWrite
siStartInfo.hStdOutput = hStdOutPipeWrite
siStartInfo.hStdInput = hStdInPipeRead
siStartInfo.dwFlags = BOR(siStartInfo.dwFlags,STARTF_USESHOWWINDOW)
siStartInfo.wShowWindow = SW_HIDE
ZeroMemory(ADDRESS(piProcInfo), SIZE(PROCESS_INFORMATION))
CurrentDirectory = PATH()
SETPATH(laravelPath)
bSuccess = CreateProcess( |
0, | ! application name
szCmdline, | ! command line
0, | ! process security attributes
0, | ! primary thread security attributes
TRUE, | ! handles are inherited
0, | ! creation flags
0, | ! use parents environment
0, | ! The full path to the current directory for the process.
siStartInfo, | ! STARTUPINFO pointer
piProcInfo | ! receives PROCESS_INFORMATION
)
SETPATH(CurrentDirectory)
IF bSuccess = FALSE
DO ProcedureReturn
END
CloseHandle(hStdOutPipeWrite)
CloseHandle(hStdInPipeRead)
CloseHandle(hStdErrPipeWrite)
OPEN(Window)
ACCEPT
CASE EVENT()
OF EVENT:Timer
bSuccess = ReadFile(hStdOutPipeRead,ADDRESS(chBuf),128,ADDRESS(dwRead),0)
IF NOT bSuccess OR dwRead = 0
0{PROP:Timer} = 0
BREAK
END
chBuf[dwRead + 1] = '<00>'
?OutputText{PROP:Text} = ?OutputText{PROP:Text} & chBuf
DISPLAY(?OutputText)
END
END
CLOSE(Window)
!bSuccess = ReadFile(hStdOutPipeRead,ADDRESS(buf),128,ADDRESS(dwRead),0)
!LOOP WHILE bSuccess = TRUE
! buf[dwRead + 1] = '<00>'
! MESSAGE(buf)
! bSuccess = ReadFile(hStdOutPipeRead,ADDRESS(buf),128,ADDRESS(dwRead),0)
!END
CloseHandle(hStdOutPipeRead)
CloseHandle(hStdInPipeWrite)
DO ProcedureReturn
!---------------------------------------------------------------------------
ProcedureReturn ROUTINE
RETURN
!---------------------------------------------------------------------------
PROGRAM
MAP
END
Command1 CSTRING(100)
Text1 CSTRING(10000)
QuickWindow WINDOW('Test 1'),AT(,,500,329),CENTER,GRAY,IMM,SYSTEM,FONT('MS Sans Serif',8,,FONT:regular),COLOR(0F8FFFDH)
TEXT,AT(25,75,449,228),USE(Text1),SKIP,VSCROLL,FONT('Consolas')
ENTRY(@s100),AT(72,33,402,11),USE(Command1),FONT('Consolas',10)
BUTTON('Run command'),AT(25,50,78),USE(?Button:Run),SKIP
PROMPT('Command:'),AT(25,34),USE(?Prompt:Command1)
END
CODE
OPEN(QuickWindow)
ACCEPT
IF EVENT() = EVENT:Accepted
RUN('Test1.bat ' & Command1, 1)
Text1 = CLIPBOARD(1)
DISPLAY(?Text1)
END
END
Above is a little program that puts the output of a cmd into a window.
Here is the Test1.bat file referenced:
@echo off
rem echo %1 %2 %3 %4
%1 %1 %2 %3 %4 | CLIP
For example, enter a command, DIR *.exe, and see the output in a window.
Bob
An alternative to using | CLIP
for the Clipboard would be Redirection > to a File. Then use the ASCII BASIC DOS driver to read that file, or StringTheory.
That would have a batch file like this:
@echo off
rem echo %1 %2 %3 %4
rem Write [Failed] to the file so if fails to run we have a way to tell
echo [Failed] > TestResult.TXT
%1 %1 %2 %3 %4 > TestResult.TXT
Instead of always > TestResult.TXT
I would pass the output name in the Clarion RUN as a parameter so it could be unique per user and run instance. I would probably have it in the Temp folder using GetTempFileNameA
Also in Clarion I would write [Failed] to that file so should the RUN not work I’ll know, there will be no chance of stale or invalid data. I would do the same in your code before Run e.g. SetClipboard('Failed]')
Good suggestions. Thanks Carl.
I’ll give it a try.
I think I can put >> in the RUN command line and not use a bat file.
The RUN command doesn’t seem to treat the stile character as DOS piping character.
On another note, I hope Clarion will someday have a driver to get the output of a PowerShell command. Z talked about this at CIDC 2024.
Bob
One nice thing about the code I posted that for long processes, the output to the screen will progress as the command does. Good feedback.