Writing to the console from within the window procedure

Started by bf2, November 19, 2011, 08:18:19 AM

Previous topic - Next topic

bf2

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.
   

MichaelW

You link it as a console app, so in addition to whatever window(s) your code creates the app will have a console.
eschew obfuscation

Vortex

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

bf2

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).

Vortex

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

dedndave

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

bf2

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.

mineiro

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

jj2007

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
   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