Menu

Using CRT Output In GUI

Fred
2007-09-26
2012-09-26
  • Fred

    Fred - 2007-09-26

    Hello!

    I'm engaged in what I hope is a learning experience for me in that I'm trying to create and use printf style console output statements in an AllocConsole() created console in a Windows GUI app. There is a problem with this and a work around to the problem from Microsoft. Below is a button press message handler from an sdk
    style windows program I created to illustrate the issue, and below that is a brief description of the problem from Microsoft article...

    Calling CRT Output Routines from a GUI Application
    Article ID : 105305
    Last Review : November 21, 2006
    Revision : 4.2

    http://support.microsoft.com/kb/105305

    long fnWndProc_OnCommand(lpWndEventArgs Wea) //This is code I extracted from an app I
    { //wrote to test the fix from Microsoft
    unsigned int i;
    int hCrt;
    FILE *hf;

    if(LOWORD(Wea->wParam)==IDC_BUTTON)
    {
    AllocConsole();
    hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
    hf = _fdopen( hCrt, "w" );
    stdout = hf;
    i = setvbuf( stdout, NULL, _IONBF, 0 );
    printf("My Name Is Fred!\n");
    MessageBox(Wea->hWnd,"Hopefully, You See A Console?","See A Console?",MB_ICONINFORMATION);
    }

    return 0;
    }

    below from Microsoft article...

    This code opens up a new low-level CRT handle to the correct console output handle, associates a new stream
    with that low-level handle, and replaces stdout with that new stream. This process takes care of functions
    that use stdout, such as printf(), puts(), and so forth. Use the same procedure for stdin and stderr. Note
    that this code does not correct problems with handles 0, 1, and 2. In fact, due to other complications, it
    is not possible to correct this, and therefore it is necessary to use stream I/O instead of low-level I/O.

    When a GUI application is started with the "start" command, the three standard OS handles STD_INPUT_HANDLE,
    STD_OUTPUT_HANDLE, and 'STD_ERROR_HANDLE are all "zeroed out" by the console initialization routines. These
    three handles are replaced by valid values when the GUI application calls AllocConsole(). Therefore, once
    this is done, calling GetStdHandle() will always return valid handle values. The problem is that the CRT has
    already completed initialization before your application gets a chance to call AllocConsole(); the three low
    I/O handles 0, 1, and 2 have already been set up to use the original zeroed out OS handles, so all CRT I/O is
    sent to invalid OS handles and CRT output does not appear in the console. Use the workaround described above
    to eliminate this problem.

    So what I'm saying here is that I've successfully implemented Microsoft's 'fix' and if the above message
    handler is placed in a GUI program which has a IDC_BUTTON on the main form, the click of the button will
    create a console and satisfactorily printf to it. What my problem is is that I don't understand how it
    works! For what I'm really trying to do so as to increase my knowledge of programming is to convert this
    technique to Bob Zale's PowerBASIC language, which is another programming language I use. So far I have
    been able to successfully translate the first two of the three required lines over to PowerBASIC and get them
    working, that is, the _open_osfhandle() function and the _fdopen() function in stdio.h, but I'm pretty
    badly stuck on the stdout = hf statement. I have made some progress but my grasp of C seems to be failing
    me. What I have accomplished is that I have successfully converted the FILE structure over to PowerBASIC
    and I have that working. I am able to use PowerBASIC to open a file with fopen() and fprintf to it, then
    close it with fclose(). I think that counts for something.

    But where I'm stuck is best described by an excerpt from stdio below that shows some of the machinations
    going on with _iobuf and FILE...

    /
    * The three standard file pointers provided by the run time library.
    * NOTE: These will go to the bit-bucket silently in GUI applications!
    /

    define STDIN_FILENO 0

    define STDOUT_FILENO 1

    define STDERR_FILENO 2

    /
    * The structure underlying the FILE type.
    *
    * Some believe that nobody in their right mind should make use of the
    * internals of this structure. Provided by Pedro A. Aranda Gutiirrez
    * <paag@tid.es>.
    /

    typedef struct _iobuf
    {
    char _ptr;
    int _cnt;
    char
    _base;
    int _flag;
    int _file;
    int _charbuf;
    int _bufsiz;
    char* _tmpfname;
    } FILE;

    / The standard file handles /

    extern FILE (_imp___iob)[]; / A pointer to an array of FILE */

    define _iob (_imp___iob) / An array of FILE */

    Like I said, I have managed to get the _iobuf (FILE) type created and working in PowerBASIC, but I don't understand what is going on with...

    extern FILE (*_imp___iob)[];

    Here is something else interesting from Microsoft's VC++ 6 stdio.h...

    typedef struct _iobuf FILE;

    ifndef _STDIO_DEFINED

    _CRTIMP extern FILE _iob[];

    endif / _STDIO_DEFINED /

    define stdin (&_iob[0])

    define stdout (&_iob[1])

    define stderr (&_iob[2])

    For me to translate this to another language I need to understand what is happening here and I don't. I guess my biggest quandry is where in the dickens is storage being declared and created for an array of FILE or _imp___iob[] structures? FILE seems to be defined here, yet there is an extern FILE _iob[] statement? Where is storage being provided for this structure or array of FILE structures? Not here! An extern to my understanding does not allocate storage? I guess the #define stdout (&_iob[1]) statement doesn't really put anything in this storage wherever its at, as its just a macro, but in the above message handler stdout = hf certainly does access memory!

    I have searched every *.h file in the include directories of both VC++ 6 and Dev C++ for anything related to stdout or _iob but I can't find anything related to this, at least nothing that I can understand. I hope I've made clear the nature of my quandry and I hope someone here could be kind enough to shed some light on this issue for me, as I'm struggling mightily to understand it. As an aside, it was a post here several years ago by Clifford S showing me how to load the msvcrt.dll library with LoadLibrary() and GetProcAddress() to get the address of printf within that library that got me started in this interesting quest.

     
    • Fred

      Fred - 2007-09-27

      Just ran a utility program on msvcrt.dll that lists exported symbols and found that _iob[] (a struct of type FILE) is an exported symbol from that dll. So at least I'm making some progress.

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.