He aqui 'el como' funciona el tema del 'punto de entrada' desde harbour a una GUI grafica.
Siempre dicen que segundas partes nunca fueron buenas, pero....
¿ Tu que crees ?
En un mensaje en las news de Fivetech, news://news.fivetechsoft.comAntonio Linares, genio y creador de las librerias Fivewin, posteo, a un mensaje expuesta desde esta bitacora :
Normalmente cuando nos referimos al punto de entrada, nos podemos referir al
inicio de la aplicación. En una aplicación C estandard, sería main(), y en
una aplicación Windows sería WinMain().
Cuando hablamos de una aplicación xbase, se trata de cuando desde el nivel
de C se salta al nivel de PRG.
¿ En que circunstancias ocurre eso ?
En Windows, las ventanas solicitan un puntero a una función en C, que se
suele denominar "callback", que significa que es una función que será
llamada desde Windows, para notificarle de los distintos eventos que van
ocurriendo. Ahora bien, si Windows llama a ese punto de entrada en C, desde
ahí hemos de saltar a nivel PRG. En Harbour no hay problema en hacer eso ya
que todo su API es código abierto y se han publicado ejemplos al respecto.
En Linux ocurre exactamente igual. Por ejemplo la librería GTK+ tambien pide
determinados "callback"s a los que llamará, y desde esas funciones en C,
tambien tendremos que saltar a nivel PRG.
//---End...//
En mi contrareplica, mi argumentación fue más precisa , más que nada para saber si estaba o no equivocado, y de paso, que Antonio me corrigiera:
Gracias Antonio por tus respuesta, pero... ya estamos.. los ejemplos
de toda la teoria se echa en falta, y ya se que estas muy ocupado en
explicarnos, a los que posiblemente nunca llegaremos a tu nivel de
conocimientos,
aprovechare para que nos ilustres a todos.
> En una aplicación C estandard, sería main(), y en una aplicación Windows
sería WinMain().
Ok. Por lo que deduzco del codigo de harbour, veo que todo ocurre en ,
dependiendo
sobre que sistema a emplear, ocurre desde /harbour/source/main.c
Dicho fichero, simplemente seleccionara el punto de entrada en el cual
queramos
operar, y en este caso, para Windows, se haria uso de
/harbour/source/mainwin.c
en el cual , vemos como los parametros pasados a una aplicacion de harbour,
seran pasados a harbour a traves de hb_cmdargInit()
hb_cmdargInit( argc, argv );
acontinuacion, teoricamente, se pone en marcha la 'maquina virtual',
hb_vmInit( TRUE );
digamos que es ahi cuando salta a 'nuestra' Function Main() de Harbour,
( obviamente , teoricamente saltara al INIT Procedure, etc..., pero a
grandes rasgos )
Y por ultimo, la salida de la aplicacion , provoca la siguiente instruccion:
hb_vmQuit();
Si me equivoco , rectificame.
Ahora bien, siguiendo ese esquema, obtenemos, como bien dices:
Eso seria por cada sistema a implementar. Es decir, para GTK,
podemos inicializar como:
int main( ...)
if( gtk_init_check( ..) ) // Lo mismo que gtk_init() , pero devuelve si se
inicializo o no
hb_cmdargInit( argc, argv );
hb_vmInit( TRUE ); // Entramos ya en 'Harbour' Function Main()
hb_vmQuit();
else
{ fgprintf("Error de inicializacion") }
Esto, es lo que he estado buscando durante tanto tiempo, sin exito, hasta
hace 2 dias.
Pero... siempre esta el puto pero... a ser un sistema de eventos tipo
Win32/GTK+,
nos falta el decir como y donde tiene que saltar , una vez mas , desde C a
Harbour.
Claro esta, que todo esto en Fivewin/FiveLinux esta implementado, pero yo no
se como,
logico cada cual protege su inversion/producto como mas le apetezca, y ahi
es donde
estoy mosqueado, en el 'como'.
Lógicamente, hablare sobre Win32 pues es lo que mas conozco, por que
ciertamente
en GTK+ la cosa es distinta, pero ya se como implementarlo o al menos creo
saberlo. ;-)
Para poder entendernos y que nos entiendan, voy a tratar de 'averiguar' como
realiza Fivewin la magia,
en parte pues no tengo el codigo.
Bien, si os habeis fijado, en Fivewin todo control debe de ser registado, es
logico porque asi lo
requiere el api Win32.
Ahora bien, que pasa realmente cuando registramos un control, y es asi
cuando se lleva a cabo
el control de los eventos del sistema.
>En Windows, las ventanas solicitan un puntero a una función en C, que se
>suele denominar "callback", que significa que es una función que será
>llamada desde Windows, para notificarle de los distintos eventos que van
>ocurriendo
En el siguiente paso, nos vamos de la mano al C, donde se rellena una
estructura llamada WNDCLASS.
Dicha estructura se llena con los valores necesarios, MAS una cosa muy
importante en uno de sus miembros :
wndclass.lpfnWndProc = WndProc;
Lo que hace eso es decirle que funcion será la encargada de procesar los
mensajes para todas los controles
en base a esa clase de ventana.
Como bien has dicho antes, el puntero de la llamada a la funcion 'WndProc'
sera:
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
La cual nos informa la 'ventana' que a producido el evento, hWnd, que evento
se a producido , message, y
dos parametros mas.
Hasta aqui, creo que todo es correcto, pero aqui si que puede diferir en la
forma en que devolver dichos
parametros a Harbour, el famoso method HandleEvent() de Fivewin.
( Si me equivoco en algun punto, por favor, rectificarme... )
Lógicamente, de alguna manera debemos de informar a Harbour de lo que esta
ocurriendo, sino,
no serviria de mucho, porque si tenemos que gestionar los eventos desde C,
para que quiero el Harbour ? ;-)
Dentro de Wndproc, y he aqui lo que puede diferenciar a los diferentes GUI
es como tratar esto :
( Esto me lo enseño Jose Gimenez e Ignacio Ortiz , sobre una pregunta al
respecto )
PHB_DYNS pDynSym;
pDynSym = hb_dynsymFind( "HandleEvent" ); // Busca una funcion llamada
HandleEvent
hb_vmPushSymbol( pDynSym->pSymbol ); // Mete en la pila el simbolo a la
que me voy a ir
hb_vmPushNil();
hb_vmPushLong( ( LONG ) hWnd ); // mete el hWnd
hb_vmPushLong( message ); // el message
hb_vmPushLong( wParam ); //
hb_vmPushLong( lParam ); //
hb_vmDo( 4 ); // Llama a la funcion
HandeEvent en Harbour y le pasas los cuatros parametros
// No estoy seguro, pero creo que esta linea se ejecutara, cuando la func
HandleEvent retorne.
return DefWindowProc( ( HWND ) hWnd, message, wParam, lParam ); //
procesa todos los mensajes que no se tienen en cuenta
Básicamente, consiste en algo parecido.
Claro esta, que en harbour habria que crear un mecanismo de control para
determinar a traves del objeto:hWnd que sea igual
a hWnd, y saltar a su method HandleEvent. Vamos, vamos a ver nuestra
function HandleEvent de harbour:
// Imaginamos que todos los controles estan contenidos en una array llamado
aControls
Function HandleEvent( hWnd, nMsg, nParam1, nParam2 ) // Aqui vienen a parar
los mensajes de Windows
local nPos := AScan( aControls, { | oControl | oControl:hWnd == hWnd } )
local nReturn := 0
if nPos != 0 // Hey!! Se encontro
nReturn := aControl[ nPos ]:HandleEvent( nMsg, nParam1, nParam2 )
endif
Return nReturn
Veamos, veamos, si matamos la aplicacion, al final de todo llegara este
method, del objeto en cuestion,
con el mensaje VM_DESTROY
METHOD HandleEvent( nMsg, nParam1, nParam2 ) CLASS MICLASSE
do case
case nMsg == WM_DESTROY
? "Que nos morimos"
PostQuitMessage( 0 ) // Introduce en la cola de mensajes
"terminar", WM_QUIT, y termina ejecucion del programa.
return 0
endcase
return nil
Esto, que es una estupidez, si no te lo explican, creo que muy pocos de
aqui, son capaces por si mismo de haber
llegado a esta conclusion, o al menos entender 'el como se hace'.
Creo que no me equivocado mucho, si no, puedes corregirme en algo.
>En Harbour no hay problema en hacer eso ya que todo su API es código
abierto
>y se han publicado ejemplos al respecto.
Creo, que si estoy en lo cierto, mi explicacion es mejor para entender el
mecanismo, que cualquier
codigo fuente que halla, eso hablando de personas que no tenemos 'mucho'
nivel de conomientos.
Y si, estoy de acuerdo contigo, en que con el codigo fuente de ejemplos, hay
gente que a realizado sus GUIs,
gracias en parte a tu trabajo sobre harbour, pero dime.. ¿ Cuantos...? se
cuenta con los dedos de la mano,
y yo creo que eso solamente se debe a la ignorancia de la gente, aparte de
otros aspectos, claro esta. ;-)
// ---- End ------
A su vez , Antonio, me hizo una pequeña correción:
Totalmente correcta tu explicación. Tan sólo una observación: Solo se
llamará a DefWindowProc() cuando tu no proceses el evento desde PRG.
Asi que espero con estos explicaciones tengais ahora una mejor vision de lo que
ocurre dentro de todo tu codigo, aunque quizas no os sirva de nada a la practica, el simple hecho de tener el conocimiento de como suceden las cosas,
os haga un pelin mas y mejor informados.
Saludos.