Desarrollo y Depuración de Servidores
COM con VFP
http://www.theproblemsolver.nl/ source.zip
Desde la salida de Visual FoxPro versión 5 podemos construir
Servidores COM. Esto ha creado un nuevo rango de posibilidades a Visual FoxPro
y da a los desarrolladores de VFP un nuevo campo para crear soluciones. Sin
embargo, los servidores COM tienen sus dificultades y problemas a la hora de
desarrollarlos.
El principal problema viene del hecho de que el
desarrollador de Servidores COM tiene que escribir el código, compilarlo en un
.EXE ó .DLL y ejecutar le programa cliente para probarlo. Esto significa que uno siempre ejecuta
código que está compilado y bajo el control de VFP. No hay forma de usar el
depurador o inspeccionar el valor de las variables usadas. Si se produce un bug
de algún tipo en el código fuente del servidor COM la prueba fallaría o se entregaría
un código de error a la aplicación cliente. Siempre que esto suceda el
desarrollador tiene que cambiar el fuente del servidor COM, recompilarlo y
ejecutar el cliente de nuevo.

Figura 1: Fallo en un Servidor COM con una ventanita de error que ayuda
muy poco.
Comprobar el valor de las variables se puede hacer sólo
añadiendo código extra al servidor COM y las respuestas redirigirlas a la
pantalla o a un archivo log. Una forma de resolver este problema es probar el
servidor COM como un objeto normal de FoxPro
creandolo en el entorno de desarrollo de Visual FoxPro. Sin embargo,
esto deja de ser una solución practica ya que Visual FoxPro no puede simular
cada tipo de aplicación cliente
igualmente bien. De la misma forma los servidores COM que se usan en los
scripts de las páginas activas son dificiles de depurar ya que es imposible, en
el entorno de Visual FoxPro simular los
objetos nativos de ASP.
Compara el desarrollo de los servidores COM al poder de
Visual FoxPro cuando se desarrollan aplicaciones interactivas. El desarrollador no tiene que construir un
ejecutable, puede justo ejecutar el código y abrir el depurador siempre que quiera.
Si se produce un error de runtime, aparecerá un diálogo con Cancelar, Suspend e
Ignorar ofreciendo al desarrollador la
opción de suspender el programa e inspeccionar el entorno usando el depurador.
Con frecuencia puedes cambiar algunas variables o parte del código y ejecutarlo
de nuevo.

Figura 2: Un mensaje de error que te da poca información con la
posibilidad de suspender el programa e iniciar el depurador.
El resultado es que la productividad varía mucho a la hora
de construir un servidor COM o una aplicación normal en VFP. Una forma de poder
solucionar esto sería el dar la opción al desarrollador de poder ejecutar su código
del Servidor COM desde dentro de VFP de la misma forma a como hacer con un
desarrollo interactivo normal.
Ejecutemos Visual Basic 6 para una rápida comparación de
cómo el desarrollo de una aplicación web se realiza en Visual FoxPro y Visual
Basic:
1. Inicia Visual Basic 6.
2. Crea un nuevo proyecto del tipo IIS Application.
3. Abre la clase WebClass1.
4. Establece un breakpoint en el método WebClass_Start.
5. Pulsa F5 para ejecutar la aplicación.
6. Para la aplicación.
7. Cambia algo del código.
8. Pulsa F5 para ejecutar de nuevo la aplicación.
Unas pocas grandes diferencias con Visual FoxPro son obvias de forma inmediata:
1. No hay necesidad de crear un web share o un directorio virtual en Internet Information Server. El entorno de desarrollo de Visual Basic 6 ha hecho esta parte de forma automática.
2. Se lanza automáticamente Internet Explorer y navega directamente al sitio web correcto.
3. Se abre el depurador de Visual Basic cuando se establece un breakpoint.
4. Cuando se para la aplicación y el código cambia, pulsar F5 no es bastnte para empezar de nuevo. No es necesario compilar una DLL o reiniciar el Internet Information Server.
Sólo con que se pudieran hacer las mismas cosas en VFP se ganaría mucho en productividad.

