News:

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

Console buffer

Started by Neil, October 04, 2008, 02:08:04 PM

Previous topic - Next topic

Neil

I'm having a problem returning the buffer (rows) back to it's original size after I've displayed a database consisting of many hundreds of lines. The code that increases the number of rows is :-

    invoke GetStdHandle,STD_OUTPUT_HANDLE
    mov hConsoleOutput,eax
    invoke GetConsoleScreenBufferInfo,hConsoleOutput,ADDR csbi
    mov ax,Data    ;Number of rows required
    shl eax,16
    mov ax,csbi.dwSize.x
    invoke SetConsoleScreenBufferSize,hConsoleOutput,eax

That works no problem, but when I try to do the opposite i.e return the buffer back to 25 lines :-

    mov ax,25      ;Original buffer size
    shl eax,16
    mov ax,csbi.dwSize.x
    invoke SetConsoleScreenBufferSize,hConsoleOutput,eax

The buffer remains at the larger size. Anyone got a suggestion as to what is wrong.


akane

This is a common problem, you must ensure that console window will be not larger than the buffer. So, you need first to call SetConsoleWindowInfo, resizing the window (if needed).
While expanding the screen buffer, you will have never problems, because console screen can be smaller than the buffer. But if you try to resize the window to 100 while buffer is 99, you'll get an error.

Neil

Thanks for the info akane, I'll look into your suggestion

Neil

I've just got around to trying invoke SetConsoleWindowinfo

I've defined a small rectangle :-

                                       small_rect      SMALL_RECT <>

The problem I'm having is how to put the 4 coordinates required into this structure, I've tried a number of ways & always end up with an error, so if somebody could point me in the right direction it would be a great help.

MichaelW

I'm assuming that the problem is the WORD members. For the RECT structure there is an API function, SetRect, that can load the members in single function call. This does the same for a SMALL_RECT.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      small_rect SMALL_RECT <>
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
SetSmallRect proc ps_r:DWORD,left:DWORD,top:DWORD,right:DWORD,bottom:DWORD
    mov edx, ps_r
    mov eax, left
    mov [edx].SMALL_RECT.Left, ax
    mov eax, top
    mov [edx].SMALL_RECT.Top, ax
    mov eax, right
    mov [edx].SMALL_RECT.Right, ax
    mov eax, bottom
    mov [edx].SMALL_RECT.Bottom, ax
    ret
SetSmallRect endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke SetSmallRect, ADDR small_rect, 1, 2, 3, 4

    movzx eax, small_rect.Left
    print ustr$(eax),13,10
    movzx eax, small_rect.Top
    print ustr$(eax),13,10
    movzx eax, small_rect.Right
    print ustr$(eax),13,10
    movzx eax, small_rect.Bottom
    print ustr$(eax),13,10

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

SMALL_RECT STRUCT
  Left      WORD      ?
  Top       WORD      ?
  Right     WORD      ?
  Bottom    WORD      ?
SMALL_RECT ENDS


eschew obfuscation

Neil

Thanks Michael, to the rescue once again. I'd have never found that API in a million years :U

Neil

Michael, I've looked up SetRect API & it says this is not available in English? Very odd.
But the program now works perfectly, I can now return the console back to its original size :U

jj2007

Quote from: Neil on October 10, 2008, 06:23:29 PM
Michael, I've looked up SetRect API & it says this is not available in English? Very odd.
But the program now works perfectly, I can now return the console back to its original size :U

It's perfectly available, but frankly speaking it's kind of superfluous. Four m2m's do the job as well, with the same number of bytes, and somewhat faster.

Neil

JJ,
I,ve followed this link to the Microsoft API reference site :-

                     http://msdn.microsoft.com/en-us/library/aa383749(VS.85).aspx

But all it says when I look up SetRect is:-

                     Content cannot be found

The content you requested is not available in your language English (United States). The list below contains all copies of this page for all supported locales and versions. Click on one of the links to view an alternate copy of the content.

日本語 (日本) cc428714(ja-jp,MSDN.10).aspx

I take your advice on using m2m & when I get round to optimising the code I'll give it a try, just at the moment I'm happy that it works.

MichaelW

I was assuming that this was a case were convenience was more important than speed. I think MSDN has a temporary problem. SetRect has been available since Windows 95, and it is documented in the PSDK.
eschew obfuscation

GregL


jj2007

Quote from: MichaelW on October 11, 2008, 05:16:32 PM
I was assuming that this was a case were convenience was more important than speed.

Sorry, I was just trying to eschew obfuscation  :bg

jj2007

#12
Quote from: MichaelW on October 10, 2008, 03:58:32 PM
I'm assuming that the problem is the WORD members. For the RECT structure there is an API function, SetRect, that can load the members in single function call. This does the same for a SMALL_RECT.

Just for fun, another SetSmallRect, slightly shorter (19 instead of 37 bytes) and equally fast. By the way, when timing these algos (see full code attached), I had trouble with the macro version - it crashed inside the counter_begin/counter_end loop.

-----------------------------------------------
EDIT: Problem solved...:

No good:
    push left
    pop [edx].SMALL_RECT.Left

Much better:
    push left
    pop dword ptr [edx].SMALL_RECT.Left

The macro is 6 bytes longer than the procedure, but calling the procedure costs 27 bytes; and the macro is clearly the fastest option, with 7 cycles. Strangely enough the PopSmallRect version became faster after I fixed the macro: 10 instead of 13 cycles :dazzled:
-----------------------------------------------

EDIT(2): Zip removed, correct version is attached further down.

The timings below show that the WinApi SetRect is remarkably close to the two roll-your-own versions, 15 instead of 13 cycles.

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
PopSmallRect proc ps_r:DWORD,left:DWORD,top:DWORD,right:DWORD,bottom:DWORD
pop edx ; trash the return address
pop edx ; move the first argument to edx
pop dword ptr [edx].SMALL_RECT.Left
pop dword ptr [edx].SMALL_RECT.Top
pop dword ptr [edx].SMALL_RECT.Right
pop dword ptr [edx].SMALL_RECT.Bottom
sub esp, 6*4 ; correct for 6 pops
ret 5*4 ; correct stack for five arguments
PopSmallRect endp
osPopSmallRect:
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef


Timings:
27     SetSmallRect call
37     SetSmallRect procedure
13     cycles

101
201
301
401

33     SmallRect macro
7      cycles

102
202
302
402


27     PopSmallRect call
19     PopSmallRect procedure
10     cycles

103
203
303
403

WinApi SetRect
15     cycles

104
204
304
404

MichaelW

The pops in the macro are messing up the alignment of the stack pointer, note the operand size prefix on the pops:

00401365 6A66                   push    66h
00401367 668F02                 pop     [edx]
0040136A 68CA000000             push    0CAh
0040136F 668F4202               pop     [edx+2]
00401373 682E010000             push    12Eh
00401378 668F4204               pop     [edx+4]
0040137C 6892010000             push    192h
00401381 668F4206               pop     [edx+6]


And you can verify that this is the problem by changing the code to:

    pop [edx].SMALL_RECT.Left
    pop ax
    push top
    pop [edx].SMALL_RECT.Top
    pop ax
    push right
    pop [edx].SMALL_RECT.Right
    pop ax
    push bottom
    pop [edx].SMALL_RECT.Bottom
    pop ax


Which will run OK.
eschew obfuscation

jj2007

Michael, you probably did not see my earlier edit in red above. You are perfectly right, of course. I have tried now to optimise this routine, and results look ok:

27     bytes SetSmallRect call
37     bytes SetSmallRect procedure
13     cycles

27     bytes PopSmallRect call
20     bytes PopSmallRect procedure
10     cycles

The new PopSmallRect algo looks as follows:

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
PopSmallRect proc ps_r:DWORD,left:DWORD,top:DWORD,right:DWORD,bottom:DWORD
pop edx ; trash the return address
pop edx ; move the first argument to edx
pop dword ptr [edx].SMALL_RECT.Left
pop dword ptr [edx].SMALL_RECT.Top
pop dword ptr [edx].SMALL_RECT.Right
if GoodOne
pop word ptr [edx].SMALL_RECT.Bottom
sub esp, 6*4-2 ; correct for 5 dword and one word pop
else
; this version overwrites the word below the structure!!
pop dword ptr [edx].SMALL_RECT.Bottom
sub esp, 6*4 ; correct for 6 pops
endif
ret 5*4 ; correct stack for five arguments
PopSmallRect endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

Note the "GoodOne" conditional assembly. The three pops before overwrite the following word member of the structure, which is not a problem, but the last one must not go beyond the structure, therefore the pop word ptr.

Full code attached, I have removed the earlier zip above to avoid confusion.

[attachment deleted by admin]