Click here to Skip to main content
Click here to Skip to main content

CaptureConsole.DLL - A Universal Console Output Redirector for all Compilers

By , 28 Oct 2010
 

Introduction

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:

  1. executes a Console Application or DOS Script invisible in the background
  2. waits until the Console has finished
  3. returns all printed output via stdout and stderr as Strings to the calling application

Features

  1. This DLL is ultra easy to use for any application which wants to start a Console Process/Script and needs the output written by the Console.
  2. The only exported function "Execute" in this DLL uses the same calling convention as all Windows DLLs. (WINAPI = __stdcall)
  3. You can use this DLL in ANY compiler for ANY programming language which supports API calls. (If you can call Kernel32.dll, you can also call CaptureConsole.dll)
  4. This download contains a Demo Application for C++, Visual Basic 6, VB.NET and C# which demonstrate how to load the DLL and call the function "Execute".
  5. The DLL is thread-safe: You can execute multiple Console applications at the same time from different threads.
  6. You can choose if you want stdout and stderr separated or as mixed output.
  7. The Exit Code of the Console Application is returned to the caller.
  8. You can define the Working Directory (GetCurrentDirectory) for the console application.
  9. You can pass additional Environment Variables (GetEnvironmentVariable) to the Console Application or replace existing ones.
  10. The DLL can be compiled as Unicode (exports ExecuteW) or ANSI (exports ExecuteA). The DLL can be compiled as 32 Bit and as 64 Bit.
  11. The DLL is a MFC C++ project, but no external MFCxx.DLL is required because MFC is statically linked. (CaptureConsole.DLL depends only on standard Windows DLLs)
  12. The DLL internally uses CStrings and exports BSTR, so a buffer overflow is impossible. If your console prints 50 MB text output, that's no problem.
  13. All API errors that may happen while starting the Console process are handled and returned as a human readable error message.
  14. You can specify an optional timeout. If it elapses, the Console process will be killed. This avoids dead processes hanging around when used on a server.
  15. Special characters (like äöüáéú) are converted to the DOS Codepage when passed as commandline parameters.
  16. Special characters are converted back to the ANSI codepage when returned to the calling application.

Capturing in Real Time

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: 

  1. The code is weak: You may lose characters if the console application prints faster than you read the buffer or the console is scrolled
  2. You don't get stdout and stderr separated
  3. You need an additional EXE file which calls the Console process
  4. You have to implement the receiving pipe code into your main application. This code is very complex and has a lot of traps. It is much simpler to call a function in a DLL which does all the dirty work for you.

How It Works

CaptureConsole.DLL uses 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 string.
When the Console application has exited, the string(s) is (are) returned to the calling application.

A Really Stupid Microsoft Design

When a Console application writes its output using printf() and 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 2
In the calling process which starts the Console application, you have NO CHANCE to influence this behaviour!
If you have the source code of the Console process, you can include the following commands at the start of 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 fflush().

How to Use this DLL

If the DLL is compiled as Unicode, it exports the function ExecuteW.
If the DLL is compiled as MBCS, it exports the function ExecuteA.

ExecuteA/W Parameters

  • 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 null if not used.
  • s_Environment = Additional Environment Variables to be passed to the Console Application: "UserVar1=Value1\nUserVar2=Value2\n"
    You can also override the system variables with your own values. Pass null if not used.
  • b_SeparatePipes = true -> Capture stdout and stderr with two separate pipes and return them in s_StdOut and s_StdErr
  • b_SeparatePipes = false -> Capture stdout and stderr with one common pipe and return them in s_StdOut
  • u32_Timeout = 0 -> No timeout
  • u32_Timeout > 0 -> Timeout in milliseconds after which the Console process will be killed

ExecuteA/W Returns

Returns the Exit Code of the Console application and the strings s_ApiError, s_StdOut, s_StdErr.
If 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!

C#

[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);

VB .NET

<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)

C++

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);

VB 6

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.

Codepage Conversions

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 !!

