Hi again. I search throught all the internet and all the methods to make an event Hover and Leave has wast quite nice to me. One of the main trhoubles was that only the message procesor of the window could get the events. so that means that if im making a form with a couple of buttons that make diferent things in the events i would have to create a lot of code. Also i dont find vb a good language to process message, cause that has to be fast as posible cause all message have to pass trhu the hook process, and every added reference is a lil more of time processing.
The search method in the list is not optimized, but im almost sure that is better than make it in vb.
well, i made a function that can redirect any message of any window to your own object function, this object require only implement an interface called IMessageCatcher, and thats all, cant be more simple.



vb code
Implements IMessageCatcher
Const WM_MOUSEHOVER = &H2A1&
Const WM_MOUSELEAVE = &H2A3&
Const WM_LBUTTONDOWN = &H201&
Const WM_LBUTTONUP = &H202&

Private WithEvents mouseeventsCommand2 As MessageCatcher
Private WithEvents mouseeventscommand3 As MessageCatcher
Private Declare Function EndWindowRedirection Lib "..\msgredir\msgredir.dll" (ByVal hWnd As Long) As Boolean
Private Declare Function RedirectMessage Lib "..\msgredir\msgredir.dll" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal obj As IMessageCatcher) As Boolean

Private Sub cmdCommand1_Click()
    MsgBox "This is the original event"
End Sub

Private Sub Form_Click()
    MsgBox "Original event"
End Sub

Private Sub Form_Load()
    Set mouseeventsCommand2 = New MessageCatcher
    Set mouseeventscommand3 = New MessageCatcher
   
    Call RedirectMessage(Me.hWnd, WM_MOUSEHOVER, Me)
    Call RedirectMessage(Me.hWnd, WM_MOUSELEAVE, Me)
    Call RedirectMessage(Me.hWnd, WM_LBUTTONDOWN, Me)
   
    Call RedirectMessage(Me.cmdCommand1.hWnd, WM_MOUSEHOVER, Me)
    Call RedirectMessage(Me.cmdCommand1.hWnd, WM_MOUSELEAVE, Me)
    Call RedirectMessage(Me.cmdCommand1.hWnd, WM_LBUTTONUP, Me)
   
    'now we r redirecting direfent messages of direfents windows on the same
    'message processor, you may need to separate without doing a if.elseif.endif
    'you could do this
    Call mouseeventsCommand2.Redirect(Me.cmdCommand2.hWnd, WM_MOUSEHOVER)
    Call mouseeventsCommand2.Redirect(Me.cmdCommand2.hWnd, WM_MOUSELEAVE)
    Call mouseeventsCommand2.Redirect(Me.cmdCommand2.hWnd, WM_LBUTTONDOWN)
    Call mouseeventsCommand2.Redirect(Me.cmdCommand2.hWnd, WM_LBUTTONUP)
    Call mouseeventscommand3.Redirect(Me.cmdCommand3.hWnd, WM_MOUSEHOVER)
    Call mouseeventscommand3.Redirect(Me.cmdCommand3.hWnd, WM_MOUSELEAVE)
   
End Sub

