Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2005

Tip: Looking for answers? Try searching our database.

Redirect stdout from unmanaged DLL

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Thomas W. Brown - 20 Jun 2005 18:36 GMT
I redirect the console's output and error streams in my C# application in
order to prepend some basic information for diagnostics (timestamp, thread
name, etc.).  This works fine for all Console.WriteLine and
Console.Error.WriteLine output from my managed code.  However, I use PInvoke
to call down to some older, unmanaged C++ DLLs which write progress feedback
out to stdout (and possibly error diagnostics out to stderr).  This output is
not redirected.  It simply appears on the console without having gone through
my redirection.

I guess the unmanaged code is using a different "console" than the managed
code.  Has anyone tackled this one yet?  I'm assuming that I need to do
something along the lines of using PInvoke to freopen the stdout and stderr
handles for the unmanaged code but I'm not sure how to do this in a way that
will still get me the output from the unmanaged code in a "real time" way
(i.e. interleaved with my managed code output).

Thanks!
-- Tom
William DePalo [MVP VC++] - 20 Jun 2005 20:43 GMT
>I redirect the console's output and error streams in my C# application in
> order to prepend some basic information for diagnostics (timestamp, thread
[quoted text clipped - 17 lines]
> will still get me the output from the unmanaged code in a "real time" way
> (i.e. interleaved with my managed code output).

Good question. Can you get the native handle of the device to which you have
redirected the console?

If so, I use this little bit of voodo

//---------------------------------------------------------------
#include <io.h>
#include <stdio.h>

// handle is a non-overlapped native device or file handle or socket

fd = _open_osfhandle( (intptr_t) handle);
fp = _fdopen(fd, "w");

*stdout = *fp;
setvbuf(stdout, NULL, _IONBF, 0);
//---------------------------------------------------------------

all the time to redirect the standard output device of native Win32
executables.

The big question is whether you will have to execute that code in the DLL or
not. Not having tried it, I don't know.

Regards,
Will
Thomas W. Brown - 20 Jun 2005 20:52 GMT
> >I redirect the console's output and error streams in my C# application in
> > order to prepend some basic information for diagnostics (timestamp, thread
[quoted text clipped - 41 lines]
> The big question is whether you will have to execute that code in the DLL or
> not. Not having tried it, I don't know.

Hmm... maybe using freopen instead of "*stdout = *fp;" will work and I can
try it via PInvoke.  I'll give it all a shot and post a reply with the
results.

Thanks!
-- Tom
Thomas W. Brown - 22 Jun 2005 19:09 GMT
> >I redirect the console's output and error streams in my C# application in
> > order to prepend some basic information for diagnostics (timestamp, thread
[quoted text clipped - 41 lines]
> The big question is whether you will have to execute that code in the DLL or
> not. Not having tried it, I don't know.

I don't think this will work in my case -- I've been scratching my head to
try and figure out; 1) how I can do this from my managed code layer, and 2)
even if I could, what to I supply as the low-level device handle that
corresponds to my TextWriter that I use for the redirection.

(1) is necessary because I do not have the ability to alter the unmanaged
DLLs -- they are black boxes for me.

Thanks, though,  I'll keep on this as a background task and maybe stumble on
a solution.  I can always redirect stdout for my entire process and just grab
the resulting file which should be everything that I wasn't able to redirect
from the managed side.  The only downside is losing the "place" of the output
and not being able to apply my prepended timestamp and other information to
the output.

-- Tom
William DePalo [MVP VC++] - 23 Jun 2005 20:16 GMT
> I don't think this will work in my case -- I've been scratching my head to
> try and figure out; 1) how I can do this from my managed code layer, and
> 2)
> even if I could, what to I supply as the low-level device handle that
> corresponds to my TextWriter that I use for the redirection.

Well, what I posted is a way to "wire" a "file" known to the C/C++ runtime
to an operating system handle. If you could have communicated the Win32
handle of the file to which you redirected your console, then my little hack
would have done the job.

