wxAutomationObject - WORD - DOC to RTF [SOLVED]

This forum can be used to talk about general design strategies, new ideas and questions in general related to wxWidgets. If you feel your questions doesn't fit anywhere, put it here.
Post Reply
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

wxAutomationObject - WORD - DOC to RTF [SOLVED]

Post by Phil-ok »

Hello,
I want to ask WORD to convert a .DOC file to .RTF
Could anybody advice me ?
Best regards
Philippe
Last edited by Phil-ok on Mon Sep 19, 2016 1:44 pm, edited 1 time in total.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

1. First you need to know the VBA code to do what you want.
2. Translate the VBA code into matching wxAutomationObject calls.

I have never automated MS Word but I would start with its Macro Recorder to produce the VBA code. I suppose by converting you mean to open the doc file and then save it in rich text format. Should not be difficult to do, just few calls...
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

Perhaps the code could look e.g. like this, of course it would need thorough testing and review in order to be used in production code, not to mention better dealing (reporting) with errors. Also make sure you pass full paths for both formats.

Code: Select all

bool ConvertDocToRTF(const wxString& docFileName, const wxString& RTFFileName, wxString& errorMsg)
{    
    wxCHECK( docFileName.IsSameAs(RTFFileName, false) == false, false );

#ifdef NDEBUG
    // in the release mode suppress possible LogErrors() produced by wxAutomationObject
    // as these are not suitable for the end user to see
    wxLogNull logNull; 
#endif // #ifdef NDEBUG

    wxAutomationObject application;
    application.CreateInstance("Word.Application");
    if ( !application.IsOk() )
    {
        errorMsg = _("Failed to create MS Word application instance.");
        return false;
    }
    application.PutProperty("DisplayAlerts", false);
    application.PutProperty("Visible", false);
   
    wxAutomationObject documents;
    application.GetObject(documents, "Documents");
    if ( !documents.IsOk() )
    {
        application.CallMethod("Quit");
        errorMsg = _("Failed to obtain Word.Documents property.");
        return false;
    }
       
    wxVariant docVariant;
    docVariant = documents.CallMethod("Open",
        docFileName,
        false, // do not show conversion dialog if necessary (should never be needed for MS Word document)
        true,  // open as read only
        false  // do not add the file to the MRU
    );

    if ( !docVariant.GetVoidPtr() )
    {
        application.CallMethod("Quit");
        errorMsg.Printf(_("Failed to open file %s."), docFileName);        
        return false;
    }

    const long wdFormatRTF = 6;
    const long wdDoNotSaveChanges = 0;
    wxAutomationObject document((WXIDISPATCH*)docVariant.GetVoidPtr());
    
    document.CallMethod("SaveAs2",
        RTFFileName,
        wdFormatRTF,
        wxNullVariant,
        wxNullVariant,
        false // do not add the file to the MRU
    );
    bool saved = document.GetProperty("Saved");

    document.CallMethod("Close", wdDoNotSaveChanges);
    application.CallMethod("Quit");

    if ( !saved )
    {
        errorMsg.Printf(_("Failed to save file %s."), RTFFileName);
        return false;
    }    
    
    errorMsg.clear();
    return true;
}
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

Thank you very much !
If I use the ConvertDocToRTF function like this :

Code: Select all

void ImportsFrame::OnconvbClick(wxCommandEvent& event)
{
const wxString docFileName=_T("C:\\Temp\\Test.docx");
const wxString RTFFileName=_T("C:\\Temp\\Test.rtf");
wxString errorMsg;
ImportsFrame::ConvertDocToRTF(docFileName,RTFFileName,errorMsg) ;
}
I get this error : "Imports Error - OLE Automation error in SaveAs2: Unknown name or named argument"

Have you got an idea ?

Philippe
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

Which version of Word do you have? It appears that the method is not available in very old MS Word versions (2007 and older) and you need to use a different one there. After a bit of googling I found this (the first answer). The code there should be easy to rewrite in C++ using wxAutomationObject. For MS Word 2007 you may only need changing the method name (from SaveAs2 to SaveAs). I don't know what versions of MS Word you need to support but it should not be difficult.

Here is the documentation for MS Word 2007 Document.SaveAs: https://msdn.microsoft.com/en-us/librar ... e.12).aspx
If you need to look up the methods or properties of MS Office objects, I suggest googling for "VBA <officeProduct> object model <officeVersion">, e.g. "VBA Word object model 2007" was how I got to the documentation for "SaveAs".

The stub of the code supporting MS Word 2003 through 2016 could look like this.

Code: Select all

