Automatizando Office Con Visual Foxpro

Visual FoxPro es una poderosa herramienta, pero hay tareas que no las puede realizar él solo. Por ejemplo si tenemos una

Views 348 Downloads 16 File size 800KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Conferencia Visual FoxPro España 2003

Automatizando Office con Visual FoxPro

Luis María Guayán Vicente Trapani S.A. Tucumán, Argentina [email protected]

Luis María Guayán es programador en lenguajes xBase desde el año 1990. En 1994 comenzó a desarrollar en Microsoft FoxPro 2.6 para Windows. Desde allí transitó por todas las versiones de FoxPro, hasta la actualidad con la última versión de Visual FoxPro. Es el Responsable del Área de Desarrollo Informático de Vicente Trapani S.A., un establecimiento citrícola industrial en la provincia de Tucumán, en la República Argentina. Es cofundador en el año 2000, y SysOp de PortalFox, el mayor portal gratuito para todos los desarrolladores en Visual FoxPro de habla hispana. En los años 2002 y 2003 fue nombrado por Microsoft como MVP (Most Valuable Professional) en Visual FoxPro, por su colaboración en las distintas comunidades en línea.

Automatizando Office con Visual FoxPro

Página 2

Automatizando Office con Visual FoxPro

Automatizando Office con Visual FoxPro Tabla de contenidos Automatizando Office con Visual FoxPro......................................................................................3 Tabla de contenidos................................................................................................................3 Introducción.............................................................................................................................4 ¿Cómo comenzar?.....................................................................................................................4 Instanciando un Servidor de Automatización ...............................................................................4 El Examinador de Objetos de Visual FoxPro..................................................................................5 Aprendamos con IntelliSense......................................................................................................6 El uso de las Macros de Office.....................................................................................................7 Las constantes de Office............................................................................................................8 Combinar correspondencia con Word...........................................................................................9 Definición de la clase cWord....................................................................................................9 El programa MailMerge.prg....................................................................................................10 Los métodos en la clase cWord..............................................................................................10 Abrir y/o crear la carta.......................................................................................................11 La fuente de los datos........................................................................................................12 Combinar la carta..............................................................................................................12 Guardar la carta................................................................................................................12 Gráficos y tablas dinámicas con Excel........................................................................................12 ¿Dónde está la ayuda?..........................................................................................................13 Formas de exportar los datos de Visual FoxPro a Excel.............................................................13 Definición de la clase cExcel...................................................................................................14 Los métodos de la clase cExcel..............................................................................................14 Exportar los datos..............................................................................................................15 Abrir los libros exportados..................................................................................................15 Guardar y cerrar el libro.....................................................................................................15 Generar un gráfico................................................................................................................15 El programa Grafico.prg.....................................................................................................16 Generar una tabla dinámica...................................................................................................17 Programa TablaDinamica.prg..............................................................................................18 Otros métodos auxiliares....................................................................................................19 Enviar y leer correo con Outlook...............................................................................................19 Versiones de Outlook............................................................................................................20 Un breve ejemplo.................................................................................................................20 Problemas de seguridad........................................................................................................20 ¿Y ahora que? ...................................................................................................................21 Definición de la clase cOutlook...............................................................................................21 El formulario de ejemplo.......................................................................................................22 Los métodos de la clase cOutlook...........................................................................................22 Enviar un correo................................................................................................................23 Leer los correos.................................................................................................................24 Resumen................................................................................................................................25

Página 3

Automatizando Office con Visual FoxPro

Introducción Visual FoxPro es una poderosa herramienta, pero hay tareas que no las puede realizar él solo. Por ejemplo si tenemos una aplicación en la cual queremos enviar un correo, realizar un gráfico, escribir un documento, formatear un texto, etc., necesitamos de otras herramientas. Para automatizar estas tareas desde Microsoft Visual FoxPro, elegimos la herramienta Microsoft Office. En este documento vamos a ver como podemos Automatizar Office desde Visual FoxPro, vamos a conocer las distintas herramientas que disponemos y veremos algunos ejemplos de código. Todos los ejemplos descriptos fueron realizados con Microsoft Visual FoxPro 8 y Microsoft Office XP.

¿Cómo comenzar? Lo primero que debemos preguntarnos es ¿cómo comenzar la tarea de automatización? Esta pregunta pareciera que tiene una respuesta difícil, pero veremos... La mayoría de la información disponible en: la Ayuda de Office, los artículos de la Base de Conocimientos de Microsoft (MSKB) o en la Red de Desarrolladores de Microsoft (MSDN) esta escrita en Visual Basic y Visual Basic for Application. Como una desventaja más para los desarrolladores en Visual FoxPro de habla hispana, la información disponible en Internet esta generalmente en inglés. En español, existen varios artículos, ideas y trucos disponibles en los siguientes sitios de la Web:      

Sitio de MSDN Latinoamérica: http://www.microsoft.com/latam/msdn Sitio de MSDN España: http://www.microsoft.com/spain/msdn Sitio de MSDN en Español: http://www.microsoft.com/spanish/msdn PortalFox: http://www.portalfox.com Revista FoxPress: http://www.fpress.com Revista UTMag (edición en español): http://www.universalthread.com/spanish/magazine

En inglés existe un excelente libro para tener en cuenta a la hora de automatizar Office: "Microsoft Office Automation with Visual FoxPro" escrito por Tamar E. Granor y Della Martin, editado en el mes de Junio de 2000. Está disponible para su compra en formato impreso y electrónico en el sitio de Hentzenwerke: http://www.hentzenwerke.com

Instanciando un Servidor de Automatización Para comenzar a utilizar la automatización de Office, vamos a crear una instancia del servidor. Esto se logra desde Visual FoxPro con las funciones CREATEOBJECT() o GETOBJECT(). Con CREATEOBJECT() siempre se crea una nueva instancia del servidor, aunque exista una instancia de dicho servidor. Para crear una instancia de Word, Excel y Outlook se ejecutan las siguientes funciones: loWord = CREATEOBJECT('Word.Application') loExcel = CREATEOBJECT('Excel.Application')

