Word Automation C++ Class

Environment: VC++ 6.0, Windows 2000 with MS-Office installed.

In this article, I will describe the implementation of a C++ class that automates Microsoft Word application. The class uses low-level COM and is quite handy in its usage. The idea came into my mind when I answered two queries on this topic on a discussion forum in just one day!

I named the class 'CAutoWord'. It can open a Word documment file and print its contents on the default printer. Everything works in the background. A typical application can be an NT service which generally runs without any UI. It has following exposed methods.

1. CAutoWord() : Constructor function that initializes COM.
2. int InitAutomation() : Initializes the automation. In case of failure, it returns -1 else 0 is returned.
3. int PrintDocument() : This function will load the file and print the contents on the default printer. Negative return value indicates that an error occurred.

More functions can be added using the same framework.

Usage Scenario

The code snippet given below demonstrates its usage.
#include "AutoWord.h"

int PrintWordDocument(CString szFilePath)
{
 // Instantiate an object of CAutoWord
 CAutoWord	AutoWord;

 // Set filepath 
 int iRetVal = AutoWord.InitAutomation();
 if (iRetVal != 0)
 {
  printf("LoadDocument operation failed.");
 }

 // Set filepath 
 char* strFilePath = szFilePath.GetBuffer(szFilePath.
                                          GetLength));

 // Print the WORD document
 iRetVal = AutoWord.PrintDocument(strFilePath);
 if (iRetVal == 0)
 {
  AfxMessageBox(szFilePath+" was sent to printer.");
 }
 else
 {
  AfxMessageBox("Print operation failed.");
 }

 return iRetVal;
}

Implementation

Following is CAutoWord class declaration :
#include <oaidl.h>

class CAutoWord  
{
 void Destroy(); // Cleaup function

public:
 // Opens, Prints and closes a document
 int PrintDocument(char* strFilepath); 

 // Initializes the automation class and prepares 
 // it for use.
 int InitAutomation(); 

 // Constructor : Initializes COM libraries
 CAutoWord();      
 
 // Destructor : Calls Detroy() and UnInitializes COM.
 virtual ~CAutoWord(); 

private:
 // Keeps value of Dispatch pointer to 
 // 'Word.Application' instance
 IDispatch* m_pDispApp;    

 // Keeps a pointer to 'Documents' property of 
 // m_pDispApp interface.
 IDispatch* m_pDocuments;  
};

Most of the work is done InitAutomation() and PrintDocument() functions.

InitAutomation() creates an instance of the 'Word.Application' object and obtains the pointer to the instance's IUnknown interface.

IUnknown* pUnk;
HRESULT hr = ::CoCreateInstance( clsid, 
                                 NULL, 
                                 CLSCTX_LOCAL_SERVER, 
                                 IID_IUnknown, 
                                 (void**) &pUnk);
Calling QueryInterface() on IUnknown gives a pointer to the IDispatch interface (m_pDispApp).
hr = pUnk->QueryInterface(IID_IDispatch, 
                          (void**)&m_pDispApp);
Using GetIDsOfNames(), we get Dispatch Id of 'Documents' property of m_pDispApp interface.
LPOLESTR szDoc = L"Documents";   
hr = m_pDispApp->GetIDsOfNames(IID_NULL, 
                               &szDoc, 
                               1, 
                               LOCALE_SYSTEM_DEFAULT, 
                               &dispID);
Now, Invoke() function is called that gives us Dispatch pointer to its 'Documents' property. The pointer is saved in m_pDocuments member variable.
hr = m_pDispApp->Invoke(dispID, 
                        IID_NULL, 
                        LOCALE_SYSTEM_DEFAULT, 
                        DISPATCH_PROPERTYGET, 
                        &dp, 
                        &varRetVal, 
                        NULL, 
                        NULL);
...
m_pDocuments = varRetVal.pdispVal;

PrintDocument() method gets the Dispatch Id of 'Open' method of m_pDocuments interface. Then the invoke function is called with the Word Document's filepath as a parameter. This returns a pointer to the Dispatch interface to this Word document. We call it pDocument.