Figura 3: Una clase en Visual Basic 6
Por qué, podrías pensar, no puedo hacer las mismas cosas
en VFP? El principal problema reside en la incapacidad de crear un objeto
Servidor COM en el diseñador de VFP en lugar de la runtima de VFP. Una forma mediante la que se podría evitar
esto es mediante CreateObject(“VisualFoxPro.Application”) en lugar del COM
server que estás tratando de crear y usar en las aplicaciones de VFP. Aunque
esta opción funciona tiene dos problemas. Primero, requiere un poco de código
en el cliente que es totalmente diferente del código que usarías cuando esté en
producción. En segundo lugar, empieza una sesión nueva de Visual FoxPro cada
vez en lugar de reusar la session existente lo que produce problemas de
compilación cuando el fichero FXP está en uso por la otra sessión. Tomar el
handle de un objeto en la session activa de Visual FoxPro no es posible.
Otra forma de evitar esto es permitir a las sesiones
comunicarse a través de los archivos. Esto significa que debería haber un
objeto en Visual FoxPro comprobando los archivos solicitados e iniciando una
petición cuando se encuentre. Esto tiene el inconveniente de que todas las
comunicaciones se tienen que hacer a través de los archivos del sistema y
nosotros no podemos pasar objetos, como hace de forma nativa ASP al Servidor
COM de Visual FoxPro.
Con la salida de Visual FoxPro 7 Microsoft ha añadido
soporte para la Active Accessibility en Visual FoxPro. La Active Accessibility
está originalmente diseñada para soportar a usuarios desactivados. Además de su
finalidad original, es también muy útil para otros propósitos como la capacidad
de crear herramientas de testeo con interfaz gráfico. Visual FoxPro 7 viene con
una herramienta, el Active Accessibility Test Harness, que hace justamente eso.
Una de las muchas funciones del API del Active Accessibility es
AccessibleObjectFromWindow. Esta función del API permite al desarrollador
recupear un objeto IAccessible con la
referencia a otro objeto. Una vez que tenemos una referencia a este objeto
IAccessible podemos usar la otra función del API Active Accessibility para
conseguir más información. Una de estas funciones del API es el AccChild() que
tiene la capacidad de devolver la referencia a un objeto de Visual FoxPro
Application o _VFP. Una vez que se ha hecho esto todo lo que puedas hacer
dentro del entorno de desarrollo de Visual FoxPro queda accesible para ti.
Listing 1: El método usado para crear el objeto en tiempo de diseño en el entorno de Visual FoxPro.
************************************
Procedure GetDebugObject() as Object
************************************
* Return an object reference to a debugable copy of this COM server
Local loServer, loAcc, lnHwnd, lcGuid, loVFP, lcComLink
loServer = Null
#If c_ComDebugging
loAcc = Null
lnHwnd = 0
lcComLink = Addbs(JustPath(_vfp.ServerName)) + 'ComLink.dbf'
If File(lcComLink)
* There is an ComLink file with the required HWnd value of the design time VFP
Use (lcComLink) In 0 Again Shared
* Get the _VFP.hWnd value
lnHwnd = ComLink.iHwnd
* Close the table again
Use In ComLink
EndIf
If lnHwnd <> 0
* We where able to load the required _VFP.hWnd value
* Declare the required Active Accessibility function
Declare Integer AccessibleObjectFromWindow In OleAcc Integer, Integer, String, Object @
* Convert the IAccecssible to a useable format
lcGuid = Str2Guid(c_IAccGuid)
* Try to get a handle on the IAccecssible interface of _VFP
AccessibleObjectFromWindow(lnHWnd, c_ObjIdClient, lcGuid , @loAcc)
If Type('loAcc.AccChild(Int(2^31-1))') = 'O'
* Retreive the _VFP reference from the IAccecssible object
loVFP = loAcc.AccChild(Int(2^31-1))
If Type('loVFP.Name') = 'C'
* We got the _VFP reference, use it to check if the status form exists
If loVFP.Eval('Type([poStatus.chkDebug.Value]) = [L]')
* The test succeeded, retreive the object
loServer = loVFP.Eval('CreateObject([' + This.Class + '])')
* Set any required properties of the debug server
This.ConfigureDebugServer(loServer)
EndIf
EndIf
EndIf
EndIf
#EndIf
* Return this server as the object to use if we are unable to reach the VFP design time environment
loServer = Nvl(loServer, This)
Return loServer
Mediante el uso de las funciones
descritas anteriormente, he creado una tecnica para copiar el servidor COM
original que se ha creado y es
almacenado en el entorno de diseño de VFP. La solución tiene dos partes, una
parte es un método incluido en el Servidor COM original y la segunda es una
utilidad de monitorización para el entorno de diseño de VFP.
Para el entorno de desarrollo de
Visual FoxPro he desarrollado un formulario que monitoriza el estado y permite
al desarrollador ver cuando ha empezado una petición y cuanto tiempo ocupa.
Antes de mostrar el estado del formulario crea una tabla llamada ComLink con un
simple registro y un campo en el directorio actual que contiene el valor del _VFP.hWnd de la session actual de
Visual FoxPro. La aplicación se asegura de que todas las librerías de clases
requeridas y archivos de procedimientos se carguen de forma que los objetos
requeridos puedan ser creados. El formulario de estado también incluye una
opción para lanzar el depurador al principio del siguiente request.

Figure 4: El formulario de estado del ASP
Debido a que desarrollar
componentes ASP es más duro que desarrollar servidores COM normales decidí
crear un formulario separado para monitorizar que no solo permitiera al
desarrollador iniciar el depurador al principio de la petición sino también la
opción de añadir el contenido actual del objeto ASP al final de la página de
response.
Por el lado del servidor el
principal método envuelto es GetDebugObject(). Este método primero comprueba si
hay una tabla llamada ComLink en la misma situación que el archivo ejecutable
del COM. Si se encuentr se devuelve el valor hWnd y se usa con las funciones
del Active Accessibility descritas anteriormente para conseguir una referencia
a un Objeto Aplicación de Visual FoxPro. Si esto es exitoso el método
_VFP.Eval() se usa entonces para crear un nuevo objeto de la misma clase que el
Servidor COM. Este nuevo objeto, o si el intento falla por alguna razón el
Servidor COM se devuelve al cliente. Para usar esto desde una aplicación
cliente la única cosa que hay que hacer es añadir una línea justo depués de la
instrucción CreateObject(). Por ejemplo, lo siguiente en Visual Basic for
Applications script en una hoja de Excel:
Listing 2: El código de Visual Basic for Applications utilizado en el Excel workbook.
Dim oDemo Set oDemo = CreateObject("ComDebug.ComDebug") Set oDemo = oDemo.GetDebugObject() oDemo.LoadData ActiveWorkbookSe han añadido dos métodos
adicionales en la clase base como son el Init() y el Destroy(). Ambos se usan
para registrar el inicio y el final de la petición con el formulario de
monitorización de estatus en tiempo de diseño.
La Depuración de Servidores ASP
COM es algo más complejo que depurar un servidor COM usado por excel en una
macro de VBA. La principal diferencia es que no puedes correr la aplicación ASP
desde dentro de VFP, necesitarás asegurarte de que el directorio virtual del
Internet Information Server virtual existe y está configurado adecuadamente.
Esto no es nada nuevo pero puede ser facilmente automatizado usando los objetos
del Windows ADSI. El formulario de
estado usa los objetos ADSI para asegurarse de que hay un directorio
virtual para el directorio especificado
y determinar la URL que se debe usar para acceder a ese directorio. Si no se
encuentra directorio virtual al desarrollador se le pregunta si quiere crear un
nuevo directorio de Internet Information Server con la apropiada configuración.
He desarrollado este código con la estructura de directorios en la cabeza que
siempre uso para los sitios web. Podrías quizas necesitar cambiarlo un poco
para tus propositos. Uso una estructura de directorio con un directorio
principal, por ejemplo AspDebug, para el proyecto. Este directorio siempre
tiene un subdirectorio llamado WWWRoot. Este directorio se comparte con el
Internet Information Server directorio virtual web bajo el nombre del
directorio del proyecto principal. Por ejemplo: el directorio
C:\AspDebug\WWWRoot se alzanza a través del browser mediante el URL http://LocalHost/AspDebug.

