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.
You link it as a console app, so in addition to whatever window(s) your code creates the app will have a console.
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
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).
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
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
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.
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
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