bool ConvertDocToRTF(const wxString& docFileName, const wxString& RTFFileName, wxString& errorMsg)
{    
    wxCHECK( docFileName.IsSameAs(RTFFileName, false) == false, false );

#ifdef NDEBUG
    // in the release mode suppress possible LogErrors() produced by wxAutomationObject
    // as these are not suitable for the end user to see
    wxLogNull logNull; 
#endif // #ifdef NDEBUG

    wxAutomationObject application;    

    application.CreateInstance("Word.Application");
    if ( !application.IsOk() )
    {
        errorMsg = _("Failed to create MS Word application instance.");
        return false;
    }
    application.PutProperty("DisplayAlerts", false);
    application.PutProperty("Visible", false);
   
    wxAutomationObject documents;
    wxAutomationObject document;    
    bool result = true;

    try {    
        application.GetObject(documents, "Documents");
        if ( !documents.IsOk() )                    
            throw wxString(_("Failed to obtain Word.Documents property."));
            
        wxVariant docVariant;
        docVariant = documents.CallMethod("Open", docFileName,
            false, // do not show conversion dialog if necessary (should never be needed for MS Word document)
            true,  // open as read only
            false  // do not add the file to the MRU
        );
        if ( !docVariant.GetVoidPtr() )        
            throw wxString::Format(_("Failed to open file %s."), docFileName);
        document.SetDispatchPtr((WXIDISPATCH*)docVariant.GetVoidPtr());    

        wxString MSWordVersionStr = application.GetProperty("Version");    
        double MSWordVersion;
        wxString saveMethodName;
    
        if ( !MSWordVersionStr.ToCDouble(&MSWordVersion) ) // should never happen        
            throw wxString::Format(_("Could not obtain MS Word version (%s)."), MSWordVersionStr);
            
        // see https://en.wikipedia.org/wiki/Microsoft_Word#Release_history for MS Word versions
        if ( MSWordVersion < 11 ) // MS Word 2002 (Office XP) or older                    
            throw wxString::Format(_("Unsupported MS Word version (%s)."), MSWordVersionStr);            
        if ( MSWordVersion == 11 || MSWordVersion == 12 ) // MS Word 2003 or 2007
            saveMethodName = "SaveAs";
        else // MS Word 2010 or newer
            saveMethodName = "SaveAs2";
                   
        document.CallMethod(saveMethodName, RTFFileName,
            6, // wdFormatRTF
            wxNullVariant, wxNullVariant,
            false // do not add the file to the MRU
        );        
        if ( !document.GetProperty("Saved") )        
            throw wxString::Format(_("Failed to save file %s."), RTFFileName);    
    }
    catch ( const wxString& e )
    {
        result = false;
        errorMsg = e;
    }    
    
    if ( document.IsOk() )
        document.CallMethod("Close", 0 /* 0 = wdDoNotSaveChanges */ );
    application.CallMethod("Quit");
        
    return result;
}
But I have only Office 2010 and 2016 installed so I cannot really test it. Also if MS decides to remove SaveAs2 from the next yet unreleased versions of MS Word, the code ceases to work, but there's nothing you can do about it.

Also please notice the code posted is not production quality. It is only demonstration of how to use wxAutomationObject with emphasis on code brevity. It needs to be adapted for a use in a real application
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

Excellent !
Thank you very much.
It works so good !

Just a question : I am in release mode and the LogErrors() are not suppressed.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

Phil-ok wrote:I am in release mode and the LogErrors() are not suppressed.
Do you have NDEBUG defined in the release mode builds, as expected? If you do not, you have to check whether you are running in the debug or release mode another way, e.g. checking for _DEBUG. I advise leaving wxAutomationObject reporting on during debugging as it is definitely very useful information to have.
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

Thanks for the explanation !

I dare asking another question : I want, if there is no accurate MSWordVersion installed, to make the conversion with Writer :

a) Can I use wxAutomationObject with OOO ? If yes, has anybody an example with Writer ?

b) Is there also a solution with UNO ? If yes, do I have to install libs ? Would then my program do the treatments on OOO files by itself ? Has anybody an example with Writer ?

Thanks a lot

Philippe
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

Sorry, I have never used Open Office let alone automated it (assuming OOO = Open Office). I do not even know what UNO is. I'm sure you will be able to find information on how to do that, in general it should be possible with wxAutomationObject but be aware that it has certain limitations.
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

PB,
Thanks for all !
Philippe
iwbnwif
Super wx Problem Solver
Super wx Problem Solver
Posts: 282
Joined: Tue Mar 19, 2013 8:52 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by iwbnwif »

Hi,
a) Can I use wxAutomationObject with OOO ? If yes, has anybody an example with Writer ?
It may be possible, but (obviously) only on MSW. It is worth having a look at the examples here:

https://www.openoffice.org/udk/common/m ... ridge.html

But sorry, I never tried this.
b) Is there also a solution with UNO ? If yes, do I have to install libs ? Would then my program do the treatments on OOO files by itself ? Has anybody an example with Writer ?
I have tried this a long time ago and if I remember correctly it was not at all easy. You need to install the OpenOffice SDK. Unfortunately I have uninstalled this and lost the relevant files. All I can say is that the files that I used for my tests were located in:

Program Files (x86)/OpenOffice_4.1.0_SDK/sdk/examples/DevelopersGuide/ProfUNO/CppBinding

I believe I included office_connect.cxx and string_samples.cxx in a project to make a simple connection to write into a Writer document. I was then able to get the code in the last message of the following forum post to work.

https://forum.openoffice.org/en/forum/v ... 44&t=71155
wxWidgets 3.1.2, MinGW64 8.1.0, g++ 8.1.0, Ubuntu 19.04, Windows 10, CodeLite + wxCrafter
Some people, when confronted with a GUI problem, think "I know, I'll use Eclipse RCP". Now they have two problems.
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

Thank you
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxAutomationObject - WORD - DOC to RTF

Post by PB »

Automating OpenOffice from C++ seems extremely complicated when compared to that of MS Office. I googled a bit and found that OO/LO can convert files from command line, e.g. this

Code: Select all

"C:\Program Files (x86)\LibreOffice 5\program\soffice.exe" --headless  --convert-to rtf:"Rich Text Format" test.doc
produced the RTF file named test.rtf located in the same folder as test.doc with LibreOffice 5.0.2.2.

But there may be few issues, such as conversion not being done if there is already an instance of the application running. It appears there are workarounds for that though.

As I see it the main issue is how well OO/LO handles complex MS Word documents. This is always tricky, I do not know why you need to convert from doc(x?) to rtf, perhaps a different approach would be appropriate...
Phil-ok
Knows some wx things
Knows some wx things
Posts: 47
Joined: Tue Mar 29, 2016 6:32 am

Re: wxAutomationObject - WORD - DOC to RTF

Post by Phil-ok »

Thanks for all
Post Reply