SQLExpress - Xb2.NET     ot4xb  
xfree.public
ot4xb
Thread Starter: Osvaldo Ramirez Started: 6/6/2008 5:24 PM UTC
Replies: 1
ot4xb
Hello guys

#include "ot4xb.ch"
#include "Appevent.ch"
// ---------------------------------------------------------------------------
#define WM_NCHITTEST        0x0084
#define WM_MOVING           0x0216
#define WM_DESTROY          0x0002
// ---------------------------------------------------------------------------
proc main()
local nEvent,oSle,mp1 := NIL,mp2 := NIL, oXbp := NIL

   SETCOLOR( "N/W" )
   CLS
   ?? "Try to Drag & drop the GET"
   oSle:= DragableGet():new()
   oSle:tabStop := .T.
   oSle:create( , , {230,192}, {140,24} )
   SetAppfocus( oSle )

   nEvent := 0
   while nEvent != xbeP_Close
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
      oXbp:HandleEvent( nEvent, mp1, mp2 )
   end
return
// ---------------------------------------------------------------------------
CLASS DragableGet FROM XbpSLE
EXPORTED:
       // --------------------------------------------------------------------
INLINE METHOD WndProc(hWnd,nMsg,wp,lp)
       if( nMsg == WM_NCHITTEST )
          @user32:SetFocus(hWnd)
          return 2
       elseif( nMsg == WM_MOVING )
          ::Moving( lp )
          return 1
       end
       return NIL
       // --------------------------------------------------------------------
INLINE METHOD Create( oParent, oOwner, aPos, aSize, aPP, lVisible )
       ::xbpSLE:create( oParent, oOwner, aPos, aSize, aPP, lVisible )
       ot4xb_SubclassWindow( ::GetHWnd() , Self , WM_DESTROY)
       return Self
       // --------------------------------------------------------------------
INLINE METHOD Moving(pRect)
       local aRect := iif( Empty(pRect) , NIL , PeekDWord(pRect,0,4) )
       if( aRect != NIL )
          @user32:MapWindowPoints(0, ::SetParent():GetHWND() , @aRect , 2)
          DispOutAt(0,35, "L:" + StrZero(aRect[1],5) +;
                        ", T:" + StrZero(aRect[2],5) +;
                        ", R:" + StrZero(aRect[3],5) +;
                        ", B:" + StrZero(aRect[4],5) )
       end
       return NIL
       // --------------------------------------------------------------------
ENDCLASS


Question ...

To make an xbp that recive any event of the OS, do I need to make a subclassing ? ( ot4xb_SubclassWindow( ::GetHWnd() , Self , WM_DESTROY)

So then, this function call automaticly the WndProc(hWnd,nMsg,wp,lp)
where in this place I can trap any events of the OS ... Is it right ?



---------------------------------


Solo para confirmar

Para hacer que un xbp reciva eventos del OS, necesito hacer dicho xbp un subclassing () ?
Y este automaticamente llama la funcion wndproc ? en donde ahi atrapamos todos los eventos de windows ? Es correcto.

Entonces si quiero poner algo asi como ot4xb_SubclassWindow( oDlgVentanPrincipal ) , Self , WM_DESTROY)

Ahi puedo atrapar todos los eventos de windows hasta el cntrl-alt-delete ?

Saludos
Osvaldo Ramirez
Re: ot4xb
Hi Osvaldo,

First you need to understand the xbp event mechanism:

When the system call to the xbp wndproc (always in the GUI thread)
the wndproc do what they need to do and only for a subset of messages
post an xb event to the xbp thread and return inmediatelly ignoring the return value of the xb event.  

This is not bad at all, as allow to have multiple worker threads in a easy way, but have some limitations.
The first limitation is that the xb events are handling asyncronously so you can not control the behavior of the system based on the result of your event processing. And the second limitation is that not all the messages that your xbp wndproc receive will be reflected as xb events in the user thread.

Every window have a pointer to a wndproc that will process the received messages in the thread where the window has been created. All xbp windows will be created in the GUI thread so all windows messages will be procesed in that thread, and xb events will be posted to the thread where the user was called to the method oXbp:Create()  

WndProc subclassing is a common way to add custom functionality to existing windows and controls, and consist in save the previous wndproc and replace for a new one. The new wndproc will add some code for certain messages and return a value to the system or delegate the control to the old wndprocedure. Finally before destroy the control will restore the old wndproc.

To make an xbp that recive any event of the OS, do I need to make a subclassing ?
Subclassing a xbp window you can handle any message that reach to your xbp wndproc. But the message must be reach your wndproc

So then, this function call automaticly the WndProc(hWnd,nMsg,wp,lp)
where in this place I can trap any events of the OS ... Is it right ?
Not always, as I was told you before, because not all messages will reach your window.

For this task there is a function in user32.dll  called SetWindowsHookEx() that allow you to trap any messages in a specific thread or also in all threads of the same desktop.

You can use SetWindowsHookEx() using ot4xb and the xppcbk.exe callback compiler, only for threads that have been initialized from Xbase++ , but for all threads in the desktop ( as required if you want to trap ctrl+alt+del) you will need to provide a hook function writed in C.

Regards,
Pablo Botella

---------------------------------------------

Lo primero necesitas conocer un poco como funcionan los eventos de los xbp:

Cuando el sistema llama al procedimiento de ventana de un xbp (siempre en el GUI thread)
el procedimiento de la ventana hace lo que necesite y en algunos casos envia un evento xbase al thread que creo el objeto xbp y retorna inmediatamente ignorando la posible respuesta al evento xbase

La verdad es que la tecnica no es mala del todo, nos permite separar el trabajo en diferentes threads de una manera fácil, per claro tiene sus limitaciones.

La primera limitación es que los eventos se procesan en modo asíncrono asi que no podemos modificar el comportamiento de nuestro control devolviendo un valor al sistema.

La segunda limitación es que no todos los mensajes que el sistema envia a nuestra ventana se ven reflejados por un evento xbase en nuestro thread de usuario.

Todas las ventanas almacenan un puntero a su procedimiento de ventana que es el va a procesar todos los mensajes que recibe la ventana en el mismo hilo en que se creo la ventana. Todos los xbps crean su ventana en el GUI thread, no importa en que thread hallamos creado el objeto sin embargo los eventos xbase si se recibirán en el thread donde hallamos llamado al método oXbp:Create()  

Subclasear el procedimiento de ventana es una técnica muy corriente para añadir funcionalidad a ventanas y controles que ya existan  y consiste en guardar el puntero al procedimiento de ventana actual y cambiarlo por uno nuevo. El procedimiento de ventana añadirá codigo para algunos eventos y devolverá el control al sistema o al procedimiento antiguo si quiere reutilizar parte del comportamiento. Finalmente antes de que se destruya la ventana restaurará el procedimiento de ventana antiguo.

Para hacer que un xbp reciva eventos del OS, necesito hacer dicho xbp un subclassing () ?
Subclaseando una ventana xbp conseguiremos procesar cualquier mensaje que llegue a nuestro procedimiento de ventana,
pero claro a veces no llegan :-)

Entonces si quiero poner algo asi como ot4xb_SubclassWindow( oDlgVentanPrincipal ) , Self , WM_DESTROY)
Ahi puedo atrapar todos los eventos de windows hasta el cntrl-alt-delete ?

Pues como te he dicho antes, no siempre, porque no todos los mensajes van allegar al wndproc de tu ventana.

Para esto tenemos una función en user32.dll que se llama SetWindowsHookEx() y nos permite atrapar cualquier mensaje de un thread específico o incluso de cualquier thread en el mismo escritorio.

Puedes usar SetWindowsHookEx() junto con ot4xb y mi compilador de callbacks, pero solo para los hilos que haya creado Xbase++ , porque solo puedes ejecutar una funcion de Xbase++ si el hilo lo ha creado él.

Sin embargo para atrapar mensajes de cualquier thread en el mismo escritorio (como nos haría falta para atrapar el ctrl+alt+del) necesitamos pasarle una función en C