> (1) is necessary because I do not have the ability to alter the unmanaged
> DLLs -- they are black boxes for me.

OK. There is almost always more than one way to skin a cat. The little C#
hack below does three things:

1) it points the Console at a file
2) it redirects the standard output device of the application to that file
using a bit of interop
3) it calls a function exported from DLL written in C++ which uses the plain
vanilla I/O stream for output

//--------------------------------------------------------------------------------------------------------------
using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Redirect
{
class Class1
{
 [ DllImport("Kernel32.dll", SetLastError = true) ]
 public static extern int SetStdHandle(int device, IntPtr handle);

 [ DllImport("SayHello.dll") ]
 public static extern void SayHello();

 [STAThread]
 static void Main(string[] args)
 {
  int status;
  IntPtr handle;
  FileStream fs;
  StreamWriter sw;

  fs = new FileStream("console.txt", FileMode.Create);

  sw = new StreamWriter(fs);
  sw.AutoFlush = true;
  Console.SetOut(sw);

  Console.WriteLine("This is a test of output via C#.");

  handle = fs.Handle;
  status = SetStdHandle(-11, handle);

  SayHello();
 }
}
}
//--------------------------------------------------------------------------------------------------------------

This is the source to the DLL I used to test the redirection:

//--------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <iostream>

void WINAPI SayHello()
{
std::cout << "This is a test of output in C++" << std::endl;
}
//--------------------------------------------------------------------------------------------------------------

Both lines were written to the file. That should do you, right?

> Thanks, though,

You are welcome.

Note that I/O is complicated. If the DLL had chosen to use the Win32 API
function WriteConsole() instead of the C++ I/O stream then it's I/O wouldn't
have been written to the file (at least I don't think so but I am frankly
too lazy and too busy now to test that).

Further if the call to SetStdHandle() does not precede the load of a DLL
whose output you want to capture then it will go to the real console instead
of the file.

Finally, the mysterious looking number -11 in the C# source is the manifest
constant STD_OUTPUT_HANDLE defined in <winbase.h>. I don't do enough interop
to know if there are .Net equivalents of such things. If there is one, I'm
all ears. :-)

Regards,
Will
Thomas W. Brown - 23 Jun 2005 20:46 GMT
Thanks again, Will..

"I/O is complicated" kind of says it all.  I will be able to use this
approach to cleanly get the stdout of the unmanaged code into an external
file.

My wish, though, was to be able to route the console output to the non-file
based StreamWriter that I had created for special handling of output.  For
diagnostic purposes I prepend output lines with a timestamp and thread name
and then, well, then it gets complicated because I route the resulting text
through delegates on an event to any of several possible clients; one of
which displays these lines in a multi-line text control, another just dumps
to its own console window, etc.  

Actually, I'm wondering, had the unmanaged code used the Win32 Console
routines, whether it might have worked correctly -- after all, a lot of the
.NET stuff is built up atop of the Win32 code.

-- Tom
William DePalo [MVP VC++] - 23 Jun 2005 23:25 GMT
> My wish, though, was to be able to route the console output to the
> non-file
[quoted text clipped - 7 lines]
> dumps
> to its own console window, etc.

This is the kind of thing that would be done on the native side of the house
with a "pipe". A pipe is a two ended device that supports two way
communication. What you would do natively would be to create a pipe to which
naked output would be delivered. A background thread could read from the
pipe and then send it off to your custom stream.

This is just thinking out loud but as pipes have "file" names of the form

   \\machineName\pipe\pipeName

you might be able to replace "console.txt" and add a thread to the mix which
reads from the pipe and writes to the console. Of course, I haven't tried
this.

Regards,
Will
Thomas W. Brown - 23 Jun 2005 23:35 GMT
> > My wish, though, was to be able to route the console output to the
> > non-file
[quoted text clipped - 21 lines]
> reads from the pipe and writes to the console. Of course, I haven't tried
> this.

Ahh... that sounds feasible (although a lot more work than I can afford
right this moment) -- I'll put that on the top of my list of approaches,
though.  Thanks!

-- Tom

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.