Word Automation using wxAutomation and wxVariant

Talk here about issues with one of the components hosted at wxCode, or suggest features for it.
Post Reply
charles_5577
In need of some credit
In need of some credit
Posts: 7
Joined: Mon Apr 25, 2022 9:18 am

Word Automation using wxAutomation and wxVariant

Post by charles_5577 »

First of all I have been programming in C++ for many years. However, it has just been a few weeks that I have attacked automation. Initially for Excel I got a bundle of help from the forum for using wxAutoExcel. Works fine. Now I am trying to control Word. My first task for this is to add a table to Word. On the internet I found the following link which describes the classes, properties and methods for Word Automation.

Microsoft.Office.Interop.Word Namespace | Microsoft Docs

In this documentation, to create a table we use Tables.Add which needs a Range.

Tables.Add(Range, Int32, Int32, Object, Object) Method

Unlike a lot of the other classes there is no Ranges collection class with a Add function to create a Range. So I first got a Bookmark which has a Range Property and used it.

So two questions:

How do you create a Range?
What do you use for the second parameter of the tables.CallMethod("Add", ?????????????, 6, 7); ?

My code is below.

wxAutomationObject application;
application.CreateInstance("Word.Application");
application.PutProperty("DisplayAlerts", false);
application.PutProperty("Visible", true);
wxAutomationObject documents;
application.GetObject(documents, "Documents");
wxVariant docVariant;
docVariant = documents.CallMethod("Add");
wxAutomationObject document((WXIDISPATCH*)docVariant.GetVoidPtr());
document.CallMethod("Activate");

// All good until here. Now I need to get a Range. There is no Range collection so I get a bookmark first which has a Range

wxAutomationObject bookmarks;
document.GetObject(bookmarks, "Bookmarks");
wxVariant variant;
variant = bookmarks.CallMethod("Item", "\\EndOfDoc"); // Get a existing bookmark
wxAutomationObject bookmark((WXIDISPATCH*) variant.GetVoidPtr());
wxAutomationObject range;
bookmark.GetObject(range, "Range");

// OK I have a Range. Now to add a table

wxAutomationObject tables;
document.GetObject(tables, "Tables") ;
wxVariant tableVariant;
wxVariant rangeVariant;
rangeVariant.Clear();

// From above the Tables.Add requires a Range, number of rows and columns and two optional
//parameters. The wxAutomationObject.CallMethod function requires a wxVariant for the second parameter.
// How do I turn a Range into a wxVariant?

tableVariant = tables.CallMethod("Add", ?????????????, 6, 7);
charles_5577
In need of some credit
In need of some credit
Posts: 7
Joined: Mon Apr 25, 2022 9:18 am

Re: Word Automation using wxAutomation and wxVariant

Post by charles_5577 »

I think I just figured out how to add a table by looking at some of the code in wxAutoExcel. This weems to work.

wxVariant rangeVariant;
rangeVariant.Clear();
IDispatch* dispatch = (IDispatch*)range.GetDispatchPtr();
dispatch->AddRef();
rangeVariant = (void*)dispatch;
tableVariant = tables.CallMethod("Add", rangeVariant, 6, 7);

I still would like to find out how to create a Range
PB
Part Of The Furniture
Part Of The Furniture
Posts: 3558
Joined: Sun Jan 03, 2010 5:45 pm

Re: Word Automation using wxAutomation and wxVariant

Post by PB »

Please use the code tags for code, it makes your posts more readable and thus increases changes of getting help.

I recommend using VBA documentation for automating MS Word.

As for the Range object, it depends which one (i.e., where) you want it: https://docs.microsoft.com/en-us/office ... ge-objects

For example, this SSCCE adds a styled table at the beginning of a new document:

Code: Select all

#include <wx/wx.h>
#include <wx/msw/ole/automtn.h>

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        wxVariant v;
        wxAutomationObject application, document, range, table;        

        // start word instance and show it
        if ( !application.GetInstance("Word.Application") )
        {
            wxLogError("Could not start Word.");
            return false;
        }
        application.PutProperty("Visible", true);
        application.PutProperty("DisplayAlerts", false);

        // Add empty document
        v = application.CallMethod("Documents.Add");
        if ( !v.IsType("void*") )
        {
            wxLogError("Could not add a new Document.");
            return false;
        }
        document.SetDispatchPtr((IDispatch*)v.GetVoidPtr());

        // Obtain a range from first characters in the document
        v = document.CallMethod("Range", 0, 1);
        if ( !v.IsType("void*") )
        {
            wxLogError("Could not obtain Range from a Document.");
            return false;
        }
        range.SetDispatchPtr((IDispatch*)v.GetVoidPtr());

        // Add table with 5 columns and 15 rows to range
        IDispatch* rangeIDispatch = (IDispatch*)range.GetDispatchPtr();
        rangeIDispatch->AddRef(); // we need to this because wxAutomationObject::Invoke() decreases the ref count of its parameters
        v = (void*)rangeIDispatch;
        v = document.CallMethod("Tables.Add", v, 15, 5);
        if ( !v.IsType("void*") )
        {
            wxLogError("Could not add a Table.");
            return false;
        }
        table.SetDispatchPtr((IDispatch*)v.GetVoidPtr());
        table.PutProperty("Style", -171); // -171 = wdStyleTableColorfulList

        return false;
    }
}; wxIMPLEMENT_APP(MyApp);
There is nothing difficult about using wxAutomationObject. One just needs to learn its API and understand how to convert between wxVariant and wxAutomationObject. The rest is just painful drudgery.

EDIT Simplified the code a bit by removing unused objects.
Last edited by PB on Wed Aug 03, 2022 9:05 am, edited 1 time in total.
charles_5577
In need of some credit
In need of some credit
Posts: 7
Joined: Mon Apr 25, 2022 9:18 am

Re: Word Automation using wxAutomation and wxVariant

Post by charles_5577 »

Once again, thanks PB. I am just now starting to understand how to use wxAutomationObject. In almost all cases I have been able to resolve the problems after what you call hours of drugery. Small things such as changing border styles of a table takes a while of going through. I hope that I do have to bother you too much in the futher.
Post Reply