O.T.: Cómo capturar objetos individuales

Post Reply
User avatar
Rafael Clemente
Posts: 365
Joined: Sat Oct 08, 2005 7:59 pm
Location: Barcelona, Spain

O.T.: Cómo capturar objetos individuales

Post by Rafael Clemente »

Un amigo me enseñó una versión antigua del PaintShop 4 (versión de 1997...) Este programa tiene una interesante función de captura de objetos, es decir, permite "recortar" y guardar como imagen los objetos de otra aplicación. Es especialmente útil para hacer manuales o helps, ya que permite capturar imágenes de botones, listboxes, e incluso says y gets.

Lo curioso es que la identificación del objeto es automática e inmediata. Basta con poner el cursor sobre él. El Paint Shop lo identifica como un objeto y lo marca con un recuadro negro. Pulsa una tecla de función y su imagen queda capturada en el formato que deses...

Mi pregunta es: ¿Alguien sabe cómo implem
entar algo semejante desde FWH? Quiero decir, lo de que un prorgama de FWH sea capaz de identificar y "recortar" los controles que componen otra aplicación. Hasta ahora conseguido capturar como BMPs pantallas enteras y ventanas de otras aplicaciones. Eso no es problema. Lo que no sé por dónde empezar es lo de identificar los controls individuales, en especial, Says y Gets

¿Alguna sugerencia?

Rafael
User avatar
Paco Garcia
Posts: 172
Joined: Fri Oct 07, 2005 12:00 pm
Contact:

Post by Paco Garcia »

¡¡ compañero !!!

ahi va:

Code: Select all


      pt := GetCursorPos()
      hWnd := ::SmallestWindowFromPoint( pt )

/*****************************************************************************************/
  METHOD SmallestWindowFromPoint( point ) CLASS TSpy
/*****************************************************************************************/
	local rect, rcTemp
	local hParent, hWnd, hTemp

	hWnd := WindowFromPoint( point[2], point[1] )
	if hWnd != 0

		rect := GetWndRect( hWnd )
		hParent := GetParent( hWnd )

		// Has window a parent?
		if hParent != 0

			// Search down the Z-Order
			hTemp := hWnd
			do while .t.

				hTemp  := GetWindow( hTemp, GW_HWNDNEXT )

				// Search window contains the point, hase the same parent, and is visible?
				rcTemp := GetWndRect( hTemp )
				if PtInRect( point[1],point[2], rcTemp  ) .and. GetParent(hTemp) == hParent .and. IsWindowVisible(hTemp)

					// Is it smaller?
					if (rcTemp[4] - rcTemp[2]) * (rcTemp[3] - rcTemp[1]) < ((rect[4] - rect[2]) * (rect[3] - rect[1]))
						// Found new smaller window!
						hWnd := hTemp
						rect := GetWndRect(hWnd)
					endif
				endif
				if hTemp == 0
				   exit
				endif
			enddo
		endif
	endif

	return hWnd
Ya sabes, estoy de guardia :lol: :D :D

Parte es de mi cosecha y parte del Google.

Un saludo
User avatar
Rafael Clemente
Posts: 365
Joined: Sat Oct 08, 2005 7:59 pm
Location: Barcelona, Spain

Post by Rafael Clemente »

Paco:
Es fantástico esto de tener un informático de guardia!!!! :D
Me lo estudio y te digo algo.
10E6 de gracias!!!
Rafael
User avatar
Rafael Clemente
Posts: 365
Joined: Sat Oct 08, 2005 7:59 pm
Location: Barcelona, Spain

Post by Rafael Clemente »

Paco:
Lo acabo de probar a fondo. FORMIDABLE!!! Es exactamente lo que yo buscaba. Y pensar que he gastado un montón de horas en pruebas inútiles...
Muchas gracias otra vez.
Rafael
User avatar
Paco Garcia
Posts: 172
Joined: Fri Oct 07, 2005 12:00 pm
Contact:

Post by Paco Garcia »

Ya, yo tambien lo habia buscado exactamente igual y lo solucione hace ya una temporada larga. Por si te interesa se puede hacer muchas cosas con esto, por ejemplo:

- inspeccionar las propiedades de los controles, ventanas, dialogos etc a nivel de API.
- Mandar mensajes a una ventana que los recogera y procesará de la forma que le programes.
- sacar fotos, por supuesto
y un monton de cosas mas

En cuanto al efecto de rectángulo negro, usa el truco de una ventana estilo WS_POPUP que ocupe toda la pantalla y con la brocha NULL. De esta forma puedes pintar lo que quieras "sobre las ventanas" a base de obtener el hDC de la ventana transparente.

Un saludo

Paco (PDG)

:)
User avatar
Rafael Clemente
Posts: 365
Joined: Sat Oct 08, 2005 7:59 pm
Location: Barcelona, Spain

Post by Rafael Clemente »

Paco:
Una última pregunta para dar el tema por cerrado (de momento... :wink: ).

Ya tengo tu receta funcionando. Puede capturar sin problemas los handles de los controles que componen otra aplicación. Con GetWindowText(hWnd) en un Say puedo leer el texto del Say; en un checkbox, puedo leer su prompt... ¿Hay alguna forma de leer el contenido de un Get? ¿Y de una casilla de un browse?
Saludos,

Rafael
User avatar
Paco Garcia
Posts: 172
Joined: Fri Oct 07, 2005 12:00 pm
Contact:

Post by Paco Garcia »

Hola

Que yo sepa sin mas, no. Lo que si que puedes hacer es preparar tus programas para que sean capaces de interpretar mensajes especiales que tu envies y en función de eso establecer un protocolo de comunicación entre dos aplicaciones. Por ejemplo con WM_COPYDATA.

Con este ejemplo puedes enviar y recibir datos de una aplicación a otra:

Code: Select all

#include "FIVEWIN.CH"


static oWnd
#define WM_COPYDATA                74



function MAIN()


   LOCAL oBtn, oBtn2, oGet, nVar1 := 1
   LOCAL oGet2, nVar2 := 1
   LOCAL oGet3, cVar := "Pulsa el boton Send y busca un alert"

   DEFINE WINDOW oWnd TITLE "Prueba WM_COPYDATA"

         @  10, 10 GET    oGet  VAR nVar1 SIZE 50, 18 PIXEL OF oWnd
         @  30, 10 GET    oGet2 VAR nVar2 SIZE 50, 18 PIXEL OF oWnd
         @  50, 10 GET    oGet3 VAR cVar SIZE 250, 18 PIXEL OF oWnd
         @  80, 10 BUTTON oBtn  PROMPT "Send" SIZE 50, 24 PIXEL OF oWnd ACTION SendInfo( nVar1, nVar2, cVar )
         @ 110, 10 BUTTON oBtn2 PROMPT "Fin" SIZE 50, 24 PIXEL OF oWnd ACTION oWnd:End()


   ACTIVATE WINDOW oWnd

RETURN nil


function SendInfo( nVar, nVar2, cVar )
local hWnd := FindWindow(0,"Escuchando" )
// BUSCAS EL HANDLE DE LA VENTANA CON EL NOMBRE

DEFAULT nVar  := 1
DEFAULT nVar2 := 1
DEFAULT cVar  := ""


if hWnd != 0
   if cVar == ""
      Enviar( oWnd:hWnd, hWnd, 101, nVar, nVar2, cVar )
   else
      Enviar( oWnd:hWnd, hWnd, 100, nVar, nVar2, cVar )
   endif
else
   MsgInfo( "No encontre la ventana" )
endif

return nil


#pragma BEGINDUMP
#include "windows.h"
#include "hbapi.h"

