12,066,626 members (56,178 online)
You find a lot of code on the internet to capture Console output.
But normally, you find only a class written for a specific programming language.
The big advantage of this easy to use DLL is that you can use it in ALL projects independent of the programming language or compiler.
With 2 lines of code in your application, you can load this DLL which:
stderras Strings to the calling application
Execute" in this DLL uses the same calling convention as all Windows DLLs. (
stderrseparated or as mixed output.
GetCurrentDirectory) for the console application.
GetEnvironmentVariable) to the Console Application or replace existing ones.
ExecuteW) or ANSI (exports
ExecuteA). The DLL can be compiled as 32 Bit and as 64 Bit.
CStrings and exports BSTR, so a buffer overflow is impossible. If your console prints 50 MB text output, that's no problem.
If you need the Console Output in REALTIME, this is not the correct project for you:
CaptureConsole.DLL waits until the Console process has exited and THEN returns stdout and stderr.
If you need Console Output in real time, please read Oliver's article, which directly reads from the Console buffer.
But Oliver's technique has severe disadvantages:
CreateProcess() to start the Console Process.
The outputs stdout and stderr are redirected to one or two pipes which send the printed characters to the calling application.
While the Console application is running, the pipe(s) is (are) read by the calling process and output is stored in a
When the Console application has exited, the
string(s) is (are) returned to the calling application.
When a Console application writes its output using
perror() a STUPID design in the CRT defines that the printed characters are NOT immediately sent to the pipe.
This does not matter as long as the Console does not write to stderr.
It also does not matter if you are not interested in the original order of stdout and stderr.
If your Console application does this:
printf("Text 1"); perror("Error 1"); printf("Text 2"); perror("Error 2");
You see the output in the Console window in the same order:
Text 1 Error 1 Text 2 Error 2
But if the output is redirected to a pipe, Microsoft writes the printed characters to an internal buffer and they are sent to the pipe all together when the Console exits.
Although you capture stdout and stderr with only one and the SAME pipe, you get a wrong order:
Text 1 Text 2 Error 1 Error 2In the calling process which starts the Console application, you have NO CHANCE to influence this behaviour!
main()to turn off this stupid buffering:
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0);
Another option is to use
_write() instead of
printf() or call
If the DLL is compiled as Unicode, it exports the function
If the DLL is compiled as MBCS, it exports the function
s_CommandLine= The entire commandline to be executed. e.g. "
C:\Test\Test.bat Param1 Param2"
u32_FirstConvert = 0-> Commandline parameter codepage conversion is turned off
u32_FirstConvert > 0-> The first commandline parameter to be converted to the DOS codepage (see next chapter for more details)
s_CurrentDir =The current working directory for the Console Application or
nullif not used.
s_Environment =Additional Environment Variables to be passed to the Console Application:
nullif not used.
b_SeparatePipes = true-> Capture stdout and stderr with two separate pipes and return them in
b_SeparatePipes = false-> Capture stdout and stderr with one common pipe and return them in
u32_Timeout = 0-> No timeout
u32_Timeout > 0-> Timeout in milliseconds after which the Console process will be killed
Returns the Exit Code of the Console application and the
s_ApiError is not empty, this means that an error has occurred while creating the console process or the communication pipe. You get a human readable error message.
IMPORTANT: You must ALWAYS check
s_ApiError. If this
string is not empty, the other return values are invalid!
IMPORTANT: Do not forget to free the BSTR afterwards with
SysFreeString() to avoid a memory leak!
In the demo projects, you see how to do it correctly.
This is not necessary in .NET where the Marshalling frees the
strings automatically for you!
[DllImport("CaptureConsole.dll", EntryPoint="ExecuteW", CharSet=CharSet.Unicode)] static extern UInt32 ExecuteW(string s_Commandline, UInt32 u32_FirstConvert, string s_CurrentDir, string s_Environment, bool b_SeparatePipes, UInt32 u32_Timeout, [MarshalAs(UnmanagedType.BStr)] out string s_ApiError, [MarshalAs(UnmanagedType.BStr)] out string s_StdOut, [MarshalAs(UnmanagedType.BStr)] out string s_StdErr); string s_ApiError, s_StdOut, s_StdErr; UInt32 u32_ExitCode = ExecuteW(@"C:\Test\Console.exe Hello Wörld", 1, null, null, true, 120000, out s_ApiError, out s_StdOut, out s_StdErr);
<DllImport("CaptureConsole.dll", EntryPoint:="ExecuteW", CharSet:=CharSet.Unicode)> _ Public Shared Function ExecuteW(ByVal s_Commandline As String, _ ByVal u32_FirstConvert As Int32, _ ByVal s_CurrentDir As String, _ ByVal s_Environment As String, _ ByVal b_SeparatePipes As Boolean, _ ByVal u32_Timeout As Int32, _ <MarshalAs(UnmanagedType.BStr)> ByRef s_ApiError As String, _ <MarshalAs(UnmanagedType.BStr)> ByRef s_StdOut As String, _ <MarshalAs(UnmanagedType.BStr)> ByRef s_StdErr As String) As UInt32 Dim s_ApiError, s_StdOut, s_StdErr As String Dim u32_ExitCode As UInt32 = ExecuteW("C:\Test\Console.exe Hello Wörld", 1, Nothing, Nothing, True, 120000, s_ApiError, s_StdOut, s_StdErr)
typedef DWORD (WINAPI* tExecute)(const WCHAR*, DWORD, const WCHAR*, const WCHAR*, BOOL, DWORD, BSTR*, BSTR*, BSTR*); HMODULE h_Dll = LoadLibraryW(L"CaptureConsole.dll"); tExecute f_Execute = (tExecute)GetProcAddress(h_Dll, "ExecuteW"); BSTR s_ApiError, s_StdOut, s_StdErr; DWORD u32_ExitCode = f_Execute(L"C:\\Test\\Console.exe Hello Wörld", 1, NULL, NULL, TRUE, 120000, &s_ApiError, &s_StdOut, &s_StdErr);
Private Declare Function ExecuteW Lib "CaptureConsole" ( ByVal s_CommandLine As Long, ByVal s32_FirstConvert As Long, ByVal s_CurrentDir As Long, ByVal s_Environment As Long, ByVal b_SeparatePipes As Boolean, ByVal s32_Timeout As Long, ByRef s_ApiError As Long, ByRef s_StdOut As Long, ByRef s_StdErr As Long) As Long Dim bs_ApiError, bs_StdOut, bs_StdErr, s32_ExitCode As Long s32_ExitCode = ExecuteW(StrPtr("C:\Test\Console.exe Hello Wörld"), 1, 0, 0, _ True, 120000, bs_ApiError, bs_StdOut, bs_StdErr) Dim s_ApiError, s_StdOut, s_StdErr As String s_ApiError = ConvertBSTR(bs_ApiError) s_StdOut = ConvertBSTR(bs_StdOut) s_StdErr = ConvertBSTR(bs_StdErr)
You find the definition of the function
ConvertBSTR() in the demo project.
Console applications and DOS scripts use the OEM codepage to display characters above ASCII code 127.
To display characters like äöüáéú correctly, it is necessary to convert them.
CaptureConsole.dll converts all output (stdout and stderr) from OEM (DOS codepage) to ANSI / Unicode before it is returned to the calling application.
But the input to the Console application or DOS script is more complicated:
If you call a Console.exe application, the commandline parameters must be converted in CaptureConsole.dll.
But if you call a Console.bat script, this will be executed by CMD.EXE which already does this conversion automatically.
So when you call a DOS script, the conversion in CaptureConsole.dll must be turned off. (
u32_FirstConvert = 0)
But there are also other cases where the conversion is not desired:
java -cp "C:\Programación\Transacción.jar" Classname Hello Wörld
If you pass a commandline parameter which contains a path or filename with special characters, this path/filename must NOT be converted.
In this case, the conversion must start at the third parameter, because the first "
-cp" and the second "C:\Programación\Transacción.jar" must not be converted.
So here you must set
u32_FirstConvert = 3.
If the case is more complicated, turn off the conversion in CaptureConsole.dll (
u32_FirstConvert = 0) and convert the commandline in your calling application:
C:\Железнодо\Console.exe Param1 Param2
The first part of the commandline is always the EXE, BAT or CMD file to be executed.
If you use
ExecuteW in the Unicode compiled CaptureConsole.dll this path may contain Chinese, Russian or Greek Unicode characters.
But all the following parameters must never exceed ASCII code 255 !!