CJ_S
asked on
Console output
I am trying to redirect the output generated by the console window to a file, and read it out. the following is what I have so far, and it works. It just does not write out the command to the file. Can anybody help me out a bit, it's probably just a small thing...
Private Const NORMAL_PRIORITY_CLASS = &H20
Private Const STARTF_USESTDHANDLES = &H100
Private Const STARTF_USESHOWWINDOW = &H1
Private Const STILL_ACTIVE = &H103
Private Const CREATE_NEW_CONSOLE = &H10
Private Const INFINITE = &HFFFF
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const CREATE_ALWAYS = 2
Private Const CREATE_NEW = 1
Private Const OPEN_ALWAYS = 4
Private Const OPEN_EXISTING = 3
Private Const TRUNCATE_EXISTING = 5
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_HIDDEN = &H2
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_ATTRIBUTE_READONLY = &H1
Private Const FILE_ATTRIBUTE_SYSTEM = &H4
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const FILE_FLAG_NO_BUFFERING = &H20000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Private Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Private Const FILE_FLAG_WRITE_THROUGH = &H80000000
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Private Declare Function DeleteFile Lib "kernel32" Alias "DeleteFileA" (ByVal lpFileName As String) As Long
Private Declare Function lread Lib "kernel32" Alias "_lread" (ByVal hFile As Long, lpBuffer As Any, ByVal wBytes As Long) As Long
Private Declare Function lopen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long
Private Declare Function lclose Lib "kernel32" Alias "_lclose" (ByVal hFile As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Function StartProcess(ByVal sProgram As String) As String
Dim stInfo As STARTUPINFO
Dim prInfo As PROCESS_INFORMATION
Dim sTmpFile As String
sTmpFile = App.Path & "\test2.cof"
stInfo.cb = Len(stInfo)
stInfo.lpReserved = vbNull
stInfo.wShowWindow = 5
stInfo.cbReserved2 = 0
stInfo.lpReserved2 = vbNull
stInfo.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
Dim hFile As Long
hFile = CreateFile(sTmpFile, GENERIC_READ Or GENERIC_WRITE, 0, ByVal CLng(0), CREATE_ALWAYS, 0, ByVal CLng(0))
If hFile Then
stInfo.hStdOutput = hFile
End If
Dim ret As Long, ExitCode As Long, lProcessTime As Long
lProcessTime = 0
ret = CreateProcess(sProgram, vbNullString, ByVal CLng(0), ByVal CLng(0), True, CREATE_NEW_CONSOLE, ByVal CLng(0), vbNullString, stInfo, prInfo)
If (ret = 0) Then MsgBox "Not created!"
Do
GetExitCodeProcess prInfo.hProcess, ExitCode
lProcessTime = lProcessTime + 500
Sleep 500 '1000 = 1 second.
If (lProcessTime > 20000) Then
MsgBox "Processing exceeds time limit!"
GoTo closeHandler
End If
Loop While ExitCode = STILL_ACTIVE
CloseHandle prInfo.hProcess
If hFile Then
Dim numOfBytes As Long
Dim buf
numOfBytes = GetFileSize(hFile, ByVal 0&)
CloseHandle (hFile)
If (numOfBytes >= 0) Then
buf = String(numOfBytes, "*")
hFile = lopen(sTmpFile, 0)
lread hFile, buf, numOfBytes
lclose (hFile)
' Returns
StartProcess = buf
End If
'DeleteFile (sTmpFile)
End If
Exit Function
closeHandler:
End Function
Public Function DoCommand(ByVal sCommand As String) As String
MsgBox StartProcess("c:\winnt\sys tem32\ping .exe")
End Function
Private Const NORMAL_PRIORITY_CLASS = &H20
Private Const STARTF_USESTDHANDLES = &H100
Private Const STARTF_USESHOWWINDOW = &H1
Private Const STILL_ACTIVE = &H103
Private Const CREATE_NEW_CONSOLE = &H10
Private Const INFINITE = &HFFFF
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const CREATE_ALWAYS = 2
Private Const CREATE_NEW = 1
Private Const OPEN_ALWAYS = 4
Private Const OPEN_EXISTING = 3
Private Const TRUNCATE_EXISTING = 5
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_HIDDEN = &H2
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_ATTRIBUTE_READONLY = &H1
Private Const FILE_ATTRIBUTE_SYSTEM = &H4
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const FILE_FLAG_NO_BUFFERING = &H20000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Private Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Private Const FILE_FLAG_WRITE_THROUGH = &H80000000
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Private Declare Function DeleteFile Lib "kernel32" Alias "DeleteFileA" (ByVal lpFileName As String) As Long
Private Declare Function lread Lib "kernel32" Alias "_lread" (ByVal hFile As Long, lpBuffer As Any, ByVal wBytes As Long) As Long
Private Declare Function lopen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long
Private Declare Function lclose Lib "kernel32" Alias "_lclose" (ByVal hFile As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Function StartProcess(ByVal sProgram As String) As String
Dim stInfo As STARTUPINFO
Dim prInfo As PROCESS_INFORMATION
Dim sTmpFile As String
sTmpFile = App.Path & "\test2.cof"
stInfo.cb = Len(stInfo)
stInfo.lpReserved = vbNull
stInfo.wShowWindow = 5
stInfo.cbReserved2 = 0
stInfo.lpReserved2 = vbNull
stInfo.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
Dim hFile As Long
hFile = CreateFile(sTmpFile, GENERIC_READ Or GENERIC_WRITE, 0, ByVal CLng(0), CREATE_ALWAYS, 0, ByVal CLng(0))
If hFile Then
stInfo.hStdOutput = hFile
End If
Dim ret As Long, ExitCode As Long, lProcessTime As Long
lProcessTime = 0
ret = CreateProcess(sProgram, vbNullString, ByVal CLng(0), ByVal CLng(0), True, CREATE_NEW_CONSOLE, ByVal CLng(0), vbNullString, stInfo, prInfo)
If (ret = 0) Then MsgBox "Not created!"
Do
GetExitCodeProcess prInfo.hProcess, ExitCode
lProcessTime = lProcessTime + 500
Sleep 500 '1000 = 1 second.
If (lProcessTime > 20000) Then
MsgBox "Processing exceeds time limit!"
GoTo closeHandler
End If
Loop While ExitCode = STILL_ACTIVE
CloseHandle prInfo.hProcess
If hFile Then
Dim numOfBytes As Long
Dim buf
numOfBytes = GetFileSize(hFile, ByVal 0&)
CloseHandle (hFile)
If (numOfBytes >= 0) Then
buf = String(numOfBytes, "*")
hFile = lopen(sTmpFile, 0)
lread hFile, buf, numOfBytes
lclose (hFile)
' Returns
StartProcess = buf
End If
'DeleteFile (sTmpFile)
End If
Exit Function
closeHandler:
End Function
Public Function DoCommand(ByVal sCommand As String) As String
MsgBox StartProcess("c:\winnt\sys
End Function
Debugging shows that a valid file handle is created and output should be redirected to that file, yes? What OS are you running?
ASKER
I am running Windows 2000 Advanced Server.
I too found nothing that could be the problem. I also tried it with CreatePipe, but that won't work either...
CJ
I too found nothing that could be the problem. I also tried it with CreatePipe, but that won't work either...
CJ
Yea, I think I tried very similar code to the above using the sample at VB2theMax by Dino Esposito:
"Capturing the Output of a MS-DOS Program"
http://www.vb2themax.com/HtmlDoc.asp?Table=Articles&ID=40
It didnt work, and I emailed him. He claimed he could offer no support for why it did not work on my machine (Windows 2000 Professional). I don't know what has been altered with the OS, but it looks like it may be the problem. I got around it using another method (can't recall off hand what it was right now), but I will look through my files when I get home and see if I can find it.
"Capturing the Output of a MS-DOS Program"
http://www.vb2themax.com/HtmlDoc.asp?Table=Articles&ID=40
It didnt work, and I emailed him. He claimed he could offer no support for why it did not work on my machine (Windows 2000 Professional). I don't know what has been altered with the OS, but it looks like it may be the problem. I got around it using another method (can't recall off hand what it was right now), but I will look through my files when I get home and see if I can find it.
ASKER
I'd appreciate that very much!
CJ
CJ
It probably has some bugs, but hopefully its enough to go on, and is commented well enough for you to understand. It was written specifically to work on Win2k so if you're looking for cross OS functionality, it'll need a little tweaking. Any questions, let me know. It was written as a class:
Option Explicit
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA" (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As String) As Long
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal lBuffer As Long) As Long
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const STATUS_PENDING = &H103&
Private Const MAX_PATH = 260
Public Enum OMETHOD
None = 0
ToFile = 1
ReturnString = 2
End Enum
'************************* ********** ********** ********** ********** ********** ******
'Function Name : Execute
'Purpose : Execute command line functions
'
'Parameters : ProgramPath - path to program (leave blank for DOS commands)
' CommandLineParameters - any parameters to be passed to program
' (for DOS commands place entire string here)
' WaitForTermination - wait for completion of command before
' returning back to calling app
' OutputMethod - method by which output is to be rendered
' OutputPath - path of file to write output to
'
'Return Values : string of output if specified
'************************* ********** ********** ********** ********** ********** ******
Public Function Execute(ProgramPath As String, _
Optional CommandLineParameters As String = "", _
Optional WaitForTermination As Boolean = False, _
Optional OutputMethod As OMETHOD = None, _
Optional OutputPath As String = "") As String
Dim lret As Long
Dim lFile As Long
Dim hProc As Long
Dim exitCode As Long
Dim strBuff As String
Dim strTempFile As String
Dim strFullCommand As String
'if redirect to file and no output file is specified, change to return string
If OutputMethod = ToFile And Trim$(OutputPath) = "" Then OutputMethod = ReturnString
If OutputMethod = ReturnString Then
OutputPath = GetTempFile
End If
'create the temp file
If OutputMethod <> None Then
lFile = FreeFile
Open OutputPath For Output As #lFile
Close #lFile
'convert path to short path
OutputPath = GetShortPath(OutputPath)
End If
'get the short path to the program
ProgramPath = GetShortPath(ProgramPath)
'create the full command line string
strFullCommand = " /c " & LTrim$(ProgramPath) & " " & LTrim$(CommandLineParamete rs)
'create the process
If OutputMethod = None Then
lret = Shell(Environ("COMSPEC") & strFullCommand, vbHide)
Else
lret = Shell(Environ("COMSPEC") & strFullCommand & " > " & OutputPath, vbHide)
End If
'if option to wait, then wait
If lret And WaitForTermination Then
hProc = OpenProcess(PROCESS_QUERY_ INFORMATIO N, False, lret)
Do
Call GetExitCodeProcess(hProc, exitCode)
DoEvents
Loop While exitCode = STATUS_PENDING
Call CloseHandle(hProc)
End If
'return string if applicable
If OutputMethod = ReturnString Then
lFile = FreeFile
Open OutputPath For Binary As #lFile
strBuff = Space$(LOF(lFile))
Get #lFile, , strBuff
Close #lFile
'kill the temp file
Kill OutputPath
Execute = strBuff
End If
End Function
Private Function GetTempFile() As String
Dim strTempFile As String
Dim strTempFolder As String
Dim ret As Long
strTempFile = Space$(MAX_PATH)
'
'find the temporary folder
'
strTempFolder = Space$(MAX_PATH)
ret = GetTempPath(MAX_PATH, strTempFolder)
strTempFolder = Left$(strTempFolder, ret)
'
'create the temp file
'
ret = GetTempFileName(strTempFol der, "EXE", 0, strTempFile)
If ret <> 0 Then
strTempFile = Left$(strTempFile, InStr(1, strTempFile, Chr$(0)) - 1)
GetTempFile = strTempFile
End If
End Function
Private Function GetShortPath(strFileName As String) As String
Dim lpos As Long
Dim strPath As String
strPath = Space$(255)
lpos = GetShortPathName(strFileNa me, strPath, Len(strPath))
GetShortPath = Left$(strPath, lpos)
End Function
Option Explicit
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA" (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As String) As Long
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal lBuffer As Long) As Long
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const STATUS_PENDING = &H103&
Private Const MAX_PATH = 260
Public Enum OMETHOD
None = 0
ToFile = 1
ReturnString = 2
End Enum
'*************************
'Function Name : Execute
'Purpose : Execute command line functions
'
'Parameters : ProgramPath - path to program (leave blank for DOS commands)
' CommandLineParameters - any parameters to be passed to program
' (for DOS commands place entire string here)
' WaitForTermination - wait for completion of command before
' returning back to calling app
' OutputMethod - method by which output is to be rendered
' OutputPath - path of file to write output to
'
'Return Values : string of output if specified
'*************************
Public Function Execute(ProgramPath As String, _
Optional CommandLineParameters As String = "", _
Optional WaitForTermination As Boolean = False, _
Optional OutputMethod As OMETHOD = None, _
Optional OutputPath As String = "") As String
Dim lret As Long
Dim lFile As Long
Dim hProc As Long
Dim exitCode As Long
Dim strBuff As String
Dim strTempFile As String
Dim strFullCommand As String
'if redirect to file and no output file is specified, change to return string
If OutputMethod = ToFile And Trim$(OutputPath) = "" Then OutputMethod = ReturnString
If OutputMethod = ReturnString Then
OutputPath = GetTempFile
End If
'create the temp file
If OutputMethod <> None Then
lFile = FreeFile
Open OutputPath For Output As #lFile
Close #lFile
'convert path to short path
OutputPath = GetShortPath(OutputPath)
End If
'get the short path to the program
ProgramPath = GetShortPath(ProgramPath)
'create the full command line string
strFullCommand = " /c " & LTrim$(ProgramPath) & " " & LTrim$(CommandLineParamete
'create the process
If OutputMethod = None Then
lret = Shell(Environ("COMSPEC") & strFullCommand, vbHide)
Else
lret = Shell(Environ("COMSPEC") & strFullCommand & " > " & OutputPath, vbHide)
End If
'if option to wait, then wait
If lret And WaitForTermination Then
hProc = OpenProcess(PROCESS_QUERY_
Do
Call GetExitCodeProcess(hProc, exitCode)
DoEvents
Loop While exitCode = STATUS_PENDING
Call CloseHandle(hProc)
End If
'return string if applicable
If OutputMethod = ReturnString Then
lFile = FreeFile
Open OutputPath For Binary As #lFile
strBuff = Space$(LOF(lFile))
Get #lFile, , strBuff
Close #lFile
'kill the temp file
Kill OutputPath
Execute = strBuff
End If
End Function
Private Function GetTempFile() As String
Dim strTempFile As String
Dim strTempFolder As String
Dim ret As Long
strTempFile = Space$(MAX_PATH)
'
'find the temporary folder
'
strTempFolder = Space$(MAX_PATH)
ret = GetTempPath(MAX_PATH, strTempFolder)
strTempFolder = Left$(strTempFolder, ret)
'
'create the temp file
'
ret = GetTempFileName(strTempFol
If ret <> 0 Then
strTempFile = Left$(strTempFile, InStr(1, strTempFile, Chr$(0)) - 1)
GetTempFile = strTempFile
End If
End Function
Private Function GetShortPath(strFileName As String) As String
Dim lpos As Long
Dim strPath As String
strPath = Space$(255)
lpos = GetShortPathName(strFileNa
GetShortPath = Left$(strPath, lpos)
End Function
ASKER
I like the code Azra (just read through it) I will try it in a while. There's just one thing that is bothering me a little bit. And that is the use of the > to redirect the output to a file. It is exactly the same as my first attempt, but wouldn't work in my scenario. I'll see what I can do with the above bit of code. Thnx in advance, and I'll get back to you!
Regards,
CJ
Regards,
CJ
ASKER
I just tried the code, and it works fine for ping-commands. It does not work for net.exe which is why I am creating the program :-(
Maybe you know why?
CJ
Maybe you know why?
CJ
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
"", "c:\winnt\system32\net.exe ", True, ReturnString
It should show me the help from net.exe, but it doesn't.
There's also another thing that I would need to do, but that can wait for another question, and I still have to try the terminateprocess api, and a couple of others.
Reason that I am using the full command to net.exe is because on the actual server those commands are placed in another directory... just in case you wonder :-)
CJ
It should show me the help from net.exe, but it doesn't.
There's also another thing that I would need to do, but that can wait for another question, and I still have to try the terminateprocess api, and a couple of others.
Reason that I am using the full command to net.exe is because on the actual server those commands are placed in another directory... just in case you wonder :-)
CJ
ASKER
ASKER
cleaning up