News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Suggestion with MSVCRT code.

Started by hutch--, June 06, 2005, 04:59:13 AM

Previous topic - Next topic

hutch--

Just as a later thought, I am yet to understand the prejudice against polling loops, they are like anything else, write them properly and they work fine, do it wrong and they will almost lock a box up. Over time I have heard many fashions in programming, you should not use GOTO in a program but should use structured loops. You should not use GLOBAL scope variables but always use LOCALS passed on the stack.

The problem is there is a whole mountain of code that you cannot write if you have restrictions on such techniques. Now in response the the GOTO boogie, I instead only use JUMPS and as few as I can get away with and I simply ignore the "rule" on LOCALS only if I need the scope of a GLOBAL so I wonder if there is a new rule of fashion on using polling loops ?

The basic mechanics is there is no other way of performing regular interval checks on events that test for a result. You can pass this off to the operating system if you like but it still must do the same to determine the results of events. On the win2k and later OS versions this is the 7 to 8% at idle processor usage of interrupts so I don't see that it is all that efficient in terms of processor usage. While I see that Windows is poorly designed in terms of low level access, this type of loop is trivial to write from ring3 access and they test up fine if they are written properly.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

This is the latest version of the test piece, added title bar text control for a console using standard API functions. The wait_key procedure needs to be added to the masm32 library.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    date$ MACRO
      IFNDEF @_@_current_local_date_@_@
        .data?
          @_@_current_local_date_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,
                           NULL,NULL,ADDR @_@_current_local_date_@_@,128
      EXITM <OFFSET @_@_current_local_date_@_@>
    ENDM

    time$ MACRO
      IFNDEF @_@_current_local_time_@_@
        .data?
          @_@_current_local_time_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetTimeFormat,LOCALE_USER_DEFAULT,NULL,NULL,NULL,
                           ADDR @_@_current_local_time_@_@,128
      EXITM <OFFSET @_@_current_local_time_@_@>
    ENDM

    ;; ----------------------------------
    ;; display user defined text, default
    ;; text or none if NULL is specified.
    ;; ----------------------------------
    inkey MACRO user_text:VARARG
      IFDIF <user_text>,<NULL>                  ;; if user text not "NULL"
        IFNB <user_text>
          print user_text                       ;; print user defined text
        ELSE
          print "Press any key to continue ..." ;; print default text
        ENDIF
      ENDIF
      call wait_key
      print chr$(13,10)
    ENDM

    SetConsoleCaption MACRO title_text
      invoke SetConsoleTitle,reparg(title_text)
    ENDM

    GetConsoleCaption$ MACRO
      IFNDEF @@_console_caption_buffer_@@
      .data?
        @@_console_caption_buffer_@@ db 260 dup (?)
      .code
      ENDIF
      invoke GetConsoleTitle,ADDR @@_console_caption_buffer_@@,260
      EXITM <OFFSET @@_console_caption_buffer_@@>
    ENDM

    env$ MACRO item
      fn crt_getenv,item
      EXITM <eax>
    ENDM

    setenv MACRO value
      fn crt__putenv,value
    ENDM

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL penv  :DWORD

    SetConsoleCaption "Ain't MASM beautiful ?"

    print "Today's date is "
    print date$(),13,10,13,10
    print "You started this program at "
    print time$(),13,10,13,10

    print "The console caption is '"
    print GetConsoleCaption$(),"'",13,10

    setenv "link=\masm32\bin\"

    mov penv, env$("link")
    .if penv != 0
      print penv,13,10
    .endif

    inkey NULL

    inkey

    inkey "Wait for keyboard input with user defined text ",62," "

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

  @@:
    invoke Sleep,10
    call crt__kbhit
    test eax, eax
    jz @B

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,

I tried out the latest macros, they look good to me. I watched the CPU Usage when 'wait_key' is looping and it is essentially zero.


hutch--

Greg,

Thansk for giving it a blast, I don't think it works any better than either yours or Michaels but its smaller and simpler. It makes more sense to put it in a library module than inline it as its hardly speed critical and just let the macro handle the string options. I think your suggestion to use FlushConsoleInputBuffer() was a good idea as it did simplify the code.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

#19
Here is a freestyle variation of the wait_key proc, it automatically counts down from 10 seconds to zero and exits if a key has not been pressed while updating the console window title. It could probably do with some tidying up but it seems to work OK.

LATER : Tidied up a bit.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

    LOCAL tc    :DWORD
    LOCAL cnt   :DWORD
    LOCAL buf   :DWORD
    LOCAL buffer[32]:BYTE

    mov tc, rv(GetTickCount)
    add tc, 1000
    mov cnt, 10

    jmp ifin

  @@:
    invoke Sleep,10
    .if rv(GetTickCount) >= tc
      add tc, 1000
      sub cnt, 1
      jz @F
    ifin:
      mov buf, ptr$(buffer)
      SetConsoleCaption cat$(buf,str$(cnt)," seconds left")
    .endif
    test rv(crt__kbhit), eax
    jz @B
  @@:

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Mark Jones

Are we adding all these tasty little tidbidts to SP3? :bg
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

zooba

Here's my suggestion for a pause/wait_key function. It doesn't use the function from the C runtime (which I had to avoid because I couldn't find an include/library for it :eek) but I think it's just as neat:

wait_key PROC
    LOCAL   hConsole:DWORD
    LOCAL   dwConsoleMode:DWORD
   
    invoke  GetStdHandle, STD_INPUT_HANDLE
    mov     hConsole, eax
   
    invoke  GetConsoleMode, hConsole, ADDR dwConsoleMode
    invoke  SetConsoleMode, hConsole, 0
    invoke  ReadFile, hConsole, NULL, 1, NULL, NULL
    invoke  SetConsoleMode, hConsole, dwConsoleMode

    invoke  FlushConsoleInputBuffer, hConsole
    ret
wait_key ENDP


The local variables could probably be avoided by using push/pops or registers, but either way its going to use the stack so I decided to go with the easiest to read. And as hutch (I think) mentioned earlier, it's hardly time critical code and when you play with APIs optimization goes out the MS Windows anyway  :bg :cheekygreen:

hutch--

zooba,

Thanks for this piece of genius, it works fine, handles the combined keys correctly and has very low processor usage.  :U
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Jibz

#23
None of the 'special' keys (like CTRL, ALT, SHIFT, ESC, arrow keys, F-keys, etc.) seem to work with that version?

Edit: I just noticed that CTRL, ALT and SHIFT did not seem to work with the polling loop version either.

Edit 2: Of course those three don't work with the 'pause' command either, so it's not a big problem unless you're the type who takes "Press any key to continue..." very literally :toothy.

MazeGen

Quote from: Greg on June 10, 2005, 07:27:10 PM
Note: I am using ML.EXE v6.15 and it doesn't like 'pause'. I can't find a reference to that instruction.  If I change it to 'waitkey' no problem.

pause.asm(58) : error A2085: instruction or register not accepted in current CPU mode


PAUSE is new since Pentium4, but is backward compatible with all IA-32 processors, because its opcode corresponds to REP NOP instruction.

GregL

zooba,

  Nice code :U,  that works better than the Win32 API version of "waitkey" I had.

MazeGen,

  Thanks for the info, I never found anything on the PAUSE instruction and gave up.


hutch--

 :bg

> Edit: I just noticed that CTRL, ALT and SHIFT did not seem to work with the polling loop version either.

But look on the bright side, it would be easy enough to add URL checking, DRM testing and with just a bit more work, multimedia support. Imagine having music while you made up your mind which key to press. We could usher in a new era of user interaction at the console level that may see the BIG return to true console apps.  :toothy
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Tedd

Please excuse Hutch, he's been 'testing' his homebrew again :lol
No snowflake in an avalanche feels responsible.

hutch--

Nah,

My code is unlicenced as GPA, Glenfiddich Powered Assembler.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

Hutch,

I see a potential problem with your latest waitkey procedure. If the user presses a key at some point before waitkey is called, it will not wait. While some users might expect a key pressed ahead of time to have an effect, I think most users would not.
eschew obfuscation