Writing to an active log window

Hey everyone,

I am trying to make a program (that executes mostly in backround) to write strings to a "Log Window" to show the user what its doing. The program would send the strings to its log window. My problem is I can't get the program to write its test data to the log window.
This is what I want it to do:


#include <windows.h>
#include <fstream>
#include <string>
include other stuff (what?)
int WINAPI main()
{
string = "test string"

--> write the test string to the log window as normal text.
--> Save it to a text file.

}//end main.


Thanks in advance!
That can be tricky. This might help.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <windows.h>
#include <stdio.h>          //contains _fdopen
#include <fcntl.h>          //contains equate _O_TEXT
#include <io.h>             //contains declare for _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
#define  IDC_BUTTON  1500

long __stdcall fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) 
{ 
 HWND hButton;
 HINSTANCE hIns;
 int hCrt,iWeight;
 FILE *hf;	

 switch (msg)                                                            
 {                                                                       
  case WM_CREATE:
    hIns=((LPCREATESTRUCT)lParam)->hInstance;  
    hButton=CreateWindow("button","Show Console",WS_CHILD|WS_VISIBLE,110,65,200,25,hwnd,(HMENU)IDC_BUTTON,hIns,0);
    return 0;     
  case WM_COMMAND:
    if(LOWORD(wParam)==IDC_BUTTON)
    {
       AllocConsole();
       hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
       hf = _fdopen( hCrt, "w" );
       _iob[1]=*hf;
       iWeight=210;
       printf("My Name Is Fred And I Weight %u Pounds!\n",iWeight);
    }
    return 0;
  case WM_CLOSE:
    DestroyWindow(hwnd);
    PostQuitMessage(WM_QUIT);
    return 0;                                      
 }                                                                       
                                                                         
 return DefWindowProc(hwnd,msg,wParam,lParam);                           
}


int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{                                   
 char szBuffer[64];       
 WNDCLASSEX wc;                    
 MSG messages;                     
 HWND hWnd;                        
 
 strcpy(szBuffer,"Console_Output");
 wc.lpszClassName=szBuffer   ;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND;   wc.cbWndExtra=0;
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0; 
 RegisterClassEx(&wc);
 strcpy(szBuffer,"GUI Console Output With C Runtime Library From C!");  
 hWnd=CreateWindow("Console_Output",szBuffer,WS_OVERLAPPEDWINDOW,500,500,440,200,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
 }

 return messages.wParam;
}


I see there isn't much in the way of explanatory comment in that code, so here is a slightly fancier version of the same written in PowerBASIC that explains somewhat what is going on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
'Program demonstrates how to restore standard output handle in C Runtime Library
'which is zeroed out by initialization of GUI process.
#Compile Exe
#Include "Win32api.inc"           'Translation of Windows.h for PowerBASIC
%IDC_BUTTON1 = 1250               'ctrl id of button
%O_TEXT      = &H4000             'from Fcntl.h

Type FILE      'From stdio.h      'When a GUI application is started the three standard OS handles
  pChar        As Asciiz Ptr      'STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE are all
  cnt          As Long            'zeroed out by the console initialization routines.  These three
  pBase        As Asciiz Ptr      'handles are replaced by valid values when a GUI application calls
  flag         As Long            'AllocConsole(). Therefore, once this is done, calling GetStdHandle()
  fil          As Long            'will always return valid handle values. The problem is that the
  charbuf      As Long            'CRT has already completed initialization before an application gets
  bufsize      As Long            'a chance to call AllocConsole(); the three low I/O handles 0, 1,
  TmpFileName  As Asciiz Ptr      'and 2 have already been set up to use the original zeroed out OS
End Type                          'handles, so all CRT I/O is sent to invalid OS handles and CRT output
                                  'does not appear in the console.

Declare Function GetConsoleWindow Lib "Kernel32.dll" Alias "GetConsoleWindow" () As Dword


Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _   'printf from stdio.h
( _
  szFmtStr As Asciiz _
  [, _
     Byval lpVar1 As Any, _
     Byval lpVar2 As Any, _
     Byval lpVar3 As Any, _
     Byval lpVar4 As Any _
  ] _
) As Long


Declare Function Open_OSFileHandle CDecl Lib "msvcrt.dll" Alias "_open_osfhandle" _  'from IO.h
( _
  Byval hHandle As Long, _
  Byval iType   As Long _
) As Long


Declare Function FDOpen CDecl Lib "msvcrt.dll" Alias "_fdopen" _   'from stdio.h
( _
  Byval hHandle As Long, _
  ByRef pszStr As Asciiz _
) As Dword


Function WndProc(Byval hWnd As Long,Byval wMsg As Long,Byval wParam As Long,Byval lParam As Long) As Long
  Select Case wMsg
    Case %WM_CREATE
      Local hButton As Dword
      Local hIns As Dword
      hIns=GetModuleHandle(Byval 0)
      hButton=CreateWindow("button","Show Console!",%WS_CHILD Or %WS_VISIBLE,110,65,200,25,hWnd,%IDC_BUTTON1,hIns,Byval 0)
      WndProc=0
      Exit Function
    Case %WM_COMMAND
      If Lowrd(wParam)=%IDC_BUTTON1 And HiWrd(wParam)=%BN_CLICKED Then
         Local hStdOutput As Dword              'Standart Output Handle
         Local hf,ptrFile As FILE Ptr           'FILE *
         Local hDll,hCrt,dwWeight As Dword
         Local hSysMenu As Dword
         Register i As Long
         hDll=LoadLibrary("msvcrt.dll")         'Load/Increment Reference Count on msvcrt.dll
         If hDll Then                           'Get base address of exported symbol _iob from msvcrt.dll.  _iob is an
            ptrFile=GetProcAddress(hDll,"_iob") 'array of FILE structs that holds the stdin, stdout, and stderr handles.
            Call AllocConsole()                 'These handels are zeroed out at initialization of a GUI process, and
            hSysMenu=GetSystemMenu(GetConsoleWindow(),Byval 0)   'must be reset with valid operating system handles if
            Call DeleteMenu(hSysMenu,6,%MF_BYPOSITION)           'console output is desired in a GUI process.  With a
            hCrt=Open_OSFileHandle(GetStdHandle(%STD_OUTPUT_HANDLE),%O_TEXT)  'valid handel to stdout returned in hf, it
            hf=FDOpen(hCrt,"w")                 'is restored back in position 1 of the i/o buffer FILE array with
            @ptrFile[1]=@hf                     '@ptrFile=@hf. printf output using CRT in PowerBASIC!
            dwWeight=210
            For i=1 To 200                     '
              printf("%d" + Chr$(9) + "My Name Is Fred And I Weigh %u Pounds!"+$Cr+$Lf,i,dwWeight)
            Next i
            Call FreeLibrary(hDll)              'Free/decrement reference count on msvcrt.dll
         End If
      End If
      WndProc=0
      Exit Function
    Case %WM_DESTROY
      Call PostQuitMessage(0)
      WndProc=0
      Exit Function
  End Select

  WndProc=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function

Function WinMain(Byval hIns As Long, Byval hPrev As Long, Byval lpCL As Asciiz Ptr, Byval iShow As Long) As Long
  Local szBuffer As Asciiz * 64
  Local wc As WNDCLASSEX
  Local Msg As tagMsg
  Local hWnd As Dword

  szBuffer="Console_Output"                           : wc.lpszClAssName=Varptr(szBuffer)
  wc.lpfnWndProc=Codeptr(WndProc)                     : wc.cbSize=Sizeof(wc)
  wc.style=%CS_HREDRAW Or %CS_VREDRAW                 : wc.hInstance=hIns
  wc.cbClsExtra=0                                     : wc.cbWndExtra=0
  wc.hIcon=LoadIcon(%NULL, Byval %IDI_APPLICATION)    : wc.hCursor=LoadCursor(%NULL, Byval %IDC_ARROW)
  wc.hbrBackground=%COLOR_BTNFACE+1                   : wc.lpszMenuName=%NULL
  Call RegisterClAssEx(wc)
  szBuffer="GUI Console Output With C Runtime Library From PowerBASIC!"
  hWnd=CreateWindow("Console_Output",szBuffer,%WS_OVERLAPPEDWINDOW,500,550,440,200,0,0,hIns,Byval 0)
  Call ShowWindow(hWnd,iShow)
  Call UpdateWindow(hWnd)
  While GetMessage(Msg,%NULL,0,0)
    TranslateMessage Msg
    DispatchMessage Msg
  Wend

  Function=msg.wParam
End Function
Last edited on
Thanks mate!
The code looks good, but when I try to compile I get 1 error(I use MS Visual Studio 2010 Prof.)

error C2065: '_iob' : undeclared identifier
That refers to line 26 of the C++ code.

Do you know as what I have to declare it? Thanks.

Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#define  IDC_BUTTON  1500


// I just reinvented printf function!
void myprintf(const char *fmt,...)
{
    DWORD dwRead;
    va_list vl;
    va_start(vl,fmt);
    char buff[2048];
    vsprintf(buff,fmt,vl);
    va_end(vl);
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),buff,strlen(buff),&dwRead,0);

}



