If I remember correctly when you make function in C/C++ that function is allocated on stack, uses local variables allocated on stack, etc. When it's finished it's simply deleted from stack. The end. You HAVE to pass result in some global var or to pass it as value or pointer. If you fail to do that result will be lost as stack is filled with new data. Forever. I think I got this right.
But functions seems to behave different in MASM! Why?
For instance, why this function works? Because RegisterClassEx passes no parameters or because once declared WNDCLASSEX is no longer needed if we use fn RegisterClassEx or something else...
RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
Icon:DWORD, Cursor:DWORD, bColor:DWORD
LOCAL wc:WNDCLASSEX
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_BYTEALIGNCLIENT or \
CS_BYTEALIGNWINDOW
m2m wc.lpfnWndProc, lpWndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
m2m wc.hInstance, hInstance
m2m wc.hbrBackground, bColor
mov wc.lpszMenuName, NULL
m2m wc.lpszClassName, lpClassName
m2m wc.hIcon, Icon
m2m wc.hCursor, Cursor
m2m wc.hIconSm, Icon
invoke RegisterClassEx, ADDR wc
ret
Further more, if I use LOCAL var:DWORD in WndProc it does not work! Why?
Example is Icz's tute 25. Simple bitmap:
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL hdc:HDC
LOCAL hMemDC:HDC
LOCAL rect:RECT
LOCAL hBitmap:HDC <---it does not show picture if hBitmap is defined in WndProc! Works fine if hBitmap is defined in .DATA?
.if uMsg==WM_CREATE
invoke LoadBitmap,hInstance,IDB_MAIN
mov hBitmap,eax
Why? Why pc and hdc and rect work nicely but hbitmap does not?
Another question:
OPTION PROC PUBLIC is default in MASM. And that means that I can make jmp IN some fn if I want. Even if it's not smart option. Right? And that also means that I can not use same label names for jmps and can not use same var names in different fn. Am I right?
But if OPTION PROC PRIVATE is set every fn is threated as closed set of instructions. Somewhat like C/C++ right?
Is PRIVATE little better for bigger project?
RegisterClassEx() works the same way as it does with any other language. You place the appropriate values in the WNDCLASSEX structure then pass the address of the WNDCLASSEX structure to the RegisterClassEx() function. It is a common technique used in Windows coding that came from the VAX guys who designed the architecture of 32 bit Windows.
MASM handles scope issues like any other language, LOCAL variables are built on the stack and are only available for the duration of the procedure they are created within where GLOBAL variables are stored in the DATA section and can be accessed from anywhere in the module and can be modified by one proc for use in another.
Greetings,
To further what Hutch said, you will find that is perfectly safe and encouraged to pass the address of a structure that is residing on the stack to win32 apis. This is because the api generally copies the structure before returning (and the timely demise of your temporary data). If you don't need access to the structure data later on, just let it live (and die) on the stack.
To answer your question regarding the bitmap, I think you will find that the first time through the WNDPROC your bitmap handle is valid (during your WM_CREATE handler) and then it is promptly erased when your WNDPROC returns. This explains why it works as a global and doesn't as a local.
Regards,
Tim
:cheekygreen: All right! IT WORKS! :green Yeeeee, thanks a lot :toothy
You know, sometimes it's tough to be beginner.
Timbo, you are right!
If bmp is loaded in WM_CREATE it's deleted later when WndProc exit the stack. But if I load bmp in WM_PAINT it works :bg
Basically, I realize for the first time, that all fn are constantly being called depending on WM_. CPU really has tough job in WndProc.
Last two questions:
1. If I want to make more than one window with same wc class and same WndProc, should I try to put as many as possible variables on the stack?
2. Should I use ret after every WM_?
@@:
cmp uMsg,WM_something
jne @F
...code...
ret
@@:
cmp uMsg,WM_something else
jne @F
...code...
ret
@@:
Just to speed up little bit exiting from WndProc. Or I have to check all possible WM_ combinations I need before exiting WndProc? I do not think uMsg can have more than one value... But better to ask and be on safe side :)
QuoteI do not think uMsg can have more than one value...
; WM_MOUSEMOVE || uMsg == WM_NCMOUSEMOVE.....
.ELSEIF uMsg == 200h || uMsg == 0A0h
hope you don't mind the butt-in with an extra question ... uMsg seems to handle these two values (if they are actually separate values) when using the .if statement. My question is how would do it using cmp and jne with this line of code ?
Cor,
You don't want to load the bitmap with each repaint. You will be loading the same bitmap over and over again. I would just use a global to store the handle and load it once in WM_CREATE handler. Don't forgot to delete it when you are done with it with DeleteObject.
See MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_1vsk.asp
Also, you should use ret to short circuit the WNDPROC but don't forget to set eax appropriately before doing so.
ic2,
I would use cmp x2 against those values and jne over your handler for these values. You could also use cmp to je to the same label for both cases (assuming you are handling the messages in the same fashion). I'm a newcomer to assembly myself, so maybe someone else can chime in with a more optimized approach to this.
Regards,
Tim
"short circuit"
Heavy ... Welcome Timbo :)
QuoteYou could also use cmp to je to the same label for both cases
There a lot of things i don't know but I never, I mean, i NEVER came close to even think of that and i tried HARD ()... Thanks a lot, ic now. but what do you mean by the cmp x2 idea. Could you draw an example. It even sounds like FUN ...
Ok, now I am puzzled. As ic2 have said uMsg seemingly can have more that one value! Welcome to quantum computer world :green2
I think I have seen one example where we check uMsg for WM_keystroke and WM_mouse click.
How is that possible? Quote from: Timbo on March 08, 2007, 12:26:00 AM
Also, you should use ret to short circuit the WNDPROC but don't forget to set eax appropriately before doing so.
"Short circut" WndProc... And that's good, right? I mean if it's done right. I saw come examples where ret is used after every WM_ case. But I also saw many examples there WM_ checking just propagate till WM_DESTROY where we ret 0 in eax.
What's better? Or both are ok to be used?
Quote from: Timbo on March 08, 2007, 12:26:00 AM
You don't want to load the bitmap with each repaint. You will be loading the same bitmap over and over again.
I realize that. But if I want to make multiwindow it's either constant reloading of bmp or one global load of every bmp I'll use... Well, maybe you are right. One global load for all WndProc will be better :toothy
CoR,
The second parameter passed to the WndProc can be any of a large number of different Windows messages, this is normal operation for a message driven windowing system like Windows. For any active window running in the system, it has a reasonably large number of messages sent to it on a regular basis ranging from user triggered events (WM_COMMAND etc ...) to automatic repaints if a window has been covered by another window and of course many others that perform specific functions.
Here is an example i use from masm32/icztutes/Tute20/subclass.asm with triple plus values in it that makes it a bit more interesting.
Since you do things the right way by wanting to know why things work this may prove strongly related to what hutch just said. Now I'm looking into why things happen more seriously myself instead of just finding ways to step around it. So it's all about the larger, whatever goes forward and can come next ... 1234 — ABCD
.if uMsg== 102h ; WM_CHAR
mov eax,wParam
.if (al>="0" && al<="9") || (al>="A" && al<="Z") || (al>="a" && al<="z") || al==8h
.if al>="a" && al<="z"
sub al,20h
.endif
Here is a sample of the things i would do if something simply can't be solved. So i step around it. Stuff like this is what makes ASM so exciting to me :) ... In the start up proc I jump over or run things once by using a cmp something
; WM_PAINT ............................................
.if uMsg == 0Fh ; WM_PAINT
cmp flag_1, 1
jz NOT_ON_START_UP
CALL PAINT_BAR
NOT_ON_START_UP:
.endif
;....................................................
Down in the control proc I turn it on or off. Maybe something like this will help when demanding one time per anything.
.elseif wmsg == 201h ; WM_LBUTTONDOWN
mov eax, hWin
.if eax == [ Butt_1 ]
; Turn PAINT_BAR on.... Now After_START_UP
mov flag_1, 0
These are only things you may already know but sometimes even i need a reminder when i get stuck on a problem and refuse to give up until i find a new or better way.
Thanks for replies!
But I still would love to know what is proper way of using ret in WndProc.
Should I use it in every WM_ check or to let checking propagate till WM_DESTROY?
I have been reading Charles Petzold - Programming Windows 5th ed.chm and he exits WM_check with return 0.
So it looks safe to:
xor eax,eax
ret
after every WM_message.
CoR,
The correct value as a return in a WndProc depends on the message being processed. With most messages you allow the default processing using the return value from "DefWindowProc()". When a message specifies returning ZERO you then zero EAX and call ret (RETN) so that the default processing is not performed.
Now note that this is NOT the case with a dialog message handling procedure (DlgProc) where you normally set EAX to ZERO then call ret (RETN).
Mmmmmm, thanks Hutch. I am not blind any more :red
Win32hlp for EVERY WM_message clearly states:
QuoteReturn Values
-If an application processes this message, it should return zero.
-The return value indicates the... It may be any of the following: ...
- so on...
The eye do not see what mind do not understand!
Hi CoR,
you need not ret from each message...
Another method is have only a ret at the end on the proc
.if eax == WM_xxx
.elseif eax == WM_yyy
.else
invoke CallWindowProc(....) / (or FALSE for DlgProc)
ret
.endif
xor eax, eax
ret
Single point of exit is what I am more comfortable with! :bg
HTH,
Shantanu
CoR,
You might find the links below...interesting. I too have used Petzold's 5th edition for learning Windows programming, and have converted most of the C programs within into MASM without using PROCs at all. Some people can't get along without PROCs, but I detest them. The choice is yours. Ratch
http://www.masm32.com/board/index.php?topic=5916.0
http://www.masm32.com/board/index.php?topic=4650.0
http://www.masm32.com/board/index.php?topic=3783.0
Shantanu Gadgil,
I have seen that "one ret at the end of proc" and I wondered why people use it. I honestly thought about option that uMsg can have more than one value and we should check for all WM_xyz possibilities at one pass through whole WndProc :dazzled: And I really don't like what I do not understand!
For now I want to learn to write as "clean" as possible. It's not too hard to look for every WM_xxx in win32hlp and read what should I return. I'll remember WM_'s better and WndProc will have 30-50 CPU ticks less to process (depending of the number of WM_'s before DefWindowProc).
I even reorder WM_'s! Ones that are most likely to be called are at front, and ones that are called only once are at the bottom of WndProc :toothy
I know it saves only a few CPU ticks but it puts my mind at ease :wink
Ratch,
I am sorry but I can not tell heads and tails of your examples. Asm is still one big puzzle to me. Iczelion tute is familiar to me because I have previous knowledge of C/C++. But as soon as I see:
mov eax, [esp+2*4]
push [esp+16]
MOV EAX, [ESP+DWORD]
SUB EAX, DWORD
CMP B[EAX+0*BYTE],0
call dword ptr[ebp]+PostQuitMessage ;instead of normal push var, call procedure
I am completely lost :(
I started at "Campus". Now I am at "The Workshop" level. The Laboratory is light years away.
However if you are willing to write some "in detail, in depth, fully explained, for beginners" example... I'll gladly read it! And do my best to understand it. I need to learn much more if I want to understand what are you guys talking about in "The Lab".
Btw, I don't know if you have seen this, but maybe it can help you in some way: http://www.masm32.com/board/index.php?topic=6825.0