Hello !
I am kind of stuck on this.
Don't know why the second call to "crt__kbhit" deadlocks ? :(
Any idea?
Thanks beforehand!
include masm32rt.inc
.486
option casemap :none
; #########################################################################
include msvcrt.inc
includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib
include \masm32\macros\macros.asm
WinMain PROTO
.data
CommandLine dd 0
hInstance dd 0
.code
start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain
invoke ExitProcess,eax ; cleanup & return to operating system
; #########################################################################
WinMain proc
invoke AllocConsole
print "First console",10,13
print "Press <any> key to continue..."
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
call FreeConsole
invoke AllocConsole
print "Second console",10,13
print "Press <any> key to end"
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
ret
WinMain endp
end start
A FreeConsole before the first AllocConsole was missing, but apparently it does not solve the problem. I added some error checking...
include \masm32\include\masm32rt.inc
WinMain PROTO
.data
CommandLine dd 0
hInstance dd 0
.code
start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain
invoke ExitProcess,eax ; cleanup & return to operating system
; #########################################################################
WinMain proc
if 1
invoke FreeConsole ; needed; otherwise, AllocConsole will fail
.if eax==0
print "Free first console FAIL",10,13
.endif
invoke Sleep, 100
endif
invoke AllocConsole
.if eax==0
print "First console FAIL",10,13
.endif
print "First console",10,13
print "Press <any> key to continue..."
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
invoke FreeConsole
.if eax==0
print "Free second console FAIL",10,13
.endif
invoke Sleep, 100
invoke AllocConsole
.if eax==0
print "Second console FAIL",10,13
.endif
print "Second console",10,13
print "Press <any> key to end"
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
ret
WinMain endp
end start
just to be sure it is crt__kbhit......
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
print chr$('key pressed'),13,10 ;temporary test code
ret
that way, if the ret is somehow messed up because of the stack, you will know
(better to use exit or invoke ExitProcess,0)
also, i suggest a sleep time of 100 or something
no need to test for a key every millisecond
It looks like the CRT _kbhit function does not monitor the second console.
i was just reading AllocConsole
it says you only get one console
Maybe this will shed some light on it. I'm assume you are linking with /SUBSYSTEM:WINDOWS as you have a WinMain.
INFO: Calling CRT Output Routines from a GUI Application (http://support.microsoft.com/kb/105305)
Quote from: Greg on July 24, 2009, 04:09:51 AM
I'm assume you are linking with /SUBSYSTEM:WINDOWS as you have a WinMain.
Greg, I tried both console and windows, same behaviour...
Quote from: dedndave on July 24, 2009, 12:54:52 AM
i was just reading AllocConsole
it says you only get one console
Yes, only one console at a time, but by second console I mean the console allocated after the first is freed.
If I build this as a console app:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke AllocConsole
print ustr$(eax),13,10
print "print to original console",13,10
invoke crt_printf, chr$("crt_printf to original console",13,10)
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@:
invoke Sleep, 1
call crt__kbhit
test eax, eax
jz @B
call crt__getch
invoke FreeConsole
invoke AllocConsole
print "print to new console",13,10
invoke crt_printf, chr$("crt_printf to new console",13,10)
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
@@:
invoke Sleep, 1
call crt__kbhit
test eax, eax
jz @B
call crt__getch
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
Then the first call to AllocConsole fails (returns zero) and everything works except crt__kbhit in the second console. But if I build it with just assemble and link, then the first call to AllocConsole succeeds and print works, but the only CRT component that works is crt__kbhit in the first console.
i think the inkey macro uses both crt__kbhit and crt__getch
in fact, the loop you are using looks very similar to the macro
anyways, try Sleep,100 in the loops - it seems to matter (if i remember that's what the macro uses)
What I used was copied directly from the inkey macro, including the Sleep 1.
BTW, the resolution for Sleep is normally 10ms.
kinda obvious, but could it possibly be that your handles are destroyed when you do the freeconsole
then when you do the allocconsole, you need to do the GetStdHandle api's to get the new handle?
i wrote a function similar to crt__kbhit/crt__getch
it always empties the buffer on exit
the FlushConsoleInputBuffer could be removed from the routine, but i was trying to fix a different kind of bug
this is something i have been working on for a while - lol
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
.data?
hStdInp dd ?
EventCount dd ?
InpEvntRec INPUT_RECORD <>
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke AllocConsole
print ustr$(eax),13,10
print "print to original console",13,10
invoke crt_printf, chr$("crt_printf to original console",13,10)
invoke GetStdHandle,STD_INPUT_HANDLE
mov hStdInp,eax
invoke FlushConsoleInputBuffer,eax
@@:
invoke Sleep, 1
call crt__kbhit
test eax, eax
jz @B
call crt__getch
invoke FreeConsole
invoke AllocConsole
print "print to new console",13,10
invoke crt_printf, chr$("crt_printf to new console",13,10)
invoke GetStdHandle,STD_INPUT_HANDLE
mov hStdInp,eax
invoke FlushConsoleInputBuffer,eax
print chr$('Press any key to close this console')
test00:
invoke Sleep,100
call InKyb
jz test00
exit
;--------------------------------------------------------------------------
InKyb PROC
;Poll keyboard
InKyb0: INVOKE PeekConsoleInput,
hStdInp,
addr InpEvntRec,
1,
addr EventCount
mov eax,EventCount
or eax,eax
jz InKyb1 ;ZF set if no key
INVOKE ReadConsoleInput,
hStdInp,
addr InpEvntRec,
1,
addr EventCount
movzx eax,word ptr InpEvntRec.EventType
dec eax
jnz InKyb0
dec dword ptr InpEvntRec.KeyEvent.bKeyDown
jnz InKyb0
INVOKE FlushConsoleInputBuffer,
hStdInp
xor eax,eax
inc eax ;ZF cleared if key
movzx eax,word ptr InpEvntRec.KeyEvent.wVirtualScanCode
InKyb1: ret
InKyb ENDP
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
EDIT
you may want to "hide" the cursor during the inkey loop
i usually turn it off at the beginning of the program and turn it back on just before exit
.data?
hStdOut dd ?
CursInfo CONSOLE_CURSOR_INFO <>
.code
;save initial cursor visibility value
;set cursor visibility to false (off)
INVOKE GetStdHandle,
STD_OUTPUT_HANDLE
mov hStdOut,eax
INVOKE GetConsoleCursorInfo,
eax,
ADDR CursInfo
push CursInfo.bVisible
mov dword ptr CursInfo.bVisible,FALSE
INVOKE SetConsoleCursorInfo,
hStdOut,
ADDR CursInfo
pop CursInfo.bVisible
;set cursor visibility to initial setting
INVOKE SetConsoleCursorInfo,
hStdOut,
ADDR CursInfo
Thanks guys !
I have learned a lot. :bg
I come up with a "home-made" kbhit.
It seems to work. :8)
- It even won't distruct "crt__kbhit" in the second console. -
include \masm32\include\masm32rt.inc
WinMain PROTO
.data
CommandLine dd 0
hInstance dd 0
.code
start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain
invoke ExitProcess,eax ; cleanup & return to operating system
; #########################################################################
WinMain proc
;invoke FreeConsole ; needed only if compiled as console
LOCAL lpBuffer :INPUT_RECORD
LOCAL hConsoleInput :DWORD
LOCAL lpNumberOfEventsRead :DWORD
.if eax==0
print "Free first console FAIL",10,13
.endif
invoke Sleep, 100
invoke AllocConsole
.if eax==0
print "First console FAIL",10,13
.endif
invoke GetStdHandle, STD_INPUT_HANDLE
mov hConsoleInput, eax
invoke FlushConsoleInputBuffer, hConsoleInput
print "First console",10,13
print "Press <any> key to continue...",10,13
call kbhit
invoke FreeConsole
.if eax==0
print "Free second console FAIL",10,13
.endif
invoke Sleep, 100
invoke AllocConsole
.if eax==0
print "Second console FAIL",10,13
.endif
invoke FlushConsoleInputBuffer, rv(GetStdHandle,STD_INPUT_HANDLE)
print "Second console",10,13
print "Press <any> key to end"
@@: invoke Sleep, 1
call crt__kbhit
test eax, eax
je @B
ret
; ########### kbhit PROC ###########
kbhit: .repeat
invoke PeekConsoleInput, hConsoleInput,ADDR lpBuffer,1,ADDR lpNumberOfEventsRead
.until (lpNumberOfEventsRead != 0)
.if (lpBuffer.EventType != KEY_EVENT) || (lpBuffer.KeyEvent.bKeyDown == 0)
invoke FlushConsoleInputBuffer, hConsoleInput
jmp kbhit
.endif
retn
WinMain endp
end start
i try to write routines that replace the crt functions
they are great for development, but if i write code to be released, i prefer no crt
crt functions are large and probably require some type of licensing statement
some of the masm32 library macros use crt functions - inkey is one of them
Hi Dave,
There is no need to specify any licensing statement to use msvcrt functions.
dedndave,
The CRT functions are generally large and slow, but they are very stable and reliable. They have been "tried and tested" by years and years of C programmers. So, I tend to have the opposite view, I would trust a CRT function much more than a "home brew" function. It is a lot of fun to write your own though.
Quote
very stable and reliable
Yes I use CRT a lot as well but this particular case it seems to have a bug. :naughty:
Quote from: Greg on July 24, 2009, 05:26:33 PM
The CRT functions are generally large and slow
Can't you safely assume that crtdll.dll sits in C:\WINDOWS\system32?? In that case, they can be as large and bloated as Microsoft wants them to be - but calling them costs only a handful of bytes - the same as for Masm32 lib functions. And the crt algos are
not slow. In fact, it's generally hard to beat them.
Quote
It is a lot of fun to write your own though.
I agree 100% :bg
well - it is fun - and i have learned a lot in doing so (even if i didn't need to - lol - oops)
as for this particular bug, it's not the first one i have run across with the console
i am not sure about how different windows versions act, but this makes my console bug count = 4
i am using windows xp pro mce2005
(i guess my next little project will be to ID OS's like we did for CPU's)
jj2007,
MSVCRT.DLL is included in every version of Windows since Windows 98.
Quote from: jj2007And the crt algos are not slow. In fact, it's generally hard to beat them.
What?? You're the last person I'd expect to hear that from. :bg The CRT functions usually come in much slower in speed tests when comparing them to asm functions that replace them.
Quote from: FickoYes I use CRT a lot as well but this particular case it seems to have a bug.
Yes, I would expect it to just work. But, I think the work-around would be to remap the low-level handles as shown in the link I posted above (haven't tried it).
Ficko,
You got me, I can't get it to work. _getch doesn't work either.
Quote from: Greg on July 24, 2009, 09:52:36 PM
MSVCRT.DLL is included in every version of Windows since Windows 98.
Indeed. That's why the statement "they are large" is pretty meaningless. You call them, you don't embed them in your executable.
Quote
Quote from: jj2007And the crt algos are not slow. In fact, it's generally hard to beat them.
What?? You're the last person I'd expect to hear that from. :bg The CRT functions usually come in much slower in speed tests when comparing them to asm functions that replace them.
It depends. There are some you can beat only with SSE2 versions...
Algo memcpy MemCo1 MemCo2 MemCoC3 MemCoP4 MemCoC2 MemCoL
Description CRT rep movs movdqa lps+hps movdqa movdqa Masm32
dest-al psllq CeleronM dest-al src-al library
Code size ? 70 291 222 200 269 33
---------------------------------------------------------------------------
2048, d0s0-0 556 566 363 363 373 363 560
I changed the name to waitkey because unlike _kbhit this coding removes all events from the buffer and leaves it empty. I chose to respond to the key-release event instead of the key-press event to avoid having the pending release trigger unexpected actions. Build as a console app.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; ---------------------------------------------------------
; The INPUT_RECORD structure in the MASM32 windows.inc,
; prior to MASM32 version 10, is a direct translation of
; the structure from the API header files and as such it
; lacks the alignment padding that the C/C++ compiler
; would add, and that Windows expects, ahead of the union.
; ---------------------------------------------------------
_INPUT_RECORD STRUCT DWORD
EventType WORD ?
UNION
KeyEvent KEY_EVENT_RECORD <>
MouseEvent MOUSE_EVENT_RECORD <>
WindowBufferSizeEvent WINDOW_BUFFER_SIZE_RECORD <>
MenuEvent MENU_EVENT_RECORD <>
FocusEvent FOCUS_EVENT_RECORD <>
ENDS
_INPUT_RECORD ENDS
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
waitkey proc
LOCAL hStdIn: DWORD
LOCAL nRead: DWORD
LOCAL ir: _INPUT_RECORD
invoke GetStdHandle, STD_INPUT_HANDLE
mov hStdIn, eax
invoke FlushConsoleInputBuffer, hStdIn
waitLoop:
;----------------------------------------------------------------
; A 10ms sleep is sufficient to drop the CPU usage to near zero.
;----------------------------------------------------------------
invoke Sleep, 10
invoke ReadConsoleInput, hStdIn, ADDR ir, 1, ADDR nRead
cmp nRead, 0
je waitLoop
;-----------------------------
; Discard any non-key events.
;-----------------------------
movzx eax, ir.EventType
cmp eax, KEY_EVENT
jne waitLoop
;----------------------------------
; Return on the key-release event.
;----------------------------------
cmp ir.KeyEvent.bKeyDown, 0
je @F
jmp waitLoop
@@:
ret
waitkey endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
print "print to original console",13,10
invoke crt_printf, chr$("crt_printf to original console",13,10)
print "Press any key to continue...",13,10
call waitkey
invoke FreeConsole
invoke AllocConsole
print "print to new console",13,10
invoke crt_printf, chr$("crt_printf to new console",13,10)
print "Press any key to exit...",13,10
call waitkey
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
Compliments, that works perfectly even with multiple consoles :U
print "print to original console",13,10
invoke crt_printf, chr$("crt_printf to original console",13,10)
print "Press any key to continue...",13,10
call waitkey
REPEAT 5
invoke FreeConsole
invoke AllocConsole
print "print to new console",13,10
invoke crt_printf, chr$("crt_printf to new console",13,10)
print "Press any key to exit...",13,10
call waitkey
ENDM
exit
didn't i already do that on page one of the thread, guys ? - lol
in fact, with my routine, you can continue executing other code until a key is pressed (i.e. it polls the keyboard)
with waitkey, it requires a keypress in order to exit
jj2007,
Quote from: jj2007That's why the statement "they are large" is pretty meaningless. You call them, you don't embed them in your executable.
If you statically link them they are embedded in your executable.
You just want to argue, don't you?
Quote from: Greg on July 25, 2009, 05:50:59 PM
jj2007,
Quote from: jj2007That's why the statement "they are large" is pretty meaningless. You call them, you don't embed them in your executable.
If you statically link them they are embedded in your executable.
You just want to argue, don't you?
No, Greg. But I am curious to know why several people apparently think that calls to crt bloat the executable. For example, I have a proc that uses crt_strstr. Here is what I get from Olly:
004030B7 |. FF15 68404000 |call near [<&msvcrt.strstr>] ; \strstr
strstr 8B4C24 08 mov ecx, [esp+8]
77C17C64 57 push edi ; ntdll.7C920738
That doesn't look like a part of my executable... or am I wrong?
well, to be honest - there are problems associated with the console keyboard
it is a pain in the arse, when it should be very simple
problems arise because keyboard events are placed into the same buffer as mouse and other input events
this is logical, as it provides a time-line for managing input events without time-stamping them
the problems i have been having involve the mouse events, especially with regard to copy/paste
in fact, copy/paste is buggish, even when the console is sitting at the command prompt (i.e. no process running)
but - these are bugs - it's not something that is easy to program around
in other words, if the functions acted like they ought to, there would be no problems
one problem is that mouse-pasted text can show up in the output buffer
so, as a plan to eliminate that problem, i have tried using SetConsoleMode to disable the mouse events
well - SetConsoleMode does not do what it is supposed to do
the fact is, if the console has bugs, even with no process running, it may be impossible to make it act correctly
that means that the problems arise, whether you use the crt or not
it doesn't matter how stable it is or how many years of improvement it has seen
one soultion i have been looking at is to modify the contents of the output buffer - removing the pasted text
that means you have to process all input events, not just the keyboard events we are interested in
another problem i have seen is that the display positions may get bumped if you use right-click/mark
once they have been bumped this way, that console window is trashed
terminating the program and restarting it in the same console still yields bumped positions
you have to close that window and open a fresh one to make it act right again
this could be programmed around, but not simply
at some point, you have to start looking into fixing the console instead of trying to fix your program
i haven't attempted to contact ms and report these bugs
that may be the best solution, too
that way, they can generate KB999999 and fix everyones console windows
i don't know if they care enough about console-mode apps to mess with it
i may have a solution for the paste bug
prior to writing text to the screen, you could flush the output buffer by writing it to the NUL device
let me play with it...
You are right about the Windows Console, it does have it problems. Design problems from the beginning, I think.
yes - i am just finishing a demo program
it uses multiple consoles and stationary display updates
i even managed to tame the orignal console upon returning to it
i am cleaning it up and i want to comment it before i post it in this thread
it will give us something to demonstrate a few of the console mode bugs, i think
maybe we can work together and find some solutions........
ok - here it is ! - lol :bg
the program that does it all, and yet, does very little
it demonstrates a few ways to make the console fancier than the scrolling white text, then terminate, that we all know and love
it uses no crt or masm32 libraries or macros
it can create any number of new consoles, then return to the original and make that one still usable, too (that was tricky - lol)
it can also be used to demonstrate some of the console bugs i was talking about
this is version 1 - no buffer fixes added, yet
should be a good program for n00bies who want to learn their way around the console
[attachment deleted by admin]
Looks good :U
i'm glad you like it Jochen - thank you
i hope there is stuff in there everyone can make use of
i even tried to use ebp instead of esp - lol - just to make the code copy/paste-able
Hello,
Tried it out and got an error popup.
CONDEMO1.EXE - Entry Point Not Found
The procedure entry point AttachConsole could not be located
in the dynamic link library kernel32.dll.
Version problems?
Regards,
Steve N.
it must be - hmmmmmm
i am using xp mce 2005
QuoteTo compile an application that uses this function, define _WIN32_WINNT as 0x0501 or later
i did not do that, of course - lol
it is supported on xp and server 2003
you could rem that line out and put an ExitProcess there
it re-attaches the original console
when you return to the original console, it will be unusable - just exit
here you go, Steve
i modified this one for Win2K
[attachment deleted by admin]
You forgot the attachment! :bdg
Best regards,
Astro.
Dave,
Works fine, thanks. :U
Quote from: dedndave on July 27, 2009, 11:29:55 PM
here you go, Steve
i modified this one for Win2K
Hi,
This one does work. Very nice.
Thank you,
Steve N.