In the code example, the event has vectored to the code by previously doing a SetWindowLong to the address of this proc.

!StaticText1+492 contains the result of a previous GetWindowLong for the control.

!StaticText1+44 contains the handle for the control.

StaticText1_intercept sets !PassInterceptEvent to a 1.



proc !InterceptProc1,OBMain,wmsg,wparam,lparam
enter
push ebx esi edi
mov [!PassInterceptEvent],0
mov [!Desc],!StaticText1
call StaticText1_intercept
cmp [!PassInterceptEvent],0
je !NoPass1
invoke CallWindowProc,[!StaticText1+492],[!StaticText1+44],[wmsg],[wparam],[lparam]
!NoPass1:
xor eax,eax
jmp !Finish


The problem is that once this routine is entered, the control no longer responds to mouse clicks.

Please help.
Posted on 2004-01-12 21:41:35 by msmith
You have to Set the focus to the new edit window by using the new handle.
Posted on 2004-01-15 11:11:36 by mrgone
You should use the CallWindowProc function to call the original windo procedure at the end of your subclassed procedure (If you want to keep the original functionality)
Posted on 2004-01-15 15:52:25 by ENF

You should use the CallWindowProc function to call the original windo procedure at the end of your subclassed procedure (If you want to keep the original functionality)


You are absolutely right!

Looking at my example, it appears that I already did that.

Why doesn't it work?
Posted on 2004-01-15 17:07:12 by msmith
msmith,

Normally a subclass is used with controls where you don't normally construct a WNDCLASSEX with the callback address in it. Below is the output from one of the toys in MASM32 but it should be easy enough for you to convert the format


; #########################################################################

; ---------------------------------------------------
; Prototype
; ~~~~~~~~~
; CtrlProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
;
; .DATA section entries
; ~~~~~~~~~~~~~~~~~~~~~
; lpCtrlProc dd 0
; hCtrl dd 0
;
; The following API call should be placed on the line
; following the function call that creates the control
;
; invoke SetWindowLong,hCtrl,GWL_WNDPROC,CtrlProc
; mov lpCtrlProc, eax
; ---------------------------------------------------

; #########################################################################

CtrlProc proc hCtl :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD


; -----------------------------
; Process control messages here
; -----------------------------

invoke CallWindowProc,lpCtrlProc,hCtl,uMsg,wParam,lParam

ret

CtrlProc endp

; #########################################################################
Posted on 2004-01-15 20:03:55 by hutch--
Hi Hutch,

Are you saying that:



invoke SetWindowLong,hCtrl,GWL_WNDPROC,CtrlProc
mov lpCtrlProc, eax


will save a different address in lpCtrlProc than:



invoke GetWindowLong,hCtrl,GWL_WNDPROC
mov lpCtrlProc, eax


?

If so, then what use is the GetWindowLong function?

Thanks,

Mike
Posted on 2004-01-15 20:48:11 by msmith
GetWindowLong and SetWindowLong return the same Address, The only difference is that SetWindowLong changes the address so that the returned address can now be considered the old address. For subclassing there is no need to use GetWindowLong because you will get the original address from SetWindowLong.Do you call CallWindowProc after the code @
!Finish?
Posted on 2004-01-16 04:15:50 by ENF
ENF,

Here is the code @ !Finish:



!Finish:
pop edi esi ebx
return


My original post stated that I was using GetWindowLong. Hutch posted that I should use SetWindowLong. That is why I asked the question concering these two functions.

Maybe the way for me to find out what I want to know is to see if someone can illustrate how to intercept a control's events and then pass back control to the original Proc (doing nothing in the intercept proc). So far for me that is not working.
Posted on 2004-01-16 09:50:28 by msmith
The most basic subclassed proc is like this (this is masm syntax)



SubClassProc PROC hWnd:HWND, uMsg:UINT, wParam:DWORD, lParam:DWORD
push esi
push edi
push ebx

push lParam
push wParam
push uMsg
push hWnd
push lpOriginalProc
call CallWindowProc
pop ebx
pop edi
pop esi
ret
SubClassProc ENDP