LPOLESTR szOpenDoc = L"Open";
HRESULT hr = m_pDocuments->GetIDsOfNames(IID_NULL, 
                                         &szOpenDoc, 
                                         1, 
                                         LOCALE_SYSTEM_DEFAULT, 
                                         &dispOpenID);
hr = m_pDocuments->Invoke(dispOpenID, 
                          IID_NULL, 
                          LOCALE_SYSTEM_DEFAULT, 
                          DISPATCH_METHOD, 
                          &dpOpen, 
                          &varRetVal, 
                          &excepInfo, 
                          NULL);
...
IDispatch* pDocument = varRetVal.pdispVal;
After pDocument is obtained, it's 'PrintOut' method is called. This actually prints out the contents of the Word Document on the default printer and the document is closed.
LPOLESTR szPrintDoc = L"PrintOut";
hr = pDocument->GetIDsOfNames(IID_NULL, 
                              &szPrintDoc, 
                              1, 
                              LOCALE_SYSTEM_DEFAULT, 
                              &dispPrintID);
hr = pDocument->Invoke(dispPrintID, 
                       IID_NULL, 
                       LOCALE_SYSTEM_DEFAULT, 
                       DISPATCH_METHOD, 
                       &dpPrint, 
                       &varRetVal, 
                       NULL, 
                       NULL);
...
LPOLESTR szCloseDoc = L"Close";
hr = pDocument->GetIDsOfNames(IID_NULL, 
                              &szCloseDoc, 
                              1, 
                              LOCALE_SYSTEM_DEFAULT, 
                              &dispCloseID);
hr = pDocument->Invoke(dispCloseID, 
                       IID_NULL, 
                       LOCALE_SYSTEM_DEFAULT, 
                       DISPATCH_METHOD, 
                       &dpClose, 
                       &varRetVal, 
                       &excepInfo, 
                       NULL);

The Destroy() method simply quits the Word Application's instance.

LPOLESTR szQuit = L"Quit";
HRESULT hr = m_pDispApp->GetIDsOfNames(IID_NULL, 
                                       &szQuit, 
                                       1, 
                                       LOCALE_SYSTEM_DEFAULT, 
                                       &dispQuit);
hr = m_pDispApp->Invoke(dispQuit, 
                        IID_NULL, 
                        LOCALE_SYSTEM_DEFAULT, 
                        DISPATCH_METHOD, 
                        &dpQuit, 
                        &varRetVal, 
                        &excepInfo, 
                        NULL);
The Demo project uses CAutoWord class to print the Word files.

Downloads

Download source - 2 Kb
Download demo project - 4 Kb