History

  • 31st January, 2009: Initial post
  • 3rd February, 2009: Added a code sample for Visual Basic .NET
  • 6th February, 2009: Added Environment Variables, Current Directory and fixed a Pipe problem
  • 30th October, 2009: Updated source code
  • 19th November, 2009: Updated source code

Elmü

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Elmue
Software Developer (Senior) ElmüSoft
Chile Chile
Member
Software Engineer since 27 years.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: HRESULT: 0x8007000B on x64 compilationmvpElmue27 Oct '10 - 2:53 
I have not a minor glimpse what you are talking about ?????
 
HRESULT ???
CaptureConsole.dll does not use COM errors in no place.
What are you doing ???
 
Corflags ???
This tool is for MANAGED Assemblies!
Did you try to use it for the UNMANAGED CaptureConsole.dll ???
 

I guess that you want to load CaptureConsole.dll into a 64 Bit process ???
Did you first compile the CaptureConsole project into a 64 Bit DLL ???
 
Elmü
GeneralRe: HRESULT: 0x8007000B on x64 compilationmemberclaus.dieter27 Oct '10 - 4:38 
Right Guess:
- I started your binary "demo.exe" and everything was fine
- I started vs2010 express on vista 64bit and started your dotnet-demo-source without 64bit-dll-re-compiling captureconsole.dll ending with error: "HRESULT: 0x8007000B bad image format exception was unhandled" (nothing said about COM)
- vs2010 does not have the dropdown-switchbox "target platform=x86/x64 to compile 32bit-code only (target platform is "any")
 
so I asked for captureconsole64.dll ...
- thought that it's a good idea to have all stuff together and documented
- thought that it's better to do the "64Bit-job once and qualified"
(like You did it with "captureconsole(32Bit)".dll)
 
"help yourself/myself"
- I will install visual studio professional and switch to 32Bit-only
- I will compile captureconsole.* to 64bit later too

Corflags.exe:
I was browsing for the error code and found Corflags, learned that it's not the right tool. Sorry for the confusion, I intended only to prevent other people from making my mistakes!
 
Cites to think about:
"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."
"You can use this DLL in ANY compiler for ANY programming language which supports API calls."
 
Thanks Claus-Dieter
NewsCaptureConsole Version 3.3b releasedmvpElmue27 Oct '10 - 14:50 
Hello
 
All error codes greater than 0x80000000 are COM error codes.
CaptureConsole.dll internally does not use any COM so this error cannot come from my code.
So I was asking myself where do you get this error from ?
I suppose that the framewok has spit it out.
 
It is completely impossible to convert an already compiled 32 Bit C++ DLL into a 64 Bit DLL.
There is no tool that could do that and such a tool will never exist.
The only way is to recompile the source code.
 
Converting a 32 Bit C++ project to 64 Bit and setting all the Visual Studio Settings correctly may be cumbersome. Especially for a pure .NET programmer without C++ knowledge it is more difficult.
 
So I invested the time today and created a 64 Project with a - ready to use - DLL.
I also converted the C++ Demo project to 64 Bit to test this DLL.
It works fine.
 
Some notes:
You must always use the 64 CaptureConsole.dll when the process that loads it is a 64 Bit process.
It does NOT matter what your console application is.
You can call a 64 Bit console application from a 32 Bit process with the 32 Bit CaptureConsole.dll and vice versa. This does not provoke any problem because the data is passed through a pipe betweeen the processes.
 
You can NOT load the 32 Bit CaptureConsole.dll into a 64 Bit process or vice versa!
 
Possible are these combinations:
 
32 Bit process + 32 CaptureConsole.dll starting a 32 Bit Console process
32 Bit process + 32 CaptureConsole.dll starting a 64 Bit Console process
64 Bit process + 64 CaptureConsole.dll starting a 32 Bit Console process
64 Bit process + 64 CaptureConsole.dll starting a 64 Bit Console process
 
You can now download version 3.3b here on Codeproject.
 
Elmü
GeneralSlow output (not your implementation actually)memberd1879 Sep '10 - 23:01 
Elmue, thank you for sharing this good bit of code!
 
Stdout is very slow though. How to make it faster? It takes 20-30 seconds to get 1Megabyte output from stdout...
GeneralRe: Slow output (not your implementation actually)mvpElmue11 Sep '10 - 2:01 
Hello
 
Yes, it is extremely slow.
But this is a problem inside of Windows.
You will not be able to improve this.
 
The data sent from a console application to CaptureConsole.dll goes through a pipe.
Normally pipes are ultra fast.
I have no idea what is so slow.
 
Maybe Microsoft has slowed it down intentionally because the Console is deprecated ?
 
Elmü


GeneralRe: Slow output (not your implementation actually)memberMember 4558662 Feb '11 - 7:28 
Hi, Thank!
Have you tried this problem using Reactive Extensions for. NET (Rx)?
Rand

GeneralRe: Slow output (not your implementation actually)memberElmue4 Feb '11 - 2:36 
You don't need Reactive Extensions here.
CaptureConsole.DLL is threadsafe and can be called directly from any thread.
GeneralFeedback for Long operationsmemberGianniEVS24 May '10 - 22:48 
Hello and Thanks for your code.
 
I'm trying to use your dll in my vb6 code.
Only a single question:
it's possible give feedback during long operations?
 
Regards
Gianni
GeneralRe: Feedback for Long operationsmvpElmue25 May '10 - 2:47 
Hello
 
The DLL waits until the console process has exited.
 
Elmü
Questiontype mismatch?membermeir livneh17 May '10 - 4:17 
In RunProcess.cpp:
 
// If Unicode compiled: DOS codepage -> Unicode
s_CommandLine = s_Leave + s8_OEM;
 
s_CommandLine and s_Leave are defined as Cstring, s8_OEM is char* :
so, shouldn't it be:
s_CommandLine = s_Leave + CString(s8_OEM); ?
AnswerRe: type mismatch?mvpElmue17 May '10 - 13:49 
Hello
 
The comment in the code shows that this is pure intention and not a "typo".
 
When you use the + operator on a Unicode CString you can append either ANSI or Unidode to the existing string. MFC does the conversion automatically. Otherwise the compiler would complain!
 
To understand this simply trace into the code of CString in your debugger!
 
So compiling
s_CommandLine = s_Leave + s8_OEM
and
s_CommandLine = s_Leave + CString(s8_OEM);
is exactly the same!
 
Elmü


GeneralCaptureConsole as COM and/or ActiveX DLLmembermeir livneh5 May '10 - 8:52 
I bumped into the CaptureConsole DLL you developed, kudos, a very nice piece of code.
I'm not much of a C++ programmer, so I was wondering if you can compile it as a COM or ActiveX DLL
so it can be registered and called from a .Net application.
GeneralRe: CaptureConsole as COM and/or ActiveX DLLmvpElmue6 May '10 - 3:13 
What ??????
Did you read the article at all ?
Did you look into the .NET sample code ?
I doubt.
 
There is a working example code that shows how to use the DLL in .NET code.
There is no need for an ugly awkward ActiveX component that is fussy to install.
Why do you want to do the things complicated that are so easy ?
 
Elmü
GeneralRe: CaptureConsole as COM and/or ActiveX DLLmembermeir livneh6 May '10 - 10:16 
I did read the article.
I tried to register the dll (regsvr32) and got the following error message:
"C:\CaptureConsole\Release\CaptureConsole.dll was loaded,but the Dllregisterserver entry point was not found, This file can not be registered"
 
This usually happens when attempting to register a "simple dll" (i.e. non Com or ActivX dll).
You don't need to register a dll in order to use it, you can just place it in any directory and explicitly call it, using the explicit path to it.
In my case however I'm required to register the dll.
I'm writing a Firefox AddOn (in Javascript) that needs to communicate with a legacy console application. This requires the Dll to be registered.
Any idea as to why CaptureConsole.dll is "un-registerable" ?
Am I missing something?
Thanks
meir
GeneralRe: CaptureConsole as COM and/or ActiveX DLLmvpElmue6 May '10 - 15:54 
Hello
 
You can only register COM Dlls.
CaptureConsole.Dll is not a COM Dll, so it cannot be registered.
 
In you first email you said that you program in .NET.
Now you say that it is Javascript ???
????
 
In .NET you can load the DLL directly.
There is no need to register it, as I already explained!
 
And please explain me why do you post your question 5 times ??
 
Elmü
GeneralRe: CaptureConsole as COM and/or ActiveX DLLmembermeir livneh8 May '10 - 10:37 
need it as a COM dll
thanks
meir
General"stupid design" and output bufferingmembergrmcdorman3 Nov '09 - 9:27 
The issue with output not appearing immediately in pipes - or any redirected I/O streams - is not a bug or misfeature.
 
All streams, when sent to a non-interactive device, will by default buffer output. This is because most devices do not write data a byte at a time (especially disks).
 
This is standard ISO C stuff, and will apply not only to all Microsoft compilers on Windows, but any other compiler on other systems, such as GNU C on Linux or Sun's Forte on Solaris.
 
However, if you want to change the buffering you can. Call setvbuf(file, NULL, _IONBF, 0) (for C FILE * streams) to disable buffering entirely. This must be done on both ends of the pipe.
 
For more on buffering, see http://msdn.microsoft.com/en-us/library/cc644950%28VS.85%29.aspx[^]
GeneralRe: "stupid design" and output bufferingmemberElmue4 Nov '09 - 1:35 
Hello
 
> However, if you want to change the buffering you can. Call setvbuf(file, NULL, _IONBF, 0)
 
Did you read the article ?
The article says exaclty the same!
 
> is not a bug or misfeature.
 
Yes it is definitely!
It would be so easy for Microsoft to automatically call setvbuf() for ALL Console applications that run on Windows!
The buffering is usless if you write to the screen.
And the buffering is usless if you write to a Pipe! A Pipe has it's own buffering logic!
 
And it is completely meaningless if Microsoft uses ISO C or not.
 
How do you explain that the characters you print in your Console application appear IMMEDIATELY on the black screen? Why don't you have to call flush() each time you want a character to appear on the screen? Why does it work seamless on the screen but not on a Pipe?
 
The reason is that there is a switch in the MS code which detects if output goes to the screen or to a pipe. If it goes to a Pipe an internal buffer is enabled, otherwise not. And that stupid switch is definitely a misdesign! At least for Console applications this switch should be disabled! A pipe has it's own internal buffer there is no need for an additional buffer in the Console application. It would be a very very easy task for Microsoft to change this behaviour so Console applications write immediately to Pipes.
 
But Microsoft has never cared about their old bugs!
The MS managers think: It's not worth to invest developer hours into fixing Console bugs, who uses the Console? Microsoft fixes bugs only if MANY MANY people complain about them! The Console is tooo meaningless!
 
> http:....MSDN....
 
The link you post is completely misplaced here!
You did not understand the difference between a disk cache and an internal buffer in Console applications!
 
Elmü


GeneralRe: "stupid design" and output bufferingmember_Olivier_4 Mar '10 - 4:04 
To work around this weird behavior and obtain Console output in real-time, see my article Real-Time Console Output Redirection[^]
GeneralRe: "stupid design" and output bufferingmvpElmue6 Mar '10 - 2:48 
Hello
 
Yes but your code is weak.
It may happen that you lose characters
1.) if the console writes fast output
2.) or very long output
3.) or when the CPU runs with high load.
 
The Console has never been designed to do what you are doing in your code.
I cannot recommend to use your code for all those who need reliability!
Your code is weak.
 
Your article is a nice scientific experiment to see what is possible,
but it is not to be used in an application which must work stable.
 
Elmü
GeneralRe: "stupid design" and output bufferingmembermeir livneh5 May '10 - 8:55 
I bumped into the CaptureConsole DLL you developed, kudos, a very nice
piece of code.
I'm not much of a C++ programmer, so I was wondering if you can
compile it as a COM or ActiveX DLL
so it can be registered and called from a .Net application.
Thank you
GeneralRe: "stupid design" and output bufferingmembermeir livneh5 May '10 - 8:56 
I bumped into the CaptureConsole DLL you developed, kudos, a very nice
piece of code.
I'm not much of a C++ programmer, so I was wondering if you can
compile it as a COM or ActiveX DLL
so it can be called from a .Net application.
Thank you
GeneralSleep improvementsmembergarret_fick2 Nov '09 - 11:17 
I have another suggestion for your library.
 
I see you've used Sleep to wait so you don't tax the processor while the process completes. I suggest you change the loop from
DWORD u32_Elapsed  = 0;
do
{
	Sleep(200);
	u32_Elapsed += 200;
	...
	if (u32_TimeOut && u32_Elapsed > u32_TimeOut)
	{
		TerminateProcess(k_Proc.hProcess, 0);
		return _T("CaptureConsole.dll: Timeout elapsed.");
	}
	...
}
while (*pu32_ExitCode == STILL_ACTIVE);
with
DWORD dwEndTime = (u32_TimeOut) ? GetTickCount() + u32_TimeOut : 0;
do
{
	//Sleep for up to 200ms
	if (WaitForSingleObject(k_Proc.hProcess, 200) == WAIT_FAILED)
	{
		return _T("CaptureConsole.dll: Error waiting for the processgetting ExitCode from Process. ") + GetLastErrorMsg();
	}
	...
	//Kill it if we've waited too long
	if (u32_TimeOut && GetTickCount() > dwEndTime)
	{
		TerminateProcess(piProcInfo.hProcess, 0);
		return _T("CaptureConsole.dll: Timeout elapsed.");
	}
	...
}
while (*pu32_ExitCode == STILL_ACTIVE);
 
The difference if of course replacing Sleep with WaitForSingleObject. The advantage with this approach is that the previously, the code would wait at up to 200s after the process completed to return. Also, the timer is more accurate in determining how long to wait.
 
Note: There might be some syntax errors. I've modified the code more significantly, and so I tried to put it back together in this window.
GeneralRe: Sleep improvementsmemberElmue4 Nov '09 - 1:23 
Hello
 
1.)
If we are talking about accuracy the worst you can do is using GetTickCount().
The tick counter is incremented every Millisecond as you expect ONLY on Windows CE.
On ALL other Windows versions which run on a "real" Mainboard the tick counter is derived from the CLOCK INTERUPT. This has approximately a frequency of 64 Hertz depending on the hardware of your mainboard.
So the Tickcounter does not advance continously.
It jumps by aproximately 15 Milliseconds.
 
2.)
What you may gain with your code may be that it returns a maximum of 200 ms earlier than my code.
If you think that this is worth to make changes, OK do it!
 
But its easier to add 200 to a counter variable in every loop as I do in my code.
 
3.)
Your code lacks correct checking of return values.
You must check for WAIT_OBJECT_0 and WAIT_TIMEOUT !
 
Elmü
GeneralRe: Sleep improvementsmembergarret_fick6 Nov '09 - 7:56 
Hi,
 
I'm not using GetTickCount() for accuracy. The is a potential issue with the logic (and what I wrote is a start to the solution).
 
The issue is if you have a process that is writing excessive data to stdout/stderr. The code could become stuck in ReadPipe, as reading the pipe cannot keep up with the writing. Alternatively, ReadPipe might end, but could have spend much more than a few ms, and ultimately, the timeout could far exceed the expectation. GetTickCount gives a better way of determining how long the process has been running. A third alternate end point could be an exception being thrown. However, it is difficult to say what might happen first. As the string buffer gets larger, it takes long to reallocate the string, and you might reach the intended timeout before running out of memory.
 
I think the error checking is correct. There only fail case would be if wait failed.
 
Btw, I my case, 200ms makes a difference because I need to call the exe repeatedly to know what information is available for the next call. 200ms can add up quickly. Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 28 Oct 2010
Article Copyright 2009 by Elmue
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid