The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: bf2 on November 19, 2011, 08:18:19 AM

Title: Writing to the console from within the window procedure
Post by: bf2 on November 19, 2011, 08:18:19 AM
I know that Windows programs should be linked with the switch /subsystem:windows and console programs should be linked with the switch /subsystem:console.

How do I link a program that writes a line to the console from a Windows program?

Something like this (just to illustrate):


WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT

INVOKE GetStdHandle, STD_OUTPUT_HANDLE ; -11
INVOKE  WriteConsole, EAX, cString("It's me!"), cString("It's me!"), num, 0

; message processing follows...



TIA.
   
Title: Re: Writing to the console from within the window procedure
Post by: MichaelW on November 19, 2011, 08:32:10 AM
You link it as a console app, so in addition to whatever window(s) your code creates the app will have a console.
Title: Re: Writing to the console from within the window procedure
Post by: Vortex on November 19, 2011, 09:02:21 AM
Hi bf2,

Maybe this is not what you are trying to do but have a look at this example :


include     ConsoleTest.inc

.data

msg1        db 'Click OK to write to the console',0
msg2        db 'This is a StdOut test',0
msg3        db 'Click OK to terminate the application',0
capt        db 'Console test',0

.code

start:

    invoke  AllocConsole

    invoke  MessageBox,0,ADDR msg1,ADDR capt,MB_OK

    invoke  StdOut,ADDR msg2

    invoke  MessageBox,0,ADDR msg3,ADDR capt,MB_OK
   
    invoke  ExitProcess,0

END start
Title: Re: Writing to the console from within the window procedure
Post by: bf2 on November 19, 2011, 11:05:35 AM
Quote from: Vortex on November 19, 2011, 09:02:21 AM
Hi bf2,

Maybe this is not what you are trying to do but have a look at this example :


include     ConsoleTest.inc

.data

msg1        db 'Click OK to write to the console',0
msg2        db 'This is a StdOut test',0
msg3        db 'Click OK to terminate the application',0
capt        db 'Console test',0

.code

start:

    invoke  AllocConsole

    invoke  MessageBox,0,ADDR msg1,ADDR capt,MB_OK

    invoke  StdOut,ADDR msg2

    invoke  MessageBox,0,ADDR msg3,ADDR capt,MB_OK
   
    invoke  ExitProcess,0

END start


Vortex, that exactly what I was trying to do, so thank you. And your code works perfectly when linked with the console switch, mine doesn't. Actually mine doesn't write anything regardless of whether it's linked with the console switch or the windows switch.

I'll now investigate the differences between the procedures you are calling (AllocConsole and StdOut) and what I'm calling (GetStdHandle and WriteConsole).
Title: Re: Writing to the console from within the window procedure
Post by: Vortex on November 19, 2011, 11:23:37 AM
Hi bf2,

The source of code of \masm32\m32lib\stdout.asm :


.
.
StdOut proc lpszText:DWORD

    LOCAL hOutPut  :DWORD
    LOCAL bWritten :DWORD
    LOCAL sl       :DWORD

    invoke GetStdHandle,STD_OUTPUT_HANDLE
    mov hOutPut, eax

    invoke StrLen,lpszText
    mov sl, eax

    invoke WriteFile,hOutPut,lpszText,sl,ADDR bWritten,NULL

    mov eax, bWritten
    ret

StdOut endp
.
.


LATER : WriteConsole works fine.



include     ConsoleTest.inc

.data

msg1        db 'Click OK to write to the console',0
msg2        db 'This is a StdOut test',0
msg3        db 'Click OK to terminate the application',0
capt        db 'Console test',0

.data?

hOutPut     dd ?
bWritten    dd ?

.code

start:

    invoke  AllocConsole

    invoke  MessageBox,0,ADDR msg1,ADDR capt,MB_OK

    invoke  GetStdHandle,STD_OUTPUT_HANDLE
    mov     hOutPut,eax

    invoke  StrLen,ADDR msg2

    invoke  WriteConsole,hOutPut,ADDR msg2,eax,ADDR bWritten,0

    invoke  MessageBox,0,ADDR msg3,ADDR capt,MB_OK
   
    invoke  ExitProcess,0

END start
Title: Re: Writing to the console from within the window procedure
Post by: dedndave on November 19, 2011, 11:45:44 AM
sometimes, we want a temporary console
try this little test program...

open it by clicking on the exe in explorer - not by typing the name at a console prompt   :P
Title: Re: Writing to the console from within the window procedure
Post by: bf2 on November 19, 2011, 12:56:27 PM
I am sorry guys, I have just realised that my original code had a silly error in it.


INVOKE GetStdHandle, STD_OUTPUT_HANDLE ; -11
INVOKE  WriteConsole, EAX, cString("It's me!"), cString("It's me!"), num, 0


The third parameter to WriteConsole should have been the length of the string, not the string itself !!!

Apologies for wasting your time.

With that corrected it runs fine when linked with the console switch.
Title: Re: Writing to the console from within the window procedure
Post by: mineiro on November 19, 2011, 01:21:46 PM
just another example
include masm32rt.inc

.data
message db "type exit to quit",00h
quit db "exit",00h

.data?
buffer db 1024 dup (?)

.code
Main proc
LOCAL houtput:DWORD,hinput:DWORD,bytes_writen:DWORD

invoke GetStdHandle,STD_INPUT_HANDLE
mov hinput,eax
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov houtput,eax
invoke WriteFile,houtput,addr message,sizeof message,addr bytes_writen,0
@@: invoke RtlZeroMemory,addr buffer,sizeof buffer
invoke ReadFile,hinput,addr buffer,sizeof buffer,addr bytes_writen,0
or eax,eax
jz @F
lea eax,buffer
cmp dword ptr [eax],"tixe" ;typed exit?
jz @F
invoke WriteFile,houtput,addr buffer,bytes_writen,addr bytes_writen,0
jmp @B
@@: invoke ExitProcess,0
Main endp
end Main
Title: Re: Writing to the console from within the window procedure
Post by: jj2007 on November 19, 2011, 05:41:33 PM
And just for fun, the shortest print ever - 35 bytes instead of 58:

push Chr$("Hello World", 13, 10)
call MbStdOut2


MbStdOut2 proc
   pop edx
   pop eax   ; bufStart
   push edx   ; restore ret address
   push ecx   ; save reg
   xchg eax, ecx   ; we need bufStart in ecx
   push eax   ; slot for bytes read
   mov eax, esp   ; get ptr to slot
   push 0   ; lpOverlapped
   push eax   ; ptrBytesWritten
   if 1
      push len(ecx)   ; bufCt - works fine, but it is not documented that len preserves ecx
   else
      push Len(ecx)   ; bufCt - safer but requires MasmBasic (http://www.masm32.com/board/index.php?topic=12460)
   endif
   push ecx   ; bufStart
   invoke GetStdHandle, STD_OUTPUT_HANDLE
   push eax   ; hWrite
   call WriteFile   ; invoke WriteFile, hWrite, bufStart, bufCt, ptrBytesWritten, 0
   pop eax   ; contains bytes written
   pop ecx
   ret
MbStdOut2 endp

:wink