Hola Jorge en esta web encontre unos excelentes tutos de ASM basico y avanzado, ademas esta en español:
http://www.angelfire.com/rnb/byte/tut_es.htm#indexMira esto, esta en MASM:
Tutorial 24: Ganchos de Windows
En este tutorial aprenderemos sobre los ganchos [hooks] en Windows. Los ganchos de Windows son muy poderosos. Con ellos, puedes "pescar" [pook] dentro de otros procesos e incluso modificar su conducta.
Bajar el ejemplo aquí.
Teoría:
Los ganchos de Windows pueden considerarse uno de los rasgos más poderosos de Windows. Con ellos podemos atrapar eventos que ocurrirán en tus procesos o en otros remotos. A través del "enganche" [hooking], dices cosas a Windows sobre una función, una función filtro llamada también procedimiento del gancho, que será llamado cada vez que ocurra un evento que te interese. Hay dos tipos de ellos: ganchos locales y ganchos remotos.
Ganchos Locales atraparán eventos que ocurrirán en tus propio proceso.
Ganchos Remotos atraparán eventos que ocurrirán en otro(s) proceso(s). Hay dos tipos de ganchos remotos
específicos-a-un-hilo [thread-specific] atrapan eventos que ocurren en un hilo específico de otro proceso. En pocas palabras, quieres observar un hilo específico en un proceso específico.
ancho-de-sistema [system-wide] atrapa todos los eventos de todos los hilos en todos los procesos en el sistema.
Cuando instales ganchos, recuerda que ellos afectan el sistema de desempeño. Los ganchos de ancho de sistema [system-wide] son los más notorios en este aspecto. Como TODOS los eventos relacionados serán dirigidos a través de tu función filtro, tu sistema puede ralentizarse un poco. Así que si quieres usar un gancho de ancho de sistema, deberías usarlo juiciosamente y desactivarlo tan pronto ya no lo necesites. También tienes una probabilidad más alta de quebrar [crashing] los otros procesos, ya que puedes mediar [meddle] con otros procesos y si algo va mal en tu función filtro, se pueden derribar los otros procesos y lanzarlos al olvido. Recuerda: el poder viene con responsabilidades.
Tienes que entender como trabaja un gancho antes de que puedas usarlo con eficiencia. Cuando creas un gancho, Windows crea una estructura de datos en la memoria, que contiene información sobre el gancho, y lo agrega a una lista enlazada de ganchos existentes. El gancho nuevo es agregado en frente de los ganchos antiguos. Cuando un evento ocurre, si instalas un gancho local, la función filtro en tu proceso es llamada de una manera directa. Pero si es un gancho remoto, el sistema debe inyectar el código para el procedimiento del gancho dentro del espacio de direcciones del(os) otro(s) proceso(s). Y el sistema puede hacer eso sólo si la función reside en una DLL. De esta manera, si quieres usar un gancho remoto, tu procedimiento de gancho debe residir en una DLL. Hay dos excepciones a esta regla: ganchos de grabación diaria [journal record] y ganchos de ejecución diaria [journal playback]. El procedimiento de gancho para estos dos ganchos debe residir en el hilo que instala los ganchos. La razón por la que debe ser así, es porque ambos ganchos tienen que ver con la intercepción de bajo-nivel de los eventos de entrada del hardware. Los eventos de entrada deben ser grabados/ejecutados [recorded/playbacked] en el orden que aparecen. Si el código de estos dos ganchos está en un DLL, los eventos de entrada pueden dispersarse entre varios hilos y es imposible saber su orden. Así que la solución es: el procedimiento de gancho de esos dos gancho deben estar solamente en un hilo, en el hilo que instala los ganchos.
Hay 14 tipos de ganchos:
WH_CALLWNDPROC llamado cuando SendMessage es llamado
WH_CALLWNDPROCRET llamado cuando regresa el mensaje SendMessage
WH_GETMESSAGE llamado cuando GetMessage o PeekMessage son llamados
WH_KEYBOARD llamado cuando GetMessage o PeekMessage regresan WM_KEYUP o WM_KEYDOWN desde la cola de mensajes
WH_MOUSE llamado cuando GetMessage o PeekMessage regresan un mensaje de ratón desde la cola de mensajes
WH_HARDWARE llamado cuando GetMessage o PeekMessage regresa algún mensaje hardware que no está relacionado con el teclado ni con el ratón.
WH_MSGFILTER llamado cuando una caja de diálogo, el menú o la barra de pergamino [scrollbar] está apunto de [is about] procesar un mensaje. Este gancho es local. Se usa específicamente para esos objetos que tienen sus propios bucles de mensajes internos.
WH_SYSMSGFILTER lo mismo que WH_MSGFILTER pero de ancho de sistema [system-wide]
WH_JOURNALRECORD llamado cuando Windows regresa mensajes desde hardware input queue
WH_JOURNALPLAYBACK llamado cuando es solicitado un evento del hardware desde la cola de entrada del sistema.
WH_SHELL llamado cuando algo interesante sobre el shell ocurre, tal como cuando la barra de tareas necesita redibujar su botón.
WH_CBT usado específicamente para entrenamiento [computer-based training (CBT)].
WH_FOREGROUNDIDLE usado internamente por Windows. Poco usada para aplicaciones generales
WH_DEBUG usado para depurar el procedimiento de enganche
Ahora que sabemos algo de teoría, podemos ver ahora cómo instalar/desinstalar los ganchos.
Para instalar un gancho, llamas a SetWindowsHookEx que tiene la siguiente sintaxis:
SetWindowsHookEx proto HookType:DWORD, pHookProc:DWORD, hInstance:DWORD, ThreadID:DWORD
HookType es uno de los valores en la lista de arriba, e.g., WH_MOUSE, WH_KEYBOARD
pHookProc es la dirección del procedimiento de gancho que será llamada para procesar los mensajes para el gancho específico. Si el gancho es remoto, debe residir en una DLL. Si no, debe estar en tu proceso.
hInstance es el manejador de instacia de la DLL en la cual reside el procedimiento de gancho. Si el gancho es local, este valor debe ser NULL
ThreadID es el ID del hilo para el cual quieres instalar el gancho que lo espíe. Este parámetro es el que determina si el gancho es local o remoto. Si este parámetro es NULL, Windows interpretará el gancho como un gancho remoto de ancho de sistema [system-wide] que afecta todos los hilos del sistema. Si quieres especificar el ID de un hilo en tu propio proceso, este hilo es local. Si especificas el ID del hilo de otro proceso, el gancho es thread-specific remote one. Hay dos excepciones a esta regla: WH_JOURNALRECORD y WH_JOURNALPLAYBACK siempre son ganchos de ancho de sistema [system-wide] locales que no se requieren que estén en una DLL. Y WH_SYSMSGFILTER siempre es un gancho remoto de ancho de sistema [system-wide]. Realmente es idéntica al gancho WH_MSGFILTER con ThreadID==0.
Si la llamada tiene éxito, regresa el manejador de gancho en eax. Si no, regresa NULL. Debes salvar el manejador del gancho para poder desinstalarlo después.
Puedes desinstalar un gancho llamando a UnhookWindowsHookEx que sólo acepta un parámetro, el manejador del gancho que quieres desinstalar. Si la llamada tiene éxtito, regresa un valor diferente a cero en eax. En caso contrario, regresa NULL.
Ahora que sabes cómo instalar/desinstalar ganchos, podemos examinar el procedimiento de gancho.
El procedimiento de gancho será llamado cada vez que ocurre un evento asociado con el tipo de gancho que haz instalado. Por ejemplo, si instalas el gancho WH_MOUSE, cuando ocurre un evento de ratón, será llamado tu procedimiento de gancho. Independientemente del tipo de gancho que instalaste, el procedimiento de gancho siempre tiene el siguiente prototipo:
HookProc proto nCode:DWORD, wParam:DWORD, lParam:DWORD
nCode especifica el código del gancho.
wParam y lParam contienen información adicional sobre el evento
HookProc es realmente un comodín [placeholder] para el nombre de la función. Puedes llamarla de la forma que quieras siempre que conserves el prototipo de arriba. La interpretación de nCode, wParam y lParam depende del tipo de gancho que instales, así como del valor de retorno del procedimiento de gancho. Por ejemplo:
WH_CALLWNDPROC
nCode sólo puede ser HC_ACTION lo cual significa que hay un mensaje enviado a la ventana
wParam contiene el mensaje que está siendo enviado, si no lo tiene es cero
lParam apunta a una estructura CWPSTRUCT
return value: no se usa, regresa cero
WH_MOUSE
nCode puede ser HC_ACTION o HC_NOREMOVE
wParam contiene el mensaje del ratón
lParam apunta a una estructura MOUSEHOOKSTRUCT
return value: cero si el mensaje debería ser procesado. 1 si el mensaje deberúia ser descartado.
La línea de abajo es: debes consultar tu referencia de la api de win32 para detalles sobre los significados de los parámetros y regresar un valor al gancho que quieres instalar.
Ahora hay un poco de catch sobre el procedimiento de gancho. Recuerda que los ganchos estan encadenados en una lista enlazada con el gancho instalado más recientemente colocado en la cabeza de la lista. Cuando ocurre un evento, Windows llamará sólo al primer gancho de la cadena. Es responsabilidad de tu procedimiento de gancho llamar al siguiente gancho en la cadena. Tú no eliges llamar al siguiente gancho, pero mejor deberías saber qué estás haciendo. Muchas veces, es una buena práctica llamar al siguiente procedimiento de manera que otros ganchos puedan tener una impresión [shot] del evento. Puedes invocar al siguiente gancho llamando a CallNextHookEx que tiene el siguiente prototipo:
CallNextHookEx proto hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD
hHook es tu propio manejador de gancho. La función usa este manejador para atravesar la lista enlazada y buscar el siguiente procedimiento de gancho que debería ser llamado.
nCode, wParam y lParam puedes pasar estos tres valores que recibes de Windows a CallNextHookEx.
Una nota importante sobre los ganchos remotos: el procedimiento de gancho debe residir en una DLL que será proyectada dentro de otro proceso. Cuando Windows proyecta la DLL dentro de otros procesos, no proyectará la(s) sección(es) de datos(s) dentro de otros procesos. En pocas palabras, todos los procesos comparten una copia sencilla del código, ¡pero ellos tendrán su propia copia privada de la sección de datos de la DLL! Esto puede resultar una gran sorpresa para el incuto. Puedes pensar que cuando almacenas un valor dentro de una variable en la sección de datos de una DLL, ese valor será compartido entre todos los procesos que cargan la DLL dentro de su espacio de direcciones. No es tan cierto. En una situación normal, esta conducta es deseable ya que provee la ilusión de que cada proceso tiene su propia copia de la DLL. Pero no cuando hay involucrados ganchos de Windows. Queremos que la DLL sea idéntica en todos los procesos, incluyendo los datos. La solución: debes marcar la sección de datos como compartida. Puedes hacer esto especificando el atributo de la(s) sección(es) en el conmutador [switch] del enlazador [linker]. Para MASM, necesitas usar este conmutador:
/SECTION:<section name>, S
El nombre de la sección de datos inicializada es .data y el de la de los datos no-inicializados es .bss. Por ejemplo, si quieres ensamblar una DLL que contiene un procedimiento de gancho y quieres que la sección de datos no inicialoizados sea compartida entre procesos, debes usar la siguiente línea:
link /section:.bss,S /DLL /SUBSYSTEM:WINDOWS ..........
El atributo S marca la sección como compartida.
Ejemplo:
Hay dos módulos: uno es el programa principal que hará la parte de GUI y otra es la DLL que instalará/desinstalará el gancho.
;--------------------------------------------- Este es el código fuente del programa principal -----------------------------------
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include mousehook.inc
includelib mousehook.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
wsprintfA proto C :DWORD,:DWORD,:VARARG
wsprintf TEXTEQU <wsprintfA>
.const
IDD_MAINDLG equ 101
IDC_CLASSNAME equ 1000
IDC_HANDLE equ 1001
IDC_WNDPROC equ 1002
IDC_HOOK equ 1004
IDC_EXIT equ 1005
WM_MOUSEHOOK equ WM_USER+6
DlgFunc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.data
HookFlag dd FALSE
HookText db "&Hook",0
UnhookText db "&Unhook",0
template db "%lx",0
.data?
hInstance dd ?
hHook dd ?
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_MAINDLG,NULL,addr DlgFunc,NULL
invoke ExitProcess,NULL
DlgFunc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL hLib:DWORD
LOCAL buffer[128]:byte
LOCAL buffer1[128]:byte
LOCAL rect:RECT
.if uMsg==WM_CLOSE
.if HookFlag==TRUE
invoke UninstallHook
.endif
invoke EndDialog,hDlg,NULL
.elseif uMsg==WM_INITDIALOG
invoke GetWindowRect,hDlg,addr rect
invoke SetWindowPos, hDlg, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW
.elseif uMsg==WM_MOUSEHOOK
invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128
invoke wsprintf,addr buffer,addr template,wParam
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer
.endif
invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128
invoke GetClassName,wParam,addr buffer,128
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer
.endif
invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128
invoke GetClassLong,wParam,GCL_WNDPROC
invoke wsprintf,addr buffer,addr template,eax
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer
.endif
.elseif uMsg==WM_COMMAND
.if lParam!=0
mov eax,wParam
mov edx,eax
shr edx,16
.if dx==BN_CLICKED
.if ax==IDC_EXIT
invoke SendMessage,hDlg,WM_CLOSE,0,0
.else
.if HookFlag==FALSE
invoke InstallHook,hDlg
.if eax!=NULL
mov HookFlag,TRUE
invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText
.endif
.else
invoke UninstallHook
invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText
mov HookFlag,FALSE
invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL
invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL
invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL
.endif
.endif
.endif
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgFunc endp
end start
;----------------------------------------------------- Este es el código fuente de la DLL --------------------------------------
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
.const
WM_MOUSEHOOK equ WM_USER+6
.data
hInstance dd 0
.data?
hHook dd ?
hWnd dd ?
.code
DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD
.if reason==DLL_PROCESS_ATTACH
push hInst
pop hInstance
.endif
mov eax,TRUE
ret
DllEntry Endp
MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD
invoke CallNextHookEx,hHook,nCode,wParam,lParam
mov edx,lParam
assume edx:PTR MOUSEHOOKSTRUCT
invoke WindowFromPoint,[edx].pt.x,[edx].pt.y
invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0
assume edx:nothing
xor eax,eax
ret
MouseProc endp
InstallHook proc hwnd:DWORD
push hwnd
pop hWnd
invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL
mov hHook,eax
ret
InstallHook endp
UninstallHook proc
invoke UnhookWindowsHookEx,hHook
ret
UninstallHook endp
End DllEntry
;---------------------------------------------- Est es el makefile de la DLL ----------------------------------------------
NAME=mousehook
$(NAME).dll: $(NAME).obj
Link /SECTION:.bss,S /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm\lib $(NAME).obj
$(NAME).obj: $(NAME).asm
ml /c /coff /Cp $(NAME).asm
Análisis:
El ejemplo desplegará una caja de diálogo [dialog box] con tres controles de edición que serán llenados con el nombre de la clase, el manejador [handle] de ventana y la dirección del procedimiento de ventana asociada con la ventana bajo el cursor del ratón. Hay dos botones, Hook (gancho) y Exit (Salir). Cuando presionas el botón Hook, el programa engancha la entrada del ratón y el texto en el botón cambia a Unhook (desenganchar). Cuando mueves el cursor del ratón sobre la ventana, la info acerca de esa ventana será desplegada en la ventana principal del ejemplo. Cuando presionas el botón Unhook, el programa remueve el ganchjo del ratón.
El programa principal usa una caja de diálogo [dialog box] como su ventana principal. Define un mensaje hecho a la medida [custom message], WM_MOUSEHOOK que será usado entre el programa principal y la DLL de gancho. Cuando el programa principal recibe este mensaje, wParam contiene el manejador de la ventana sobre la cual está el cursor del ratón. Por supuesto, este es un plan arbitrario. Yo decido enviar un manejador en wParam por razones de simplicidad. Tú puedes escoger tu propio método de comunicación entre la ventana principal y la DLL de gancho.
.if HookFlag==FALSE
invoke InstallHook,hDlg
.if eax!=NULL
mov HookFlag,TRUE
invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText
.endif
El programa mantiene una bandera, HookFlag, para monitorear el estado del gancho. Es FALSE si no se instala el gancho y TRUE si el gancho es instalado.
Cuando el usuario presiona el botón Hook, el programa chequea si el gancho ya está instalado. Si no lo está, se llama a la función InstallHook en la DLL de gancho para instalarlo. Nota que pasamos el manejador de la ventana principal como parámetro de la función de manera que la DLL de gancho pueda enviar mensajes WM_MOUSEHOOK a la ventana correcta,es decir la tuya propia.
Cuando el programa es cargado, la DLL de gancho tabmbién es cargada. Realmente, las DLLs son cargadas inmediatamente después de que el programa está en memoria. El punto de entrada de la DLL es llamado incluso antes de que se ejecute la primera instrucción del programa principal. Así que cuando el programa principal ejecuta la(s) DLL(s) es/son inicializada(s). Ponemos el siguiente código en el punto de entrada de la DLL de gancho:
.if reason==DLL_PROCESS_ATTACH
push hInst
pop hInstance
.endif
El código salva el manejador de instancia de la DLL de gancho misma a una variable global llamada hInstance para usar dentro de la función InstallHook. Ya que la función del punto de entrada de la DLL es llamada antes de que sean llamadas otras funciones de la DLL, hInstance siempre es válido. Ponemos hInstance en la sección .data, así que este valor es guardado en la base de la sección por proceso [is kept on per-process basis]. Debido a que cuando el cursor del ratón pasa sobre una ventana, la DLL de gancho es proyectada en el proceso. Imagina que ya hay una DLL que ocupa las direcciones de la DLL de gancho que se intentó cargar, la DLL de gancho debería ser re-proyectada a otra dirección. El valor de hInstance será actualizado para las de las nuevas direcciones cargadas. Cuando el usuario presiona el botón Unhook y luego el botón Hook, SetWindowsHookEx será llamada de nuevo. Sin embargo, esta vez, se usará el nuevo espacio de direcciones cargado como el manejador de instacia lo cual será erróneo porque en este proceso ejemplo la dirección de carga de la DLL de gancho no ha sido cambiada. El gancho será local donde puedes enganchar sólo los eventos de ratón que ocurren en tu propia ventana. Difícilmente deseable [hardly desirable].
InstallHook proc hwnd:DWORD
push hwnd
pop hWnd
invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL
mov hHook,eax
ret
InstallHook endp
La función InstallHook es muy simple. Salva el manejador de ventana pasado como su parámetro a una variable global llamada hWnd para ser usada luego. Luego llama a SetWindowsHookEx para instalar un gancho de ratón. El valor de retorno de SetWindowsHookEx es almacenado en una variable global llamada hHook para usar con UnhookWindowsHookEx.
Después de que es llamada SetWindowsHookEx, el gancho del ratón es funcional. Cada vez que ocurre un evento de ratón del sistema, es llamada MouseProc (tu procedimiento de ventana).
MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD
invoke CallNextHookEx,hHook,nCode,wParam,lParam
mov edx,lParam
assume edx:PTR MOUSEHOOKSTRUCT
invoke WindowFromPoint,[edx].pt.x,[edx].pt.y
invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0
assume edx:nothing
xor eax,eax
ret
MouseProc endp
Lo primero que hace es llamar a CallNextHookEx para dar a otros ganchos el chance de procesar el evento del ratón. Después de eso, llma a la función WindowFromPoint para regresar el manejador de la ventana en la coordenada especificada del monitor. Nota que usamos la estructura POINT en la estructura MOUSEHOOKSTRUCT apuntada por lParam como la coordenada actual del ratón. Después de que enviamos el manejador de ventana a la ventana principal a través de PostMessage con el mensaje WM_MOUSEHOOK. Algo que deberías recordar es que: no deberías usar SendMessage dentro del procedimiento de gancho, ya que puede causar estancamiento de mensajes. Es más recomendable PostMessage. La estructura MOUSEHOOKSTRUCT se define abajo:
MOUSEHOOKSTRUCT STRUCT DWORD
pt POINT <>
hwnd DWORD ?
wHitTestCode DWORD ?
dwExtraInfo DWORD ?
MOUSEHOOKSTRUCT ENDS
pt es la coordenada del monitor actual dónde está el cursor del ratón
hwnd es el manejador de la ventana que recibirá el mensaje del ratón. Usualmente es la ventana debajo del cursor del ratón pero no siempre. Si una ventana llama a SetCapture, la entrada del ratón será desviada ahora más bien a la ventana. Debido a esta razón, no uso el miembro hwnd de esta estructura sino que más bien elijo llamara a WindowFromPoint.
wHitTestCode especifica la prueba del valor hit-test. Este valor da más información sobre la posición actual del cursor del ratón. Especifica en qué parte de la ventana está el cursor del ratón. Para una lista completa, chequea en tu referencia de la api de win32 el tópico sobre el mensaje WM_NCHITTEST.
dwExtraInfo contiene información extra asociada con el mensaje. Normalmente, este valor se establece llamando a mouse_event y regresado por la llamada a GetMessageExtraInfo.
Cuando la ventana principal recibe un mensaje WM_MOUSEHOOK, usa el manejador de ventana en wParam para regresar la información acerca de la ventana.
.elseif uMsg==WM_MOUSEHOOK
invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128
invoke wsprintf,addr buffer,addr template,wParam
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer
.endif
invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128
invoke GetClassName,wParam,addr buffer,128
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer
.endif
invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128
invoke GetClassLong,wParam,GCL_WNDPROC
invoke wsprintf,addr buffer,addr template,eax
invoke lstrcmpi,addr buffer,addr buffer1
.if eax!=0
invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer
.endif
Para evitar parpadeos [flickers], chequeamos el texto que está todavía en los controles de edición y el texto que se pondrá dentro de ellos para comprobar si on idénticos. Si lo son, los saltamos.
Regresamos el nombre de la clase llamando a GetClassName, la dirección del procedimiento de ventana llamando a GetClassLong con GCL_WNDPROC y luego los formateamos dentro de cadenas y los ponemos dentro de los controles de edición apropiados.
invoke UninstallHook
invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText
mov HookFlag,FALSE
invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL
invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL
invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL
Cuando el usuario presiona el botón Unhook, el programa llama a la función UninstallHook en la DLL de gancho. UninstallHook llama a UnhookWindowsHookEx. Después de eso, cambia el texto del botón una vez más a "Hook", HookFlag a FALSE y se limpia el contenido de los controles de edición.
Nota que el conmutador [switch] del enlazador en el makefile.
Link /SECTION:.bss,S /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS
Especifica a la sección .bss como una sección compartida para hacer que todos los procesos compartan la sección de datos no inicializados de la DLL de gancho. Sin este conmutador [switch], tu DLL de gancho no funcionará correctamente.