Search and replace in OLE Word automation - how to cover header and footer?
Asked Answered
I

1

10

I've a perfectly working function to find and replace a variable with text in word documents.

HRESULT CMSWord::FindReplace( CString szVar, CString szText, bool bOnlyOnce/*=false*/ )
{
    if(m_pWApp==NULL || m_pActiveDocument==NULL) return E_FAIL;
    IDispatch *pDocApp;
    {  
        VARIANT result;
        VariantInit(&result);
        OLEMethod(DISPATCH_PROPERTYGET, &result, m_pActiveDocument, L"Application", 0);
        pDocApp= result.pdispVal;
    }
    IDispatch *pSelection;
    {
        VARIANT result;
        VariantInit(&result);
        OLEMethod(DISPATCH_PROPERTYGET, &result, pDocApp, L"Selection", 0);
        pSelection=result.pdispVal;
    }
    IDispatch *pFind;
    {
        VARIANT result;
        VariantInit(&result);
        OLEMethod(DISPATCH_PROPERTYGET, &result, pSelection, L"Find", 0);
        pFind=result.pdispVal;
    }
    OLEMethod(DISPATCH_METHOD, NULL, pFind, L"ClearFormatting",0);

    szText.Replace(_T("\r\n"), _T("\v")); 
    COleVariant sVariable(szVar);
    COleVariant sReplaceText(szText);
    COleVariant replace((long)2);
    COleVariant varBoolTrue;
    varBoolTrue.boolVal = true;
    COleVariant varBoolFalse;
    varBoolFalse.boolVal = false;
    COleVariant wdContinue((long)1);
    bool bFound=false;
    IDispatch *pExecute = NULL;
    {
        for(;;) {
            VARIANT result;
            VariantInit(&result);

            if(OLEMethod(DISPATCH_METHOD, &result, pFind, L"Execute", 8, wdContinue, varBoolTrue, varBoolFalse, varBoolFalse, varBoolFalse, varBoolTrue, varBoolFalse, sVariable)==S_OK) {
                pExecute=result.pdispVal;
                if(!pExecute) break;
                bFound = true;
                if(szText.IsEmpty()) DeleteChar(false);         else SetSelectionText(szText);
            }
            else break;
            if(bOnlyOnce) break;
        }
    }
    pDocApp->Release();
    pSelection->Release();
    pFind->Release();
    if(!bFound) return E_FAIL;
    else return S_OK;
}

The problem is, that this code won't touch any text in the header or the footer.

Maybe there is a parameter for the pFind execute method?

Honestly I've been looking in to this problem since Monday. The most of my search results are VB, C#, .NET and VBA documentation, but there is little documentation on VC++ OLE, a few lines of code, but nothing helpful. I even started to create and translate some Word macros, nothing works.

Here on Stack Overflow I found many questions related to this topic. Some of them looked promising, but it seems they're using some framework I don't know and people have left no response if I asked for sample code or links.

If someone can me help on this matter it'd be awesome and I'd really appreciate links to documentation and code on the general topic of OLE Word automation (besides this codeproject article).

Thanks in advance!

Icbm answered 20/12, 2012 at 14:53 Comment(10)
I thingk you need to search and replace in all Story Ranges, as described here: word.mvps.org/faqs/customization/ReplaceAnywhere.htmPreeminent
In the meantime I've tried to adapt many VB and VBA macro codes. There are a few functions on the internet that works, but my own creations crashes. I need some kind of documentations how to adapt those funktions to c++.Icbm
OLEMethod(DISPATCH_METHOD, &result, pFindReplace, L"Execute", 15, v_false, //match control v_false, //match Alef Hamza v_false, //match didactics v_false, //match kashida v_replace, //replace v_replace_text, //replace with v_false, //format v_wrap, //find wrap v_true, //forward v_false, //match all word forms v_false, //match sounds-like v_true, //match wildcards v_true, //match whole word v_true, //match case v_find); //find text Find/Replace directly. None of the param helps. :-(Icbm
Is it possible to extract the headers and fotting as strings, do the replacement on the strings and then put the strings back? There should be an easy way to get and set the headers and footings? Btw, any specific reason that you use C++ for this?Pape
I were happy if I knew how to read or set the whole footer or header per OLE. This is only a tiny part of a huge mfc project.Icbm
Maybe you could just run the macro given at the link from the first comment by Simon Mourier using the method described at support.microsoft.com/kb/183369 ...Agar
So, I guess this means there is no way adding/altering header/footer only per c++, am I right? A word macro is unfortunately no option because, we are generating rtf documents and is unable for me to insert a new macro there during or after generating.Icbm
If you're only using RTF, then why do you need to use Word at all, at least for this part? Why not just use simple string S & R?Neat
Hi! Are you still interested by your question?Puttergill
Sure, if you got any hints.But I'm quite convinced, that this problem can't be solved with unmanaged VC++.Icbm
M
1

Here is a Delphi function that searches and replaces in the header. I know this is a C++ question, but you can see from the functions what you need to do.

I always find that the simplest way to do something in work is to use the MacroRecorder and see how word does it, then call that code from your app.

I pity you doing COM programming in C++

Procedure Find_ReplaceText(find, ReplaceWith: String; Header : Boolean = false);
var
    tmpText: String;
    spos , epos : Integer;
begin
    {Start on first page.}
    fWordApp.Selection.Goto(wdGoToPage,wdGotoFirst);
    {Extra code is needed if I'm trying to replace text in the header}
    if Header then
    begin
        fWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekCurrentPageHeader;



        If fWordApp.Selection.HeaderFooter.IsHeader = False Then
        begin
            fWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekCurrentPageHeader;
        end;

        tmpText := fWordApp.ActiveDocument.sections.item(1).Headers.item(wdHeaderFooterPrimary).Range.text;
        spos := pos('[' ,tmptext);
        epos := pos(']' , tmpText);

        tmptext := copy(tmptext,1, spos);
        tmptext := tmptext + ReplaceWith + ']';
        fWordApp.ActiveDocument.sections.item(1).Headers.item(wdHeaderFooterPrimary).Range.text := tmptext;
        fWordApp.ActiveWindow.ActivePane.View.SeekView := wdSeekMainDocument;
    end
    else
    begin
        fWordApp.Selection.Find.Text := find;
        fWordApp.Selection.Find.Execute;
        fWordApp.Selection.typeText(' ');
        fWordApp.Selection.InsertAfter(ReplaceWith);
    end;

end;
Madison answered 23/12, 2014 at 20:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.