Automatización de Microsoft Word para realizar una combinación de correspondencia mediante Visual C++ y MFC

Resumen

En este artículo se muestra cómo crear y manipular un documento de Microsoft Word mediante Automation desde Microsoft Visual C++ y Microsoft Foundation Classes (MFC).

Más información

Este artículo es paralelo a un artículo de Microsoft Knowledge Base que describe el mismo proceso mediante Microsoft Visual Basic.

Creación del ejemplo de automatización

  1. Con Microsoft Developer Studio, inicie un nuevo proyecto "MFC AppWizard (exe)" denominado "AutoProject".

  2. En el paso 1 del Asistente para aplicaciones MFC, elija "Basado en cuadros de diálogo" para el tipo de aplicación y, a continuación, haga clic en Finalizar.

    Aparece el cuadro de diálogo Nueva información del proyecto e indica que las clases que se van a crear incluyen:

    Application: CAutoProjectApp in AutoProject.h and AutoProject.cpp
    Dialog: CAutoProjectDlg in AutoProject.h and AutoProjectDlg.cpp
    

    Haga clic en Aceptar para crear el proyecto.

  3. El cuadro de diálogo "IDD_AUTOPROJECT_DIALOG" se abre en el área de diseño o edición de Visual Studio. Modifíquelo según las instrucciones de los dos pasos siguientes.

  4. Quite el control Etiqueta (IDC_STATIC) y el botón Cancelar (IDCANCEL).

  5. Cambie el nombre del botón Aceptar a "IDRUN" y el título a "Ejecutar". Cierre el formulario de diseño del cuadro de diálogo AutoProject.rc.

  6. Haga clic en ClassWizard en el menú Ver (o presione CTRL+W).

  7. Seleccione la pestaña Mapas de mensajes. Seleccione IDRUN en el cuadro de lista Ids de objeto y seleccione "BN_CLICKED" en el cuadro de lista Mensajes. Haga clic en Agregar función y acepte el nombre de función "OnRun". Haga clic en Aceptar para cerrar classwizard.

    NOTA:** Este paso agrega una declaración para el miembro de función "OnRun();" al archivo de encabezado denominado AutoProjectDLG.h. En este paso también se agrega una función de controlador de mensajes de esqueleto vacía denominada CAutoProjectDlg::OnRun() al archivo denominado AutoProjectDLG.cpp.

  8. Haga clic en ClassWizard en el menú Ver (o presione CTRL+W).

  9. Seleccione la pestaña Automatización. Haga clic en Agregar clase y elija "Desde una biblioteca de tipos". Vaya a seleccionar la biblioteca de objetos de la aplicación que desea automatizar (para este ejemplo, si va a automatizar Excel 97, elija la Biblioteca de objetos de Microsoft Excel 8.0; la ubicación predeterminada es C:\Archivos de programa\Microsoft Office\Office\Excel8.olb).

    Si va a automatizar Microsoft Excel 2000, elija Biblioteca de objetos de Microsoft Excel 9.0 para la que la ubicación predeterminada es C:\Archivos de programa\Microsoft Office\Office\Excel9.olb.

    Si va a automatizar Microsoft Excel 2002 y Microsoft Office Excel 2003, la biblioteca de objetos se incrusta en el archivo Excel.exe. La ubicación predeterminada para Excel.exe en Office 2002 es C:\archivos de programa\Microsoft Office\Office10\Excel.exe. La ubicación predeterminada para Excel.exe en Office 2003 es C:\archivos de programa\Microsoft Office\Office11\Excel.exe. Una vez que haya seleccionado la biblioteca de objetos adecuada, haga clic en Abrir. Seleccione todas las clases en la lista Confirmar clases y, a continuación, haga clic en Aceptar.

    NOTA El cuadro de lista del cuadro de diálogo Confirmar clases contiene todas las interfaces IDispatch (que son prácticamente idénticas a las clases) de la biblioteca de tipos de Microsoft Excel. En la mitad inferior del cuadro de diálogo verá que un archivo de implementación denominado Excel8.cpp contiene contenedores de clase generados derivados de ColeDispatchDriver() y el archivo de encabezado de declaración adecuado se denomina Excel8.h. (Para Excel 2002 y Excel 2003, los archivos se denominan Excel.cpp y Excel.h.)

    Nota Elija la biblioteca de tipos correcta para la versión de Word que va a automatizar. Consulte la sección referencias a continuación para obtener información sobre cómo buscar la biblioteca de tipos correctamente.

  10. Haga clic en Aceptar para cerrar el cuadro de diálogo ClassWizard de MFC.

  11. Agregue el código siguiente a la función CAutoProjectApp::InitInstance(), que carga y habilita la biblioteca de servicios COM:

    BOOL CAutoProjectApp::InitInstance()
      {
         if(!AfxOleInit())  // Your addition starts here
         {
            AfxMessageBox("Could not initialize COM dll");
            return FALSE;
         }                 // End of your addition
    
         AfxEnableControlContainer();
      .
      .
      .
    
      }
    
  12. Agregue la siguiente línea a las instrucciones #include en la parte superior del archivo de programa AutoProject.cpp:

      #include <afxdisp.h>
    
  13. Agregue la instrucción include para el archivo de encabezado que se creó anteriormente (msword8.h, msword9.h o msword.h) en AutoProjectDlg.cpp después de la instrucción include para stdafx.h. Un ejemplo para Word 97 sería:

       #include "stdafx.h"
       #include "msword8.h"
    
    
  14. Agregue código de Automation al método CAutoProjectDlg::OnRun para que aparezca como se muestra a continuación:

    void CAutoProjectDlg::OnRun()
    {
    _Application oWord;
    Documents oDocs;
    _Document oDoc;
    Selection oSelection;
    Paragraphs oParagraphs;
    Tables oTables;
    Table oTable;
    Range oRange;
    Columns oColumns;
    Column oColumn;
    Rows oRows;
    Row oRow;
    
    Cells oCells;
    Cell oCell; 
    Shading oShading;
    Hyperlinks oHyperlinks;
    MailMerge oMailMerge;
    MailMergeFields oMailMergeFields;
    COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR),
            vtTrue((short)TRUE),
    vtFalse((short)FALSE);
    CString StrToAdd;
    
    // Create an instance of Word
    if (!oWord.CreateDispatch("Word.Application")) {
    AfxMessageBox("Word failed to start!");
    } else {
    // Set the visible property
    oWord.SetVisible(TRUE);
    // Add a new document
    oDocs = oWord.GetDocuments();
    oDoc = oDocs.Add(vtOptional,vtOptional);
    
    CreateMailMergeDataFile(&oWord,&oDoc);
    // Add the address header
    
    StrToAdd = "State University\r\nElectrical Engineering " \ 
           "Department";
    oSelection = oWord.GetSelection();
    
    oParagraphs = oSelection.GetParagraphs();
    oParagraphs.SetAlignment(1);  // 1 = wdAlignParagraphCenter  
    oSelection.TypeText(StrToAdd);
    
    InsertLines(&oSelection,4);
    
    oParagraphs.SetAlignment(0);  // 0 = wdAlignParagraphLeft
    oMailMerge = oDoc.GetMailMerge();
    oMailMergeFields = oMailMerge.GetFields();
    oMailMergeFields.Add(oSelection.GetRange(),"FirstName");
    oSelection.TypeText(" ");
    oMailMergeFields.Add(oSelection.GetRange(),"LastName");
    oSelection.TypeParagraph();
    oMailMergeFields.Add(oSelection.GetRange(),"Address");
    oSelection.TypeParagraph();
    oMailMergeFields.Add(oSelection.GetRange(),"CityStateZip");
    
    InsertLines(&oSelection,4);
    // Set the paragraph alignment to Right justified
    oParagraphs = oSelection.GetParagraphs();
    
    oParagraphs.SetAlignment(2);  // 2 = wdAlignParagraphRight
    // Insert the current date
    oSelection.InsertDateTime(COleVariant("dddd, MMMM dd, yyyy"),\ 
     vtFalse,vtOptional);
    
    InsertLines(&oSelection,2);
    
    // Reset the justification to Justify
    
    oParagraphs = oSelection.GetParagraphs();
    oParagraphs.SetAlignment(3);  // 3 = wdAlignParagraphJustify
    
    oSelection.TypeText("Dear ");
    oMailMergeFields.Add(oSelection.GetRange(),"FirstName");
    oSelection.TypeText(",");
    
    InsertLines(&oSelection,2);
    
    // Add the body of the message
    StrToAdd = "Thank you for your recent request for next " \ 
           "semester's class schedule for the Electrical " \ 
           "Engineering Department.  Enclosed with this letter " \ 
           "is a booklet containing all the classes offered " \ 
           "next semester at State University.  Several new " \ 
           "classes will be offered in the Electrical " \ 
              "Engineering Department next semester.  These " \ 
           "classes are listed below.";
    oSelection.TypeText(StrToAdd);
    
    InsertLines(&oSelection,2);
    
    // Add a new table with 9 rows and 4 columns
    oRange = oSelection.GetRange();
    oTables = oDoc.GetTables();
    oTable = oTables.Add(oRange,9,4);
    
    // Set the width of each column
    oColumns = oTable.GetColumns();
    oColumn = oColumns.Item(1);
    oColumn.SetWidth(51.0,0);  // 0 = wdAdjustNone
    oColumn = oColumns.Item(2);
    oColumn.SetWidth(198.0,0);  // 0 = wdAdjustNone
    oColumn = oColumns.Item(3);
    oColumn.SetWidth(100.0,0);  // 0 = wdAdjustNone
    oColumn = oColumns.Item(4);
    oColumn.SetWidth(111.0,0);  // 0 = wdAdjustNone
    
    // Set the shading for row 1 to wdGray25
    oRows = oTable.GetRows();
    oRow = oRows.Item(1);
    oCells = oRow.GetCells();
    oShading = oCells.GetShading();
    oShading.SetBackgroundPatternColorIndex(16); // 16 = wdGray25
    
    // Turn on BOLD for the first row
    oRange = oRow.GetRange();
    oRange.SetBold(TRUE);
    
    // Set the alignment for cell (1,1) to center
    oCell = oTable.Cell(1,1);
    oRange = oCell.GetRange();
    oParagraphs = oRange.GetParagraphs();
    oParagraphs.SetAlignment(1);  // 1 = wdAlignParagraphCenter
    
    // Fill in the class schedule data
    FillRow(&oTable,1,"Class Number","Class Name",\ 
    "Class Time","Instructor");
    FillRow(&oTable,2, "EE220", "Introduction to Electronics II", \ 
    "1:00-2:00 M,W,F", "Dr. Jensen");
    FillRow(&oTable,3, "EE230", "Electromagnetic Field Theory I", \ 
    "10:00-11:30 T,T", "Dr. Crump");
    FillRow(&oTable,4, "EE300", "Feedback Control Systems", \ 
    "9:00-10:00 M,W,F", "Dr. Murdy");
    FillRow(&oTable,5, "EE325", "Advanced Digital Design", \ 
    "9:00-10:30 T,T", "Dr. Alley");
    FillRow(&oTable,6, "EE350", "Advanced Communication Systems", \ 
    "9:00-10:30 T,T", "Dr. Taylor");
    FillRow(&oTable,7, "EE400", "Advanced Microwave Theory", \ 
    "1:00-2:30 T,T", "Dr. Lee");
    FillRow(&oTable,8, "EE450", "Plasma Theory", \ 
    "1:00-2:00 M,W,F", "Dr. Davis");
    FillRow(&oTable,9, "EE500", "Principles of VLSI Design", \ 
    "3:00-4:00 M,W,F", "Dr. Ellison");
    
    // Go to the end of the document
    oSelection.GoTo(COleVariant((short)3), // 3 = wdGoToLine
    COleVariant((short)-1),vtOptional,vtOptional);  // -1 = wdGoToLast
    
    InsertLines(&oSelection,2);
    
    // Add closing text
    StrToAdd = "For additional information regarding the " \ 
                 "Department of Electrical Engineering, " \ 
                 "you can visit our website at ";
    oSelection.TypeText(StrToAdd);
    
    // Add a hyperlink to the homepage
    oHyperlinks = oSelection.GetHyperlinks();
    oHyperlinks.Add(oSelection.GetRange(),\ 
    COleVariant("http://www.ee.stateu.tld"),vtOptional);
    
    // Finish adding closing text
    StrToAdd = ".  Thank you for your interest in the classes " \ 
                 "offered in the Department of Electrical " \ 
                 "Engineering.  If you have any other questions, " \ 
                 "please feel free to give us a call at (999) " \ 
                 "555-1212.\r\n\r\n" \ 
                 "Sincerely,\r\n\r\n" \ 
                 "Kathryn M. Hinsch\r\n" \ 
                 "Department of Electrical Engineering\r\n";
    oSelection.TypeText(StrToAdd);
    
    // Perform mail merge
    oMailMerge.SetDestination(0); // 0 = wdSendToNewDocument
    oMailMerge.Execute(vtFalse);
    
    // Close the original form document
    oDoc.SetSaved(TRUE);
    oDoc.Close(vtFalse,vtOptional,vtOptional);
    
    }
    }
    
    
  15. Inserte el código siguiente en el código que se indica en el paso 3:

    void InsertLines(Selection *pSelection, int NumLines)
    {
    int iCount;
    
    // Insert NumLines blank lines
    for (iCount = 1; iCount <= NumLines; iCount++)
    pSelection->TypeParagraph();
    }
    
    void FillRow(Table *pTable,int Row, CString Text1, 
     CString Text2, CString Text3, CString Text4)
    {
    Cell oCell;
    Range oRange;
    
    // Insert data into the specific cell
    oCell = pTable->Cell(Row,1);
    oRange = oCell.GetRange();
    oRange.InsertAfter(Text1);
    oCell = pTable->Cell(Row,2);
    oRange = oCell.GetRange();
    oRange.InsertAfter(Text2);
    oCell = pTable->Cell(Row,3);
    oRange = oCell.GetRange();
    oRange.InsertAfter(Text3);
    oCell = pTable->Cell(Row,4);
    oRange = oCell.GetRange();
    oRange.InsertAfter(Text4);
    
    }
    
    void CreateMailMergeDataFile(_Application *pApp,_Document *pDoc)
    {
      _Document oDataDoc;
      MailMerge oMailMerge;
      Documents oDocs;
      Tables oTables;
      Table oTable;
      Rows oRows;
      int iCount;
      COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR),
    vtFalse((short)FALSE);
    
    // Create a data source at C:\DataDoc.doc containing the field data
      oMailMerge = pDoc->GetMailMerge();
      oMailMerge.CreateDataSource(COleVariant("C:\\DataDoc.doc"), \ 
            vtOptional,vtOptional, \ 
            COleVariant("FirstName, LastName, Address,CityStateZip"),\ 
            vtOptional, vtOptional,vtOptional,vtOptional,vtOptional);
      // Open the file to insert data
      oDocs = pApp->GetDocuments();
      oDataDoc = oDocs.Open(COleVariant("C:\\DataDoc.doc"), \ 
           vtOptional,vtOptional,vtOptional,vtOptional,\ 
           vtOptional,vtOptional,vtOptional,vtOptional,\ 
           vtOptional);
      oTables = oDataDoc.GetTables();
      oTable = oTables.Item(1);
      oRows = oTable.GetRows();
      for (iCount=1; iCount<=2; iCount++)  
        oRows.Add(vtOptional);
    
    // Fill in the data
      FillRow(&oTable, 2, "Steve", "DeBroux", \ 
            "4567 Main Street", "Buffalo, NY  98052");
      FillRow(&oTable, 3, "Jan", "Miksovsky", \ 
            "1234 5th Street", "Charlotte, NC  98765");
      FillRow(&oTable, 4, "Brian", "Valentine", \ 
            "12348 78th Street  Apt. 214", "Lubbock, TX  25874");
      // Save and close the file
      oDataDoc.Save();
      oDataDoc.Close(vtFalse,vtOptional,vtOptional);
    }
    
    
  16. Compile y ejecute el programa. Haga clic en el botón Ejecutar y Microsoft Word debería iniciar y mostrar una letra de ejemplo. Tenga en cuenta que algunos métodos han cambiado con Word 2000 y Word 2002. Para obtener más información sobre estos cambios, consulte la sección "Referencias".

Referencias

Notas para automatizar Microsoft Word 2000 y Microsoft Word 2002

Algunos métodos y propiedades han cambiado para Microsoft Word 2000 y Microsoft Word 2002.

Para obtener más información sobre Office Automation, visite el sitio de soporte técnico de Desarrollo de Microsoft Office en: Soporte técnico de Microsoft