Página 4

Automatizando Office con Visual FoxPro

loOutlook = CREATEOBJECT('Outlook.Application') Con GETOBJECT() se instancia al servidor de la siguiente forma: loExcel = GETOBJECT( , 'Excel.Application') Si no existe una instancia disponible del servidor, el comando fallará y aparecerá el Error OLE 1426. Para evitar este error sin importar si existe o no una instancia del servidor, pasamos como parámetro el nombre del archivo. loExcel = GETOBJECT('C:\MiPlanilla.xls', 'Excel.Application') Por defecto, la instancia del servidor estará oculta. Podemos hacer visible la instancia con la propiedad Visible = .T. Esto lo haremos solo para ver los cambios que producimos, generalmente en la etapa de desarrollo, ya que esto hará más lento el proceso de automatización.

El Examinador de Objetos de Visual FoxPro A partir de la versión 7 de Visual FoxPro, podemos disponer del "Examinador de Objetos" que nos permite examinar una gran cantidad de información útil sobre las propiedades y métodos de cualquier servidor de automatización, en este caso de las aplicaciones de Microsoft Office. El Examinador de Objetos de Visual FoxPro también nos permite ver la ubicación del archivo de ayuda, con solo hacer clic en el nodo raíz. El nombre del archivo de ayuda es mostrado en la parte inferior del Examinador de Objetos (Figura 1). Si el archivo de ayuda se encuentra en la misma carpeta de la aplicación, éste se mostrará como un vínculo y lo podemos abrir desde allí. Si el archivo de ayuda no se encuentra, el Examinador de Objetos nos indicará "No instalado". Se puede copiar el archivo de ayuda a la carpeta de la aplicación. En el caso de Microsoft Office XP en Español este se encuentra en "C:\Archivos de programa\Microsoft Office\Office10\3082\"

Figura 1: El Explorador de Objetos de Visual FoxPro Con el Explorador de Objetos, podemos recorrer las distintas propiedades, eventos y métodos (PEMs), con la sintaxis correspondiente a cada caso (Figura 2).

Página 5

Automatizando Office con Visual FoxPro

Figura 2: Los métodos y su sintaxis Con el Examinador de Objetos también podemos tener acceso a los valores de las distintas constantes de cada aplicación (Figura 3).

Figura 3: Las constantes y sus valores

Aprendamos con IntelliSense Uno de los cambios más llamativos a partir de la versión 7 de Visual FoxPro, es la implementación de IntelliSense. Esta herramienta nos permite conocer acerca de los objetos, sus métodos y propiedades directamente desde la "Ventana de Comandos" o desde el "Editor de programas" de Visual FoxPro.

Página 6

Automatizando Office con Visual FoxPro

Una vez instanciado el objeto desde la "Ventana de Comandos" o declarado desde el "Editor", con solo escribir el nombre del objeto nos aparecerán sus propiedades y métodos (Figura 4) y la sintaxis correspondiente (Figura 5).

Figura 4: Las distintas propiedades y métodos mostrados con IntelliSense

Figura 5: La sintaxis de un método

El uso de las Macros de Office Una manera fácil de comenzar la tarea de automatización, es generar el código de automatización grabando una Macro con la aplicación de Office que deseamos automatizar. Esto lo logramos con el "Grabador de Macros" que recuerda las tareas que ejecutamos y genera automáticamente un código en VBA (Visual Basic for Application).

Figura 6: Grabar una macro en Word

Página 7

Automatizando Office con Visual FoxPro

Figura 7: Código VBA generado automáticamente Podemos fácilmente traducir el código generado en VBA a Visual FoxPro: ChangeFileOpenDirectory 'D:\Espana\Automation\Documentos\' Documents.Open FileName:='Automation.doc', ConfirmConversions:=False, _ ReadOnly:=False, AddToRecentFiles:=False, PasswordDocument:='', _ PasswordTemplate:='', Revert:=False, WritePasswordDocument:='', _ WritePasswordTemplate:='', Format:=wdOpenFormatAuto El código en Visual FoxPro quedaría: loWord.Documents.Open('D:\Espana\Automation\Documentos\Automation.doc', ; .F., .F., .F., '', '', .F., '', '',wdOpenFormatAuto) Los pasos a seguir para esta traducción son los siguientes:  Encerrar con paréntesis la lista de parámetros  Observar una llamada tipo del método y ordenar los parámetros en el orden que estos aparecen.  Quitar los nombres de los parámetros y los símbolos ':='  Reemplazar los nombres de constantes por sus valores, como por ejemplo "True" con .T. ó 1. Una alternativa (como en el ejemplo) es definir estos valores con: #DEFINE wdOpenFormatAuto 0 #DEFINE true .T.

Las constantes de Office Si bien disponemos de las herramientas como el Examinador de Objetos o IntelliSense para facilitar la tarea de automatización, existen otras herramientas que nos permitirán tener acceso a las constantes y crear fácilmente un archivo de encabezados ("Archivo.h") para definirlas y utilizarlas directamente desde Visual FoxPro. Un ejemplo de un archivo de encabezados es: #DEFINE olTo #DEFINE olCC #DEFINE olBCC

1 2 3

En Visual FoxPro incluimos un archivo de cabecera con la siguiente orden:

Página 8

Automatizando Office con Visual FoxPro

#INCLUDE 'Archivo.h' Para la creación de estos archivos disponemos al menos de dos herramientas: Código en VFP de Trevor Hancock (Base de Conocimientos de Microsoft, Artículo 285396) disponible en: http://support.microsoft.com/?scid=285396 Programa de utilidades de Rick Strahl (GetConstants) disponible libremente en: http://www.west-wind.com/webtools.asp

Combinar correspondencia con Word En este ejemplo vamos a abrir, crear y completar con datos una carta en Microsoft Word desde Visual FoxPro, y vamos a utilizar una gran herramienta de Word como lo es "Combinar Correspondencia" (Mail Merge). Los datos a combinar en este ejemplo los tomaremos de la base de datos "Northwind". En un caso desde Visual FoxPro y en el otro desde un servidor SQL Server 2000.

Definición de la clase cWord Para combinar correspondencia disponemos de una clase definida por el usuario, llamada cWord con los métodos necesarios para esta tarea. Miremos las primeras líneas de la definición de esta clase: DEFINE CLASS cWord AS CUSTOM *-- Interfaz de ApplicationEvents2 IMPLEMENTS ApplicationEvents2 IN 'Word.Application' *-* Propiedades *-oWord = .NULL. && Objeto Word ... ... En la definición de la clase cWord vemos la cláusula IMPLEMENTS que nos especifica que la definición de la clase hereda la interfaz de otro componente COM (en este caso Word). Esto nos permitirá que los eventos de Word interactúen con el código de Visual FoxPro. Con ello podremos controlar, por ejemplo si hacemos la aplicación visible, cuando el usuario cierra Word y evitar que un objeto de Visual FoxPro quede referenciado a este. Cuando implementamos una interfaz debemos incluir en la definición de clase todos los métodos de dicha interfaz. Utilizamos el nombre de interfaz como principio del nombre de los métodos (por ejemplo, ApplicationEvents2_Quit). Así evitamos conflictos entre dos interfaces que contengan métodos con el mismo nombre. Para esta tarea que pareciera tan compleja, usamos el Examinador de Objetos de Visual FoxPro para arrastrar y colocar una definición de interfaz en el código y ahorrar tiempo. La instrucción IMPLEMENTS, junto con los demás métodos implementados con sus parámetros, ¡¡¡se escribirá automáticamente!!! Para vincular los métodos del servidor con los métodos de la interfaz implementados en el objeto de Visual FoxPro, utilizamos la función EventHandler() presente desde la versión 7 de Visual FoxPro. Este tipo de vínculo requiere que el objeto Visual FoxPro y el componente COM estén activos. Como expresamos anteriormente, toda esta implementación en nuestra aplicación es solo para saber cuando se ejecuta el evento Quit en el servidor de automatización. Cuando esto ocurre liberamos el objeto de Visual FoxPro con la siguiente sentencia en el método

Página 9

Automatizando Office con Visual FoxPro

ApplicationEvents2_Quit: THIS.oWord = .NULL.

El programa MailMerge.prg Este es el código de nuestro programa "MailMerge.prg", en donde creamos una instancia de la clase cWord y comenzamos a ejecutar sus métodos. LOCAL lo AS OBJECT, loDoc AS OBJECT lo = NEWOBJECT('cWord','cWord.prg') IF lo.CrearServidor() *-- Vinculo los eventos de Word a métodos del objeto 'lo' IF NOT EVENTHANDLER(lo.oWord, lo) MESSAGEBOX('No se pudo vincular a los eventos de Word', 16, 'Error!' ) ENDIF *-- Maximizo y hago visible lo.oWord.WINDOWSTATE = 1 && wdWindowStateMaximize lo.oWord.VISIBLE = .T. loDoc = lo.AbrirCarta('Carta') lo.GenerarDataSource('CSV') *lo.GenerarDataSource('ODC') lo.CombinarCarta(loDoc) lo.GuardarCarta(loDoc, .T.) *-- Desvinculo los eventos de Word IF NOT EVENTHANDLER(lo.oWord, lo, .T.) MESSAGEBOX('No se pudo desvincular a los eventos de Word', 16, 'Error!' ) ENDIF ELSE MESSAGEBOX('No se pudo instanciar el servidor', 16, 'Error!') ENDIF lo = .NULL. RETURN

Los métodos en la clase cWord En primer lugar invocamos el método CrearServidor() que nos crea una instancia de Word. Ante– riormente vimos que podíamos instanciar a Word con la función: GETOBJECT('Word.Application') y si no existía una instancia de Word, surge el Error OLE 1426. Para evitar esto, Visual FoxPro 8 trae un nuevo mecanismo para el manejo de errores, implementado mediante el bloque de sentencias TRY ... CATCH ... FINALLY. El código que potencialmente puede producir un error, se aísla en la cláusula TRY (estas se pueden anidar), y cuando el error efectivamente ocurre, el control de la ejecución pasa al código en la cláusula CATCH, en el orden que aparecen dentro del bloque (en forma similar a cómo funciona el DO CASE). La cláusula opcional FINALLY, se ejecuta, se haya producido o no el error. Lo novedoso de este mecanismo es que siempre que se produce un error dentro de un bloque TRY ... CATCH ... FINALLY, Visual FoxPro crea un objeto de la nueva clase Exception. *-- Manejo el error con TRY ... CATH ... FINALLY TRY *-- Instancio el objeto THIS.oWord = GETOBJECT( , 'Word.Application') WAIT WINDOW 'Ya existe una instancia de Word...' TIMEOUT 2 CATCH TRY

Página 10

Automatizando Office con Visual FoxPro

*-- Creo el objeto THIS.oWord = CREATEOBJECT('Word.Application') WAIT WINDOW 'Nueva instancia de Word...' TIMEOUT 2 CATCH MESSAGEBOX('Microsoft Word no está instalado.', 16, 'Problemas!!!') FINALLY ENDTRY FINALLY ENDTRY RETURN VARTYPE(THIS.oWord) = 'O' Para que este ejemplo sea más descriptivo, vamos a hacer visible a la aplicación Word para ver paso a paso como se ejecutan los distintos métodos. Esto lo hacemos en la sentencia: lo.oword.VISIBLE = .T.

