The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: MaynardG_Krebs on March 03, 2007, 06:31:21 PM

Title: Pause function
Post by: MaynardG_Krebs on March 03, 2007, 06:31:21 PM
I am playing around with Win32 console functions and obviously don't know what I am doing. The following code seems to assemble and link alright but when I try to run it the console window flashes on the screen and disappears.

Is there another function or procedure I need to call to get the window to pause before exiting to the operating system?


include \masm32\include\masm32rt.inc
   
    .data?
        bytesWritten DWORD ?    ; number of bytes written

    .data
        endl EQU <0dh,0ah>      ;end of line
        mesg BYTE "Hello World",0,endl
        messagesz = ($-mesg)
   
        consoleHandle DWORD 0

    .code

start:

    INVOKE GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleHandle, eax

    INVOKE WriteConsole,
        consoleHandle,
        ADDR mesg,
        messagesz,
        ADDR bytesWritten,
        0

    INVOKE ExitProcess, 0

end start


Thanks
Title: Re: Pause function
Post by: TNick on March 03, 2007, 06:53:48 PM
Maybe you should see how inkey macro works (\masm32\macros\macros.asm). This is the one that does the job in my console programs.

Nick
Title: Re: Pause function
Post by: dsouza123 on March 03, 2007, 07:08:44 PM
A couple of options inkey or wait_key

As Nick wrote inkey


   inkey
   INVOKE ExitProcess, 0



   wait_key
   INVOKE ExitProcess, 0


The difference, inkey writes the message
Press any key to continue ...
wait_key doesn't show a message,

inkey uses wait_key to wait for a key press.
Title: Re: Pause function
Post by: MaynardG_Krebs on March 03, 2007, 07:39:34 PM
Thanks TNick and dsouza123 that makes it do what I wanted. :U
I'll take a look at the macros to see how they work.
Title: Re: Pause function
Post by: Ehtyar on March 03, 2007, 08:16:44 PM
inkey is a rather nasty hack IMO, and requires the crt and a loop function. I would recommend setting the console mode to ENABLE_PROCESSED_INPUT and reading a single character from stdin. That requires only winapi and no loop.

Ehtyar.
Title: Re: Pause function
Post by: MichaelW on March 03, 2007, 09:17:34 PM
Quote
inkey is a rather nasty hack IMO, and requires the crt and a loop function. I would recommend setting the console mode to ENABLE_PROCESSED_INPUT and reading a single character from stdin. That requires only winapi and no loop.

To duplicate even most of the functionality of wait_key your method would require calls to GetStdHandle, SetConsoleMode, FlushConsoleInputBuffer, and ReadConsole or ReadFile, plus a buffer, and additional code to move the returned character into EAX. And after all of this it still would not respond to the escape, function, or navigation keys as wait_key does.
Title: Re: Pause function
Post by: PBrennick on March 04, 2007, 12:00:38 AM
Which is...


ConsoleIn proc lpbuffer:DWORD,bufflen:DWORD

  ; -----------------------------------------------------------
  ; lpbuffer should be 260 bytes on win2k and later os versions
  ; -----------------------------------------------------------
    LOCAL stdhandle :DWORD
    LOCAL readcount :DWORD

    invoke GetStdHandle,STD_INPUT_HANDLE
    mov stdhandle, eax

    invoke SetConsoleMode,stdhandle,ENABLE_LINE_INPUT or \
                                    ENABLE_ECHO_INPUT or \
                                    ENABLE_PROCESSED_INPUT

    invoke ReadFile,stdhandle,lpbuffer,bufflen,ADDR readcount,NULL

  ; ---------------
  ; strip CRLF pair
  ; ---------------
    mov eax, lpbuffer
    sub eax, 1
  @@:
    add eax, 1
    cmp BYTE PTR [eax], 0
    jz @F
    cmp BYTE PTR [eax], 13
    je @F
    cmp BYTE PTR [eax], 10
    ja @B

  @@:
    mov BYTE PTR [eax], 0
    sub eax, lpbuffer

    ret

ConsoleIn endp


Not too bad, in my opinion. It is in my library. All the user has to supply is a buffer and its length.  :U
Paul

