Definición de la clase cWord
Para combinar correspondencia definimos de una clase llamada cWord con los métodos necesarios para esta tarea. El código de la clase es el siguiente:
*--------------------------------------------------
* Clase cWord
*--------------------------------------------------
DEFINE CLASS cWord AS CUSTOM
*--
* Propiedades
*--
oWord = .NULL. && Objeto Word
cDirApp = ADDBS(SYS(5) + SYS(2003))
cDirDat = ADDBS(HOME(2) + 'Northwind')
cDataSource = ''
*--------------------------------------------------
* Creo el servidor de automatización
*--------------------------------------------------
PROCEDURE CrearServidor()
*-- Creo el objeto
THIS.oWord = CREATEOBJECT('Word.Application')
RETURN VARTYPE(THIS.oWord) = 'O'
ENDPROC
*--------------------------------------------------
* Cierro el servidor de automatización
*--------------------------------------------------
PROCEDURE CerrarServidor()
*-- Cierro Word
THIS.oWord.QUIT()
THIS.oWord = .NULL.
RETURN
ENDPROC
*--------------------------------------------------
* Abro la Carta, si no existe la creo
*--------------------------------------------------
PROCEDURE AbrirCarta(tcArchivo)
LOCAL loDoc AS 'Word.Document'
tcArchivo = FORCEEXT(tcArchivo,'DOC')
IF NOT FILE(THIS.cDirApp + 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.cDirApp + tcArchivo)
*-- y me aseguro que no tiene un documento asociado
loDoc.MailMerge.MainDocumentType = -1 && wdNotAMergeDocument
ENDIF
*-- Retorno un objeto Document
RETURN loDoc
ENDPROC
*--------------------------------------------------
* Creo la Carta
*--------------------------------------------------
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.cDirApp + tcArchivo)
*-- Activo el documento
loDoc.ACTIVATE
*-- Comienzo a 'escribir' el documento
WITH THIS.oWord.SELECTION
.FONT.NAME = 'Tahoma'
.FONT.SIZE = 10
.ParagraphFormat.ALIGNMENT = 2 && wdAlignParagraphRight
.TypeText('San Miguel de Tucumán, ' + DTOC(DATE()))
.TypeParagraph
.ParagraphFormat.ALIGNMENT = 0 && wdAlignParagraphLeft
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeText('Señores: ')
.FONT.Bold = .T.
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD CompanyName ')
.FONT.Bold = .F.
.TypeParagraph
.TypeText('At: ')
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD ContactName ')
.TypeParagraph
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD Address ')
.TypeParagraph
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD PostalCode')
.TypeText(' - ')
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD City ')
.TypeParagraph
.FONT.Underline = 1 && wdUnderlineSingle
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD Country ')
.FONT.Underline = 0 && wdUnderlineSingle
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeText(CHR(9) + 'Estimado/a ')
.FIELDS.ADD(.RANGE, -1, 'MERGEFIELD ContactName ')
.TypeParagraph
.TypeParagraph
.TypeText(CHR(9) + 'Nos dirigimos a Ud. con el objeto de comunicarle ' + ;
'la nueva dirección de nuestra empresa')
.TypeParagraph
.TypeParagraph
.FONT.Bold = .T.
.TypeText('Informática del Tucumán')
.FONT.Bold = .F.
.TypeParagraph
.TypeText('9 de Julio 123, 1° Piso')
.TypeParagraph
.TypeText('4000 - San Miguel de Tucumán')
.TypeParagraph
.TypeText('Tucumán, Argentina')
.TypeParagraph
.TypeText('Teléfono (+54) (381) 681-4521')
.TypeParagraph
.TypeParagraph
.TypeText(CHR(9) + 'Sin otro particular lo saludamos atte.')
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeParagraph
.TypeText('Manuel Belgrano')
.TypeParagraph
.TypeText('Socio Gerente')
.TypeParagraph
.TypeText('Informática del Tucumán')
.TypeParagraph
ENDWITH
*-- Retorno un objeto Document
RETURN loDoc
ENDPROC
*--------------------------------------------------
* Creo archivo DataSource
*--------------------------------------------------
PROCEDURE GenerarDataSource
LOCAL lcArchivo AS CHARACTER
IF NOT DBUSED('Northwind')
OPEN DATABASE (THIS.cDirDat + 'Northwind') SHARED
ENDIF
SET DATABASE TO 'Northwind'
*-- Consulta a los Clientes de Northwind
SELECT CompanyName, ContactName, ;
Address, PostalCode, City, Country ;
FROM Customers ;
INTO CURSOR Clientes
*-- Copio el cursor al archivo para combinar
lcArchivo = SYS(2015)
COPY TO (THIS.cDirApp + lcArchivo) TYPE CSV
USE IN Clientes
THIS.cDataSource = THIS.cDirApp + FORCEEXT(lcArchivo,'CSV')
RETURN
ENDPROC
*--------------------------------------------------
* Combino la Carta
*--------------------------------------------------
PROCEDURE CombinarCarta(toDoc)
WITH toDoc.MailMerge
.MainDocumentType = 0 && wdFormLetters
.OpenDataSource(THIS.cDataSource)
.Execute()
ENDWITH
WITH THIS.oWord
*-- Cambio la Carpeta del cuadro de diálogo 'Guardar...'
.ChangeFileOpenDirectory(THIS.cDirApp)
*-- Maximizo y hago visible
.WINDOWSTATE = 1 && wdWindowStateMaximize
.VISIBLE = .T. && True
ENDWITH
RETURN
ENDPROC
*--------------------------------------------------
* Guardo el Documento, si tlCierra = .T. lo cierra
*--------------------------------------------------
PROCEDURE GuardarCarta(toDoc, tlCierra)
*-- Guardo el documento
toDoc.SAVE()
IF tlCierra
*-- Cierro el documento
toDoc.CLOSE()
ENDIF
ENDPROC
ENDDEFINE
*--------------------------------------------------
* Fin Clase cWord
*--------------------------------------------------
El programa Combinar.prgEl siguiente es el código de nuestro programa "Combinar.prg" donde creamos una instancia de la clase cWord y comenzamos a ejecutar los métodos de esa clase.
*-------------------------------------------------
* Combinar.prg
*-------------------------------------------------
LOCAL lo AS OBJECT, loDoc AS OBJECT
lo = NEWOBJECT('cWord','cWord.prg')
IF lo.CrearServidor()
*-- Ejecuto métodos de la clase
loDoc = lo.AbrirCarta('MiCarta')
lo.GenerarDataSource()
lo.CombinarCarta(loDoc)
lo.GuardarCarta(loDoc, .T.)
ELSE
MESSAGEBOX('No se pudo instanciar el servidor', 16, 'Error!')
ENDIF
lo = .NULL.
RETURN
*-------------------------------------------------
* Fin Combinar.prg
*-------------------------------------------------
Ejecutando los métodos en la clase cWordEn primer lugar invocamos el método CrearServidor() que nos retorna el objeto oWord que será nuestro servidor de automatización.
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.

