News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Quick question about Subclassing - and Iczelion's Tutorial

Started by Lightman, December 02, 2015, 08:22:31 PM

Previous topic - Next topic

Lightman

Hello Everybody,

I'm going through Iczelion's Tutorial series and it's time to learn about Sub classing. I think I understand the concepts involved, a widget has it own code - originally created by our friends at Microsoft - that governs how a widget works, how it acts, it's messages and the like. I can redirect calls to these functions through a procedure I have created with my own actions in it before passing the messages back to the original. The effect is to modify the behavior of the widget, allowing me to mold an existing widget to my needs rather than write my own from scratch.

Mr Iczelion's tutorial 20 show this feature in action. But... I can't get my version to work. It compiles correctly, but I think I have added a bug somewhere in the Sub class code. I'm following the example code, my only difference is that using RadASM, my dialog and widgets are created by the resource file and brought into the code with the use of the GetDialogItem function rather than being created with the CreateWindowEx function.

I think I've missed a mov somewhere or something.  I've attached my code, please would you guys take a look and point me in the right direction?

Regards,

Lightman
Regards,

Lightman

jj2007

Your control gets many messages, and they all need processing. Therefore, you must always permit CallWindowProc to do its job, except the few cases where MSDN says "return zero if your app processes this message":

EditWndProc PROC hEdit:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
  mov ecx, uMsg
  mov eax, wParam
  .if ecx==WM_CHAR
.if (al>='0' && al<='9') || (al>='A' && al<='F') || (al>='a' && al<='f') || al==VK_BACK
.if al>='a' && al<='f'
sub al, 20h
.endif
; Having done what we want to do, the message is passed back
; to the original control procedure, but with eax instead of wParam
invoke CallWindowProc, hOldWndProc, hEdit, uMsg, eax, lParam
.else
xor eax, eax ; invalid character
.endif
ret
  .elseif ecx==WM_KEYDOWN
.if al==VK_RETURN
invoke MessageBox, hEdit, addr Message, addr AppName, MB_OK or MB_ICONINFORMATION
invoke SetFocus, hwndEdit
.endif
  .endif
DefProc:
  invoke CallWindowProc, hOldWndProc, hEdit, uMsg, wParam, lParam
  ret
EditWndProc endp


Note also the MB_OK or MB_ICONINFORMATION. Using + is a bad habit that will hit you one day when you don't expect it 8)

Lightman

Many thanks jj2007,

Code now works as it should; example attached.

That also clears up another mystery... I was curious to know how Windows knows which messages I had processed before passing the message on.

You'd shifted the uMsg to ecx. I'm guessing that this is more efficient code, since in my version I load up the value of wParam with each message I process.

...and replacing + with 'or'... OK, duly noted for the future.

Regards,

Lightman
Regards,

Lightman

jj2007

Have a look again on what exactly I posted above ("with eax instead of"):
; Having done what we want to do, the message is passed back to the
; original control procedure.
jmp DefaultProc

Lightman

Hi,

Revised code...

In the last version I was calling the CallWindowProc by 'jmp'ing to the default entry at the end of the procedure. In doing this I lost my value in eax. Replacing this with a direct call to CallWindow retained the value in eax.

I'm still a bit confused by the difference between the 'ret' and the call to CallWindowProc. The ret prevents the message being run again by the Windows control procedure?

Regards,

Lightman
Regards,

Lightman

jj2007

Quote from: Lightman on December 03, 2015, 01:04:13 AMThe ret prevents the message being run again by the Windows control procedure?

Yes, exactly. Normally, in a subclass you do something, then hand over to the default proc. The ret means that Windows will not have a chance to do the default processing.