Private Function IMessageCatcher_OnMsg(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Me.txtText1 = "IMessageCatcher_OnMsg of the form" & vbCrLf
    If hWnd = Me.hWnd Then
        Me.txtText1 = Me.txtText1 & "Window: Form" & vbCrLf
    ElseIf hWnd = Me.cmdCommand1.hWnd Then
        Me.txtText1 = Me.txtText1 & "Window: Command1" & vbCrLf
    End If
    If uMsg = WM_LBUTTONUP Then
        Me.txtText1 = Me.txtText1 & "Message: Click"
    ElseIf uMsg = WM_MOUSEHOVER Then
        Me.txtText1 = Me.txtText1 & "message: Mouse Hover"
    ElseIf uMsg = WM_MOUSELEAVE Then
        Me.txtText1 = Me.txtText1 & "message: Mouse Leave"
    End If
End Function

Private Sub mouseeventsCommand2_OnMsg(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long)
    If uMsg = WM_MOUSEHOVER Then
        Me.cmdCommand2.Caption = "Hover"
    ElseIf uMsg = WM_LBUTTONDOWN Then
        Me.cmdCommand2.Caption = "Click.."
    ElseIf uMsg = WM_LBUTTONUP Then
        Me.cmdCommand2.Caption = "ClickOut"
    Else
        Me.cmdCommand2.Caption = "Leave"
    End If
End Sub

Private Sub mouseeventscommand3_OnMsg(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long)
    If uMsg = WM_MOUSEHOVER Then
        Me.cmdCommand3.Caption = "Hover"
    Else
        Me.cmdCommand3.Caption = "Leave"
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    'in this case you dont need to call EndWindowRedirection
    'cause is made it automatically when the windows get the wm_destroy
    EndWindowRedirection Me.hWnd
    EndWindowRedirection Me.cmdCommand1.hWnd
    EndWindowRedirection Me.cmdCommand2.hWnd
    EndWindowRedirection Me.cmdCommand3.hWnd
End Sub

'WARNING!! everytime u call redirectmessage the asm make a node in a list
'this is destroyed when the hook process of the window WM_DESTROY
'if u hook another windows that is not of yours remember to call EndWindowRedirection
'else if the IMessageCatcher is destroyed before the window a message is catched by asm,
'it will make an error trying to call the first public function of the interface of the
'deleted object
'Second WARNING: call twice RedirectMessage with same window and message dont work
'the first one only gets it (ill improve this when i have time)
'Third WARNING: if diferent objects whith IMessageCatcher are hooking diferent
'message of same window if some object have to be deleted then it have to call
'to EndWindowREdirect and in secondary efect makes the other object stop hooking
'messages, this is cause i didnt have time, and i didnt need it to make a function
'in the dll RemoveMessageRedirection, ill do it when i need it or have the time
'i think thats all, cant remember now, im too sleepy







asm code of the dll (only the important part)

.386
.model flat,stdcall
option casemap:none

include msgredir.inc



this is the way you define any object interface:

vbClass_VirtualTable struct
unk1 dd ?
unk2 dd ?
unk3 dd ?
unk4 dd ?
unk5 dd ?
unk6 dd ?
unk7 dd ?
vbClass_VirtualTable ends
IMessageCatcher_VirtualTable struct
unknown vbClass_VirtualTable <>;no idea what this info is
Func1 dd ?  ;my function
IMessageCatcher_VirtualTable ends
vbObject struct
pVirtualTable dd ?
vbObject ends



.data
hInstance dd 0
hWindowsList dd ?
hDllVbVm dd 0

.code
DllEntry proc hInst:HINSTANCE, reason:DWORD, reserver1:DWORD
LOCAL hList:DWORD

.if reason == DLL_PROCESS_ATTACH
push hInst
pop hInstance
invoke CreateDataList
mov hWindowsList,eax
.elseif reason == DLL_PROCESS_DETACH
invoke EndAllWindowsRedirection
invoke DataList_Delete,hWindowsList
.endif
mov eax,TRUE
ret

DllEntry endp


MsgRedirectorProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL retv:DWORD
LOCAL tme:TRACKMOUSEEVENT

push esi

invoke DataList_Get,hWnd,hWindowsList
;allways is going to return a list entry
mov esi,eax;esi = ptr WindowNode
invoke CallWindowProc,.WindowNode.pProc,hWnd,uMsg,wParam,lParam
push eax
.if uMsg== WM_DESTROY
invoke EndWindowRedirection,hWnd
ret
.elseif uMsg==02a3h;leave
mov .WindowNode.inside,0
mov tme.cbSize,SIZEOF(TRACKMOUSEEVENT)
mov tme.dwFlags,TME_HOVER
mov eax,hWnd
mov tme.hwndTrack,EAX
mov tme.dwHoverTime,HOVER_DEFAULT
INVOKE TrackMouseEvent,ADDR tme
;^

.ELSEIF uMsg==WM_MOUSEMOVE && .WindowNode.inside==0;hover
mov .WindowNode.inside,1
;seems like windows dont generate hover message, so i do it for him
invoke PostMessage,hWnd,WM_MOUSEHOVER,0,0

mov tme.cbSize,SIZEOF(TRACKMOUSEEVENT)
mov tme.dwFlags,TME_LEAVE
mov eax,hWnd
mov tme.hwndTrack,EAX
mov tme.dwHoverTime,HOVER_DEFAULT
INVOKE TrackMouseEvent,ADDR tme
.endif
invoke DataList_Get,uMsg,.WindowNode.hMsgs
.if eax; if we have to redirect the message of this window
;eax = ptr WindowMessageNode
mov esi,eax;esi = ptr WindowMessageNode

;call the function number 1 of the object interface
mov eax,.WindowMessageNode.pObj
mov edx,.vbObject.pVirtualTable
lea ecx,retv
push ecx ;push the address to the return value
push lParam ;push parameters as u define in vb
push wParam
push uMsg
push hWnd
push eax ;push object reference
call .IMessageCatcher_VirtualTable.Func1
.endif

pop eax
pop esi
ret

MsgRedirectorProc endp
RedirectMessage proc hWnd:HWND,uMsg:DWORD,pObj:DWORD;As boolean(true = ok)
LOCAL et:TRACKMOUSEEVENT
push esi
invoke DataList_Get,hWnd,hWindowsList
.if eax;the window already exist in the list

mov esi,eax;esi = window node
invoke WindowNode_addMessage,esi,uMsg,pObj
.ELSE;the window dont exist in the list
mov eax,hWindowsList
invoke WindowNode_create,hWnd;put in the list
mov esi,eax
invoke DataList_Add,hWnd,esi,hWindowsList
invoke WindowNode_addMessage,esi,uMsg,pObj
invoke SetWindowLong,hWnd,GWL_WNDPROC,ADDR MsgRedirectorProc
mov et.cbSize,SIZEOF(TRACKMOUSEEVENT)
mov et.dwFlags,TME_HOVER+TME_LEAVE+TME_CANCEL
mov eax,hWnd
mov et.hwndTrack,EAX
mov et.dwHoverTime,HOVER_DEFAULT
INVOKE TrackMouseEvent,ADDR et
.endif
pop esi
ret

RedirectMessage endp

EndWindowRedirection proc hWnd:DWORD;As long (success <> 0)

push esi
invoke DataList_Get,hWnd,hWindowsList
mov esi,eax;esi = windownode
invoke SetWindowLong,.WindowNode.hWnd,GWL_WNDPROC,.WindowNode.pProc;reestablezco el proceso original
invoke DataList_Delete,.WindowNode.hMsgs;borro lista de mensajes
invoke GlobalFree,esi
invoke DataList_Remove,hWnd,hWindowsList;borro el nodo de la lista
pop esi
ret

EndWindowRedirection endp

EnumCancelRedirection proc pWindowNode:DWORD

push esi
mov esi,pWindowNode
invoke EndWindowRedirection,.WindowNode.hWnd
pop esi
ret

EnumCancelRedirection endp
EndAllWindowsRedirection proc

lea ecx, EnumCancelRedirection
invoke DataList_Enum,hWindowsList,ecx
ret

EndAllWindowsRedirection endp

end DllEntry






i hope u find this usefull.
one last comment about virtual tables of vb objects
lets say that your class called MyClass is defined in vb like this:


vb code:

public myLong as long
private myPrivateLong as long 'private members dont afect the virtual table of the object, cause dont have default get and set methods
property get myOtherLong as long
myOtherLong = 5
end property

public function myFunction() as long
myFunction = myLong + 20
end function



to can use methods of the class from ASM having a reference to the object
u have to define the virtual table like this

MyClass_VirtualTable struct
unknown vbClass_VirtualTable <>
Get_myLong dd ?
Set_myLong dd ?
Get_myOtherLong dd ?
myFunction dd ?
MyClass_VirtualTable ends



remember that the calling convention of vb passes the pointer to the ret value first
and the pointer to the object at after the parameters, and i guess u know
how to pass byval and byref parameters.
sorry my english, but is understandable enought, isnt it?
thats all
Posted on 2007-05-24 07:30:23 by mauricioprado
Anyone who reads this thread should know that none of this is new.
It might be a useful example for programmers interested in the lowlevel mechanisms that are used by object interfaces, but this is not an efficient way to write this kind of code, and it's not pretty to look at, either.

Members of this board have created many helper macros for defining and calling object interfaces and their methods.
In order of least complexity: Ernie's COINVOKE/COM macros, Ultrano's ATC oopasm framework, Biterider's OA32 oopasm framework.
So much stuff to look at!

These are just sets of helper macros that allow you to write what appears to be highlevel sourcecode, where in fact we're using macros that emit vanilla asm, so these frameworks only exist 'at buildtime', inside MASM.

In particular, OA32 supports many highlevel concepts such as N-deep single inheritance, polymorphism, runtime overloading of interface methods etc. which would make your life much more painful if you insisted on handcrafting all your code...it can create Vanilla, COM and C++ styles of interfaces.

Here's an incomplete example of some OA32-dependant code which shows what I mean:


mov ptemp, $OCall (pObj::MyObjectClass.EnumArgs,pPhrase,2)
Switch eax
Case NULL
DbgWarning "No Arguments were Enumerated"
Destroy ptemp
mov ptemp,0


I believe that ATC is now officially dead, however the other stuff is still being used regularly, and in particular OA32 is still being actively developed.
Posted on 2007-05-24 08:30:24 by Homer

Anyone who reads this thread should know that none of this is new.
It might be a useful example for programmers interested in the lowlevel mechanisms that are used by object interfaces, but this is not an efficient way to write this kind of code, and it's not pretty to look at, either.

Sorry my ignorance, i didnt know that com clases whas the same that vb objects.
I just open my debug and start to c how vb makes the calls.
did u know where i can find the interface descriptors for the common objects in vb? like command buttons, forms, etc? thanks
i dont know what u mean by eficient, is it faster with the macros? maybe u mean a lil less of code and an added complexity. Anyway, i prefeer to write high level code with high level languages and use asm to write low level, even if is longer i found it easyer to read and mantain, when i start to use all those macros and stuff asm code start to be look kind of ugly to me.
Posted on 2007-05-24 10:06:01 by mauricioprado

OOPASM allows you to write programs that look and feel like a HLL, but actually generate asm (that you will never see).

It's efficient because it dramatically speeds up development times, especially when you are using, or deriving from, a set of standard objects.
The tired old arguments that have been used by HLL coders for years to put down ASM are no longer true.
We can write HLL code AND write asm at the SAME TIME.
We can write reusable code modules and port them easily between projects, etc.

The source is more readable, faster to write, easier to debug (TRUE!), and the development times are similar to any other HLL, with the added benefits that the binary code is more efficient, faster, and smaller than that produced by a Compiler.

You don't even need to study or understand the oopasm macros and the opcodes they generate in order to USE them, which is why I responded so quickly to your post.

I am not suggesting that understanding the lowlevel output of the macros is a bad idea, I am simply stating that the User does not NEED to do so in order to benefit from using it.
Posted on 2007-05-24 11:13:04 by Homer

Anyone who reads this thread should know that none of this is new.

ive been reading the com librarys for asm. There is something new if i dont mistake, the com defines that every object interface have the iUnknown that have 6. This vb objects have 7 methods, i dont know if the 6 first belong to iunknown.
I dont know if write an app with asm even using HLL takes the same time, i would pay to c a vb programer next to a asm programer and c who ends first an entire project in just 1 languaje.
As i said before, i prefeer to use asm in things that the high level languaje that i use to write the application dont let me do it, or make it slow, or makes all confusing or make "strange" code, etc, etc
and all this discution just for 5 lines that could be replaced for a coinvoke call, i pass from low level to high leven in 5 lines. No matter how much macros i use, writting hll in asm depends more of the programer discipline than other thing, cause ull have allways at your hand to do low level code.
as i c this macros "emulate" oop, and that make trying to write Object Oriented code pretty much clumsy. Even with vb cant write acurate OO code, neither smalltalk, CLOS, Eiffel or c++ are completelly OO, so i doubt asm can be OO.
with those premises i could write fully OO with a electromagnetic pencil into a music cassette
Posted on 2007-05-25 07:55:43 by mauricioprado