7 de noviembre de 2015

Creando un servidor COM de subproceso múltiple (Parte 1 de 3)

Primera parte del artículo "Creando un servidor COM de subproceso múltiple" escrito por Antonio Muñoz de Burgos y Caravaca (eMans).


Parte 1 de 3

Temas relacionados:

   •
Instalación de IIS
   
Lista de comprobación de software
   
Microsoft Manager Console (MMC)
   
Configurando IIS
   
(indirectos)ASP & PHP & Visual FoxPro COM
   
(indirectos) Visual FoxPro y ADSI-IIS

Estos artículos los puedes encontrar en www.portalfox.com o en www.emans.com

En esta sección, veremos como crear un Servidor COM de subproceso múltiple, y la estructura utilizada en la .DLL de mi web en www.emans.com (denominada pasarela.dll), este Servidor COM nos permitirá codificar nuestra Web de una forma alternativa a la creación de múltiples .DLL y/o a la utilización de otros productos para este propósito, con esto; lo que pretendemos conseguir, es realizar llamadas a módulos .PRG de forma directa y poder utilizar toda la potencia del lenguaje, por supuesto, siempre dentro de los límites propios de una aplicación Web.

Lo único que necesitamos para crear nuestro servidor de Automatización es un proyecto que contenga una clase definida como OLEPUBLIC. La definición de la clase con OLEPUBLIC, la podemos realizar en un archivo .PRG o en una biblioteca de clases.VCX

Nuestro ejemplo estará basado en un archivo .PRG, la definición de la clase sería de la siguiente forma:



DEFINE CLASS pasarela ASSession OLEPUBLIC
    *
    *----------------------------------------------------------
    * Todo lo que definamos en esta sección,              -
    * y de esta forma, son las propiedades del objeto. -
    *----------------------------------------------------------
    *
    pn_Propiedad1                            && tipo numérica.
    pc_Propiedad2                            && tipo carácter.
    pl_Propiedad3                             && tipo lógica.
   
DIMENSION pa_Propiedad4[1,1]   && tipo array.
    *
    *------------------------------------------------------------
    * Codificación de los métodos y eventos del objeto. -
    *------------------------------------------------------------
    *
   
FUNCTION Init( )
        *
        * El evento
INIT se produce cuando se crea el objeto.
        * Aquí realizamos la codificación correspondiente y
        * necesaria.
        *
        STORE 0               TO pn_Propiedad1
        STORE SPACE( 0 ) TO pc_Propiedad2
        STORE .T.             TO pl_Propiedad3
        STORE SPACE( 0 ) TO pa_Propiedad4
        *

    RETURN
    *
    ... otros eventos y métodos del objeto...
    *   
    *-------------------------------------------------------
    * Creación y codificación de nuestros métodos. -
    *-------------------------------------------------------
    *
   
FUNCTION miFuncion( parámetro1, parámetro2, ... )
        *
       
Código de función...
        *
 
   RETURN
    *
    ... otras funciones propias...
    *
ENDDEFINE


La forma de trabajar con dicha definición de clase en cuanto a propiedades, eventos, métodos, sería exactamente igual, que si trabajáramos con el diseñador de formularios o de clases, lo que si debemos tener en cuenta que nuestro objeto pasarela está basado en la clase Session, por lo tanto a nivel de eventos y métodos propios, solamente tendremos disponibles los que corresponden a dicha clase base.

DEFINE CLASS (comando)
    Referencia del lenguaje Microsoft Visual FoxPro
©.


DEFINE CLASS
ClassName1 AS ParentClass [OF ClassLibrary] [OLEPUBLIC]
   [[PROTECTED | HIDDEN PropertyName1, PropertyName2 ...]
      [Object.]PropertyName = eExpression ...]
   [IMPLEMENTS cInterfaceName [EXCLUDE]
      IN TypeLib | TypeLibGUID | ProgID ]
   [ADD OBJECT [PROTECTED] ObjectName AS ClassName2 [NOINIT]
      [WITH cPropertylist]]
   [[PROTECTED | HIDDEN] FUNCTION | PROCEDURE Name[_ACCESS |_ASSIGN]
      ([cParamName [AS type] [@]])
      [AS type] [HELPSTRING cHelpString]
      THIS_ACCESS [NODEFAULT] cStatements [ENDFUNC | ENDPROC]]
   [PEMName_COMATTRIB = nFlags | DIMENSION PEMName_COMATTRIB[5]
      [PEMName_COMATTRIB[1] = nFlags
       PEMName_COMATTRIB[2] = cHelpString
       PEMName_COMATTRIB[3] = cPropertyCapitalization
       PEMName_COMATTRIB[4] = cPropertyType
       PEMName_COMATTRIB[5] = nOptionalParams]]