Figure 5: La estructura del directorio que uso cuando desarrollo.
El problema siguiente es la
seguridad. En ASP el servidor COM se crea bajo la cuenta de IUSR_ account en
lugar de la cuenta de usuario que has estado usando para desarrollar con Visual
FoxPro. La cuenta IUSR es por defecto una cuenta con muchas restricciones. Para
evitar estas restricciones es necesario cambiar la configuración del Internet
Information Server para la web y así evitar accesos anónimos y permitir sólo la
autentificación integrada en Windows. Esto tiene como resultdo que la página
ASP y el componente COM se ejecutan
bajo la cuenta actual de usuario enlugar de bajo el ISUR_ account. El formulario que monitoriza comprueba la
autentificación cuando empieza y ofrece corregirla cuando no está bien puesta.
Esta configuración es sólo requerida para la función del API AccessibleObjectFromWindow y no se requiere para el Servidor
en Producción.

Figure 6: The Active Server pages Authentication settings.
El siguiente problema es algo que
he sido incapaz de precisar la causa. No es un
problema tan grave como la limitación del entorno de desarrollo. El
servidor COM usado bajo ASP debe ser
compilado como un servidor fuera de proceso, un EXE, para permitir a la función
del API del Active Accessibility
trabajar. Cada vez que uso un in process server, ya sea un regular o un
multi threaded DLL, la función AccessibleObjectFromWindow falla con un error
E_FAIL. Este es un error muy genérico de COM y no ayuda a poder localizar el
problema. Una vez que el proceso de depuración se ha terminado el servidor COM
se puede construir como un single o un multi threaded DLL según lo que se
requiera.
Para hacer una prueba de
depuración, inicia Visual FoxPro7 en el directorio AspDebug. Primero
necesitarás ya sea hacer un BUILD EXE AspDebug FROM AspDebug para crear
el servidor COM inicial o hacer un
/regserver del actual AspDebug.exe usando el archivo register.bat. A
continuación, escribe DO MAIN en la ventana de instrucciones de Visual
FoxPro y pulsa Enter. La primera vez que hagas esto verás un mensaje informandote de que el directorio virtual para
este proyecto no se ha encontrado y preguntándote si quieres crearlo. Haz Click
en el botón de OK para crear el nuevo directorio virtual de Internet
Information Server. A continuación aparecerá el formulario de estado y se iniciará el browser por defecto. El
browser automáticamente navegará a la página por defecto de la web. Cuando
vuelvas a Visual FoxPro verás la primera petición ASP en el formulario de
estado.
Listing 3: The code in the Active Server Pages default.asp.
<% Dim oDemo Set oDemo = Server.CreateObject("AspDebug.AspDebug") Set oDemo = oDemo.GetDebugObject() oDemo.Test() %>
Para depurar el servidor marca el
Debug checkbox, vuelvete al browsers y pulsa F5 para refrescar la página. Se
abrirá el depurador de Visual FoxPro y te dejará al final del método
OnStartRequest(). Usa F8 para avanzar paso a paso a través del OnStartPage() y
el método OnStartAspRequest() hasta que te encuentres en el método Test(). Este
es el método que se llama desde la página Default.asp para generar el output
HTML. Nota que puedes hacer cualquier cosa que puedes hacer de forma normal
cuando depuras una aplicación normal de Visual FoxPro. Como puedes ver el
Request ASP está disponible de la misma forma como lo estaría en un servidor COM
normal corriendo bajo ASP.
Fíjate en el código del debugger cambiando una variable en el objeto Session de la ASP.
Cambiar el código es tan
fácil como desarrollar una aplicación
normal. Haz click en el botón de cerrar, abre AspDebug.prg en el editor y cambia
algo de código en el método Test(). Por
ejemplo añade la siguiente línea de código
al final del método Test():
This.oResponse.Write('<p>Hi there: ') This.oResponse.Write(This.oRequest.ServerVariables('auth_user'))
Guarda el programa y ejecuta el programa principal de nuevo sin construir un nuevo servidor COM. Deberías ahora ver el nuevo mensaje al final de la página.
Como ayuda adicional, debido a que
el depurador de Visual FoxPro no muestra todas las variables ASP que están
disponibles a través de los objetos ASP, he añadido la opción de descargar
parte o toda la información de las ASP al final del método response. Para
mostrar esto establece la descarga de la ASP a basic o full y refresca la
página.
La solución presentada genera un
gran rendimiento en productividad a la hora de desarrollar COM en general y
entornos ASP en particular. El desarrollo gana mucho en interactividad y las
posibilidades de depuración son una enorme beneficio.
Maurice
de Beijer
Copyright © 2002 ABL - The Problem Solver. All rights reserved.
FoxPress – Enero de 2003