> 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