FoxPress – Enero 2003

 

Desarrollo y Depuración de Servidores COM con VFP

Por Maurice de Beijer

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 problema a la hora de desarrollar Servidores COM

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.

 

Una rápida comparación con Visual Basic

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 

El  problema con Visual FoxPro

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.

 

La Solución

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 ActiveWorkbook
 

Se 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.

Depuración de Componentes Active Server Pages

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.

 

Conclusión

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