ENDDEFINE
 


Session (Objeto: eventos, métodos y propiedades)
    Referencia del lenguaje Microsoft Visual FoxPro
©.
 

Destroy Error Init

https://lh3.googleusercontent.com/-Wn_kSpeFWww/Vj6l1HSZGZI/AAAAAAAACLA/tKJJXio97Gg/s1600/com_titulo_metodos.gif

AddProperty NewObject ReadExpression
CREATE CLASS CREATE FORM DEFINE CLASS
ReadMethod ResetToDefault WriteExpression

Application BaseClass Class
ClassLibrary Comment DataSession
DataSessionID Name Parent
ParentClass Tag  



Ahora la pregunta sería, porqué nos hemos basado en el claseSession y no en otro?, como por ejemplo del tipo Custom.

La diferencia fundamental; es que la clase Session, tiene la capacidad de aislar datos, es decir; como si de una sesión de datos privado se tratara.
Para nuestro caso es estupendo ya que todo lo que tratáramos a partir de la instancia a nuestro objeto pasarela, estaría en una sesión privada de datos.

El funcionamiento; de Sesiones de datos privado en nuestro objeto, sería equiparable a cuando desarrollamos una aplicación de escritorio para entornos compartidos, con sesión de datos privada.Con este Sistema de Sesiones Visual FoxPro, nos asegura un duplicado exacto, un entorno seguro para múltiples instancias y con un funcionamiento independientemente.
La sesión de datos es la representación del entorno de trabajo dinámico actual, donde cada instancia mantiene su propio conjunto de áreas de trabajo, compuesto de;

Una copia diferente de cada tabla, índice, relaciones, etc.
Un número ilimitado de áreas de trabajo.
Punteros de registro independientes a cada tabla.

Las limitaciones de las sesiones de datos, solamente la tendríamos por la memoria y el espacio en disco disponible en el Sistema.

Además recordemos que en esta clase Session se han realizado las siguientes actualizaciones:

Las propiedades, métodos y eventos intrínsecos
   - ya no se escriben en la biblioteca de tipos.
Sólo se escribirán las propiedades y métodos
   - personalizados que especifiquemos.
En las versiones anteriores, teníamos que pasar
   - el valor HIDDEN a cada miembro manualmente.
Los siguientes valoresSET tienen un nuevo valor  predeterminado en:
    - La sesión de datos privada con la clase Session;

EXCLUSIVE =  OFF
TALK =  OFF
SAFETY =  OFF


Otro de las ventajas e importante de conocer en el funcionamiento y comportamiento de Visual FoxPro cuando creamos un componente de automatización (in-process), basado en la clase Session y OLEPUBLIC (ver en consideraciones)


Antes de pasar a ejemplos más concretos, veremos algunas consideraciones en el desarrollo de Servidores de Automatización.



Cual es el tratamiento de Visual FoxPro con sus Bibliotecas en tiempo de ejecución:

VFP6R|VFP7R|VFP8R.DLL: representado en adelante por VFP?R.DLL

        -
Es la biblioteca utilizada en tiempo de ejecución normal, para  la mayoría de los tipo de aplicaciones.

VFP6T|VFP7T|VFP8T.DLL: representado en adelante por VFP?T.DLL

        -
Es la biblioteca utilizada en tiempo de ejecución de varios subprocesos, especial para aplicaciones de Servidor en proceso.

Con Visual FoxPro podemos crear servidores de automatización fuera de proceso (out-process) o en proceso (in-process).


Servidor de automatización: es una aplicación componente COM, con la funcionalidad que otras aplicaciones puedan utilizar y reutilizar por medio de automatización.
Servidor fuera de proceso: son los ejecutables (servidor COM [archivos.EXE]) y que se ejecuta en su propio proceso, la comunicación entre la aplicación cliente y el servidor se denomina comunicaciónen proceso cruzado.
Servidor en proceso: es una biblioteca de vínculos dinámicos .DLL, que se ejecuta en el mismo espacio de direcciones de proceso.

La biblioteca VFP?R.DLL nos proporciona los siguientes servicios para la creación de los siguientes tipos de aplicaciones:

    Aplicaciones distribuidas (archivos.exe)
    Documentos activos (archivos.app)
    Servidores fuera de proceso (archivos.exe)
    Servidores en proceso (archivos.dll)

Como podemos ver, esta biblioteca nos proporciona la creación de Servidores en proceso, pero es importante mencionar y remarcar que no atiende a múltiples servidores de automatización .DLL en proceso.
Que es lo que se entiendo por esto; 

    Que cada .DLL en proceso utilizará una instancia diferente del tiempo de ejecución VFP?R.DLL.

