I'm learning how to scroll in Windows, and have successfully created a program that uses that capability; it's a simple (so far) hex file viewer.
It works, but there are issues. I was really happy, of course, when I got my little hex-view window to scroll correctly (for the most part). I tried it out with several files, and it seemed to work fine, so I thought "Hey, I can be the next high-tech millionaire!". (Not really, just joking.)
Then I tried it out with a big (<2MB) file. Its performance
sucks.
The program is attached here (with standard MASM32 pathnames). I'd appreciate any look-sees and suggestions.
Here are the issues:
- Scrolling is extremely sluggish on large files. I think this is due to a couple of things:
- I took my scroll code largely from this MSDN page (http://msdn.microsoft.com/en-us/library/hh298421.aspx). Normally, I don't like to do this, as I really don't completely understand what they're doing there, but I was having problems trying to implement this on my own, so I copied their code, more or less. I simplified it somewhat; there's no horizontal scrolling, and I changed the way I compute the starting position. Plus I'm not using their method of only painting the invalidated rect; I redraw all the text in the window. More below.
- I did the simplest possible thing with memory allocation: I get the size of the file, then allocate a buffer this size using HeapAlloc(). Obviously, this isn't the most efficient way to manage memory.
- It scrolls correctly. However, sometimes there's an extra blank line at the end of the window.
- It's easy to crash it with a large file, for instance by trying to drag the thumb. More below.
The MSDN sample code is actually pretty clever: what they do is to get the current scroll position (GetScrollInfo() ), calculate what they
think should be the new scroll position and set it (SetScrollInfo() ), then call GetScrollInfo()
again and use the adjusted new position that Windows has calculated. Then then compare the original saved positions with the new calculated ones, and use the new one to actually scroll the window, if the position has changed.
One problem is that this involves a lot of overhead: 4 calls to scrolling functions, plus UpdateWindow(), for each scroll message received. This may also explain wiy it's easy to crash: on a large file, the messages pile up as the system grinds away, leading to conflicting conditions. Is there a simpler (or better) way to do this?
I notice that the MASM32 programs that handle text (like the "quick editor") scroll text very quickly and nicely, as does Notepad. The large files I was using are the MASM listing files from assembling my programs, which come out to just over 2 megabytes.
I originally thought that I could handle the scroll position internally by keeping track of a variable (say, ScrollPos) in my message handler, incrementing or decrementing it as needed in response to scroll up/down by line/page requests. Maybe this is still the way to go.
I'm confused, at this point, by what appears to be two measurement systems in use here. As I understand it (not sure if I do), the scroll position (for text) is an integer quantity, specified in numbers of lines. At least it seems to behave that way; if you look at my code, you'll see that I'm using a line count as the scroll position. (Of course, for a window where an image is scrolled, the scroll position is in terms of pixels, or display units.) In the example MSDN code, they derive the scroll amount per line from the height of a line of text (from GetTextMetrics() ).
While I can track scroll up/down requests pretty easily, the one request that's not so easy to handle is SB_THUMBTRACK, where you have to read the current scroll position from the SCROLLINFO structure and use it to position the scrollbar.
Another thing: the example uses ScrollWindow() to scroll, rather than SetScrollInfo(). Good? Bad?
My program works: File--> Open to open a file (any type, binary, text, doesn't matter) to view its contents. You can select another file afterwards, and so on.
One nice thing: I hadn't planned on this, but somehow things work out so that if the file is smaller than will fit on one page, there's no scroll bar! I had actually wanted this but hadn't explicitly put anything in the code. I suspect what's happening is that in this case, the parameters I'm passing (to SetScrollInfo() in the main window proc) are invalid, so Windows doesn't put in a scroll bar at all.
Notes about my code: a little bit complicated. Most complex part is drawing the hex display lines. I use a formatted display line, into which I stuff the current character from the file, first as 2 hex digits, then as an ASCII character. The heavy lifting here is done by PutHexChar(), which receives its parameters in registers. That routine is a little ugly, since one thing it has to do is check each character to see if it's beyond EOF, since it's always called 16 times per line, and blank out any display positions at an beyond EOF (this only happens on the last line). It works correctly, but there may be a better way to implement this. At any rate, someone in there has to continually monitor for EOF.
I'm using TextOut() to display the line of text. Would DrawText() or some other function be better?
That's enough for now.
QuoteOne nice thing: I hadn't planned on this, but somehow things work out so that if the file is smaller than will fit on one page, there's
no scroll bar! I had actually wanted this but hadn't explicitly put anything in the code. I suspect what's happening is that in this case,
the parameters I'm passing (to SetScrollInfo() in the main window proc) are invalid, so Windows doesn't put in a scroll bar at all.
that happens automatically when you use "system scroll bars"
i.e. scrollbars created by adding style bits to the CreateWindow call
if you create the bars yourself, you have to turn them off and on
as for handling large files, the scroll code, itself, is probably not so much to blame
it is likely to be problems with how the file/memory is handled and the WM_PAINT handler - how you display text
Regarding the WM_PAINT handler, yes, it's doing a little more than just plopping text onto the screen.
On the other hand, I've tried to optimize this code. It seems fairly minimal: some address calculations, a per-character loop, and a subroutine that does two hex conversions and stores (XLATB/STOSB), a simple character store, and that's it. For each WM_PAINT message, there are these initial system calls:
BeginPaint()
SelectObject() (to set the display font)
GetClientRect()
GetScrollInfo()
and of course
EndPaint()
There's only one Windows function (TextOut() ) called per line (16 bytes). Does that seem like little enough overhead? or could that be causing the sluggishness?
I think it's the memory issue that's really slowing things down.
How else to display a file? Read it into a small buffer and refresh the buffer as needed? Use a memory-mapped file?
To anyone who downloads this and tries to put it together: I forgot to change the path in the #include in the resource file. Easily fixed. Sorry 'bout that.
Is the source code for the editor supplied with MASM32 ("Small Memory Footprint Editor"/Quick Editor 4.0") available? (I guess I'm directing this question at Hutch.) I'd be very curious to see how scrolling is done there. Also what memory-management scheme is used.
it hangs pretty easily
i got it to hang by scrolling the ASM file
when i started learning about windows and scrolling text, i was told that ScrollWindow was sluggish
so, i have no experience with it
but, having looked at that part of the code, i don't see an issue
the crash error is good ole C0000005h - access violation
that generally means a pointer is out of whack - like trying to read or write to/from address = 00000000h, or some similar illegal address
How do you retrieve the crash errors?
I tried looking for error logs (in Control Panel--> Administrative Tools--> Event Viewer--> Applicaton Log), but for some weird reason it reports 5,002 events but they're all BLANK?!?!?.
Quote from: NoCforMe on October 14, 2011, 12:19:37 AM
How do you retrieve the crash errors?
OllyDbg (http://www.ollydbg.de/).
not sure how that works under win 2000 - maybe Steve or Michael can give you some tips
under XP and above, Dr Watson pops up and tells you where you went wrong
... or you can use Olly, like qWord said :P
OK, now I'm confused. This scrolling code works (vPos is the scrollbar position read from GetScrollInfo() before doing the scroll, scrlInfo.nPos is the position value read back after setting the position with SetScrollInfo()-GetScrollInfo() ):
MOV EAX, vPos
MOV EDX, scrlInfo.nPos
CMP EAX, EDX
JE hx_noscroll
; Scroll window if changed:
SUB EAX, EDX
MUL LineHeight
INVOKE ScrollWindow, hWin, 0, EAX, NULL, NULL
INVOKE UpdateWindow, hWin
(but results in crashes with larger files)
However, none of the following work, even though it seems that they should:
#1:
SUB EAX, EDX
MUL LineHeight
MOV scrlInfo.nPos, EAX
MOV scrlInfo.fMask, SIF_POS ;Change pos. only
INVOKE SetScrollInfo, hWin, SB_VERT, ADDR scrlInfo, TRUE
INVOKE UpdateWindow, hWin
#2:
SUB EAX, EDX
MUL LineHeight
INVOKE ScrollWindowEx, hWin, 0, EAX, NULL, NULL, NULL, NULL, SW_INVALIDATE
INVOKE UpdateWindow, hWin
#3:
SUB EAX, EDX
MUL LineHeight
MOV scrlInfo.nPos, EAX
MOV scrlInfo.fMask, SIF_POS ;Change pos. only
INVOKE SetScrollPos, hWin, SB_VERT, EAX, TRUE
INVOKE UpdateWindow, hWin
(I also tried using InvalidateRect() instead of UpdateWindow(), but it didn't help.)
I'm confused because the description of ScrollWindow() (and ScrollWindowEx() ) says that it scrolls the contents of the specified window. However, I'm already redrawing all the text in my window; it seems to me all I want is to have Windows redraw the scrollbar itself, not my text. And yet none of those last 3 do anything (the scrollbar become completely inoperative).
I may be making some dumb mistake elsewhere, but this is a puzzle. Maybe that's why it's crashing, because both Windows and my program are redrawing the text in the window.
UpdateWindow only sends a WM_PAINT message if there is an update region
you have to tell the OS that you have invalidated the display area (or a portion of it)
you can use InvalidateRgn or InvalidateRect - or another method that i can't remember - lol
then, UpdateWindow
you have to read a lot of stuff :P
http://msdn.microsoft.com/en-us/library/dd162759%28v=vs.85%29.aspx
you can see if that's the case by minimizing the window, then restoring it
or by running another window over it and away
you will see the updates occur then, because the OS tells it there is an update region
Quote from: NoCforMe on October 13, 2011, 06:29:56 PM
Read it into a small buffer and refresh the buffer as needed? Use a memory-mapped file?
Yes and maybe. All you need is a small buffer with your binary "data window", and an edit control that displays the selection. Simple and blazing fast, and memory-mapped files would not change that, it's an overkill.
To give you an idea of the logic, here a console mode demo. Output:
0 18 00 00 00 EC 15 40 00 39 00 DA 00 18 00 00 00
1 E0 15 40 00 69 00 DE 00 18 00 00 00 EC 15 40 00
2 69 00 DA 00 18 00 00 00 E0 15 40 00 79 00 DE 00
For your app, instead of printing move the text into a small buffer, then use WM_SETTEXT to display it.
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
Init
Let edi=New$(4096) ; make a buffer
Open "U", #1, "\masm32\bin\ml.exe" ; you better not write to that one ;-)
Seek #1, 8192 ; put file pointer somewhere
Input #1, edi, 4096
Close #1
xor ecx, ecx
mov esi, edi
.Repeat
Print Str$(ecx), Tb$ ; print the line counter
inc ecx
REPEAT 4
lodsd ; get the next 4 bytes from the data window
xchg eax, ebx
REPEAT 4
movzx eax, bl ; isolate lowbyte 4 times
shr ebx, 8
add eax, 100h ; avoid trimming of bytes le 0Fh
Print " ", Right$(Hex$(eax), 2)
ENDM
ENDM
Print
.Until ecx>20 ; 20 lines is enough for a demo
Inkey "-- ok --"
Exit
end start
OK, but are you suggesting that I open and close the file for each page? Wouldn't that be really slow? Or does Windows optimize file access enough so that would actually be fast? (Also, would you mind un-translating that back to assembly language/WinAPI functions? I dunno what "Input #1" means to Windoze ...)
Regarding the scrolling issues, I got all those 3 cases above to work. The problem was that I was using the approach used by that MSDN example without really understanding it. They were scrolling the window (using ScrollWindow() ) in device units, when what I really need are just line units (as in scroll up/down by 1 or n lines). It's actually much simpler than the example. Now they all work fine.
Except that the thing still crashes on larger files. Must be something else wrong (out-of-bounds pointer somewhere).
[later that same day, in the pirates' grotto ...]
OK, problem solved. It was, once again, my fault. I was reading the whole file every time I displayed a page of text. I was actually lucky, in that my read pointer was going out bounds almost every time, but Windows (or Intel) was being forgiving, so apparently I hadn't strayed into forbidden territory, until Boom!. So that's all fixed.
And the scroll is now plenty fast. Large files no problem. Check out new version. Couple added controls; it's almost a usable tool.
So is it OK to allocate a lot of heap? I guess I could use a general-level tutorial on Windows memory management. (Still waiting to hear back from jj about that example you posted above.)
I eventually want to add editing capabilities.
Quote from: NoCforMe on October 14, 2011, 02:52:18 AM
OK, but are you suggesting that I open and close the file for each page? Wouldn't that be really slow? Or does Windows optimize file access enough so that would actually be fast? (Also, would you mind un-translating that back to assembly language/WinAPI functions? I dunno what "Input #1" means to Windoze ...)
Assembly language is language that gets assembled using standard assemblers. Input #1
is assembly language - not by accident this forum is called
Masm32, not Asm32 :bg
To answer your question, the macro uses
ReadFileQuote
(Still waiting to hear back from jj about that example you posted above.)
It's 7:00 am here. If you are impatient, next time just launch Olly
On another subject, if I wanted to make my hex viewer able to edit, would it be easiest just to use an edit control? Seems like a minor nightmare trying to implement a mouse text-selection interface on my own.
OK, here's a better working copy. Most bugs fixed.
Hey, Dave, I thought you might like this routine I cooked up to convert text input in hex to binary:
;=====================================================
; ConvertAddress()
;
; Converts a buffer to a binary number (decimal or hex input).
;
; On entry,
; EAX--> string to convert (zero-terminated)
;
; On exit,
; EAX: TRUE if valid characters found, FALSE otherwise
; If valid, result is stored in NewAddress
;
; TBD: decimal conversion
;=====================================================
ConvertAddress PROC
LOCAL buffer[20]:BYTE
PUSH ESI
PUSH EDI
PUSH EBX
PUSH ECX
LEA EDI, buffer
XOR DL, DL ;Zero char. counter
; Select conversion based on setting of HexFlag:
; CMP HexFlag, TRUE
; JE cadHex
;
; TBD Do decimal conversion
cadHex: MOV ESI, EAX ;Address of string
cadH10: LODSB
OR AL, AL ;End o'string?
JZ cadHOK
CMP AL, '0'
JB cad777 ;No good.
CMP AL, '9' ;Numeric?
JBE cadH20 ;Yes, stuff char.
CMP AL, 'A'
JB cad777 ;No good.
CMP AL, 'f'
JA cad777
CMP AL, 'F'
JBE cadH18 ;'A'-'F'
CMP AL, 'a'
JB cad777
AND AL, 5FH ;Make uppercase.
cadH18: SUB AL, 7 ;Convert A-F--> '10-15'
cadH20: SUB AL, '0'
STOSB
INC DL ;Bump count.
JMP cadH10 ;Keep scanning.
cadHOK: CMP DL, 8 ;8 chars. max.
JA cad777 ;Too many.
OR DL, DL ;But need at least 1
JZ cad777
; Finally, we have 1-8 valid hex chars: let's convert 'em!
XOR EBX, EBX ;EBX is accumulator
XOR CL, CL ;Zero shift amount
cadH30: XOR EAX, EAX ;Clear entire reg.
MOV AL, BYTE PTR [EDI - 1] ;Next char. to left
SHL EAX, CL ;Shift nybble into position
OR EBX, EAX
ADD CL, 4
DEC DI
DEC DL
JNZ cadH30
MOV NewAddress, EBX ;Return w/new address.
MOV EAX, TRUE ;Indicate valid input.
JMP SHORT cad888
cad777: XOR EAX, EAX ;Indicate no valid input.
cad888: POP ECX
POP EBX
POP EDI
POP ESI
RET
ConvertAddress ENDP
I think it's pretty slick. Could be tweaked a bit, but it's pretty lean, robust (rejects any input that's not valid hex) and works.
One other thing: run the program and try the "goto" address field. It doesn't work the way I had intended it to (thought you would press Enter to make it go), but I actually like the way it works better: it jumps to the address as you type into it. I think I'll leave it that way. (I haven't yet put in the decimal-to-binary conversion; it'll do that depending on the setting of the radio buttons.)
i usually use this little ditty to convert 4 bits to ASCII hex...
and al,0Fh
cmp al,0Ah
sbb al,69h
das ;0-9 > '0'-'9', 10-15 > 'A'-'F'
the scrolling is MUCH better :U
and no bang !
here's the one i used to use
i found this in the original IBM PC BIOS code :bg
add al,90h
daa
adc al,40h
daa
but, Larry Hammick showed us a better way...
http://www.masm32.com/board/index.php?topic=12964.0
a simple way is to use an array
Quote
ASCII db "0123456789ABCDEF",0
lea ecx,ASCII
mov edx,0 ;digit to convert
mov al,byte ptr [ecx+edx]
Yves is right (although, you don't need to terminate the string with a null)
actually, it only takes 512 bytes to make the full hex byte string look-up-table
that is probably going to be the fastest method of converting bytes to hex without using SSE instructions
you can allocate space in uninitialized data and fill it during program init
Quote
although, you don't need to terminate the string with a null
What is suspicious chain ?.It's a chain without zero.Also I put one even if it is not needed.
Quote from: dedndave on October 14, 2011, 12:34:13 PM
i usually use this little ditty to convert 4 bits to ASCII hex...
and al,0Fh
cmp al,0Ah
sbb al,69h
das ;0-9 > '0'-'9', 10-15 > 'A'-'F'
But I'm going the other way (ASCII hex--> binary), and it's even simpler than that:
cadH18: SUB AL, 7 ;Convert A-F--> '10-15'
cadH20: SUB AL, '0'
STOSB
...
MOV AL, BYTE PTR [EDI - 1] ;Next char. to left
SHL EAX, CL ;Shift nybble into position
OR EBX, EAX
keeping in mind that I've previously massaged the chars to make sure they're in the range '0'-'9':'A'-'F' (lowercase 'a'-'f' being converted to uppercase).
Quotethe scrolling is MUCH better :U
and no bang !
Thanks. Did you try the goto address field? Wondering if other people like the way it works.
ohhh - i wondered what you were talking about
i didn't see it down there
(http://www.masm32.com/board/index.php?action=dlattach;topic=17552.0;id=9835)
Oh, crap, the window isn't big enough!
Could you reassemble it and increase $mainWinHeight (near top of file, currently set at, what, 400-something?). The controls are all covered up!
Shows a difference between my OS (W2K) and yours. I made it too tight; need more padding space.
no - it's because i switched to 120 DPI video setting
you can use GetDeviceCaps(LOGPIXELSY) and SystemParametersInfo(SPI_NONCLIENTMETRICS)
to determine what the user settings are and calculate the required height
i think that is the "message" font from NONCLIENTMETRICS
then, use LOGPIXELSY to convert font size to pixels
another way to go...
set your video to Large Fonts and 120 DPI
then measure and hard-code a value that works :P
not as pretty
but, there are times when it's hard to make measurements, too
i hard-code a value like that for the minimum window width to keep the menu from wrapping
(after spending 2 days trying to find the "right" way)
OK, that DPI display setting stuff gives me a headache at the moment; will tackle it later.
If you could be so kind, there's another small problem with this app. If you minimize it, then restore it, all the controls (radio buttons, edit control and checkbox) disappear. In fact, the rectangles where they should be are transparent!
I tried to take care of this by capturing the WM_SHOWWINDOW message (where wParam=TRUE, meaning the window has been shown after being minimized) and then using InvalidateRect() and UpdateWindow() to restore the controls, but no joy. ?????
yah - you have another little problem too
until i open a file, the CPU usage is ~50%
use the task manager to see it - i always turn on the task manager CPU and CPU Usage columns
Oh, yeah, I always have the Task Manager open (minimized, ready for use). Have had to use it many times to kill an endlessly-looping application. Will check out the CPU usage issue.
Uh-oh, actually worse than you reported: 75-90%. Ugh.
What's the most likely culprit? Doesn't seem like it's doing much, just sitting there handling a few messages.
that is probably something simple :P
like painting an empty buffer or similar
you have some code for WM_SHOWWINDOW
you could just use WM_SIZE, instead :P
you get WM_SIZE whenever you first show a window - and when minimize/maximize/restore
ok - another way to solve this issue is to specify a font and size for the stuff under the text window
i.e., make em use Tahoma 10 or something
still - 10 pt on 120 DPI takes more pixels than 10 pt on 96 DPI
also - you have a lot of space ABOVE the window :bg
(http://www.masm32.com/board/index.php?action=dlattach;topic=17552.0;id=9837)
this change seems to have fixed the disappearing controls thing, as long as a file has been opened...
CMP EAX, WM_SIZE ;was WM_SHOWWINDOW
JE doshow
Control & text positioning is messed up. I'll have to post a screen shot from my end.
Fixed the controls going away after a minimize-restore:
CMP EAX, WM_SIZE
JE doshow
dodefault:
; use DefWindowProc for all other messages:
INVOKE DefWindowProc, hWin, uMsg, wParam, lParam
RET
doshow:
CMP wParam, SIZE_RESTORED ;Is window being shown?
JNE dodefault ;No, ignore.
INVOKE UpdateWindow, RBhexHandle
INVOKE UpdateWindow, RBdecHandle
INVOKE UpdateWindow, AddrFldHandle
INVOKE UpdateWindow, AddrSTHandle
INVOKE UpdateWindow, ChkHandle
XOR EAX, EAX
RET
You need to check for SIZE_RESTORED.
If I created these controls using the resource compiler, I'd still have to update them, wouldn't I?
I really need to get going on ResEd and the resource compiler so I don't have to continually tweak-remake-run to see small changes. Plus eliminate all that ugly window-creation code.
Have to think about how to size things. I'm requesting a fixed-pitch font (actually "Courier New") with a character height of 16 (derived by experimenting and viewing results). Not sure what exactly this means (MSDN says "logical units", so I really don't know what that means).
Here's what it's supposed to look like:
(http://www.masm32.com/board/index.php?action=dlattach;topic=17552.0;id=9840)
Did your try invoke SendMessage, hEdit, WM_SETFONT, rv(GetStockObject, ANSI_FIXED_FONT) ?
No, because I'm not using an edit control for the hex display. (But I might, as that might make it easier to edit the hex.) I selected the font into the DC. But would what you suggested work with a non-edit window, like my chilld window? In any case, setting the DC seem to work OK.
Fixed the CPU usage problem; that's what happens when you don't reply properly to a WM_PAINT message. If no file was open, I was just saying "whatever":
XOR EAX, EAX
RET
instead of calling DefWindowProc(). Doing so fixed that problem.
So jj, what can you tell me about using edit controls? (I've read the material on MSDN on them.) What I'd like to be able to do is to edit the hex values displayed. I'd want to restrict the editable area to just the hex-character field on the left and the character-display field on the right; not let the cursor go into the address display at far left. Any ideas? Suggestions for material to read?
Also, I'm still not 100% clear on how to read a large file more efficiently; should I read it in page-size chunks (320 bytes)?
Quote from: NoCforMe on October 14, 2011, 08:17:22 PMAlso, I'm still not 100% clear on how to read a large file more efficiently
Use a file mapping (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366556(v=vs.85).aspx) for large files and read it (e.g.) in chunks of 64KB (or 128k,...).
Quote from: NoCforMe on October 14, 2011, 07:14:15 PM
How do you get an image to appear in a message here (like your screen shot); do they have to be PNGs? (I attached a zipped GIF, which is kinda ridiculous, as the zip is just as big as the GIF!)
You just need to host the image online on your own webspace or on free space
(http://www.hereford.tv/fireworks.gif)
Ah, yes. I guess I got spoiled, as the other forum I participate on provides picture albums for members to upload images and other attachments. Oh, well.
How do you get an image to appear in a message here (like your screen shot); do they have to be PNGs?
(I attached a zipped GIF, which is kinda ridiculous, as the zip is just as big as the GIF!)
just take a PNG (or JPG or whatever) and change the extension to ZIP
then post, get a link to the attachment, and modify the post with the link as an image
i have never tried a GIF, but it probably works
the ZIP is as big as the GIF (or bigger) because they both use LZF compression
thing about LZF is, when you LZF something a second time, it usually gets bigger :P
Quote from: dedndave on October 14, 2011, 09:52:45 PM
just take a PNG (or JPG or whatever) and change the extension to ZIP
then post, get a link to the attachment, and modify the post with the link as an image
i have never tried a GIF, but it probably works
That is absolutely brilliant. Devious (love it!) and brilliant. Kicking myself for not figuring that out.
Yes, works fine with GIFs. (See above.) I was nice and named the "attachment" xxx.gif.zip to clue people in that it's not really a .zip ...
as much as i'd like to take credit - lol
someone else figured it out
then, recently (last couple days), i saw someone use the name.img.zip format, which i thought was nice
Quote from: NoCforMe on October 14, 2011, 08:17:22 PM
Suggestions for material to read?
The EN_CHANGE notification is good start. Here you can decide what you want to allow.
Quote
Also, I'm still not 100% clear on how to read a large file more efficiently; should I read it in page-size chunks (320 bytes)?
I guess "page-size" is the amount of bytes to display. Yes, that should do the job. The disk cache will make sure that your harddisk is not busy all the time... qWord, other ideas?
file mapping is good, but i'd use 32Kb :P
as for the 120 DPI setting, i had to revert to 96 DPI and change the Appearance settings
there are too many other applications that i use that do not acquire the LOGPIXELSX/Y values to determine layout
nonetheless, a good lesson in programming methods :P
Since I like facts more than urban legends, I wrote a little test:
- It opens a large file (Skype.exe, WinWord.exe, etc)
- it sets randomly the file pointer to a position between 0 and (size-320)
- it reads in 320 bytes
All that 100 times. The result is striking:
- For a "virgin" file, i.e. not yet used after booting, the average time to seek and read is about 8 milliseconds
- At run #2, it is cached, and the average time to seek and read drops to about 1.5 milliseconds
Having said that, it is always a good intellectual exercise to write a nice file mapping routine. With some luck, you can drop the response time to 1.2 milliseconds :bg
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
Init
Kill "Deblog.txt" ; use a fresh log file
stack equ <dword ptr [esp]>
push Timer ; reference ticks on stack
Let esi=ExpandEnv$("%ProgramFiles%\Microsoft Office\OFFICE11\WINWORD.EXE") ; get the WinWord file name for your OS version
Print "Checking ", esi, CrLf$
deb 5, "We check", $esi ; write to log file
.if Exist(esi)
Let edi=New$(320)
void Timer
sub eax, stack
deb 5, "Exist", eax
mov ecx, LastFileSize
sub ecx, 320 ; what we can display
deb 5, "Size", LastFileSize
Open "U", #1, esi
void Timer
sub eax, stack
deb 5, "Open", eax
m2m ebx, 100
.Repeat
void Rand(ecx)
deb 5, "New pos", eax
Seek #1, eax
void Timer
sub eax, stack
deb 5, "Seek", eax
Input #1, edi, 320
void Timer
sub eax, stack
deb 5, "Input", eax
dec ebx
.Until Sign?
Close #1
void Timer
sub eax, stack
deb 5, "Close", eax
.endif
pop eax
Inkey "OK"
Exit
end start
EDIT: Shortened by using ExpandEnv$