Comments

  • how to export/extract image in word doc?

    Posted by jauming on 04/12/2009 08:36am

    how to export/extract image in word doc?

    Reply
  • Cool -- but how to get other methods besides print to work ?

    Posted by Mike Pliam on 09/29/2007 05:34pm

    This is a nice piece of work -- but how can one get a list of the available methods and how to invoke them? Are they in a typelib (*tlb) somewhere? Where? Why are there no replies to these comments / questions ? Has the author gone into hiding?

    Reply
  • Very Good !!!

    Posted by anantwakode on 02/17/2006 06:19am

    Very Good !!!

    Reply
  • Using SaveAs method on document object

    Posted by poc0123 on 11/10/2005 01:47pm

    has anybody used this method with more than one dispparam, ie more that just the filename to save doc to? i tried and it's failing... -- poc

    Reply
  • Export text

    Posted by ceekay on 02/16/2005 08:07am

    I need to be able to select the entire document and export it to txt in C++

    Reply
  • How can I change the printer instead of printing to the default printer.

    Posted by Legacy on 05/14/2003 12:00am

    Originally posted by: Shruti Pandey

    Hi,

    I need to do load balancing of the prints, so I need to be able to set different printers on the network rather than just go to the default printer. How can I do that ??? I would really appreciate it if you could help me out.

    Thanks alot
    -Shruti

    Reply
  • How to save as HTML?

    Posted by Legacy on 12/03/2001 12:00am

    Originally posted by: Martin Bostrom

    I've tried to modify the code to save a file to HTML, without any success. First I recorded a macro in Word to see what it would look like in VBasic, then tried to do this in C++. I guess I really don't know what I'm doing with the array of arguments sent to Invoke via the DISPPARAMS structure. Any help would be appreciated.
    
    

    Code snippet (*NOT WORKING*):

    VARIANTARG vargFname;
    vargFname.vt = VT_BSTR;
    vargFname.bstrVal = _bstr_t("c:\\temp\\bar.htm");

    VARIANTARG vargFileFormat;
    vargFileFormat.vt = VT_INT;
    vargFileFormat.intVal = 103;

    VARIANTARG vargLockComments;
    vargLockComments.vt = VT_BOOL;
    vargLockComments.boolVal = VARIANT_TRUE;

    VARIANTARG vargPassword;
    vargPassword.vt = VT_BSTR;
    vargPassword.bstrVal = _bstr_t("");

    VARIANTARG vargAddToRecentFiles;
    vargAddToRecentFiles.vt = VT_BOOL;
    vargAddToRecentFiles.boolVal = VARIANT_TRUE;

    VARIANTARG vargWritePassword;
    vargWritePassword.vt = VT_BSTR;
    vargWritePassword.bstrVal = _bstr_t("");

    VARIANTARG vargReadOnlyRecommended;
    vargReadOnlyRecommended.vt = VT_BOOL;
    vargReadOnlyRecommended.boolVal = VARIANT_FALSE;

    VARIANTARG vargEmbedTrueTypeFonts;
    vargEmbedTrueTypeFonts.vt = VT_BOOL;
    vargEmbedTrueTypeFonts.boolVal = VARIANT_FALSE;

    VARIANTARG vargSaveNativePictureFormat;
    vargSaveNativePictureFormat.vt = VT_BOOL;
    vargSaveNativePictureFormat.boolVal = VARIANT_FALSE;

    VARIANTARG vargSaveFormsData;
    vargSaveFormsData.vt = VT_BOOL;
    vargSaveFormsData.boolVal = VARIANT_FALSE;

    VARIANTARG vargSaveAsAOCELetter;
    vargSaveAsAOCELetter.vt = VT_BOOL;
    vargSaveAsAOCELetter.boolVal = VARIANT_FALSE;

    VARIANTARG argArray [11];

    argArray[10]=vargFname;
    argArray[ 9]=vargFileFormat;
    argArray[ 8]=vargLockComments;
    argArray[ 7]=vargPassword;
    argArray[ 6]=vargAddToRecentFiles;
    argArray[ 5]=vargWritePassword;
    argArray[ 4]=vargReadOnlyRecommended;
    argArray[ 3]=vargEmbedTrueTypeFonts;
    argArray[ 2]=vargSaveNativePictureFormat;
    argArray[ 1]=vargSaveFormsData;
    argArray[ 0]=vargSaveAsAOCELetter;


    DISPPARAMS dpSave = { argArray, NULL, 11, 0 };
    DISPID dispSaveID;
    LPOLESTR szSaveDoc = L"SaveAs";
    hr = pDocument->GetIDsOfNames(IID_NULL, &szSaveDoc, 1, LOCALE_SYSTEM_DEFAULT, &dispSaveID);
    hr = pDocument->Invoke(dispSaveID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dpSave, &varRetVal, NULL, NULL);
    if (FAILED(hr))
    {
    OutputDebugString("The document could not be saved\n");
    Destroy();
    return -1;
    }

    Reply
  • Print Preview ?

    Posted by Legacy on 08/04/2001 12:00am

    Originally posted by: ramanan

    It's realy nice article. But my q'tion is
    How can i preview the document without printing ?
    thanks in advance

    Ramanan

    Reply
  • How to print to a printer driver whch creates a file ?

    Posted by Legacy on 04/25/2001 12:00am

    Originally posted by: Peter van de Velde

    I tried the code but when I try to print to a file (for example acrobat writer) Word will require user interaction
    while it wants a file name. How can I avoid total user interaction ?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

  • Corporate e-Learning technology has a long and diverse pedigree. As far back as the 1980s, companies were adopting computer-based training to supplement traditional classroom activities. More recently, rich web-based applications have added streaming audio and video, real-time collaboration and other new tools to the e-Learning mix. At the same time, the growing availability of informal learning tools--a category that includes everything from web searches to social media posts--are having a major impact on …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds