News:

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

The memory could not be read

Started by w0lfshad3, August 21, 2006, 09:51:13 AM

Previous topic - Next topic

Tedd

Well you must have changed that some time in between posting and me fixing it, because in the version I fixed there was already RegisterClassEx - and so, simply adding the ret made it work.
(Even the earlier version: http://wolfshade.home.ro/project1.asm has RegisterClassEx)
Anyway, it WORKS :cheekygreen:

Note: there's no need to go crazy with the ret for every message; most can fall through to return zero at the bottom, but DefWindowProc should return its own value, so you can't let it fall through.
No snowflake in an avalanche feels responsible.

w0lfshad3

Note: there's no need to go crazy with the ret for every message;

Charles Petzold, Programming Windows(read last line):
Quote

Get In and Out Fast

Windows 98 and Windows NT are preemptive multitasking environments. This means that as one program is doing a lengthy job, Windows can allow the user to switch control to another program. This is a good thing, and it is one advantage of the current versions of Windows over the older 16-bit versions.

However, because of the way that Windows is structured, this preemptive multitasking does not always work the way you might like. For example, suppose your program spends a minute or two processing a particular message. Yes, the user can switch to another program. But the user cannot do anything with your program. The user cannot move your program's window, resize it, minimize it, close it, nothing. That's because your window procedure is busy doing a lengthy job. Oh, it may not seem like the window procedure performs its own moving and sizing operations, but it does. That's part of the job of DefWindowProc, which must be considered as part of your window procedure.

If your program needs to perform lengthy jobs while processing particular messages, there are ways to do so politely that I'll describe in Chapter 20. Even with preemptive multitasking, it's not a good idea to leave your window sitting inert on the screen. It annoys users. It annoys users just as much as bugs, nonstandard behavior, and incomplete help files. Give the user a break, and return quickly from all messages.

Tedd

And your point is...?
I didn't say don't return, I meant it's unnecessary to place "xor eax,eax; ret" directly after the processing of every message. The reason is simply because, if you look at the structure of your program, then you will see that when each message has been processed it will drop out of the .IF statements and be caught by the "xor eax,eax; ret" at the bottom. The extra few clock-cycles it takes to jump will not slow down the user interface.


WndProc PROC hwnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg==WM_CREATE
        ;blah
    .elseif uMsg==WM_SIZE
        ;blah
    .elseif uMsg==WM_DESTROY
        ;blah
    .else
        invoke DefWindowProc, hwnd, uMsg, wParam, lParam
        ret
    .endif
    xor eax,eax
    ret
WndProc ENDP

Now, look at how each message returns after it has finished processing ("blah"). Except for DefWindowProc, each message will get to "xor eax,eax; ret" once it's done - so there's no need to keep adding that extra code for every message. The only time you need to cause an alternate exit is when the message doesn't want to return zero, this is necessary in some cases, but for most messages there's no need.
No snowflake in an avalanche feels responsible.

Shantanu Gadgil

Or in fancier words... "single entry single exit" (just easier to maintain)  :green :green

Cheers,
Shantanu
To ret is human, to jmp divine!

w0lfshad3

#19
Oh you mean if any of the tests catch and process it will not check the others that follow thus fall directly into "xor eax, eax; ret;", you are correct.
I got cought in Charles Petzold coding style(anyway i don't knwo what the switch/case stuff looks like from C to asm);
he uses this structure:

switch(message)
{
   case WM_CREATE
       code;
       return 0;
   case WM_SIZE
      code;
      return 0;
  case WM_DESTROY
      code;
       return 0;
       DefWindowProc(hwnd, uMsg, wParam, lParam)
}


P.S. I'll also throw a cute optimisation trick i found recently(perhaps Tedd will have something to say on this :)): i will use local variables when possible from now on because they will exist in the cache since they will be passed on the stack at procedure call thus will speed up fetching(its called fetching right?) EDIT: oh lol hutch said that

P.S. *taking a big breath* DefWindowProc cannot be moved at the top of the control tree i guess even if i test the incoming message against all the messages i process because i would have to single out the particularities of even the messages i process because if i process a message i am also taking responsability of all the possible processing through that message that has nowhere to fall because DefWindowProc would be at top corect?
*taking another big breath*

Tedd

Alternatively:

switch(uMsg) {
    case WM_CREATE:
        //code
        break;
    case WM_SIZE:
        //code
        break;
    case WM_DESTROY:
        //code
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;

(You missed out default in yours, so the DefWindowProc would never actually be reached.)


Perhaps I will have something to say? -- What exactly are you trying to imply, my friend? :P
Locality is generally a good thing. So yes, using local variables where appropriate is a good idea, not just for keeping things in cache, but also helping with organising your code. (Global variables that are accessed often would equally be in cache anyway, but local variables are created on the stack and you can expect the stack to already be cached.) Some people would go as far to say that global variables are evil and should never EVER be used, but this is a little ridiculous. (Like similar comments about "goto" ::))

I'm not sure I get exactly what you mean by moving DefWindowProc to the top.. It's meant as a catch-all for any messages you don't process. So, moving it to the top would cause it to be given every message, whether you intend to process them or not. Alternatively, you could check if the message is one you want, and if not pass it on to DefWindowProc. But this is what we're doing already. The only difference is that you'd be testing against your list of wanted messages twice. In the current arrangement, DefWindowProc is called only for messages you don't otherwise catch and process.
No snowflake in an avalanche feels responsible.

Mark Jones

What Mr. Petzold is saying is, that if you call something from within your WndProc, no other messages can be processed until your call returns. This can cause a serious problem; say when WM_CLOSE is executed your app verifies a 2GB database then closes each entry and writes all buffers to disk. During this process, which could take several minutes, the program will appear completely unresponsive because no other WndProc messages can be handled (such as WM_SIZE or WM_MOVE, etc.)

The solution to this, is to spawn a second thread and execute your lengthy process in there. That way, the WndProc is free to continue processing messages while the second thread executes. Of course if this were in the WM_CLOSE message then you'd only want to close the app after your cleanup thread had completed.

Returning after each message is not necessary, and serves little purpose because like you saw, each message just falls through. The SWITCH/BREAK syntax is a remnant of C language and is provided only for compatibility.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

w0lfshad3

#22
QuoteIf your program needs to perform lengthy jobs while processing particular messages, there are ways to do so politely that I'll describe in Chapter 20.

That chapter talks of multithreading. For now i was talking of returns. In masm the .if .elseif .else conditional structure generates the corect code, no need to return immediately. I do not know what switch/case does but i believe Charles Petzold has a good reason to return after each message processing in a switch/case structure; i was analizing a C compiled switch/case in the c replica of this program and besides lots of spaghetti code, because of jmp wich is an unconditional jump i could not see the code skip the rest of the messages after identifying one and processing.

P.S. The only reason to return even in masm after every message process could be that the jump is very long and it takes more clocks than using the return after each meassages(but i do not know anything about that yet).

w0lfshad3

QuoteI'm not sure I get exactly what you mean by moving DefWindowProc to the top.. It's meant as a catch-all for any messages you don't process. So, moving it to the top would cause it to be given every message, whether you intend to process them or not. Alternatively, you could check if the message is one you want, and if not pass it on to DefWindowProc. But this is what we're doing already. The only difference is that you'd be testing against your list of wanted messages twice. In the current arrangement, DefWindowProc is called only for messages you don't otherwise catch and process.

With the current knowledge i gained while looking in ollydbg at my code, i can explain:
When winprok gets a message it will  go through all the compares and jumps(or .if .elseif part) thus wasting time. Since i believe DefWindowProc will process more messages than i ussually do it would be a good ideea to check the message against the messages i'm processing(for example i'm only processing WM_DESTROY and WM_CREATE) thus i check against those two and if the message i'm testing isn't one of these two i call DefWindowProc, thus instead of jumps for every message test that turns out false, i process it first calling DefWinproc. This would be good in the event that DefWindowProc possibility of getting more messages in an app lifetime than the ones i'm processing. If the messages i'm processing are in greater number probability than the ones that would go to DefWindowProc then DefWindowProc would indeed be better off to be last. In this manner since WM_CREATE occurs when the app is created and only once it would be better to be amongst the last, even if at first the message would be checked against all the other messages at first, afterwards this message would not get in the way, when the test is done; since the other messages will occur more than once it will also result in an improvement in number of clocks used during the app execution.

P.S. i need a spellchecker in this forum  :bg

P.S.2 jerking around the size of the window makes aproximatively 80% CPU usage on this code, however on the C replica only 30% CPU usage  :dazzled:

w0lfshad3

Help, my code also produces a memory leak:
Jerk the window size around while having the task manager open and you'll notice the size of the app in memory increase.

http://wolfshade.home.ro/mem_leak.asm

hmm also temp3 doesn't hold 1/7 out of cyClient as i mean to, more like 1/4 but i guess i can debug that, the mem leak i have no ideea.

Tedd

Yes, I agree with you that if you expect to be passing most of the messages on to DefWindowProc, then it would be nicer to check if you wanted the message first and if not then pass it straight on. But the problem is that you can't do that without testing each one anyway. How would know if it's a message you want without comparing it against each message you want?? But this is exactly what .IFs are doing anyway! Okay, so there is an extra jump or two, but really it's not worth worrying about.
(This is a small lie - there IS a way to do it. You can make an array representing the message values, and then put the address of the handler for each of the messages in its array element - checking for the message is simply an index into the array to see where to jump, or if it's zero then go to DefWindowProc. However, this isn't worth doing unless you have a large number of messages to handle.)


The memory leak is interesting, it seems to be coming in as a result of MoveWindow. Though not the MoveWindow function itself, but the fact that it causes the children to be resized/redrawn. Funny how minimizing the window removes the 'leak.' Which would indicate it's something to do with the repainting. I can't say much more than that without checking further.

As for your 1/7th child-height. Notice that changing the height of the parent does NOT change the children's heights, but changing the width does! Meaning temp3 is 1/7th of the WIDTH, and not the height. This mistake should be obvious if you go through your code and find where you've put cxClient instead of cyClient :bdg
No snowflake in an avalanche feels responsible.

w0lfshad3

Thanks for the cxClient catch.

What is not funny at all is that through jerking i noticed my win32asm app is using 80-90% CPU unlike its C replica who uses only 20-30% CPU. Can not figure why this huge difference of 3x speed would exist. So far i think i noticed that the C code doesn't use the FPU, alltough i can very well be wrong, the C compiled and disassembled code is very twisted i don't think i can follow it.

C replica for speed comparison purpose.
http://wolfshade.home.ro/project.cpp (ctrl+c, ctrl+n, ctrl+v :) somehow c and cpp code links get stuck in a server error so copy paste.

At least the C code doesn't leek :)

P.S. Hmm i'm having a deja-vous on the event that minimizing a window in relation to some memory thing, doesn't mean anything yet to me.
P.S.2 Found out that windows operating systems reclaim memory when a window is minimized. Nice trick :) personal note: i think this need to be prevented to some extent in a game app or even just a "large" app if speed is in danger :)

w0lfshad3

Hurray you done it  :dance:
QuoteWhich would indicate it's something to do with the repainting.
Pointing me the right way, i went straight to the EndPaint() in wich i had passed the handle to the device context instead the handle to the window(wich caused the double trouble of speed loss and memory loss; i don't want to think about the havoc it created while working w/o any errors :lol, it wasn't releasing what it was supposed to release). It was the only thing i read warnings upon, and used in my code.

Now the speed issue is fixed, doesn't seem to be faster but at least its bug free. My asm programming mood is back on track :dance:

Well C code 23,040 bytes, assembly code 4096 bytes, that certainly stands for something(don't know why tough the C code would be so huge, i wonder if it increases this way the bigger the source is or it just creates some initial size overhead out of something).

w0lfshad3

#28
Hmm weird last one got double posted as a quote, either because i got careless or i got 2 ips and an electrical storm outside.