LRESULT CALLBACK fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
 HWND hButton;
 HINSTANCE hIns;
 int hCrt,iWeight;
 FILE *hf;

 switch (msg)
 {
  case WM_CREATE:
    hIns=((LPCREATESTRUCT)lParam)->hInstance;
    hButton=CreateWindow("button","Show Console",WS_CHILD|WS_VISIBLE,110,65,200,25,hwnd,(HMENU)IDC_BUTTON,hIns,0);
    return 0;
  case WM_COMMAND:
    if(LOWORD(wParam)==IDC_BUTTON)
    {
       AllocConsole();

       iWeight=210;
       myprintf("My Name Is Fred And I Weight %u Pounds!\n",iWeight);
    }
    return 0;
  case WM_CLOSE:
    DestroyWindow(hwnd);
    PostQuitMessage(WM_QUIT);
    return 0;
 }

 return DefWindowProc(hwnd,msg,wParam,lParam);
}


int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{
 char szBuffer[64];
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 strcpy(szBuffer,"Console_Output");
 wc.lpszClassName=szBuffer   ;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND;   wc.cbWndExtra=0;
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 strcpy(szBuffer,"GUI Console Output With C Runtime Library From C!");
 hWnd=CreateWindow("Console_Output",szBuffer,WS_OVERLAPPEDWINDOW,500,500,440,200,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
 }

 return messages.wParam;
}

Of course there are better ways to do this...
Last edited on

but when I try to compile I get 1 error(I use MS Visual Studio 2010 Prof.)


I don't have VS 2010 Prof but rather 2008 Pro. However, I believe I mostly used VS 6 and GNU compilers for that program. I'll test it tomorrow on 2008 Pro, but my guess is maybe the program needs a LoadLibrary() on "msvcrt.dll" (I believe that's where it would find _iob). I wouldn't have thought that, but that's my best guess now.
@ Null: Thanks a lot, this works!! Have you got an example of a better way? I mean the console isnt the best way to ensure protability.

@ freddie1: Yep, got your code to work, but it doesnt display any text, the launcher window starts yet no text appears on the console...

I used this to make _iob work:

extern "C" FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]};
I mean the console isnt the best way to ensure protability.

Why do you think so?

By "there are better ways to do this..." I meant that there must be a way to display text in console without reinventing printf function.
Perhaps a little background on that code I posted. Several years back I discovered I could call printf from the Standard C Runtime Library using function pointers through a LoadLibrary() call on "msvcrt.dll" and a GetProcAddress() on printf. I just thought this was an interesting exercise when learning to use those techniques. I had been doing that in the context of console apps. I didn't realize there was a major problem there in using the C Runtime Function printf in GUI apps, but there most certainly is as explained rather tersely in some of my comments in the PowerBASIC example.

Eventually it occurred to me that it would be really cool to call printf ( a c runtime library function ) from an entirly different non C family language such as PowerBASIC (I know some folks waste their time causing mischief by such things as writting viruses, but this is how I enjoy my self with computers), so I set out to do that. That's when I learned of the major problem with printf and GUI apps. I had no problem calling printf from a PowerBASIC console mode app, but when GUI apps start the standard OS io handles are zeroed out and printf output goes in the bit bucket. I eventally found an obscure MSDN link which I don't have handy but I could retrieve it if anyone is interested, and that's how I figured out the C code to use printf in a GUI app. It took me several weeks to figure out how to do it in PowerBASIC though because _io[] is a symbol defined as extern in stdio.h and is exported from msvcrt.dll. While I knew how to use GetProcAddress() to get the address of a procedure, I didn't know it could be used to get the address of an exported symbol. A genius from the PowerBASIC world finally turned me on to that and within minutes I had the PowerBASIC program working perfectly.

A note to c0y454: You need to eliminate the ability for a user to click on the x button of a console window you are using to display output because it will kill the whole process. There is code in the PowerBASIC app showing how to do that.

Finally, perhaps I shouldn't have even posted the code because as null says there are easier ways of displaying text in a console window from either GUI or non-gui apps and that would be WriteConsole or something like that. However, for me, anything from any of the typical libraries used by I guess all C++ coders for console output such as any of the iostream type stuff is off limits to me as I dispise them and won't use them. As far as I'm concerned they are ridiculous and I only use stdio type io in my C++ console programs. I fully realize this is heresy in a C++ forum but I don't care and my opinion on this isn't going to change. As I said, when I have a chance I'll get that program working for you, its just that I'm busy right now.
I just checked and found that I had a Visual Studio 2008 C++ version of that program which works perfectly for me. This is the more typical coding style I use...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//AllocateConsole.h
#define       IDC_BUTTON  1500

