.NET GUI application + Native library: console stdout redirection via anonymous pipes

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Hi, everyone.
Im developing .NET GUI application (WinForms, .NET 4). It uses native dll with a single exported function. This function writes some output in stdout, heres the native code sample:

<div style="color:Black;background-color:White; <pre>
#define SAMPLELIBRARY_API __declspec(<span style="color:Blue; dllexport)

SAMPLELIBRARY_API <span style="color:Blue; void LetterList(<span style="color:Blue; void)
{
cout << <span style="color:#A31515; "This function was called from LetterList() " << endl;
}

[/code]

I want to redirect output, produced by native DLL, for the purpose of further usage.
So, Ive made a class, which uses anonymous pipes for redirecting. Heres code:

<div style="color:Black;background-color:White; <pre>
<span style="color:Blue; public <span style="color:Blue; static <span style="color:Blue; class ConsoleOutRedirector
{
<span style="color:Blue; #region Constants

<span style="color:Blue; private <span style="color:Blue; const Int32 STD_OUTPUT_HANDLE = -11;

<span style="color:Blue; #endregion

<span style="color:Blue; #region Externals

[DllImport(<span style="color:#A31515; "Kernel32.dll")]
<span style="color:Blue; extern <span style="color:Blue; static Boolean SetStdHandle(Int32 nStdHandle, SafeHandleZeroOrMinusOneIsInvalid handle);
[DllImport(<span style="color:#A31515; "Kernel32.dll")]
<span style="color:Blue; extern <span style="color:Blue; static SafeFileHandle GetStdHandle(Int32 nStdHandle);

<span style="color:Blue; #endregion

<span style="color:Blue; #region Methods

<span style="color:Blue; public <span style="color:Blue; static String GetOutput(Action action)
{
Debug.Assert(action != <span style="color:Blue; null);

<span style="color:Blue; using (<span style="color:Blue; var server = <span style="color:Blue; new AnonymousPipeServerStream(PipeDirection.Out))
{
<span style="color:Blue; var defaultHandle = GetStdHandle(STD_OUTPUT_HANDLE);

Debug.Assert(!defaultHandle.IsInvalid);
Debug.Assert(SetStdHandle(STD_OUTPUT_HANDLE, server.SafePipeHandle));
<span style="color:Blue; try
{
action();
}
<span style="color:Blue; finally
{
Debug.Assert(SetStdHandle(STD_OUTPUT_HANDLE, defaultHandle));
}

<span style="color:Blue; using (<span style="color:Blue; var client = <span style="color:Blue; new AnonymousPipeClientStream(PipeDirection.In, server.ClientSafePipeHandle))
{
<span style="color:Blue; using (<span style="color:Blue; var reader = <span style="color:Blue; new StreamReader(client))
{
<span style="color:Blue; using (<span style="color:Blue; var writer = <span style="color:Blue; new StringWriter())
{
<span style="color:Blue; while (reader.Peek() != -1)
{
writer.Write(Convert.ToChar(reader.Read()));
}
<span style="color:Blue; return writer.ToString();
}
}
}
}
}

<span style="color:Blue; #endregion
}

[/code]

and usage sample:

<div style="color:Black;background-color:White; <pre>
[DllImport(<span style="color:#A31515; "SampleLibrary.dll")]
<span style="color:Blue; extern <span style="color:Blue; static <span style="color:Blue; void LetterList();

<span style="color:Blue; private <span style="color:Blue; void button1_Click(<span style="color:Blue; object sender, EventArgs e)
{
textBox1.Text = ConsoleOutRedirector.GetOutput(() => LetterList());
}

[/code]
<br/>

This all works just fine. But... only once.
The second call of GetOutput method hangs up on the readers Peek() method call.
For the testing purposes, Ive inserted explicit server.WriteByte((Byte)a) to server stream before call action(). The same result - a appears in pipe only once. Ive tried to create static instances of the server, client and reader - no changes. It seems
to me, that after first reading from the pipe, it ignores other data.

Is it normal behavior? What am I doing wrong?

P.S. In the real project Ive third-party native DLL, using stdout, and I cannot modify it. (

View the full article
 
Back
Top