[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1454
  • Last Modified:

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.




0
nockert
Asked:
nockert
  • 5
  • 3
  • 3
  • +2
1 Solution
 
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
[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

 
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

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 5
  • 3
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now