PDA

Ver la Versión Completa : El Hook no funciona desde que actúo sobre otras aplicaciones


PedroElFlaky
06-09-2007, 12:39:01
Hola a todos, es la primera vez que me registro pero siempre leo el foro y me ha ayudado mucho, lo que me sucede es lo siguiente:

Tengo un hook global de teclado que escribe las teclas pulsadas en un memo (como los que he visto en este foro). Lo que sucede es que al ejecutar mi aplicación, funciona normalmente, si paso a otra ventana activa en la que no se puede usar el teclado y pulso una tecla, mi programa sigue funcionando normalmente, pero en cuanto escribo algo en otra aplicación de las que si reciben eventos del teclado (es decir un notepad por ejemplo, en el cual se puede escribir), entonces a partir de ese momento el sistema deja de notificar a mi dll de la pulsación de las teclas.

Espero que alguien pueda orientarme para saber qué clase de cosa es lo que estoy haciendo mal.

Saludos

dec
06-09-2007, 12:52:44
Hola,


Espero que alguien pueda orientarme para saber qué clase de cosa es lo que estoy haciendo mal.


Eso va a resultar complicado, puesto que no sabemos cómo lo estás haciendo. El asunto es que si no recuerdo mal lo que quieres conseguir es posible (de ahí los famosos "Keyloggers"), pero, sin saber cómo tratas de hacerlo tú (sin conocer el código fuente que empleas) es complicado decirte qué estás haciendo mal, si es que estás haciendo algo mal, vaya.

PedroElFlaky
07-09-2007, 05:12:36
Tengo una aplicación y una dll.
Al crear la aplicación cargo la dll, le envío el handle de la aplicación con pasar_handle_a_dll () y llamo a HookOn() y al cerrarla, llamo a HookOff() y libero la dll. En la aplicación, recibo mensajes de la dll con las teclas pulsadas y las paso al memo. Puse una variable global en la dll en la que ponía la última tecla detectada, para así desde la aplicación acceder a esta variable y así pude comprobar, que cuando mi programa deja de detectar teclas, no es porque no reciba mensajes de la dll sino porque en la dll se dejan de detectar las teclas. Así que el problema debe de estar en la dll.

Lo que tengo en la dll es:

library ProjectDll; uses Windows; uses Messages; const MSG_TECLA_DOWNUP = WM_USER + $1; var MiHook : HHook; ApliHandle : THandle; ApliHandle^ : THandle; function CallBackDeMiHook ( Code : Integer; wParam : WPARAM; lParam : LPARAM ) : LRESULT; stdcall; begin {Si una tecla fue pulsada o liberada} if code=HC_ACTION then PostMessage(ApliHandle, MSG_TECLA_DOWNUP, wParam, lParam); Result := CallNextHookEx(MiHook, Code, wParam, lParam) end; procedure HookOn; stdcall; {Procedure que instala el hook} begin MiHook:=SetWindowsHookEx(WH_KEYBOARD, @ CallBackDeMiHook, HInstance, 0); end; procedure HookOff; stdcall; begin {procedure para desinstalar el hook} UnhookWindowsHookEx(MiHook); end; procedure pasar_handle_a_dll (phandle : THandle^); stdcall; begin pApliHandle = phandle; ApliHandle = *pApliHandle; end; exports{Exportamos los procedures} HookOn, HookOff, pasar_handle_a_dll; Bueno, pues eso el lo tengo, Saludos

PedroElFlaky
07-09-2007, 05:13:42
Tengo una aplicación y una dll.
Al crear la aplicación cargo la dll, le envío el handle de la aplicación con pasar_handle_a_dll () y llamo a HookOn() y al cerrarla, llamo a HookOff() y libero la dll. En la aplicación, recibo mensajes de la dll con las teclas pulsadas y las paso al memo. Puse una variable global en la dll en la que ponía la última tecla detectada, para así desde la aplicación acceder a esta variable y así pude comprobar, que cuando mi programa deja de detectar teclas, no es porque no reciba mensajes de la dll sino porque en la dll se dejan de detectar las teclas. Así que el problema debe de estar en la dll.