All this dose is call the original procedure and returns with the value returned by that procedure. I think the problem with your code is that if you don't intercept a particular message then you jump to finnish wich returns without calling the original procedure so all messages that you don't intercept are ignored because they are not handled by the original proc.
Posted on 2004-01-16 10:47:04 by ENF
You don't need the push/pop of esi,edi,ebx - yeah, you must preserve registers in callbacks, but since you're not modifying them in this code snippet there's no need for those pushes and pops.
Posted on 2004-01-16 12:08:54 by f0dder
msmith, it would be useful if you posted stripped-down example code that can be assembled and that demonstrates how the control does not respond to mouse clicks. With the above code fragments and verbal descriptions, responses can't be better than guesswork. A propos guesswork: did you call GetWindowLong before or, by accident, only after calling SetWindowLong?
Posted on 2004-01-16 12:51:24 by Frank
msmith,

Conceptually a subclass procedure is an intercept of the messages normally sent to a window, whether its a control or otherwise. You can in fact subclass a normal Wndproc from outside if you know what you are doing.

To make it work you need both the old address and the address of you own subclass procedure. To create the intercept you use SetWindowLong to set the new address for the subclass procedure and in that subclass you use the OLD address to exit to so that both your intercept code works and the original continues to work.

Regards,
http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2004-01-16 19:31:50 by hutch--
Hi Hutch,

I use subclassing elsewhere in my compiler, for example when I use a frame to hold radio buttons etc. It all works fine.

The case I describe in the first post of this thread is a little different in some respects.

At any rate, all of the things you say need to be done are being done if you view the notes and code in the first post.

At any rate thank you for your help.

The paradyme of doing this in a compiler environment is slightly different than an assembly coder would view it. That is why I want to save the original Proc address using a GetWindowLong instead of using SetWindowLong. ( My other use of subclassing does use SetWindowLong because if a control is constructed with another control as parent, I know I need to subclass it).
In the current case, I don't know whether my compiler user will ever want to intercept events or not, so I want to save the original address just in case. To compilcate things, I have to cover the case where the compiler wants to subclass the same control for its own purposes as the user wants to intercept. In that case there will be a safe for the original Proc addr and another for the user's.
Posted on 2004-01-16 20:15:28 by msmith
ENF,


All this dose is call the original procedure and returns with the value returned by that procedure. I think the problem with your code is that if you don't intercept a particular message then you jump to finnish wich returns without calling the original procedure so all messages that you don't intercept are ignored because they are not handled by the original proc.


StaticText1_intercept simply turns another static control a different background color, sets !PassInterceptEvent, and returns. In other words, it is not intercepting ANY messages. !PassInterceptEvent is simply a flag that the StaticText1_intercept routine may set.



proc !InterceptProc1,OBMain,wmsg,wparam,lparam
enter
push ebx esi edi
mov [!PassInterceptEvent],0
mov [!Desc],!StaticText1
call StaticText1_intercept
cmp [!PassInterceptEvent],0
je !NoPass1
invoke CallWindowProc,[!StaticText1+492],[!StaticText1+44
],[wmsg],[wparam],[lparam]
!NoPass1:
xor eax,eax
jmp !Finish


I changed the code to:


proc !InterceptProc1,OBMain,wmsg,wparam,lparam
enter
push ebx esi edi
jmp NoCall
mov [!PassInterceptEvent],0
mov [!Desc],!StaticText1
call StaticText1_intercept
cmp [!PassInterceptEvent],0
je !NoPass1
NoCall:
invoke CallWindowProc,[!StaticText1+492],[!StaticText1+44
],[wmsg],[wparam],[lparam]
!NoPass1:
xor eax,eax
jmp !Finish


The control STILL does not accept command events. In other words, this intercept is not transparent.

Thank you for your help.
Posted on 2004-01-16 20:27:06 by msmith
Just in case you haven't checked, is the function address at CallWindowProc the same as the value you retrieved from GetWindowLong/SetWindowLong ?

One other possible problem is that you are always returning 0. This is OK when the Intercept is invoked by DispatchMessage (PostMessage). It is not OK when the Intercept is directly invoked by SendMessage. While mouse and keyboard messages are posted, other messages may be sent via SendMessage, where some kind of meaningful value is returned. If some WM_NC* messages require return values other than 0 for effects like move window, your proc disables that.
Posted on 2004-01-16 23:02:21 by tenkey
Hi tenkey,

By golly... you got it!

I removed the xor eax,eax and boom.. it seems to work.

It is getting late here so I will do more testing tomorrow.

But, I think you fixed my problem and I really appreciate it.

Oh, and to answer your first question... yes.
Posted on 2004-01-16 23:14:33 by msmith