What's the best way to run a command line program from a Windows program and display the output of the program to a Windows control ( like an edit control or something ). I want to run a command line program "in the background" but show the output in "real time" as though it were part of the main Windows program. An examples of how to do this? Thanks for any information.
Create pipes for the std handles you want to deal with - minimally one for stdout+stderr;
Start your sub-process with CreateProcess, with the pipe handles in the STARTUPINFO structure.
The process runs, readfile its output on the pipe(s), do whatever..
Check the process has finished (WaitForSingleObject), close the pipes, clean up.
Hi cman,
You can check Iczelion's tutorial #21. It provides a nice example demonstrating the capture of command line output.
Here is a template to do that:
Quote
;useful to execute dos or windows proc
.data
SecuAttr SECURITY_ATTRIBUTES <>
startInfo STARTUPINFO <> ;structure API CreateProcess
processInfo PROCESS_INFORMATION <> ;structure API
hRead dd 0
hWrite dd 0
retourligne db 13,10,0
Pipetampon db 500h dup (0)
bytesRead dd 0
Hfile dd 0
NumberOfBytesWritten dd 0
dumpbinexe db "\masm32\bin\ml.exe /?",0
;################################################################
CreationPipe PROC
Local retour:DWORD
mov retour,0
mov SecuAttr.nLength,sizeof SECURITY_ATTRIBUTES
mov SecuAttr.bInheritHandle,TRUE
;lea edx,SecuAttr.lpSecurityDescriptor
;invoke InitializeSecurityDescriptor,edx,SECURITY_DESCRIPTOR_REVISION
invoke CreatePipe,addr hRead,addr hWrite,addr SecuAttr,NULL
mov retour,eax
mov startInfo.cb,sizeof startInfo
;retrouve les informations a la creation du prog
invoke GetStartupInfo,addr startInfo
xor eax,eax
mov startInfo.lpReserved,eax ;null avant d'appeler CreateProcess
mov eax,hWrite
mov startInfo.hStdOutput,eax
mov startInfo.hStdError,eax
mov startInfo.dwFlags,STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES
mov startInfo.wShowWindow,SW_SHOW
;invoke CloseHandle,hWrite ;made test here
;---------- close it later if not work -------------------------------
FindeCreationPipe:
mov eax,retour
ret
CreationPipe endp
;################################################################
start:
;......
invoke CreationPipe
invoke CreateProcess,NULL,addr dumpbinexe,NULL,NULL,TRUE,NULL,NULL,NULL,\
addr startInfo,addr processInfo
lecture:
; si hread déclaré avec FILE_FLAG_OVERLAPPED,dernière donnée structure
;lpSecurityDescriptor de SECURITY_ATTRIBUTES
invoke ReadFile,hRead,addr Pipetampon,sizeof Pipetampon - 1,addr bytesRead,NULL
.if eax != 0
;invoke WriteFile,Hfile,addr Pipetampon,bytesRead,addr NumberOfBytesWritten,NULL
jmp lecture
.endif
invoke CloseHandle,hRead
;.......
Take care when closing handles
And here is a sample who read the ml help output and write it in a file:
Quote
.NOLIST ;signifie: ne rien mettre dans le listing
include \masm32\include\masm32rt.inc
InitInstance PROTO :DWORD
.const
.data
hInstance dd 0
;InitCtrls INITCOMMONCONTROLSEX <sizeof INITCOMMONCONTROLSEX,0> ;commctrl.sdk
;FindFileData WIN32_FIND_DATA <>
;------------------- pipe data ----------------------------------------
SecuAttr SECURITY_ATTRIBUTES <>
startInfo STARTUPINFO <> ;structure API CreateProcess
processInfo PROCESS_INFORMATION <> ;structure API
hRead dd 0
hWrite dd 0
retourligne db 13,10,0
Pipetampon db 500h dup (0)
bytesRead dd 0
Hfile dd 0
NumberOfBytesWritten dd 0
dumpbinexe db "\masm32\bin\ml.exe /?",0
Nomfichier db "ML_help.txt",0
;------------------- end pipe data --------------------------------------
.code
;################################################################
CreationPipe PROC
Local retour:DWORD
mov retour,0
mov SecuAttr.nLength,sizeof SECURITY_ATTRIBUTES
mov SecuAttr.bInheritHandle,TRUE
;lea edx,SecuAttr.lpSecurityDescriptor
;invoke InitializeSecurityDescriptor,edx,SECURITY_DESCRIPTOR_REVISION
invoke CreatePipe,addr hRead,addr hWrite,addr SecuAttr,NULL
mov retour,eax
mov startInfo.cb,sizeof startInfo
;retrouve les informations a la creation du prog
invoke GetStartupInfo,addr startInfo
xor eax,eax
mov startInfo.lpReserved,eax ;null avant d'appeler CreateProcess
mov eax,hWrite
mov startInfo.hStdOutput,eax
mov startInfo.hStdError,eax
mov startInfo.dwFlags,STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES
mov startInfo.wShowWindow,SW_SHOW
;invoke CloseHandle,hWrite ;inutile
FindeCreationPipe:
mov eax,retour
ret
CreationPipe endp
;################################################################
start:
invoke InitInstance,1
;---- code here --------
invoke CreationPipe
invoke CreateProcess,NULL,addr dumpbinexe,NULL,NULL,TRUE,NULL,NULL,NULL,\
addr startInfo,addr processInfo
invoke CloseHandle,hWrite
lecture:
; if hread declared with FILE_FLAG_OVERLAPPED,last readfile data is a structure
;lpSecurityDescriptor de SECURITY_ATTRIBUTES
invoke ReadFile,hRead,addr Pipetampon,sizeof Pipetampon - 1,addr bytesRead,NULL
.if eax != 0
invoke WriteFile,Hfile,addr Pipetampon,bytesRead,addr NumberOfBytesWritten,NULL
jmp lecture
.endif
;invoke CloseHandle,hWrite
invoke CloseHandle,hRead
invoke InitInstance,0
invoke ExitProcess,0
;hInstance dd 0
;InitCtrls INITCOMMONCONTROLSEX <> ;include commctrl.sdk
;init=1,desinit=0
;################################################################
InitInstance PROC init:DWORD
Local retour:DWORD
mov retour,1
.if init == 1
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke CreateFile,addr Nomfichier,GENERIC_WRITE,NULL,\
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
mov Hfile,eax
.else
invoke CloseHandle,Hfile
.endif
FindeInitInstance:
mov eax,retour
ret
InitInstance endp
;################################################################
end start
For the lazy assembly coder:
Launch "SendStringsToConsole.exe", SW_MINIMIZE, cb:hEdit
P.S.: Under the hood, a slightly modified version of the MSDN example (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx) is working. Read the user comments...!
i am really lazy, i guess - lol
INVOKE AllocConsole
you can left click anywhere in the window to see some console text :P
my mistake - i misread the original post
Wow , thanks for your input , everyone! :t