Lo que tengo en la dll es:


library ProjectDll;


uses Windows;
uses Messages;

const
MSG_TECLA_DOWNUP = WM_USER + $1;

var
MiHook : HHook;
ApliHandle : THandle;
ApliHandle^ : THandle;


function CallBackDeMiHook ( Code : Integer;
wParam : WPARAM;
lParam : LPARAM
) : LRESULT; stdcall;
begin
{Si una tecla fue pulsada o liberada}
if code=HC_ACTION then
PostMessage(ApliHandle, MSG_TECLA_DOWNUP, wParam, lParam);

Result := CallNextHookEx(MiHook, Code, wParam, lParam)
end;


procedure HookOn; stdcall;
{Procedure que instala el hook}
begin
MiHook:=SetWindowsHookEx(WH_KEYBOARD, @ CallBackDeMiHook, HInstance, 0);
end;


procedure HookOff; stdcall;
begin
{procedure para desinstalar el hook}
UnhookWindowsHookEx(MiHook);
end;


procedure pasar_handle_a_dll (phandle : THandle^); stdcall;
begin
pApliHandle = phandle;
ApliHandle = *pApliHandle;
end;


exports
{Exportamos los procedures}
HookOn,
HookOff,
pasar_handle_a_dll;



Bueno, pues eso el lo tengo,

Saludos

PedroElFlaky
07-09-2007, 05:15:59
He intentado poner mi post de las 2 formas y no sé cuál es peor, no sé como hacer para que el código no salga en una sola línea.

seoane
07-09-2007, 13:34:40
Hola Pedro,

el problema es el siguiente. Cada vez que te cambias de apliacion, windows inyecta tu dll en el nuevo proceso, despues de la inyeccion las variables de la dll no contienen lo mismo que en la dll que esta cargada en tu proceso. Es decir, cada proceso va a tener su propia instancia de la dll.

Con el procedure pasar_handle_a_dll solo le estas dando el valor correcto a la variable ApliHandle que pertenece a la instancia de la dll que tiene cargada tu proceso. Para los demas procesos esa variable sigue sin inicializar.

Una vez localizado el problema tenemos dos prosibles soluciones. Las mas sencilla, si solo quieres capturar las pulsaciones de teclado, es utilizar un hook del tipo WH_KEYBOARD_LL en vez WH_KEYBOARD, estos no necesitan estar implementados en una dll y es el propio windows el que se encarga de hacer los cambios de contexto. La otra solucion es mapear las variables en la memoria global, de forma que puedan ser leidas desde cualquier proceso.

Ejemplo de la primera solución:
http://romansg.net/index.php?pg=hooks

La segunda solución no te la aconsejo a menos que necesites inyectarte en otro proceso por algún motivo en especial ;)

PedroElFlaky
09-09-2007, 08:45:41
Hola de nuevo,

lo primero aclarar que si me gustaría inyectarme en todos los procesos y capturar las teclas de todos lo procesos, y tal vez más adelante, cuando tenga todo esto claro y funcione, probar con otros tipos de hooks

he quitado lo de pasar_handle_a_dll() y en lugar de ello, es la propia dll la que obtiene el handle de la ventana de mi aplicación con FindWindow() cada vez que se llama a CallBackDeMiHook(), es decir que donde antes tenía

PostMessage(ApliHandle, MSG_TECLA_DOWNUP, wParam, lParam);

ahora tengo

WindowApliHandle = FindWindow(0, "ApliHook");
PostMessage(WindowApliHandle, MSG_TECLA_DOWNUP, wParam, lParam);

Aun así mi programa se sigue comportando igual que antes, es decir que no solo no detecta las pulsaciones en las otras aplicaciones, sino que después de haber usado el teclado en las otras ya no detecta las pulsaciones en la mía.