Title: Re: Pause function
Post by: sinsi on March 04, 2007, 12:51:34 AM
How about
WaitForKey PROC uses edi
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov edi,eax
    invoke WaitForSingleObject,edi,INFINITE
    invoke FlushConsoleInputBuffer,edi
    ret
WaitForKey ENDP

Title: Re: Pause function
Post by: GregL on March 04, 2007, 01:27:25 AM
Quote from: Ehtyarinkey is a rather nasty hack IMO, and requires the crt and a loop function.

I disagree. There's nothing wrong with using the CRT, it's just another Windows DLL that can be called. No different than calling the Windows API. Granted, the CRT functions aren't the best for speed, but for functionality and stability they are pretty darn good. The CRT has withstood the test of time.

Title: Re: Pause function
Post by: Ehtyar on March 04, 2007, 03:40:59 AM
Quote from: sinsi on March 04, 2007, 12:51:34 AM
How about
WaitForKey PROC uses edi
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov edi,eax
    invoke WaitForSingleObject,edi,INFINITE
    invoke FlushConsoleInputBuffer,edi
    ret
WaitForKey ENDP
Well i sure as hell love that, thanks sinsi, that is some awesome code :)
Quote from: MichaelW on March 03, 2007, 09:17:34 PM
Quoteinkey is a rather nasty hack IMO, and requires the crt and a loop function. I would recommend setting the console mode to ENABLE_PROCESSED_INPUT and reading a single character from stdin. That requires only winapi and no loop.
To duplicate even most of the functionality of wait_key your method would require calls to GetStdHandle, SetConsoleMode, FlushConsoleInputBuffer, and ReadConsole or ReadFile, plus a buffer, and additional code to move the returned character into EAX. And after all of this it still would not respond to the escape, function, or navigation keys as wait_key does.
You'll forgive me if i was a little vague. What i mean to say is that if you're not using the crt to begin with (i almost never do, thus my bias in this case) it's not very nice to have to include extra dependencies just for a function this simple. (and why is a loop required if you're not using the return value anyway?)

Ehtyar.
Title: Re: Pause function
Post by: sinsi on March 04, 2007, 04:43:36 AM
Quote from: Ehtyar on March 04, 2007, 03:40:59 AM
Well i sure as hell love that, thanks sinsi, that is some awesome code :)
Why thankyou  :bg
I was looking for something as simple as "sub ah,ah; int 16h" and a few beers later up it popped :bdg
Title: Re: Pause function
Post by: zooba on March 04, 2007, 05:32:26 AM
Quote from: Greg on March 04, 2007, 01:27:25 AM
Quote from: Ehtyarinkey is a rather nasty hack IMO, and requires the crt and a loop function.

I disagree. There's nothing wrong with using the CRT, it's just another Windows DLL that can be called. No different than calling the Windows API. Granted, the CRT functions aren't the best for speed, but for functionality and stability they are pretty darn good. The CRT has withstood the test of time.

The CRT simply calls the Win32 API functions. It's not 'just another Windows DLL', it's a wrapper around the Windows API and some extra functionality which isn't part of the API. If you desperately want this extra functionality, go ahead. If you don't, the Windows API route is much more efficient.

Sinsi,

Love your code, that's even better than my variant. I've thrown it into ASM Runtime if that's okay with you?

Cheers,

Zooba :U
Title: Re: Pause function
Post by: sinsi on March 04, 2007, 05:38:18 AM
Quote from: zooba on March 04, 2007, 05:32:26 AM
Sinsi,

Love your code, that's even better than my variant. I've thrown it into ASM Runtime if that's okay with you?

Cheers,

Zooba :U

No, this is my own personal code...heh heh.
Of course you can use it - anyone can do anything they want with it (except blame me) :U
Go for it!
Title: Re: Pause function
Post by: MichaelW on March 04, 2007, 08:19:11 AM
Quote from: sinsi on March 04, 2007, 12:51:34 AM
How about
WaitForKey PROC uses edi
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov edi,eax
    invoke WaitForSingleObject,edi,INFINITE
    invoke FlushConsoleInputBuffer,edi
    ret
WaitForKey ENDP