typedef struct    WindowsEventArguments               
{
 HWND             hWnd;                               
 WPARAM           wParam;                             
 LPARAM           lParam;                             
 HINSTANCE        hIns;                               
}WndEventArgs,    *lpWndEventArgs;


struct EVENTHANDLER
{
 unsigned int    Code;
 long            (*fnPtr)(lpWndEventArgs);
};

/*
command line

/OUT:"C:\Code\VStudio\VC++9\AllocateConsole\Release\AllocateConsole.exe" 
/INCREMENTAL:NO /NOLOGO /MANIFEST /MANIFESTFILE:"Release\AllocateConsole.exe.intermediate.manifest" 
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
/DEBUG /PDB:"c:\Code\VStudio\VC++9\AllocateConsole\Release\AllocateConsole.pdb" 
/SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /LTCG /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:PROMPT 
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib 
oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
*/


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

#include      <windows.h>
#include      <tchar.h>
#include      <stdio.h>
#include      <stdlib.h>
#include      <fcntl.h>
#include      <io.h>
#include      "AllocateConsole.h"
EVENTHANDLER  EventHandler[3];


long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
 HWND hButton;
	
 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;  
 hButton=CreateWindow(_T("button"),_T("Execute"),WS_CHILD|WS_VISIBLE,70,70,141,30,Wea->hWnd,(HMENU)IDC_BUTTON,Wea->hIns,0);
 return 0;                                             
}


long fnWndProc_OnCommand(lpWndEventArgs Wea)
{
 HMENU hSysMenu;
 unsigned int i;
 int hCrt;
 FILE *hf;
 
 if(LOWORD(Wea->wParam)==IDC_BUTTON)
 {
    AllocConsole();
    hSysMenu=GetSystemMenu(GetConsoleWindow(),0);
    DeleteMenu(hSysMenu,6,MF_BYPOSITION);         
    hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);  
    hf=_tfdopen(hCrt,_T("w"));   //see http://support.microsoft.com/kb/105305
    *stdout=*hf;
    i=setvbuf(stdout,NULL,_IONBF,0);
    for(i=0;i<10;i++)
        _tprintf(_T("%u\t%s\n"),i,_T("Some Of The More Wicked Code I've Ever Written!"));
 }

 return 0;
}


long fnWndProc_OnClose(lpWndEventArgs Wea)  //This function handles the WM_CLOSE message
{                                           //sent when the 'x' button is clicked.
 if(MessageBox(Wea->hWnd,_T("Do You Wish To Exit This App?"),_T("Exit Check?"),MB_YESNO)==IDYES)
 {
    DestroyWindow(Wea->hWnd);
    PostQuitMessage(WM_QUIT);
 }

 return 0;
}


void AttachEventHandlers(void)  
{
 EventHandler[0].Code=WM_CREATE,    EventHandler[0].fnPtr=fnWndProc_OnCreate;         
 EventHandler[1].Code=WM_COMMAND,   EventHandler[1].fnPtr=fnWndProc_OnCommand; 
 EventHandler[2].Code=WM_CLOSE,     EventHandler[2].fnPtr=fnWndProc_OnClose; 
}


long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
 WndEventArgs Wea;
   
 for(unsigned int i=0;i<3 ;i++)
 {
     if(EventHandler[i].Code==msg)
     {
        Wea.hWnd=hwnd,Wea.lParam=lParam,Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 } 

 return (DefWindowProc(hwnd,msg,wParam,lParam));
}



int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{                                   
 TCHAR szClassName[]=_T("AllocateConsole");  
 WNDCLASSEX wc;                     
 MSG messages;                     
 HWND hWnd;  
                      
 AttachEventHandlers();                                    
 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=0;
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0; 
 RegisterClassEx(&wc);
 hWnd=CreateWindow(szClassName,_T("Allocate Console"),WS_OVERLAPPEDWINDOW,200,100,300,250,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
 }

 return messages.wParam;
}


If that doesn't produce a GUI Window with a button that when pressed produces a console window with printf text then I can't help any further, and I'm clueless as to what Microsoft did in 2010. This is a 32 bit program, you know. Not a 64 bit. Here is that link I told you about.

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

And the code above shows how to deactivate the x button.
Thanks a lot, freddie1! This really helped me a great deal.

Everything works, the x button is disabled on the console window. Thanks!!

I experienced no compability problems with MS Visual Studio 2010, copy+paste worked. (Using a MultiByte Character set for the Project).

@Null: I meant that MS might remove the console, as PowerShell(plus a few more years development) is well capable of replacing it.
Topic archived. No new replies allowed.