471,344 Members | 1,539 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,344 software developers and data experts.

dllimport stdout gets eaten

I changed the stdout in my C# app using Console.SetOut. It works fine
for all my Console.Out.Write calls and with log4net. However, I don't
see any output from native dlls that write to stdout. What am I doing
wrong?
Jul 17 '08 #1
6 4845
not_a_commie wrote:
I changed the stdout in my C# app using Console.SetOut. It works fine
for all my Console.Out.Write calls and with log4net. However, I don't
see any output from native dlls that write to stdout. What am I doing
wrong?
Nothing.

Why should changing something inside the Console class
change what some native code does ?

You need to do something in your native code to
get output where you want it.

Arne
Jul 17 '08 #2
Arne Vajhøj wrote:
not_a_commie wrote:
>I changed the stdout in my C# app using Console.SetOut. It works fine
for all my Console.Out.Write calls and with log4net. However, I don't
see any output from native dlls that write to stdout. What am I doing
wrong?

Nothing.

Why should changing something inside the Console class
change what some native code does ?
If for example, that managed code was a wrapper around SetStdHandle. But
it's not, it changes Console.Out rather than changing stdout underneath.
>
You need to do something in your native code to
get output where you want it.
SetStdHandle, most likely. And then it doesn't have to be a change to the
native code, as long as it's called from the same process.
>
Arne

Jul 18 '08 #3
Ben Voigt [C++ MVP] wrote:
Arne Vajhøj wrote:
>not_a_commie wrote:
>>I changed the stdout in my C# app using Console.SetOut. It works fine
for all my Console.Out.Write calls and with log4net. However, I don't
see any output from native dlls that write to stdout. What am I doing
wrong?
Nothing.

Why should changing something inside the Console class
change what some native code does ?

If for example, that managed code was a wrapper around SetStdHandle. But
it's not, it changes Console.Out rather than changing stdout underneath.
I can not see how it could be a wrapper around SetStdHandle. Out is a
TextWriter. If I write my own class that extends TextWriter and call
SetOut with it. There are no handle to pass to native and no way
for the native code to call my class.
>You need to do something in your native code to
get output where you want it.

SetStdHandle, most likely. And then it doesn't have to be a change to the
native code, as long as it's called from the same process.
I was thinking freopen, but if it is documented that SetStdHandle
interacts "nicely" with the C RTL, then that can obviously be
used.

Arne
Jul 19 '08 #4
I got this to work. The setvbuf is critical. Here's my test code.
First, the dll:

#include <stdio.h>

__declspec(dllexport) void PrintMsg();

void PrintMsg()
{
setvbuf(stdout, NULL, _IONBF, 0);
printf("blah blah blah\n");
}

Second, the C# code:

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;

namespace TestPrintf
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
protected static extern bool SetStdHandle(int nStdHandle, IntPtr
hConsoleOutput);

[DllImport("PrintDll.dll", CallingConvention =
CallingConvention.Cdecl)]
protected static extern void PrintMsg();

[STAThread]
public static void Main(string[] args)
{
var id = Process.GetCurrentProcess().Id; // make this instance
unique
var serverPipe = new NamedPipeServerStream("consoleRedirect" + id,
PipeDirection.In, 1);
var clientPipe = new NamedPipeClientStream(".", "consoleRedirect" +
id, PipeDirection.Out, PipeOptions.WriteThrough);
ThreadPool.QueueUserWorkItem(state =>
{
serverPipe.WaitForConnection();
using (var stm = new StreamReader(serverPipe))
{
while (serverPipe.IsConnected)
{
try
{
var txt = stm.ReadLine();
if (!string.IsNullOrEmpty(txt))
MessageBox.Show("Got stdout with: " + txt);
}
catch (IOException)
{
break; // normal disconnect
}
}
}
}, null);
clientPipe.Connect();
var hr11 = new HandleRef(clientPipe,
clientPipe.SafePipeHandle.DangerousGetHandle());
SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
var app = new Application();
var win = new Window { Width = 300, Height = 200 };
var sp = new StackPanel { Orientation = Orientation.Horizontal };
win.Content = sp;
var b1 = new Button { Content = "Direct", Width = 100 };
sp.Children.Add(b1);
var b2 = new Button { Content = "Indirect", Width = 100 };
sp.Children.Add(b2);
var b3 = new Button { Content = "DllImport", Width = 100 };
sp.Children.Add(b3);

b1.Click += (sender, e) =Console.Out.WriteLine("Direct Button was
clicked");
b2.Click += (sender, e) =>
{
using (var stdout = Console.OpenStandardOutput())
{
var bytes = Console.OutputEncoding.GetBytes("Indirect Button
was clicked" + Console.Out.NewLine);
stdout.Write(bytes, 0, bytes.Length);
}
};
b3.Click += (sender, e) =PrintMsg();

app.Run(win);
clientPipe.Dispose();
serverPipe.Dispose();
}

}
}
Jul 21 '08 #5
Arne Vajhøj wrote:
Ben Voigt [C++ MVP] wrote:
>Arne Vajhøj wrote:
>>not_a_commie wrote:
I changed the stdout in my C# app using Console.SetOut. It works
fine for all my Console.Out.Write calls and with log4net. However,
I don't see any output from native dlls that write to stdout. What
am I doing wrong?
Nothing.

Why should changing something inside the Console class
change what some native code does ?

If for example, that managed code was a wrapper around SetStdHandle.
But it's not, it changes Console.Out rather than changing stdout
underneath.

I can not see how it could be a wrapper around SetStdHandle. Out is a
TextWriter. If I write my own class that extends TextWriter and call
SetOut with it. There are no handle to pass to native and no way
for the native code to call my class.
I agree. I was just trying to show that it wasn't an entirely unreasonable
expectation though, by mentioning a function that would behave as the OP
expected. And, as you point out, it is limited to redirecting to an OS
handle, not an arbitrary TextWriter.
>
>>You need to do something in your native code to
get output where you want it.

SetStdHandle, most likely. And then it doesn't have to be a change
to the native code, as long as it's called from the same process.

I was thinking freopen, but if it is documented that SetStdHandle
interacts "nicely" with the C RTL, then that can obviously be
used.
I didn't see any assurance that the native code was written in C, or that
the OP knew which RTL was being used. If the DLL was statically linked, it
would be next-thing-to-impossible to call the "right" freopen.
>
Arne

Jul 21 '08 #6
Ben Voigt [C++ MVP] wrote:
Arne Vajhøj wrote:
>Ben Voigt [C++ MVP] wrote:
>>Arne Vajhøj wrote:
You need to do something in your native code to
get output where you want it.
SetStdHandle, most likely. And then it doesn't have to be a change
to the native code, as long as it's called from the same process.
I was thinking freopen, but if it is documented that SetStdHandle
interacts "nicely" with the C RTL, then that can obviously be
used.

I didn't see any assurance that the native code was written in C, or that
the OP knew which RTL was being used. If the DLL was statically linked, it
would be next-thing-to-impossible to call the "right" freopen.
Good point.

Arne
Jul 28 '08 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Tsai Li Ming | last post: by
7 posts views Thread by Edward Diener | last post: by
reply views Thread by Roman Neuhauser | last post: by
reply views Thread by lickspittle | last post: by
15 posts views Thread by Jim | last post: by
6 posts views Thread by Pekka Karjalainen | last post: by
20 posts views Thread by David Mathog | last post: by
reply views Thread by Ronak mishra | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.