Abrir y/o crear la carta El método AbrirCarta(), abre la carta de Word si esta existe o crea una nueva carta con el método CrearCarta(). Ambos métodos retornan un objeto Document de Word. PROCEDURE AbrirCarta(tcArchivo) LOCAL loDoc AS 'Word.Document' tcArchivo = FORCEEXT(tcArchivo,'DOC') IF NOT FILE(THIS.cDirDoc + tcArchivo) *-- Si no existe la carta, la creo loDoc = THIS.CrearCarta(tcArchivo) ELSE *-- Si existe la carta, la abro loDoc = THIS.oWord.Documents.OPEN(THIS.cDirDoc + tcArchivo) *-- y me aseguro que no tiene un documento asociado loDoc.MailMerge.MainDocumentType = -1 && wdNotAMergeDocument ENDIF *-- Retorno un objeto Document RETURN loDoc ENDPROC PROCEDURE CrearCarta(tcArchivo) LOCAL loDoc AS 'Word.Document' *-- Creo un nuevo documento loDoc = THIS.oWord.Documents.ADD(,,0) *-- Guardo el documento como... loDoc.SAVEAS(THIS.cDirDoc + tcArchivo) *-- Activo el documento loDoc.ACTIVATE *-- Comienzo a 'escribir' el documento WITH THIS.oWord.SELECTION .FONT.NAME = 'Tahoma' .FONT.SIZE = 10 ... ENDWITH RETURN loDoc ENDPROC En el caso de crear o abrir una carta ya existente de Word, estas deben contener los nombres de los campos para su reemplazo en la combinación. Estas cartas serán los documentos principales para la combinación.

Página 11

Automatizando Office con Visual FoxPro

La fuente de los datos También debemos crear o abrir los documentos con los datos a combinar. En este ejemplo tenemos dos casos:  Crear un archivo tipo CSV (Valores Separados por Comas) desde una cláusula SELECT a la tabla "Customers" de la base de datos "Northwind" (que viene con Visual FoxPro).  Mediante una Conexión de Datos de Office (ODC) ya existente, traer los datos de la tabla "Customers" de la base de datos "Northwind", pero esta vez desde un servidor SQL Server 2000. Para esta tarea tenemos el método GenerarDataSource() que crea el archivo con los datos y establece la propiedad cDataSource.

Combinar la carta En el método CombinarCarta() ejecutamos las siguientes sentencias para:  Hacer la carta del tipo Documento Principal.  Abrir el archivo con la fuente de datos.  Ejecutar la combinación WITH toDoc.MailMerge .MainDocumentType = 0 && wdFormLetters .OpenDataSource(THIS.cDataSource) .Execute() ENDWITH

Guardar la carta Para finalizar tenemos el método GuardarCarta() que guarda el documento principal, con la posibilidad mediante un parámetro de cerrar el documento. PROCEDURE GuardarCarta(toDoc, tlCierra) *-- Guardo el documento toDoc.SAVE() IF tlCierra *-- Cierro el documento toDoc.CLOSE() ENDIF ENDPROC En este ejemplo el documento combinado que se genera quedará abierto, entonces hacemos la aplicación visible para que el usuario lo guardar directamente de la ventana de Word. También establecemos la carpeta donde están los documentos de este ejemplo, para que Word por defecto la seleccione en la ventana de "Guardar...". WITH THIS.oWord .ChangeFileOpenDirectory(THIS.cDirDoc) .VISIBLE = .T. ENDWITH

Gráficos y tablas dinámicas con Excel En nuestras aplicaciones podemos aumentar el impacto de los resultados de las consultas, mostrando los datos en distintos formatos. Para ello vamos a recurrir a dos grandes herramientas de Excel como lo son los gráficos y las tablas dinámicas.

Página 12

Automatizando Office con Visual FoxPro

Antes de comenzar a analizar el ejemplo en Visual FoxPro vamos a comprender algunos conceptos para poder hacer más fácil la automatización de Excel desde Visual FoxPro, esto siempre lo logramos con los archivos de ayuda. También vamos a conocer distintas formas que disponemos para pasar los datos de Visual FoxPro a Excel.

¿Dónde está la ayuda? Para tener una idea mas clara acerca de todos los objetos de Excel, debemos siempre examinar la ayuda disponible. Parte de esta ayuda la podemos encontrar en el tema "Referencia Visual Basic de Microsoft Excel" en el archivo de ayuda "vbaxl10.chm" en la carpeta de la instalación de Office. En esta ayuda podemos conocer acerca de los objetos disponibles en Excel, como por ejemplo el objeto Chart (Figura 8)

Figura 8: El Objeto Chart de Excel

Formas de exportar los datos de Visual FoxPro a Excel La forma mas simple, es seleccionar el área de trabajo con datos de Visual FoxPro (estos pueden estar en una tabla, un cursor o una vista) y ejecutar las ordenes COPY TO ... ó EXPORT TO ... con los parámetros correspondientes. Si elegimos esta manera, solo necesitamos tener activa la aplicación de Visual FoxPro. SELECT 'MiCursor' COPY TO 'C:\Planilla1' TYPE XL5 EXPORT TO 'C:\Planilla2' TYPE XL5 Otra forma que disponemos es usando el método DataToClip() del objeto Application de Visual FoxPro ('VisualFoxPro.Application'). La variable del sistema _VFP hace referencia al objeto Application de la instancia actual. De esta manera copiamos un conjunto de registros como texto al "Portapapeles". Recordar que el tercer parámetro del método DataToClip() debemos configurarlo en 3 para que los campos se delimiten con tabulaciones. SELECT 'MiCursor' GO TOP _VFP.DataToClip(,,3)

Página 13

Automatizando Office con Visual FoxPro

