Ir al contenido principal

WinDbg Breakpoint on key pressed

Imaginad por un momento que os surge la necesidad de detener la ejecución de un programa cuando se pulsa una determinada tecla o combinación de estas, en fin, algo normal que a cualquier persona se le puede pasar por la imaginación, ¿o no?. Bromas aparte, para conseguirlo podemos utilizar infinidad de técnicas y en esta ocasión voy a comentaros la última que he empleado yo en uno de los trabajos que estoy realizando actualmente.

Esta técnica consiste en colocar un punto de ruptura en la llamada a la API TranslateAccelerator. Ahora bien, debemos tener en cuenta que si colocamos un breakpoint de ejecución sin más, el debugger estará constantemente saltando y no podremos conseguir nuestro objetivo o, cuando menos, será muy desesperante.

Para evitar tal situación, lo que tenemos que hacer es utilizar un breakpoint condicional para indicarle al debugger que se detenga solamente cuando se cumple una determinada condición o condiciones y por consiguiente que continúe con la ejecución normal del programa en el resto de los casos.

A modo de ejemplo y haciendo uso de uno de los depuradores que más me gusta (sí el depurador de Microsoft), vamos a detener la ejecución del programa cuando se pulse la tecla INTRO. Para esto, es preciso conocer tanto el prototipo de la API TranslateAccelerator que podéis ver a continuación:

int WINAPI TranslateAccelerator(
  _In_  HWND hWnd,
  _In_  HACCEL hAccTable,
  _In_  LPMSG lpMsg
);


como las estructuras de datos involucradas, ya que, si os fijáis el tercer parámetro de la API es un puntero a la estructura MSG. En este caso la principal estructura que debemos conocer es MSG, ya que necesitaremos hacer buen uso de algunos de sus miembros:

typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
} MSG, *PMSG, *LPMSG;


Llegados a este punto, ya conocemos bien a nuestro objetivo y cómo podemos "jugar" con él. Ahora tan solo falta saber cómo le decimos al depurador que utilice toda esta información. Aunque puede hacerse de varias formas, la técnica que expongo aquí es mediante el uso del evaluador de expresiones al estilo C++ que incorpora el debugger.

Si observamos la estructura MSG, enseguida nos damos cuenta de que hay varias cosas muy útiles para conseguir nuestro objetivo. Dado que queremos detener la ejecución del programa al pulsar una tecla, será preciso acceder al miembro 'message' de MSG.

En concreto el mensaje que vamos a capturar será WM_KEYDOWN cuyo valor constante equivalente en hexadecimal es el 0x0100. Además, como no queremos que se detenga la ejecución al pulsar cualquier tecla, sino solamente la tecla ENTER, también tendremos que utilizar el miembro 'wParam' que nos indicará cual es la tecla (VK_KEY) que se ha pulsado. En este caso para la tecla ENTER el valor que deberá contener 'wParam' será 0x0D (ya sabéis el número de la suerte).

Bueno, pues ahora sí que tenemos a nuestro alcance todo lo que necesitamos, así que, manos a la obra. Vamos a indicarle al debugger cual será nuestro maravilloso breakpoint:

bp 003814ac "j @@c++((((ole32!MSG *)@eax)->message == 0x0100) && (((ole32!MSG *)@eax)->wParam == 0x0D)) ''; 'gc'"

Como digo, hay muchas maneras de conseguir esto mismo, pero para mi caso concreto, esta era la más efectiva. La expresión habla más o menos por si sola, no obstante si tenéis alguna duda, sentiros libres de comentarlo.

¡Suerte y feliz debugging!

Comentarios

  1. 003814ac es el offset del textbox/objeto, el handler de la ventana el entry point de la aplicación, o...? Gracias.

    ResponderEliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Como usar el TL431 (muy facil)

En este artículo, no vamos a entrar en el funcionamiento interno de este IC, ni tampoco en sus características técnicas, puesto que para esos fines ya existe su hoja de datos correspondiente. Más bien, lo que pretendo aquí es dejar constancia de como podemos utilizar este IC desde un punto de vista práctico, útil y sobre todo de una manera sencilla, con el objetivo de que cualquiera pueda utilizarlo. Si has llegado hasta aquí, probablemente ya sabes que por internet hay mucha información sobre este IC, pero también bastante confusa o excesivamente técnica, sin mostrar tan siquiera un ejemplo de funcionamiento, o como calcular sus pasivos. Pues se acabó, a partir de hoy y después de leer este post, ya te quedará claro como utilizar el TL431 para obtener una tensión de referencia estable y precisa. Vamos al grano y que mejor que empezar aclarando que el TL431 NO ES EXACTAMENTE UN ZENER como se empeñan en decir en muchos sitios, es verdad que se le conoce como el Zener Progra

WinRT with C++ Standard vs C++/CX

OFFTOPIC: Nota: Hoy he decidido escribir esta publicación del blog en inglés. Note: Today I decided to write this blog post in English. In a new application than I am developing for a company, I had to decide if to make use of C++/CX (C++ with Component Extension) or make all the main stuff in C++ standard and ABI/COM. All of you than have had to work with COM (Component Object Model) and fighting with the interfaces, reference count, etc. known the tricky and heavy that it can become. As an example of the easy approach using C++/CX, I am creating a new Uri object, like this: auto uriEasyWay = ref new Windows::Foundation:: Uri ( http://www.manuelvillasur.com ); assert (wcscmp(uriEasyWay->AbsoluteUri->Data(), L"http://www.manuelvillasur.com/" ) == 0); Now, I going to show you the more difficult approach using C++ Standard and  ABI/COM interfaces: HSTRING_HEADER header = {}; HSTRING string = nullptr ; HRESULT hr = WindowsCreateStringRefer

Árbol binario de expresión y Notación Posfija (II)

En una publicación anterior, hablaba sobre que es la notación posfija, para que puede ser útil y mostraba un pequeño ejemplo con una expresión aritmética simple: (9 - (5 + 2)) * 3 Pues bien, hoy voy a mostraros como podemos crear el árbol binario correspondiente para analizar o evaluar esta expresión, haciendo uso del recorrido en postorden. Lo primero que debemos hacer es crear el árbol, respetando las siguientes reglas: ⦁ Los nodos con hijos (padres) representarán los operadores de la expresión. ⦁ Las hojas (terminales sin hijos) representarán los operandos. ⦁ Los paréntesis generan sub-árboles. A continuación podemos ver cómo queda el árbol para la expresión del ejemplo (9 - (5 + 2)) * 3: Si queremos obtener la notación postfija a partir de este árbol de expresión, debemos recorrerlo en postorden (nodo izquierdo – nodo derecho – nodo central), obteniendo la expresión: 952+-3x Así, si quisiéramos evaluar la expresión, podemos hacer uso de un algoritmo