How To Use Automation to Retrieve Built-in Document Properties (179494)



The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), when used with:
    • Microsoft Visual C++, 32-bit Editions 5.0
    • Microsoft Visual C++, 32-bit Editions 6.0
    • Microsoft Word 97 for Windows
  • Microsoft Office XP Developer
  • Microsoft Office 2000 Developer

This article was previously published under Q179494

SUMMARY

This article discusses how to use version 4.2 of the Microsoft Foundation Class (MFC) library installed with Microsoft Visual C++ versions 5.0 and 6.0 to find and print the built-in document properties of a Microsoft Word document. The built-in document properties include the document's title, subject, author, keywords, comments, template, dates, number of pages, words, characters and many other properties.

MORE INFORMATION

You can copy the code in this article to the message handler function of an event defined in an MFC .cpp file. However, the purpose of the code is to illustrate the process of using the IDispatch interfaces and member functions defined in the MSWord type library. The primary benefit comes from reading and understanding the code in the example so that you can modify the example, or write code from scratch to automate finding and printing a list of the built-in document properties.

Steps to Create the Project

  1. In Microsoft Word, create a new document named Test.doc, and then save it the root directory of drive C.
  2. Follow steps 1 through 12 in the following Microsoft Knowledge Base article to create a sample project that uses the IDispatch interfaces and member functions defined in the MSWord8.olb type library:

    178749 How To Create an Automation Project Using MFC and a Type Library

  3. At the top of the AutoProjectDlg.cpp, add the following line:
          #include "MSWord8.h" // msword9.h for Word 2000, msword.h for Word 2002
    					
  4. Add the following code to CAutoProjectDlg::OnRun() in the AutoProjectDlg.cpp file.

    Sample Code

          _Application objWordApp;
          _Document objDoc;
          LPDISPATCH lpDisp;
          Range objRange;
    
          // Common OLE variants that are easy to use for calling arguments.
          COleVariant covTrue((short)TRUE),
                      covFalse((short)FALSE),
                      covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    
          objWordApp.CreateDispatch("Word.Application");
          objWordApp.SetVisible(TRUE);
    
          Documents docs(objWordApp.GetDocuments());
    
          lpDisp = docs.Open(COleVariant("C:\\Test.doc",VT_BSTR),
                                              covFalse,    // Confirm.
                                                           // Conversion.
                                              covFalse,    // ReadOnly.
                                              covFalse,    // AddToRecentFiles.
                                              covOptional, // NULL,
                                                           // PasswordDocument.
                                              covOptional, // PasswordTemplate.
                                              covFalse,    // Revert.
                                              covOptional, // Write-
                                                           // PasswordDocument.
                                              covOptional, // Write-
                                                           // PasswordTemplate.
    
                                              covOptional  // Format. //Last parameter for Word 97
                                                 covOptional, // Encoding // Word 2000/2002 from here on
                                                 covTrue,     // Visible
                                                 covOptional, // OpenConflictDocument
                                                 covOptional, // OpenAndRepair
                                                 (long)0,     // DocumentDirection 
                                                              //wdDocumentDirection LeftToRight
                                                 covOptional  // NoEncodingDialog
                                              );
    
           objDoc.AttachDispatch(lpDisp);
           lpDisp = objDoc.GetContent();
           objRange.AttachDispatch(lpDisp);
    
           // Move the insertion point to the beginning of the document.
           objRange.Collapse(COleVariant((long)1));  //0 = wdCollapseEnd.
           objRange.InsertAfter("Here are the BuiltInDocumentProperties!!");
           objRange.InsertParagraphAfter(); // Write them one-by-one in a loop.
           lpDisp = objDoc.GetBuiltInDocumentProperties();
    
           COleDispatchDriver rootDisp[64];  // Temporary object array.
           int curRootIndex = 0;             // Index into rootDisp[] array.
           DISPID dispID;                    // Temporary dispid for use in
                                             // OleDispatchDriver::
                                             // InvokeHelper().
           DISPID dispID2;                   // Dispid for 'Value'.
           unsigned short *ucPtr;            // Temporary name holder for
                                             // IDispatch::GetIDsOfNames().
           VARIANT vtResult;                 // Holds results from
                                             // OleDispatchDriver::
                                             // InvokeHelper().
           VARIANT vtResult2;                // Holds result for 'Type'.
           BYTE *parmStr;                    // Holds parameter descriptions
                                             // for COleDispatchDriver::
                                             // InvokeHelper().
           rootDisp[0].AttachDispatch(lpDisp);  // LPDISPATCH returned from
                                             // GetBuiltInDocumentProperties.
           VARIANT i;                        // integer;
           VARIANT count;                    // integer;
           char buf[512];                    // General purpose message buffer.
           char buf2[512];
    
           ucPtr = L"Count";                 // Collections have a Count
                                             // member.
    
           try
           {
    
            rootDisp[curRootIndex].m_lpDispatch->GetIDsOfNames(
                                                    IID_NULL,
                                                    &ucPtr,
                                                    1,
                                                    LOCALE_USER_DEFAULT,
                                                    &dispID);
    
    
            rootDisp[curRootIndex].InvokeHelper(dispID,
                                               DISPATCH_METHOD |
                                               DISPATCH_PROPERTYGET,
                                               VT_VARIANT,
                                               (void *)&vtResult,
                                               NULL);
    
            count = vtResult;  // Require a separate variable for loop limiter.
            // For i = 1 to count,
            // get the Item, Name & Value members of the collection.
            i.vt = VT_I4;
            for(i.lVal=1; i.lVal<=count.lVal; i.lVal++)
            {
             ucPtr = L"Item";  // Collection has an Item member.
             rootDisp[curRootIndex].m_lpDispatch->GetIDsOfNames(
                                                    IID_NULL,
                                                    &ucPtr,
                                                    1,
                                                    LOCALE_USER_DEFAULT,
    
                                                    &dispID);
    
    
             parmStr = (BYTE *)( VTS_VARIANT );
             rootDisp[curRootIndex].InvokeHelper(dispID,
                                                DISPATCH_METHOD |
                                                DISPATCH_PROPERTYGET,
                                                VT_VARIANT,
                                                (void *)&vtResult,
                                                parmStr,
                                                &COleVariant(i));
    
             // Move to the next element of the array.
             // Get the Name member for the Item.
             rootDisp[++curRootIndex].AttachDispatch(vtResult.pdispVal);
             ucPtr = L"Name";  // Collection has a Name member
             rootDisp[curRootIndex].m_lpDispatch->GetIDsOfNames(
                                                    IID_NULL,
                                                    &ucPtr,
                                                    1,
                                                    LOCALE_USER_DEFAULT,
                                                    &dispID);
    
             rootDisp[curRootIndex].InvokeHelper(dispID,
                                                DISPATCH_METHOD |
                                                DISPATCH_PROPERTYGET,
                                                VT_VARIANT,
                                                (void *)&vtResult,
                                                NULL);
    
              ucPtr = L"Value";  // Collection has a Value member.
              rootDisp[curRootIndex].m_lpDispatch->GetIDsOfNames(
                                                IID_NULL,
                                                &ucPtr,
                                                1,
                                                LOCALE_USER_DEFAULT,
                                                &dispID2);
    
              rootDisp[curRootIndex].InvokeHelper(dispID2,
                                                DISPATCH_METHOD |
                                                DISPATCH_PROPERTYGET,
                                                VT_VARIANT,
                                                (void *)&vtResult2,
                                                NULL);
           Continue: // Come back here from Catch(COleDispatchException).
    
             rootDisp[curRootIndex--].ReleaseDispatch();
    
             // Initialize buf2 with representation of the value.
    
             switch(vtResult2.vt) // Type of property.
             {
              case VT_BSTR:
                sprintf(buf2, "%s", (CString)vtResult2.bstrVal);
                break;
              case VT_DATE:
              {
                COleDateTime codt(vtResult2.date);
                sprintf(buf2, "Time = %d:%02d, Date = %d/%d/%d",
                  codt.GetHour(), codt.GetMinute(),
                  codt.GetMonth(), codt.GetDay(), codt.GetYear()
                   );
              }
                break;
              case VT_I4:
                sprintf(buf2, "%ld", vtResult2.lVal);
                break;
              default:
                sprintf(buf2, "not VT_BSTR, VT_DATE, or VT_I4");
             }  // End of Switch.
    
             sprintf(buf, "Item(%d).Name = %s, .Type = %d, .Value = %s\n",
                    i.lVal, CString(vtResult.bstrVal), vtResult2.vt, buf2);
    
             objRange.Collapse(COleVariant((long)0));  // Move insertion point
                                                       // to end of the range.
             objRange.InsertAfter(CString(buf));  // Insert after the insertion
                                                  // point.
    
            }  ////////////////// End of For loop. /////////////////////// 
    
            objRange.InsertParagraphAfter(); // Spacing.
            objRange.InsertAfter("");
            objRange.InsertParagraphAfter(); // Spacing.
    
            // Release IDispatch pointers on local objects.
            if(vtResult.vt == VT_DISPATCH) vtResult.pdispVal->Release();
            if(count.vt == VT_DISPATCH) count.pdispVal->Release();
            rootDisp[0].ReleaseDispatch();
    
            AfxMessageBox("All done, waiting...");
            objDoc.SetSaved(TRUE);  // Hides the "Save your changes..." dialog.
            AfxMessageBox("Word will close now. Goodbye");
    
            objWordApp.Quit(covFalse, covFalse, covFalse);
    
           }  // End try.
    
           catch(COleException *e)
           {
            sprintf(buf, "COleException. SCODE: %08lx.", (long)e->m_sc);
            ::MessageBox(NULL, buf, "COleException", MB_SETFOREGROUND | MB_OK);
           }
    
           catch(COleDispatchException *e)
           {
             if(vtResult2.vt ==VT_ERROR)
             {
               AfxMessageBox("Discarding vtResult2.VT_ERROR");
    
             }
             vtResult2.vt = VT_BSTR;
             vtResult2.bstrVal = L"Value not available";
             goto Continue;
           }
    
           catch(...)
           {
            MessageBox( "General Exception caught.", "Catch-All",
            MB_SETFOREGROUND | MB_OK);
           }
    
           //////////////////// For information only. ///////////////////// 
           //          Do not uncomment the following code snippet.          // 
           //  You can copy it and use it in lieu of the previous code when  // 
           //             you need to see just one property.                 // 
           /***************** Code to get a single property. *****************
           // Works for one property.
           COleDispatchDriver myDocumentProperties(lpDisp);
           COleVariant result;
           // Get myDocumentProperties.Item(1).
           // Item(n) where n = property index
           // value in properties collection.
           UCHAR *parmStr = (BYTE *)( VTS_VARIANT );
           myDocumentProperties.InvokeHelper(0, DISPATCH_METHOD |
                                             DISPATCH_PROPERTYGET,
                                             VT_VARIANT,
                                             (void *)&result,
                                             parmStr,
                                             &COleVariant((long)1));
    
           COleDispatchDriver myDocumentProperty(result.pdispVal);
    
           // Get Name of this document property.
    
           myDocumentProperty.InvokeHelper(3, DISPATCH_METHOD |
                                              DISPATCH_PROPERTYGET,
                                              VT_VARIANT,
                                              (void *)&result,
                                              NULL);
    
           AfxMessageBox(CString("Item(1).Name =") + CString(result.bstrVal));
    
           // Release this document property.
           myDocumentProperty.ReleaseDispatch();
    
           // Release the document properties collection.
           myDocumentProperties.ReleaseDispatch();
    
           //*************** End of code for single property. ****************/ 
    
    					
  5. You may need to modify the code in CAutoProjectDlg::OnRun() to indicate the correct path for your document Test.doc. The document is referenced in the following line:
          lpDisp = docs.Open(COleVariant("C:\\Test.doc",VT_BSTR),
    					

REFERENCES

For additional information about the Automation of Office applications, click the article number below to view the article in the Microsoft Knowledge Base:

222101 How To Find and Use Office Object Model Documentation


Modification Type:MinorLast Reviewed:3/18/2005
Keywords:kbAutomation kbFAQ kbhowto kbinterop KB179494