Una vez que tenemos los datos en el Portapapeles, creamos una instancia de Excel desde Visual FoxPro, creamos un nuevo Libro y pegamos los datos desde el Portapapeles con el método Paste(). loExcel = CREATEOBJECT('Excel.Application') loLibro = loExcel.Workbooks.Add() WITH loLibro .Activate() .ActiveSheet.Paste() .SaveAs('C:\Planilla3.xls') ENDWITH loExcel.Visible = .T. STORE .NULL. TO loLibro, loExcel Otra forma de pasar los datos de Visual FoxPro a Excel, es tener ambas aplicaciones activas y recorrer los datos de nuestra tabla y escribirlos directamente en una Hoja de Excel celda por celda. Esta opción es mucho más lenta que las anteriores, pero es útil cuando la hoja de Excel ya tiene un formato establecido o cuando queremos escribir fórmulas en la hoja de Excel. SELECT 'MiCursor' loExcel = CREATEOBJECT('Excel.Application') loLibro = loExcel.Workbooks.Add() loHoja = loLibro.ActiveSheet() lnFil = 1 && Nombres de campos FOR lnCol = 1 TO FCOUNT() loHoja.Cells(1,lnCol).VALUE = FIELD(lnCol) ENDFOR lnFil = lnFil + 1 && Resto de las filas SCAN ALL FOR lnCol = 1 TO FCOUNT() loHoja.Cells(lnFil,lnCol).VALUE = EVALUATE(FIELD(lnCol)) ENDFOR lnFil = lnFil + 1 ENDSCAN loLibro.SaveAs('C:\Planilla4.xls') loExcel.Visible = .T. STORE .NULL. TO loHoja, loLibro, loExcel

Definición de la clase cExcel En esta clase definida por el usuario tendremos los métodos que nos permitirán crear y manejar los gráficos y las tablas dinámicas de Excel desde Visual FoxPro. DEFINE CLASS cExcel AS CUSTOM *-* Propiedades *-oExcel = .NULL. ...

Los métodos de la clase cExcel El primer método que vamos a invocar de esta clase es CrearServidor() que establece la propiedad oExcel como una referencia a la instancia de Excel creada. THIS.oExcel = CREATEOBJECT('Excel.Application') Al igual que en la clase cWord que vimos anteriormente, este método tiene el mismo manejo de errores con el bloque TRY ... CATCH ... FINALLY para manejar el error OLE 1426.

Página 14

Automatizando Office con Visual FoxPro

Exportar los datos Para exportar nuestros datos de Visual FoxPro a Excel vamos a elegir la opción de COPY TO ... que la ejecutamos en el método ExportarDatos(). PROCEDURE ExportarDatos(tcCursor) LOCAL lcArchivo AS CHARACTER lcArchivo = FORCEEXT(THIS.cDirDoc + tcCursor, 'XLS') *-- Opción COPY TO ... SELECT (tcCursor) COPY TO (lcArchivo) TYPE XL5 RETURN ENDPROC

Abrir los libros exportados Con el método AbrirLibro() vamos a abrir el libro para comenzar con la automatización. Este método retorna un objeto WorkBook de Excel. PROCEDURE AbrirLibro(tcArchivo) LOCAL loLibro AS 'Excel.Workbook' tcArchivo = FORCEEXT(tcArchivo,'XLS') IF FILE(THIS.cDirDoc + tcArchivo) loLibro = THIS.oExcel.Workbooks.OPEN(THIS.cDirDoc + tcArchivo) ELSE *-- Si no existe el libro loLibro = .NULL. ENDIF *-- Retorno un objeto Workbook RETURN loLibro ENDPROC

Guardar y cerrar el libro Con el método GuardarLibro() vamos a guardar el libro. Este método tiene un parámetro adicional que indica si se cierra el libro luego de guardarlo. PROCEDURE GuardarLibro(toLibro, tlCierra) *-- Guardo el Libro toLibro.SAVE() IF tlCierra *-- Cierro el Libro toLibro.CLOSE() ENDIF RETURN ENDPROC

Generar un gráfico A partir de los resultados de una consulta a las tablas de la base de datos "Northwind", generaremos un gráfico del tipo de columnas en 3 dimensiones (xl3DColumnStacked) como lo vemos en la Figura 9, y daremos formato a algunos objetos del gráfico, como los títulos, los ejes y las barras.

Página 15

Automatizando Office con Visual FoxPro

Figura 9: Grafico de barras en 3 dimensiones

El programa Grafico.prg En este programa vamos a crear un objeto cExcel y ejecutaremos los métodos vistos anteriormente para la creación del gráfico. LOCAL lo AS OBJECT, loLibro AS OBJECT lo = NEWOBJECT('cExcel','cExcel.prg') *-- Genero cursor y exporto datos lo.VtaAnualEmpleado(1997, 'VtaAnualEmpleado') lo.ExportarDatos('VtaAnualEmpleado') IF lo.CrearServidor() *-- Maximizo y hago visible lo.oExcel.WINDOWSTATE = -4137 && xlMaximized lo.oExcel.VISIBLE = .T. *-- Abro el libro copiado loLibro = lo.AbrirLibro('VtaAnualEmpleado') *-- Genero gráfico lo.GenerarGrafico(loLibro, 'Ventas Anuales por Empleado (AÑO 1997)') *--- Grabo planilla y cierro lo.GuardarLibro(loLibro, .T.) *-- Cierro el servidor lo.CerrarServidor() ELSE MESSAGEBOX('No se pudo instanciar el servidor', 16, 'Error!') ENDIF lo = .NULL. RETURN El método GenerarGrafico() de la clase cExcel, es el que hace la tarea propiamente dicha. PROCEDURE GenerarGrafico(toLibro, tcTitulo) LOCAL lcRango AS CHARACTER, oGrafico AS 'Excel.Chart', ; loHoja AS 'Excel.WorkSheet' loHoja = toLibro.ActiveSheet lcRango = 'A1:' + CHR(loHoja.UsedRange.COLUMNS.COUNT + 64) + ; ALLTRIM(STR(loHoja.UsedRange.ROWS.COUNT)) loGrafico = THIS.oExcel.Charts.ADD WITH loGrafico

Página 16

Automatizando Office con Visual FoxPro

*-- Tipo, rango y localización .ChartType = 55 && xl3DColumnStacked .SetSourceData(loHoja.RANGE(lcRango), 2) .Location(1, 'Ventas Anuales') && xlLocationAsNewSheet = 1 *-- Titulo .HasTitle = .T. .ChartTitle.TEXT = tcTitulo WITH .ChartTitle.FONT .NAME = 'Arial' .SIZE = 14 .Bold = .T. ENDWITH *-- Ejes WITH .Axes(1,1) .HasTitle = .T. .AxisTitle.TEXT = 'Empleado' ENDWITH WITH .Axes(2,1) .HasTitle = .T. .AxisTitle.TEXT = '$' ENDWITH *-- Sin Leyendas .HasLegend = .F. *-- Formato 3D .RightAngleAxes = .T. .AutoScaling = .T. *-- Grupo de gráfico WITH .ChartGroups(1) *-- Ancho separación barras .GapWidth = 50 ENDWITH ENDWITH RETURN ENDPROC

Generar una tabla dinámica Nuestro programa de ejemplo es "TablaDinamica.prg" que crea una instancia de la clase cExcel y ejecuta sus métodos para generar la tabla dinámica. En nuestro ejemplo vamos a generar una tabla dinámica que nos muestra las Ventas Anuales agrupadas por País, Empleado y Tipo de Producto.

Figura 10: Diseño de la tabla dinámica

Página 17

Automatizando Office con Visual FoxPro

Con anterioridad a la programación de los métodos debemos diseñar la forma de la tabla dinámica que deseamos generar. El diseño elegido lo observamos en la Figura 10.

Programa TablaDinamica.prg Este es el código de nuestro programa: LOCAL lo AS OBJECT, loLibro AS OBJECT lo = NEWOBJECT('cExcel','cExcel.prg') *-- Genero cursor y exporto datos lo.VtaAnualPais('VtaAnualPais') lo.ExportarDatos('VtaAnualPais') IF lo.CrearServidor() *-- Maximizo y hago visible lo.oExcel.WINDOWSTATE = -4137 && xlMaximized lo.oExcel.VISIBLE = .T. *-- Abro el libro copiado loLibro = lo.AbrirLibro('VtaAnualPais') *-- Genero tabla dinámica lo.GenerarTablaDinamica(loLibro) *--- Grabo planilla y cierro lo.GuardarLibro(loLibro, .T.) *-- Cierro el servidor lo.CerrarServidor() ELSE MESSAGEBOX('No se pudo instanciar el servidor', 16, 'Error!') ENDIF lo = .NULL. RETURN Para generar la tabla dinámica ejecutamos el método GenerarTablaDinamica() de la clase cExcel. Este método nos genera la tabla dinámica (Figura 11) ordenada descendentemente por las Ventas por País. PROCEDURE GenerarTablaDinamica(toLibro) LOCAL laPagina(1), laFilas(2), laColumnas(1), lcRango *--- Arrays con los datos de la tabla dinámica laPagina(1)='Anio' laFilas(1)='Pais' laFilas(2)='Empleado' laColumnas(1)='TipoProd' lcRango = 'A1:E1275' WITH THIS.oExcel *--- Formato de los datos hoja principal .Cells.SELECT .SELECTION.COLUMNS.AUTOFIT .COLUMNS('E:E').SELECT .SELECTION.NumberFormat = '$ #,##0.00' .RANGE('A2').SELECT *--- Llamo al generador de Tablas Dinámicas .ActiveSheet.PivotTableWizard(1, lcRango, '', 'TablaDinamica') *--- Armo la Tabla dinámica WITH .ActiveSheet.PivotTables('TablaDinamica') .AddFields(@laFilas, @laColumnas, @laPagina) WITH .PivotFields('Ventas') .ORIENTATION = 4 && xlDataField .NumberFormat = '$ #,##0.00' ENDWITH .PivotFields('Pais').AutoSort(2,'Suma de ventas') && xlDescending = 2

Página 18

Automatizando Office con Visual FoxPro

ENDWITH *--- Formato de los datos hoja tabla dinámica .Cells.SELECT .SELECTION.COLUMNS.AUTOFIT .ActiveSheet.NAME = 'Ventas Anuales' .RANGE('A2').SELECT ENDWITH RETURN ENDPROC

Figura 11: Tabla dinámica generada

Otros métodos auxiliares En la clase cExcel también existen otros métodos, solo válidos para este ejemplo. Estos métodos son VtaAnualPais() y VtaAnualEmpleado() utilizados para crear los cursores con los datos para exportar a Excel. Estos cursores toman los datos de la base de datos "Northwind" que se encuentra en la carpeta "\Samples\Northwind" de la carpeta de la instalación original de Visual FoxPro.

Enviar y leer correo con Outlook El modelo de objetos de Outlook es muy rico y poderoso. Esta interfaz está disponible como un servidor de automatización, o sea, que todo lo podemos hacer por programa desde Visual FoxPro. Como en temas anteriores, siempre recurriremos a la ayuda. Allí podemos ver los distintos objetos de Outlook (Figura 12).

Figura 12: La ayuda de Outlook en el archivo "vbaol10.chm"

Página 19

Automatizando Office con Visual FoxPro

Lo primero que debemos hacer para automatizar Outlook, es crear un objeto Outlook, similar a como vimos anteriormente con las otras herramientas de Office. Una vez creado el objeto, debemos acceder al origen de los datos, pero esto no lo logramos en forma directa, debemos crear un objeto "NameSpace" apropiado que actuará como entrada (en este ejemplo MAPI). El objeto NameSpace proporciona entre otros, los métodos Logon y Logoff.

Versiones de Outlook Seguramente conocemos varias versiones de Outlook, solo daremos las principales características de cada uno.  Outlook Express: No es Outlook, es un programa completamente diferente y no es servidor de automatización.  Outlook 97 y 2000: Existen dos versiones, Internet Mail Only (IMO) y Corporate Workgroup (C/W). Ambas trabajan con Internet Mail, pero solo Corporate Workgroup trabaja con la interfaz MAPI.  Outlook XP: Combina las versiones Internet Mail y Corporate Workgroup.

Un breve ejemplo Una de las tareas más fácil de automatizar en Outlook es el envío de un correo. Veremos un ejemplo de solamente unas pocas líneas. LOCAL lcPerfil AS CHARACTER, lcContrasenia AS CHARACTER , ; lcDestinatario AS CHARACTER, lcTema AS CHARACTER , ; lcCuerpo AS CHARACTER LOCAL loOutlook AS "Outlook.Application", ; loNameSpace AS OBJECT, loMailItem AS OBJECT #DEFINE LF_CR CHR(10)+CHR(13) *-- Datos del correo lcPerfil = "Prueba" lcContrasenia = "prueba" lcDestinatario = "[email protected]" lcTema = "Prueba" lcCuerpo = "Prueba desde la Conferencia Visual FoxPro España 2003." + LF_CR lcCuerpo = lcCuerpo + "Saludos desde A Coruña." + LF_CR *-- Creo objetoa Outlook y NameSpace loOutlook = CREATEOBJECT("Outlook.Application") loNameSpace = loOutlook.GetNameSpace("MAPI") *-- Ejecuto los métodos loNameSpace.Logon(lcPerfil , lcContrasenia) loMailItem = loOutlook.CreateItem(0) loMailItem.Recipients.ADD(lcDestinatario) loMailItem.Subject = lcTema loMailItem.Body = lcCuerpo loMailItem.SEND loNameSpace.Logoff loNameSpace = .NULL. loOutlook = .NULL.

Problemas de seguridad Outlook XP y Outlook 2000 SP2, incluyen los parches de seguridad de Microsoft. Estos parches restringen, entre otras cosas, el acceso a la libreta de direcciones y el envío de correo mediante automatización, con el fin de evitar códigos maliciosos que toman los datos de nuestra libreta de direcciones y envían correo sin nuestro consentimiento.

Página 20

Automatizando Office con Visual FoxPro

Cuando intentamos enviar un correo desde Visual FoxPro, se nos presenta el siguiente cuadro de dialogo, que luego de 5 segundos habilita el botón "Si" (Figura 13).

Figura 13: "...intentando enviar correo..." Cuando intentamos acceder a la libreta de direcciones aparece el cuadro de dialogo el cual nos permitirá un acceso inmediato, o de 1, 2, 5, ó 10 minutos que debemos seleccionar (Figuras 14).

Figura 14: "...intentando tener acceso a direcciones..."

¿Y ahora que? Estas son algunas de las opciones disponemos nosotros para trabajar con estos parches de seguridad:  Mantener la versión de Office 2000 SR-1 y no actualizarla ni instalarle parches de seguridad, con los peligros que esto significa.  Si se tienen Outlook y Exchange instalados, el administrador de Exchange, puede disminuir las alertas o registrar algunas aplicaciones como seguras.  Outlook Redemption: Es un objeto COM que se adapta fácilmente a la automatización y utiliza la MAPI extendida. Esta DLL fue escrita por Dmitry Streblechenko (MS Outlook MVP) y esta disponible en http://www.dimastr.com/redemption. Este es un producto comercial con un valor de U$S 200 aproximadamente. Existe para descarga una versión libre con fines de desarrollo.  Express ClickYes: Es un pequeño programa residente que se maneja mediante la API de Windows. Este "presionará" el botón "Si" antes de que el dialogo aparezca. Este programa es gratis y esta disponible en http://www.express-soft.com/mailmate/clickyes.html. En el mismo sitio existe un ejemplo para Visual FoxPro.

Definición de la clase cOutlook En este ejemplo disponemos de una clase definida por el usuario, llamada cOutlook con los distintos métodos para realizar el envío y la lectura de los correos. La definición de esta clase es la siguiente: DEFINE CLASS cOutlook AS CUSTOM *-- Heredo la interfaz de _Application Events_10 IMPLEMENTS ApplicationEvents_10 IN 'Outlook.Application'

Página 21

Automatizando Office con Visual FoxPro

*-- Propiedades oOutlook = .NULL. oNameSpace = .NULL. ... ... Como vimos anteriormente en la definición de la clase cWord, la sentencia IMPLEMENTS nos permitirá interactuar con los eventos de Outlook desde Visual FoxPro. Solo pondremos código para interactuar ApplicationEvents_10_Quit():

con el evento

Quit de Outlook

en el método

WITH THIS .oNameSpace = .NULL. .oOutlook = .NULL. ENDWITH

El formulario de ejemplo En este ejemplo utilizaremos un formulario con un objeto PageFrame con dos Páginas, una para enviar correo y la otra para leer los correos desde la Bandeja de Entrada. En el método Init() creamos una instancia de la clase cOutlook y vinculamos los eventos de Outlook: THISFORM.oCorreo = NEWOBJECT('cOutlook','cOutlook.prg') IF THISFORM.oCorreo.CrearServidor() *-- Vinculo los eventos de Outlook a métodos del objeto oCorreo IF NOT EVENTHANDLER(THISFORM.oCorreo.oOutlook, THISFORM.oCorreo) MESSAGEBOX('No se pudo vincular a los eventos de Outllok', 16, 'Error!' ) ENDIF ENDIF También en el método Init() llamamos a un formulario para el inicio de sesión: DO FORM Inicio WITH THISFORM.oCorreo TO llAceptar IF NOT (llAceptar AND THISFORM.oCorreo.IniciarSesion()) MESSAGEBOX('Falló el inicio sesión', 48, 'Inicio de sesión') RETURN .F. ENDIF