Good idea, but I see two problems. The first is that the input buffer is not being flushed before the call to WaitForSingleObject, so the code will not wait if there is anything in the input buffer. The second is that WaitForSingleObject responds to the key-release event. If you do two calls to the procedure without a significant delay between the calls, even with a call to FlushConsoleInputBuffer placed ahead of the call to WaitForSingleObject, the second call will not wait.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
WaitForKey PROC uses edi
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov edi,eax
    invoke FlushConsoleInputBuffer,edi
    invoke WaitForSingleObject,edi,INFINITE
    invoke FlushConsoleInputBuffer,edi
    ret
WaitForKey ENDP
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke WaitForKey
    print "1",13,10
    invoke WaitForKey
    print "2",13,10
    invoke wait_key
    print "1",13,10
    invoke wait_key
    print "2",13,10
    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

Title: Re: Pause function
Post by: hutch-- on March 04, 2007, 08:54:07 AM
I have seen these odd purist comments before about predispositions of which system DLLs should be used and which should be ignored but its hard to argue a case of efficiency when an application is doing no more than waiting on a keystroke. MSVCRT.DLL has been a Windows component since win95b and it is very reliable.

Contrary to popular opinion, a polling loop with a published wait function (Sleep) is extremely efficient in terms of processor usage as it only does a periodic test for the keystroke and yields to the OS for the rest of the time. If this was a performance critical issue you would look for the most efficient way to perform the task but it is still no more than waiting for a keystroke and as its doubtful that anyone can hit any key fast enough to beat the keyboard repeat rate let alone do something that actually changes the processor usage.

I am in debt to Greg for his original design work from MSVCRT for the procedure that is simple, fast and reliable.
Title: Re: Pause function
Post by: MichaelW on March 04, 2007, 12:49:56 PM
Quote from: Ehtyar on March 04, 2007, 03:40:59 AM
(and why is a loop required if you're not using the return value anyway?)
The loop waits for a key press, with essentially a CPU utilization of zero. The call to crt__getch removes the keystroke from the buffer, leaving it empty, and returns the key character.

To me, "nasty hack" describes code that is ill designed and unreliable. The wait_key procedure is neither.
Title: Re: Pause function
Post by: MaynardG_Krebs on March 04, 2007, 04:13:51 PM
Thanks to everyone for the input and great code samples! This gives me a lot of information to digest and more code to play around with. :P
I can see advantages in each, ranging from simplicity to functionality.
Title: Re: Pause function
Post by: GregL on March 04, 2007, 07:41:31 PM
Well, I don't "desperately want" the extra functionality but there are times when it's the best option.

I prefer to use the Windows API, but there are times when recreating the functionality of a C Run-Time function is not worth it. The CRT functions work and have been exhaustively tested over the years. If you are looking for maximum speed, you probably don't want to use a CRT function. If you are looking for reliability and stability and the Windows API doesn't offer the functionality you need, they are a good way to go.

I know I will never convince the "purists" around here.  If you don't want to use the CRT functions, fine, don't use them, but criticizing people for using them is out of line.


Title: Re: Pause function
Post by: PBrennick on March 04, 2007, 09:33:06 PM
Greg,
Very well said.

Paul
Title: Re: Pause function
Post by: sinsi on March 05, 2007, 07:38:24 AM
OK, maybe I didn't have enough beers  :(

WaitForKey PROC uses edi
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov edi,eax
    invoke FlushConsoleInputBuffer,edi         ;make sure there are no keystrokes
    invoke WaitForSingleObject,edi,INFINITE    ;wait for a key down
    invoke FlushConsoleInputBuffer,edi         ;remove the keydown so it doesn't echo
    invoke WaitForSingleObject,edi,INFINITE    ;wait for a key up
    invoke FlushConsoleInputBuffer,edi         ;remove the keyup so it doesn't echo
    ret
WaitForKey ENDP

Now it's getting a bit too complicated (and maybe a bit too long time-wise?).
And there is the problem of a key held down and repeating...

I must admit I don't use CRT at all - it seems a bit much to load a big DLL just to use one function - but that is my personal preference.
Why isn't there a PressAnyKey function in kernel32 boo hoo.
Title: Re: Pause function
Post by: Mark Jones on June 22, 2008, 07:41:55 PM
The above un-pauses when I mouse-over the CUI window. :lol

I had to add:


invoke SetConsoleMode,hConsoleInput,ENABLE_LINE_INPUT or \
    ENABLE_ECHO_INPUT or \
    ENABLE_PROCESSED_INPUT