Esto significa que cada .DLL tiene el uso exclusivo de la biblioteca de tiempo de ejecución de VFP?R.DLL, con lo cual, nos llega a indicar; que si tiene el uso exclusivo de VFP?R.DLL, Visual FoxPro tendrá que aplicar un mecanismo para el tratamiento del mismo.

El mecanismo utilizado es que; por cada nueva .DLL en proceso, se creará y se cargará en memoria una copia de VFP?R.DLL, y para que queden identificadas se le asigna un nombre diferente, dicha asignación de nombre esta basado en el nombre de nuestra .DLL en proceso, el cambio se realiza añadiendo al final del nombre un letra la"r" (de VFP?R.DLL)

Debemos entender que los tiempos de ejecución de Visual FoxPro sólo cambia denombre para las .DLL en proceso que se ejecutan en el mismo espacio de direcciones de proceso. (ver definición Servidor en proceso)

Por lo tanto cuando se ejecutan dos clientes independientes cada uno en su espacio de proceso, se cargan dos .DLL en proceso diferentes de Visual FoxPro sin que se cambie el nombre del tiempo de ejecución.

Es posible, que ahora te preguntes del porqué de toda la parafernalia anterior?, la cuestión resulta simple, si lo que pretendemos es crear un Servidores de automatización en una misma .DLLen proceso con la cláusula OLEPUBLIC en el comando DEFINE CLASS, que en definitiva es el objetivo planteado o comentado al inicio de este artículo.

Si lo realizamos de esta forma, tendremos servidores de automatización que se podrán afectar entre ellos, tanto en las variables publicas, comandos SET, etc. ya que ello residirá en un subproceso común, lo que pretendemos es justamente que los procesos no interfieran entre sí.

Y como primer punto; llegamos a la utilización de la claseSession, la cual nos ahorrará ese tipo de conflictos.

El otro punto que debemos tener en cuenta es la limitación deVFP?R.DLL, además de lo comentado anteriormente sobre el mecanismo aplicado, debemos de tener en cuenta que: esta no protege completamente los datos globales y los datos de cada instancia, el motivo es el siguiente: en principio la biblioteca impide que varios objetos ejecuten el código al mismo tiempo, es decir si uno de los objetos está ejecutando código, todas las demás instancias deben esperar en la cola para ejecutarlo, tanto en la asignación de propiedades como invocaciones a métodos.

La característica del Modelo de objetos de componentes (Component Object Model, COM) cuando tiene un subproceso de ejecución, solamente puede ejecutar el código de un solo objeto a la vez, para controlar dicha situación utiliza la serialización de las peticiones, donde se van situando en una cola, y ser procesadas una a una hasta la última.

Pues entonces cual es la alternativa, para este tipo de casos?

   
Debemos de utilizar la Biblioteca en tiempo de ejecución VFP6T|VFP7T|VFP8T.DLL

Nota: Si bien cierto, que para determinadas aplicaciones, este tipo de procesos sea el ideal, pero para el tipo de aplicaciones Web que estamos comentando no es el recomendado, por lo bloqueos que se pueden plantear.

Por lo tanto, siempre es importante saber que es lo que se quiere hacer y cual es el objetivo del mismo, antes de aplicar un método u otro, ya que cada uno de ellos cumplen una funciones, con ventajas y desventajas, aplicadas a cada caso.

Hemos hablado de VFP?R.DLL, ahora entendamos un poco más a VFP?T.DLL

Con VFP?T.DLL podemos eliminar los problemas de bloqueos que se nos pueden plantear con VFP?R.DLL, ya que esta biblioteca esta solamente diseñada para implementar servidores en proceso, no bloquea la ejecución del código, y es una biblioteca de tiempo de ejecución ligeraya que se han deshabilitado muchos comandos y funciones(ver comandos deshabilitados), sobre todos aquellas de carácter visual y de entrada de usuario, recordemos que en una aplicación que se ejecuta en el lado del servidor, no tiene sentido este tipo de comandos, ni de visualizaciones.

Nota: no debemos confundir; con el código que se ejecuta en el lado del cliente, que si tiene una representación de comandos visuales y entradas de datos.

En relación a los bloqueos que se eliminan con VFP?T.DLL, podemos tomar como ejemplo el mismo que viene en el manual de Referencia de Visual FoxPro.

Por un lado, tenemos un proceso que es una consulta de tarda un par de segundos y por otro tenemos un proceso que se encarga de generar una consulta e imprimir el resultado que tarda aprox. 15 minutos.

Si utilizamos VFP?R.DLL, es posible que nuestra consulta que solo dura un par de segundos, tenga que esperar a la finalización del proceso largo, según el caso expuesto tendría que esperar 15 minutos, frente a sus 2 segundos.

Mientras que si utilizamos VFP?T.DLL, es no se produciría, ya que con esta biblioteca además de solucionar los posibles problemas de bloqueos, también elimina los conflictos de acceso a los datos globales desde varios subprocesos.

Esto es debido a la implementación del subproceso del modelo de apartamento aplicado en la biblioteca VFP?T.DLL
En Visual FoxPro en el modelo Apartamento, cada subproceso es como un apartamento; todos los objetos creados en un subproceso viven en ese apartamento y no conocen los objetos de los demás apartamentos.
(Puedes encontrar información detallada del subproceso del modelo apartamento en la Biblioteca MSDN)

Considero importante entender el funcionamiento de estas bibliotecas y los conceptos que se mueven alrededor de ellas, sobre todo cuando se desarrolla este tipo de aplicaciones, ya que nuestros desarrollos no se componen de cuatro líneas simples y muchas veces pueden existir momentos frustrantes, por errores que muchas veces lo consideramos como incomprensibles, pero siempre tienen una razón de ser y una lógica del porqué.



Compilando un servidor de automatización:

Servidor COM (.exe)
Servidor COM de subproceso único (.dll)
Servidor COM de subproceso múltiple (.dll)

Nota: en www.emans.com en el módulo pasarela es COM de subproceso múltiple (.dll)

Desde el administrador de proyectos, opción generar.
Desde los comandos: BUILD EXE | BUILD DLL | BUILD MTDLL (opciones correlativas)

Nota: Si generas el componente desde el administrador de proyectos, automáticamente se encargará de registrar el componente.


Registrando un servidor de automatización:

Componente .exe
    miComponenteServer /regserver
    miComponenteServer /unregserver&& quitar la entrada.

Componente .dll
    regsvr32 %path% miComponenteServer.dll
    regsvr32 /u %path% miComponenteServer.dll&& quitar la entrada.

Cuando se realiza el registro se guarda la ruta del fichero (miComponenteServer), por lo tanto si cambiamos o deseamos mover el fichero de directorio, el mismo cuidado tendríamos que tener si realizamos la compilación del componente creando un nuevo ID, en estos casos es conveniente realizar los pasos siguientes:

[1] Quitar la entrada del registro. (con el comando indicado)
[2] Mover el fichero al directorio deseado.
[3] Volver a registrar el componente.


Otra aspecto a considerar, son los enlaces en tiempo de compilación y en tiempo de ejecución, siempre que se pueda optimizar en lo posible.

Recordemos que los servidores COM de Visual FoxPro admiten los dos tipos de enlaces: en tiempo de compilación (vtable) y en tiempo de ejecución (IDispatch), juntos se denominan Interfaz dual.

Los enlaces en tiempo de compilación;

Mejoran el rendimiento, ya que entendemos que el cliente puede resolver la referencia al objeto en tiempo de compilación.

La sintaxis sería:

    LOCAL loExcel AS Excel.Application

Cuando realicemos la compilación, el compilado resultante sólo contendrá el código que invoca a las propiedades, métodos y eventos del objeto. Este tipo de enlaces reduce bastante el tiempo en el momento de invocar, establecer y/o recuperar los valores de propiedades, métodos.

Creación de variables
    Referencia del lenguaje Microsoft Visual FoxPro
©.


PUBLIC | LOCAL
ListaDeVariables
o
PUBLIC | LOCAL
[ARRAY] ArrayName1(nRows1 [, nColumns1])
           [, ArrayName2(nRows2 [, nColumns2])] ...
        [AS type [OF ClassLib]]

Cuando se especifica un nombre de clase válido, Visual FoxPro utiliza el valor de typelib (si especifica un ProgID) o crea una instancia del objeto para obtener la lista de propiedades, métodos y eventos.
 


Los enlaces en tiempo de ejecución;

Son más lentos para invocar propiedades o métodos, ya que en tiempo de ejecución es cuando se determinará las propiedades, métodos y eventos del objeto.

LOCAL loTMP

loTMP = CREATEOBJECT("Excel.Application")

Parte 1 de 3


Bibliografía y/o documentación adicional:

Biblioteca MSDN & Resource KIT.
Manual de Referencia de Visual FoxPro.


Antonio Muñoz de Burgos y Caravaca
www.emans.com (Web realizada en vFoxPro)
Sevilla - España

Manifestando el apoyo a la comunidad de desarrolladores de MS Visual FoxPro.
 

Todas las marcas aquí mencionadas, están registradas por sus respectivos fabricantes.

1 comentario :

  1. Estupenda informacion, gracias a personas como ustedes que comparten sus conocimientos podemos ampliar nuestros conocimientos

    ResponderEliminar