Redirecting stdout without using AllocConsole

I am developing several MFC GUI programs
that all are using libraries that use printf() and
other stdio output routines for error messages.
Since the end-user is expected to have many
of these programs running at the same time, I
don't want to open a console for each of these.

Thus, I would want to redirect these messages
to a pipe or similar where I would pick them up,
format and show them myself. The best thing
would probably be if each of my programs did
this, so that they are not dependent on an ex-
ternal program to show all error messages.

I have tried to achieve this but redirection would
only work if when AllocConsole() is used.

Hopefully someone can give me an example of
or at least a clue to how this could be done.




nockertAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

V_BapatCommented:
Look at this codeguru article:
http://codeguru.developer.com/misc/redirect.shtml
0
V_BapatCommented:
You can try to log all the messages to a log file which can be used later. A couple of articles are present in Codeguru site for this:

http://codeguru.developer.com/misc/log_class.shtml
http://codeguru.developer.com/misc/Log.shtml

Hope this helps.

Vicky
0
nockertAuthor Commented:
(Thanks Vicky.)

The code available on codeguru as well as other places all concern redirecting stdio from processes started by the GUI-program, these are expected to have stdout/stdin defined since they would most likely be command prompt applications.

Now, I have a GUI-program which does not have a console and want to redirect printf's in my program (called from libraries that I have to use, and cannot change the code of).

Log-files may eventually prove to be the only option but hopefully I can avoid them. However, I still think I might have a problem with that since I can't redirect my programs stdio calls as it is now.
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

jkrCommented:
What about providing your own version of 'printf()' which does the job for you, e.g.

int printf (PSTR psFormat, ...)
    {
    PSTR    psBuffer;
    PVOID   va_list;
    DWORD   l, n;

    n = (DWORD) -1;
    psBuffer = ( char *) LocalAlloc (LMEM_FIXED, 8192);
    if (psBuffer != NULL)
        {
        va_list = (PVOID) ((DWORD) &psFormat + sizeof (PSTR));
        wvsprintf (psBuffer, psFormat, (char *) va_list);
        l = lstrlen (psBuffer);
        if (!(WriteFile (hMyRedirectedHandle, psBuffer, l, &n, NULL) && !(l-n)))
            {
            n = (DWORD) -1;
            }
        LocalFree (psBuffer);
        }
    return n;
    }
0
nockertAuthor Commented:
That seems to work "locally", that is, in the file that I add the above code. Do you know how I should implement it so that it becomes global? I can't change anything in the libraries.

How do I solve fprintf(stderr,...)?

Anyway, if I get this to work it seems like the best alternative.


Thanks!


0
jkrCommented:
As you're creating a GUI app, you don't have to change anything in the libraries, but remove the ms libc (aka 'msvcrt.lib', either the implib or the static library) and supply 'surrogates' for the stdio function the linker reports as 'unresolved externals'...
0
mikeblasCommented:
jkr's suggestion is too radical. If you remove msvcrt.libk, your app won't build because MFC (and probably other parts of your own code) need it.  

If you take that approach as it's suggested here, you'll end up rewriting strlen(), memcpy(), and so on!

..B ekiM
0
jkrCommented:
Mike is right, it _is_ radical. When re-thinking about this, have you tried opening a file (using 'CreateFile()') and 'SetStdHandle( hFile, STD_OUTPUT_HANDLE);' along with 'SetStdHandle( hFile, STD_ERROR_HANDLE);' ?
0
mikeblasCommented:
These programs that need to be redirected--are you spawning them yourself, always?  Have you written them yourself, always?  

It seems to me that you're going about this all wrong--that you're trying to have the subordinate console programs redirect their own output. Instead, I think you should call CreateProcess() and supply handles for stdout and stdin to let the subordinate applications write to a pipe the calling program has created.

That doesn't require any changes in the subordinate apps, and you won't have to entertain suggestions about rewriting the runtime libraries. Is there a reason that you aren't considering the use of CreateProcess() and its redirection flags?

..B ekiM
0
jkrCommented:
>>These programs that need to be
>>redirected

Mike, didn't you read the Q? nockert uses _libraries_ whose output has to be redirected...
0
mikeblasCommented:
Oh! I read this:

 > I am developing several MFC GUI programs
 > that all are using libraries that use printf()  

As "I am developing several MFC GUI programs that use printf(), and also link to some libraries and that doesn't matter".

I didn't read it as "I am using libraries that use printf()".

Then, the problem is even easier--you should be able to use freopen() on stdin and stdout to get them to point someplace else.  I haven't done that since Win16, though. Something in the newest implementation of the CRTLs might preclude it.

..B ekiM
0
jkrCommented:
Weel - or, as I mentioned, 'SetStdHandle()'...
0
nockertAuthor Commented:
(Sorry, I've been away for two days)

Okay, it seems a reiteration of my problem is probably in place, i was probably a bit unclear.

jkr is correct in that I am not spawning any programs. In my GUI application (does not have stdout defined) I am forced to use certain libraries, in which printf's and fprintf(stderr)'s are used to provide error information. I have tried AllocConsole and that works flawlessly. However, since my application package is of the modular type (one executable per task), the end-user is expected to have a couple of these applications running at the same time, and to have one console per application would not really be practical. Furthermore, I have already created a shared 'console', an application consisting of little more than a rich-edit control which receive all errors/warning/information messages (except the ones the libraries are outputting) and shows/logs them. Thus, I would want the libraries error output to be formatted and sent to that window.

I have formerly used pipes to handle spawned applications output, but in this case I cannot get it to work. I get the pipes working but I cannot get redirection of the actual 'stdout' to work. I tried with freopen and SetStdHandle, and i get valid (or at least not null) handles back, it just doesn't seem to work with printf's.

Since I have unsuccessfully tried some different solutions, I would be very grateful if I could get snippets of code of the actual redirection code (I have no problem with the pipes implementation).

Thanks again for your help.
0
rmaczCommented:
     The code belows creates the anonymous pipe, gets the and attaches the write end of the pipe to the stdout stream
      (of course it is also possible with stderr). To attach the pipe to the stdout, I first get the operating
      system file number (_open_osfhandle) for the write end of the pipe, and than call fdopen to open the stdout for the
      opened file.
      To see if any data has been written to the stdout first call fflush(stdout) and than PeekNamedPipe to check if any
      data have actually been written.

      I have tried it and it works.




      HANDLE hRead, hWrite;
      BOOL b = CreatePipe( &hRead, &hWrite, NULL, 0 );            // create read and write pipe
      if ( !b )
            return false;

      int fileNo = _open_osfhandle( (long)hWrite, 0 );            // get operating system file number for the write end
                                                                                          // of the pipe
      if ( fileNo == -1 )
            return false;

      fclose( stdout );                                                            // close the stdout
      fdopen( fileNo, "wt" );                                                      // open the stdout with the new file number


      // library call!
      printf( "Just any text\n" );                                          // print the text to the standard output

      
      fflush( stdout );                                                            // flush stdout
      DWORD bytes;
      b = PeekNamedPipe( hRead, NULL, 0, NULL, &bytes, NULL );// and here it is
      // bytes == 14 -> you can read the data using ReadFile function


0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.