// AQUI TE CREAS LA ESTRUCTURA QUE QUIERAS CON LOS DATOS QUE QUIERAS PASAR
typedef struct tagMYREC
{
   HWND hWndOrigen;
   char  s1[250];
   int   nFila;
   int   nColumna;
} MYREC;




HB_FUNC( ENVIAR )
{
   HWND hWndOrigen = ( HWND ) hb_parnl( 1 );
   HWND hWndDestino = ( HWND ) hb_parnl( 2 );
   int nMsg = hb_parni( 3 ); // <<< IDENTIFICADOR DEL MENSAJE PARA QUE DESDE
                             // LA VENTANA DESTINO DECIDAS LO QUE HACER EN ESTE CASO
   COPYDATASTRUCT MyCDS;
   MYREC MyRec;

   // AQUI LE DAS VALOR A LOS DATOS DE LA ESTRUCTURA
   MyRec.hWndOrigen = hWndOrigen;
   MyRec.nFila = hb_parni( 4 );
   MyRec.nColumna = hb_parni( 5 );
   strcpy( MyRec.s1, hb_parc( 6 ) );

//
// Fill the COPYDATA structure
//
   MyCDS.dwData = nMsg;
   MyCDS.cbData = sizeof( MyRec );  // size of data
   MyCDS.lpData = &MyRec;

   // SE LO ENVIAS A LA VENTANA DESTINO SIEMPRE DE ESTA FORMA
   SendMessage( hWndDestino, WM_COPYDATA,(WPARAM)(HWND) hWndOrigen,(LPARAM) (LPVOID) &MyCDS );
   hb_ret();
}

HB_FUNC( RECIBIR )
{
   PCOPYDATASTRUCT pMyCDS;
   pMyCDS = (PCOPYDATASTRUCT) hb_parnl( 1 );

   // RECIBES LOS DATOS Y LOS DEVUELVES AL HANDLEEVENT DE LA VENTANA
   // SI QUIERES QUE LA COMUNICACIÓN SEA EN LOS DOS SENTIDOS
   // TENDRIAS QUE TENER AQUI TAMBIEN EL HANDLEEVENT REDEFINIDO

   hb_reta( 5 );
   hb_stornl( (long)((MYREC *)(pMyCDS->lpData))->hWndOrigen, -1, 1 );
   hb_storni( pMyCDS->dwData, -1, 2 );
   hb_storni( ((MYREC *)(pMyCDS->lpData))->nFila, -1, 3 );
   hb_storni( ((MYREC *)(pMyCDS->lpData))->nColumna, -1, 4 );
   hb_storc ( ((MYREC *)(pMyCDS->lpData))->s1, -1, 5 );

}

HB_FUNC( REGISTERWINDOWMESSAGE )
{
     hb_retni( RegisterWindowMessage( ( LPCTSTR ) hb_parc(1)));
}

#pragma ENDDUMP


Luego con la función RegisterWindowMessage puedes registrar un mensaje en cada aplicación a nivel de Windows, asegurandote de que ese mensaje será único en windows.

Luego en el HandleEvent de la ventana o del control capturas ese mensaje y estableces la comunicación entre la aplicación que escucha y la aplicación que espia.

    nMensaje := RegisterWindowMessage( "WM_MIMENSAJE" )

En HandleEvent tendrías que preguntar por if nMsg == nMensaje ...

Un saludo



User avatar
Rafael Clemente
Posts: 365
Joined: Sat Oct 08, 2005 7:59 pm
Location: Barcelona, Spain

Post by Rafael Clemente »

Paco:
Me estudiaré tu ejemplo pero me temo que ya empieza a superar mis habilidades. Además, lo que estaba intentando conseguir era leer una aplicación que no era mía (por ejemplo, una Contabilidad comercial) así que difícilmente la podré preparar para que responda a mis mensajes.
Buscaré otro camino. De todas formas, gracias por tu ayuda. Hasta la próxima, un saludo,

Rafael
Post Reply