Crear la carta
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.
La fuente de los datos
También debemos crear o abrir los documentos con los datos a combinar. En este ejemplo creamos un archivo del tipo CSV (Valores Separados por Comas) desde una cláusula SELECT a la tabla "Customers" de la base de datos "Northwind"

Obtener los datos a combinar

Crear la fuente de datos (archivo .CSV)
Para esta tarea tenemos el método GenerarDataSource() que crea el archivo con los datos y establece la propiedad cDataSource de la clase cWord.
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

Ejecutar la combinación
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.
En este ejemplo el documento combinado que se genera quedará abierto, entonces hacemos la aplicación visible para que el usuario lo guarde o imprima directamente desde 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...".
Pueden descargar el código fuente de los programas desde el siguiente vínculo: combinar.zip
Hasta la próxima.
Luis María Guayán
aún no lo pruebo pero creo no tener problema para implementarlo. Recién haré un pequeño software de control de obra pública para contratistas y creo que visual FoxPro 9 es una buena alternativa para ello, ya que será un sistema de escritorio. De antemano muchas gracias por tu aportación. Atentamente Juan Carlos Ojeda
ResponderBorrarTENGO UN ARCHIVO YA DISEÑADO EN WORD, AL CUAL SOLO REQUIERO PASAR ALGUNOS DATOS DE UNA TABLA DE VISUAL FOX, TIPO COMBINAR CORRESPONDENCIA, POR METODO DE REEMPLAZO, ASI EVITO REDISEÑAR DE NUEVO EL DOCUMENTO Y SOLO ACTUALIZO LOS DATOS DESDE VISUAL FOX. HABRÁ UNA MANERA DE AUTOMATIZARLO. ALGUIEN ME PUEDE AYUDAR. MI CORREO ES f3rcho68@icloud.com
ResponderBorrarHice todo el procedimiento, pero en
ResponderBorrarWITH toDoc.MailMerge
.MainDocumentType = 0 && wdFormLetters
.OpenDataSource(THIS.cDataSource)
.Execute()
ENDWITH
no me reconoce el cDataSource, y me saca el formulario sin reemplazar los campos
O sea saca el formulario original con los nombres de las variables.