Entonces tengo las siguientes dudas:
-si las variables globales son una copia diferente para cada aplicación que llama a mi dll, no estaría también la variable "MiHook" sin inicializar?
-al pasar de una aplicación a otra, las variables globales de la dll para mi aplicación, se resetean o cuando vuelva a mi aplicación conservarán su valor?

PedroElFlaky
09-09-2007, 10:01:40
Hola,

he descubierto lo que me sucede pero no sé cómo hacerlo bien,
mi programa se comporta como si el código de la dll lo hubiera implementado en una aplicación normal y no en una dll de las que es necesario para este tipo de hooks. Y creo que se está compilando la dll dentro del ejecutable de la aplicación.
Podrías decirme exactamente como se hace.

Lo que yo hice es lo siguiente:
Primero creé un proyecto para la dll, luego en otra carpeta cree el proyecto para la aplicación y luego puse los ficheros de ambos en la misma carpeta.
Estoy usando "declspec(dllexport)" en la dll para exportar HookOn y HookOff y en la aplicación estoy usando "declspec(dllimport)" para importarlas, además tengo en el proyecto de la aplicación el archivo con el código de la dll porque si no lo ponía me salía un error por usar "declspec(dllimport)".

Saludos

seoane
09-09-2007, 15:07:08
-si las variables globales son una copia diferente para cada aplicación que llama a mi dll, no estaría también la variable "MiHook" sin inicializar?

Exacto, la variable MiHook también estaría sin inicializar


-al pasar de una aplicación a otra, las variables globales de la dll para mi aplicación, se resetean o cuando vuelva a mi aplicación conservarán su valor?

Cuando se vuelve a tu aplicación, la variables conservan su valor.

Veo que has desechado la idea de WH_KEYBOARD_LL, este hook captura las teclas de todos los procesos, solo que es mas fácil de implementar. Pero si lo quieres hacer por las malas no te queda mas que mapear las variables en memoria, hay varios ejemplos en el foro y fuera de el, pero ahora mismo solo encuentro este que puede orientarte:
http://www.clubdelphi.com/foros/showthread.php?t=37902

PedroElFlaky
10-09-2007, 12:22:07
Hola a todos,

comento los progresos y las dudas que me corroen:

La dll ya no deja de funcionar al cambiar la otra aplicación, por una parte quité lo de pasar_handle_a_dll() y por otra parte como lo comenté en otro post, importaba mal la dll y lo que hacía era incluir el código en mi aplicación y compilarlo dentro de ella, ahora lo hago bien y el programa y la dll van bastante bien.

Pero me gustaría muchísimo entender lo siguiente:
-probé lo de usar memoria global mapeada en donde almaceno el handle de la ventana de mi aplicación, y también probé a usar FindWindow(), lo primero funciona perfecto pero no entiendo por qué lo segundo solo envía mensajes a mi aplicación cuando no está minimizada

-comprobé que efectivamente para las demás aplicaciones MiHook está sin inicializar, pero aun así funciona bien, y de hecho en la mayoría de ejemplos que he visto, está como hago yo que se inicializa MiHook al llamar a HookOn() y por tanto solo se hace una vez al llamarla desde mi aplicación

PedroElFlaky
11-09-2007, 11:39:32
Hola,

ya me puedo responder a las 2 cuestiones que me planteé:

-la respuesta a lo primero es que FindWindow() si funciona y es bastante más fácil de usar que el mapeo de memoria, qué opinais?, no me funcionaba al principio a mi porque tenía mi programa en un directorio con el mismo nombre y los mensajes se enviaban al directorio en lugar de enviarse a mi programa

-la respuesta a lo segundo es que como para instalar y desinstalar, MiHook si está inicializado, entonces va bien, y en el único lugar que uso MiHook sin inicializar es en Result := CallNextHookEx(MiHook, Code, wParam, lParam), pues comprobé que funciona perfectamente (y no sé por qué), si en lugar de eso pongo Result := CallNextHookEx(0, Code, wParam, lParam)

Saludos