Los métodos de la clase cOutlook En el inicio del formulario invocábamos al método CrearServidor() que establece una referencia a la instancia de Outlook en la propiedad oOutlook. THIS.oOutlook = CREATEOBJECT('Outlook.Application') Igualmente como en las clases anteriores, este método tiene el manejo de errores con el bloque TRY ... CATCH ... FINALLY. En este método también creamos un objeto NameSpace que nos permitirá acceder a las carpetas especiales de Outlook. THIS.oNameSpace = THIS.oOutlook.GetNameSpace('MAPI')

Página 22

Automatizando Office con Visual FoxPro

Enviar un correo Antes de invocar el método EnviarCorreo(), configuramos todas las propiedades necesarias para el envío de correo. Esto lo hacemos en el método Click() del botón "Enviar". WITH THISFORM.oCorreo .CargarVector(THIS.PARENT.txtTo.VALUE, 'aTO') .CargarVector(THIS.PARENT.txtCC.VALUE, 'aCC') .CargarVector(THIS.PARENT.txtAdjunto.VALUE, 'aAdjuntos') .cTema = ALLTRIM(THIS.PARENT.txtTema.VALUE) .cCuerpo = ALLTRIM(THIS.PARENT.edtCuerpo.VALUE) IF .EnviarCorreo() MESSAGEBOX('Mensaje enviado con éxito.', 64, 'Aviso') THISFORM.LimpiarPagina() ELSE MESSAGEBOX('No se pudo enviar el mensaje.', 48, 'Problemas') ENDIF ENDWITH RETURN En el método EnviarCorreo() de la clase cOutlook creo un nuevo mensaje y lo armo según las propiedades anteriormente configuradas. PROCEDURE EnviarCorreo() LOCAL loMensaje AS OBJECT, llRet AS Logical LOCAL lnI AS INTEGER, lnIndex AS INTEGER *-- Creo un nuevo mensaje WITH THIS loMensaje = .oOutlook.CreateItem(0) IF VARTYPE(loMensaje) = 'O' loMensaje.Subject = .cTema loMensaje.Body = .cCuerpo *-- Recipientes lnIndex = 0 *-- TO lnLen = ALEN(.aTO) FOR lnI = 1 TO lnLen IF NOT EMPTY(.aTO(lnI)) lnIndex = lnIndex + 1 loMensaje.Recipients.ADD(.aTO(lnI)) loMensaje.Recipients(lnIndex).TYPE = 1 ENDIF ENDFOR *-- CC lnLen = ALEN(.aCC) FOR lnI = 1 TO lnLen IF NOT EMPTY(.aCC(lnI)) lnIndex = lnIndex + 1 loMensaje.Recipients.ADD(.aCC(lnI)) loMensaje.Recipients(lnIndex).TYPE = 2 ENDIF ENDFOR *-- BCC lnLen = ALEN(.aBCC) FOR lnI = 1 TO lnLen IF NOT EMPTY(.aBCC(lnI)) lnIndex = lnIndex + 1 loMensaje.Recipients.ADD(.aBCC(lnI)) loMensaje.Recipients(lnIndex).TYPE = 3 ENDIF

Página 23

Automatizando Office con Visual FoxPro

ENDFOR *-- Adjuntos lnLen = ALEN(.aAdjuntos) FOR lnI = 1 TO lnLen IF NOT EMPTY(.aAdjuntos(lnI)) AND FILE(.aAdjuntos(lnI)) loMensaje.Attachments.ADD(.aAdjuntos(lnI)) ENDIF ENDFOR llRet = loMensaje.SEND ELSE llRet = .F. ENDIF ENDWITH RETURN llRet ENDPROC

Leer los correos Para leer los correos de la bandeja de entrada invocamos el método LeerMensajes() de la clase cOutlook desde el método Click() del botón "Leer". ZAP IN curMsg IF THISFORM.oCorreo.LeerMensajes(THIS.PARENT.opgTipo.VALUE = 1, 'curMsg') GO TOP IN curMsg THIS.PARENT.grdMensajes.SETFOCUS ELSE MESSAGEBOX('No existen mensajes para traer', 64, 'Aviso') ENDIF THIS.PARENT.edtCuerpo.REFRESH En el método LeerMensajes() creamos un objeto loInbox y traemos todos los mensajes, o solo los mensajes "No leídos" y recorremos uno a uno para cargarlos en un cursor que luego mostraremos en una Grilla y un Cuadro de Edición. PROCEDURE LeerMensajes(tlNoLeidos, tcAlias) LOCAL loInbox AS 'Outlook.MAPIFolder', loMensajes AS 'Outlook.Items' LOCAL loMsg AS OBJECT, lnI AS INTEGER, llRet AS Logical IF EMPTY(tcAlias) tcAlias = 'curMsg' ENDIF *-- Inbox loInbox = THIS.oNameSpace.GetDefaultFolder(6) *-- Mensajes del Inbox IF tlNoLeidos loMensajes = loInbox.Items.RESTRICT("[Unread] = True") ELSE loMensajes = loInbox.Items ENDIF IF VARTYPE(loMensajes) = 'O' WITH loMensajes IF .Count > 0 *-- Recorro los mensajes FOR lnI = 1 TO .COUNT loMsg = .ITEM(lnI) WITH loMsg INSERT INTO (tcAlias) ; (EnviadoPor, Tema, Recibido, Cuerpo, NoLeido) ; VALUES (.SenderName, .Subject, .ReceivedTime, .Body, .UnRead) ENDWITH ENDFOR

Página 24

Automatizando Office con Visual FoxPro

llRet = .T. ELSE llRet = .F. ENDIF ENDWITH ELSE llRet = .F. ENDIF RETURN llRet ENDPROC

Resumen En este documento vimos solo algunos ejemplos de automatización de Office. Las posibilidades son muchas y cada una depende de la solución que debemos implementar en nuestras aplicaciones. Recuerden que todo el poder que nos brindan las distintas herramientas de Office, pueden ser manejadas desde Visual FoxPro. Solo es cuestión de adoptar alguna de las técnicas vistas y ponerse a trabajar...

Página 25