Word Automation II

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Word Automation II

Germán S. Arduino-2
Hi:

I've asked about this topic time ago but only now can take again the related
work.

I'm able to do things like these:

word := IDispatch createObject: 'Word.Application'.
filename := 'C:\mydoc.doc'.
doc := (word getProperty: 'Documents')
invoke: 'Open' with: filename.
word setProperty: 'Visible' value: true.

and so, but I can't figure out how to replace by example the words
texttoreplace1, textoreplace2, textoreplace3 and so from the Word document
with data that I've in my image.

I imagine that may be #invoke: with replace or so, but nothing seems to
work. I've also searched the MSDN and Google, but can't get an example
useful for me.

Any help will be appreciated.

Best Regards.
gsa.


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Peter Kenny-2
Germán

In the Dolphin 5 image, the method IDispatch class>>example4 gives a good
example of Word automation using the approach you have, including inserting
text from within the method. I have followed this approach when automating
Excel, and it seems to work well.

Hope this helps

Peter



"Germán S. Arduino" <[hidden email]> wrote in message
news:42336cf9$[hidden email]...
> Hi:
>
> I've asked about this topic time ago but only now can take again the
related

> work.
>
> I'm able to do things like these:
>
> word := IDispatch createObject: 'Word.Application'.
> filename := 'C:\mydoc.doc'.
> doc := (word getProperty: 'Documents')
> invoke: 'Open' with: filename.
> word setProperty: 'Visible' value: true.
>
> and so, but I can't figure out how to replace by example the words
> texttoreplace1, textoreplace2, textoreplace3 and so from the Word document
> with data that I've in my image.
>
> I imagine that may be #invoke: with replace or so, but nothing seems to
> work. I've also searched the MSDN and Google, but can't get an example
> useful for me.
>
> Any help will be appreciated.
>
> Best Regards.
> gsa.
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Germán S. Arduino-2
Thanks by the response Peter.

I was examining the example before and now (following your advise).

I founded how to replace text, but I can't figure out how to select text to
after replace it.

By example:

If I start with the document with "something" selected I can get the
selected string with:

selection := word getProperty: 'Selection'.

but I can't figure out how to select from Dolphin the strings that I need
(to replace next).

Will continue trying.

Regards.

"Peter Kenny" <[hidden email]> escribió en el mensaje
news:[hidden email]...

> Germán
>
> In the Dolphin 5 image, the method IDispatch class>>example4 gives a good
> example of Word automation using the approach you have, including
> inserting
> text from within the method. I have followed this approach when automating
> Excel, and it seems to work well.
>
> Hope this helps
>
> Peter
>
>
>
> "Germán S. Arduino" <[hidden email]> wrote in message
> news:42336cf9$[hidden email]...
>> Hi:
>>
>> I've asked about this topic time ago but only now can take again the
> related
>> work.
>>
>> I'm able to do things like these:
>>
>> word := IDispatch createObject: 'Word.Application'.
>> filename := 'C:\mydoc.doc'.
>> doc := (word getProperty: 'Documents')
>> invoke: 'Open' with: filename.
>> word setProperty: 'Visible' value: true.
>>
>> and so, but I can't figure out how to replace by example the words
>> texttoreplace1, textoreplace2, textoreplace3 and so from the Word
>> document
>> with data that I've in my image.
>>
>> I imagine that may be #invoke: with replace or so, but nothing seems to
>> work. I've also searched the MSDN and Google, but can't get an example
>> useful for me.
>>
>> Any help will be appreciated.
>>
>> Best Regards.
>> gsa.
>>
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Peter Kenny-2
Germán

The following seems to work:

selection := word getProperty: 'Selection'.

find := selection getProperty: 'Find'.

find setProperty: 'Text' value: 'TextToBeFound'; invoke: 'Execute'.

selection invoke: 'Delete'; invoke: 'InsertAfter' with: 'TextToBeInserted'.



There is a property 'Replacement' for the Find object, so it should be
possible to find and replace in one operation, but I can't make it work; it
looks as though you have to use the rather clumsy delete followed by insert
.

Note that you can use other properties of the Find object to control search
direction, case matching etc.; it's all in the Word Basic help file, though
not at all easy to follow.

Good luck!

Peter





"Germán S. Arduino" <[hidden email]> wrote in message
news:[hidden email]...
> Thanks by the response Peter.
>
> I was examining the example before and now (following your advise).
>
> I founded how to replace text, but I can't figure out how to select text
to

> after replace it.
>
> By example:
>
> If I start with the document with "something" selected I can get the
> selected string with:
>
> selection := word getProperty: 'Selection'.
>
> but I can't figure out how to select from Dolphin the strings that I need
> (to replace next).
>
> Will continue trying.
>
> Regards.
>
> "Peter Kenny" <[hidden email]> escribió en el mensaje
> news:[hidden email]...
> > Germán
> >
> > In the Dolphin 5 image, the method IDispatch class>>example4 gives a
good
> > example of Word automation using the approach you have, including
> > inserting
> > text from within the method. I have followed this approach when
automating

> > Excel, and it seems to work well.
> >
> > Hope this helps
> >
> > Peter
> >
> >
> >
> > "Germán S. Arduino" <[hidden email]> wrote in message
> > news:42336cf9$[hidden email]...
> >> Hi:
> >>
> >> I've asked about this topic time ago but only now can take again the
> > related
> >> work.
> >>
> >> I'm able to do things like these:
> >>
> >> word := IDispatch createObject: 'Word.Application'.
> >> filename := 'C:\mydoc.doc'.
> >> doc := (word getProperty: 'Documents')
> >> invoke: 'Open' with: filename.
> >> word setProperty: 'Visible' value: true.
> >>
> >> and so, but I can't figure out how to replace by example the words
> >> texttoreplace1, textoreplace2, textoreplace3 and so from the Word
> >> document
> >> with data that I've in my image.
> >>
> >> I imagine that may be #invoke: with replace or so, but nothing seems to
> >> work. I've also searched the MSDN and Google, but can't get an example
> >> useful for me.
> >>
> >> Any help will be appreciated.
> >>
> >> Best Regards.
> >> gsa.
> >>
> >>
> >
> >
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Christopher J. Demers
In reply to this post by Germán S. Arduino-2
"Germán S. Arduino" <[hidden email]> wrote in message
news:42336cf9$[hidden email]...
> I've asked about this topic time ago but only now can take again the
> related work.
...
> and so, but I can't figure out how to replace by example the words
> texttoreplace1, textoreplace2, textoreplace3 and so from the Word document
> with data that I've in my image.
>
> I imagine that may be #invoke: with replace or so, but nothing seems to
> work. I've also searched the MSDN and Google, but can't get an example
> useful for me.
...

The best way to figure out stuff like this is to record a macro in Word, and
then translate the VBA code produced into Smalltalk.  This is the VBA code
produced for me:
=========
    Selection.Find.ClearFormatting
    Selection.Find.Replacement.ClearFormatting
    With Selection.Find
        .Text = "is"
        .Replacement.Text = "was"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = True
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute Replace:=wdReplaceAll
=========
So just translate the above VBA code to Smalltalk and see if it works.
Depending upon what you are actually doing you may also want to look into
some of the existing field capabilities in Word to see if that may be
useful.  Let us know if you still have trouble.

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

German Arduino
In reply to this post by Peter Kenny-2
Hi Peter:

Peter Kenny wrote:

> Germán
>
> The following seems to work:
>
> selection := word getProperty: 'Selection'.
>
> find := selection getProperty: 'Find'.
>
> find setProperty: 'Text' value: 'TextToBeFound'; invoke: 'Execute'.
>
> selection invoke: 'Delete'; invoke: 'InsertAfter' with: 'TextToBeInserted'.
>
>
>
> There is a property 'Replacement' for the Find object, so it should be
> possible to find and replace in one operation, but I can't make it work; it
> looks as though you have to use the rather clumsy delete followed by insert
> .

Yes, I've been playing with replacement but also can't make it work.

>
> Note that you can use other properties of the Find object to control search
> direction, case matching etc.; it's all in the Word Basic help file, though
> not at all easy to follow.
>
> Good luck!
>
> Peter

Thanks by your help.
gsa.


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

German Arduino
In reply to this post by Christopher J. Demers
Christopher J. Demers wrote:

>
> The best way to figure out stuff like this is to record a macro in Word, and
> then translate the VBA code produced into Smalltalk.  This is the VBA code
> produced for me:
> =========
>     Selection.Find.ClearFormatting
>     Selection.Find.Replacement.ClearFormatting
>     With Selection.Find
>         .Text = "is"
>         .Replacement.Text = "was"
>         .Forward = True
>         .Wrap = wdFindContinue
>         .Format = False
>         .MatchCase = False
>         .MatchWholeWord = True
>         .MatchWildcards = False
>         .MatchSoundsLike = False
>         .MatchAllWordForms = False
>     End With
>     Selection.Find.Execute Replace:=wdReplaceAll
> =========
> So just translate the above VBA code to Smalltalk and see if it works.
> Depending upon what you are actually doing you may also want to look into
> some of the existing field capabilities in Word to see if that may be
> useful.  Let us know if you still have trouble.
>
> Chris
>
>

Hi Chris:

I've made the same, but unfortunately I haven't clear all the details to
translate VBA to Smalltalk code. This is documented in some place? (I've
seen only the examples of IDispatch in te image).

Best Regards.
gsa.


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Christopher J. Demers
"German Arduino" <[hidden email]> wrote in message
news:42356a25$[hidden email]...
> I've made the same, but unfortunately I haven't clear all the details to
> translate VBA to Smalltalk code. This is documented in some place? (I've
> seen only the examples of IDispatch in te image).

I translated the code from VBA to Smalltalk for you bellow.  If you plan to
use Word from Dolphin often you may want to use the ActiveX wizard to
generate Smalltalk classes.  That will make it easier to look at Word from a
Smalltalk perspective and improve the performance.  You can also then add
strategic helper methods.  I had to jump through some hoops in the code
bellow to get the numeric values of some of the constants.  I did not see an
obvious easier way to get those values.  I would love to know if there is a
better way to get the values of ActiveX constants dynamically (if you use
the wizard they end up in a constants pool for you).  The code bellow is a
little yucky, but it does seem to work.

=======================
word := IDispatch createObject: 'Word.Application'.
filename := 'C:\mydoc.doc'.
doc := (word getProperty: 'Documents')
invoke: 'Open' with: filename.
word setProperty: 'Visible' value: true.
selection := word getProperty: 'Selection'.
find := selection getProperty: 'Find'.
"This will change all 'is' to 'was'."
find setProperty: 'Text' value: 'is'.
(find getProperty: 'Replacement') setProperty: 'Text' value: 'was'.
find setProperty: 'Forward' value: true.
find setProperty: 'Wrap' value: 1 "wdFindContinue".
find setProperty: 'Format' value: false.
find setProperty: 'MatchCase' value: false.
find setProperty: 'MatchWholeWord' value: true.
find setProperty: 'MatchWildcards' value: false.
find setProperty: 'MatchSoundsLike' value: false.
find setProperty: 'MatchAllWordForms' value: false.
find invoke: 'Execute' withArguments: (OrderedCollection new add: VARIANT
unspecified; add: VARIANT unspecified; add: VARIANT unspecified; add:
VARIANT unspecified; add: VARIANT unspecified; add: VARIANT unspecified;
add: VARIANT unspecified; add: VARIANT unspecified; add: VARIANT
unspecified; add: VARIANT unspecified; add: 2"wdReplaceAll"; yourself).
"The replace is done, the code bellow is FYI"
"I used this block to find the constants. Perhaps there is an easier way."
constantFinder := [ :constantName |
((find typeInfo typeLib at: constantName) constants
detect: [:item | item name = constantName]) lpvarValue value ].
"This is how I got the constants."
constantFinder value: 'wdFindContinue'. "=1"
constantFinder value: 'wdReplaceAll'. "=2"
=======================

Enjoy,
Chris


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Germán S. Arduino-2
Thanks You very much Chris.

I will study your code to try to learn to do myself.

Best Regards.

"Christopher J. Demers" <[hidden email]> escribió en el
mensaje news:[hidden email]...

> "German Arduino" <[hidden email]> wrote in message
> news:42356a25$[hidden email]...
>> I've made the same, but unfortunately I haven't clear all the details to
>> translate VBA to Smalltalk code. This is documented in some place? (I've
>> seen only the examples of IDispatch in te image).
>
> I translated the code from VBA to Smalltalk for you bellow.  If you plan
> to use Word from Dolphin often you may want to use the ActiveX wizard to
> generate Smalltalk classes.  That will make it easier to look at Word from
> a Smalltalk perspective and improve the performance.  You can also then
> add strategic helper methods.  I had to jump through some hoops in the
> code bellow to get the numeric values of some of the constants.  I did not
> see an obvious easier way to get those values.  I would love to know if
> there is a better way to get the values of ActiveX constants dynamically
> (if you use the wizard they end up in a constants pool for you).  The code
> bellow is a little yucky, but it does seem to work.
>
> =======================
> word := IDispatch createObject: 'Word.Application'.
> filename := 'C:\mydoc.doc'.
> doc := (word getProperty: 'Documents')
> invoke: 'Open' with: filename.
> word setProperty: 'Visible' value: true.
> selection := word getProperty: 'Selection'.
> find := selection getProperty: 'Find'.
> "This will change all 'is' to 'was'."
> find setProperty: 'Text' value: 'is'.
> (find getProperty: 'Replacement') setProperty: 'Text' value: 'was'.
> find setProperty: 'Forward' value: true.
> find setProperty: 'Wrap' value: 1 "wdFindContinue".
> find setProperty: 'Format' value: false.
> find setProperty: 'MatchCase' value: false.
> find setProperty: 'MatchWholeWord' value: true.
> find setProperty: 'MatchWildcards' value: false.
> find setProperty: 'MatchSoundsLike' value: false.
> find setProperty: 'MatchAllWordForms' value: false.
> find invoke: 'Execute' withArguments: (OrderedCollection new add: VARIANT
> unspecified; add: VARIANT unspecified; add: VARIANT unspecified; add:
> VARIANT unspecified; add: VARIANT unspecified; add: VARIANT unspecified;
> add: VARIANT unspecified; add: VARIANT unspecified; add: VARIANT
> unspecified; add: VARIANT unspecified; add: 2"wdReplaceAll"; yourself).
> "The replace is done, the code bellow is FYI"
> "I used this block to find the constants. Perhaps there is an easier way."
> constantFinder := [ :constantName |
> ((find typeInfo typeLib at: constantName) constants
> detect: [:item | item name = constantName]) lpvarValue value ].
> "This is how I got the constants."
> constantFinder value: 'wdFindContinue'. "=1"
> constantFinder value: 'wdReplaceAll'. "=2"
> =======================
>
> Enjoy,
> Chris
>


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

German Arduino
In reply to this post by Christopher J. Demers
Hi Chris, again me bottering with this question:

Christopher J. Demers wrote:
> "German Arduino" <[hidden email]> wrote in message
> news:42356a25$[hidden email]...
>
> find invoke: 'Execute' withArguments: (OrderedCollection new add: VARIANT
> unspecified; add: VARIANT unspecified; add: VARIANT unspecified; add:
> VARIANT unspecified; add: VARIANT unspecified; add: VARIANT unspecified;
> add: VARIANT unspecified; add: VARIANT unspecified; add: VARIANT
> unspecified; add: VARIANT unspecified; add: 2"wdReplaceAll"; yourself).

I've tried and understood your VBA to Smalltalk translation, but can't
understand the previos paragraph nor how you figured out that this is
the right syntax.

Simply I've never minded in an method as this :(

Any explanation will be appreciated.

Best Regards.


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Christopher J. Demers
"German Arduino" <[hidden email]> wrote in message
news:4238181e$[hidden email]...

> Christopher J. Demers wrote:
>>
>> find invoke: 'Execute' withArguments: (OrderedCollection new add: VARIANT
>> unspecified; add: VARIANT unspecified; add: VARIANT unspecified; add:
>> VARIANT unspecified; add: VARIANT unspecified; add: VARIANT unspecified;
>> add: VARIANT unspecified; add: VARIANT unspecified; add: VARIANT
>> unspecified; add: VARIANT unspecified; add: 2"wdReplaceAll"; yourself).
>
> I've tried and understood your VBA to Smalltalk translation, but can't
> understand the previos paragraph nor how you figured out that this is the
> right syntax.

What I did here is I looked at either the Word help file, or the IDL
(Interface Definition Language) spec for the Execute method on the Find
object.  I saw that it took a whole bunch of arguments, but that all input
arguments were optional.  The VBA code used a VBA trick called named
arguments, I believe.  That way a VBA coder can easily send one named
argument to a method that has lots of optional arguments without needing to
pad all the optional arguments.  As far as I know (corrections appreciated)
there is no equivalent to named arguments via dynamic COM code in Dolphin
(there is a little irony here given the nature of Smalltalk).  So what I had
to do was pad all of the optional arguments preceding the one I needed to
pass with VARIANT unspecified.  It looks like some of the values the macro
set on the Find object could have been passed to the Execute method instead.
When I migrated the code from VBA to Smalltalk I just worked from the top
down and I did a fairly direct translation of the generated Macro code.
There may be more elegant ways to do this.

This is the IDL code for the Execute method:
==================
'[id(0x000001bc), helpcontext(0x09b001bc)]
HRESULT __stdcall Execute(
[in, optional] VARIANT* FindText,
[in, optional] VARIANT* MatchCase,
[in, optional] VARIANT* MatchWholeWord,
[in, optional] VARIANT* MatchWildcards,
[in, optional] VARIANT* MatchSoundsLike,
[in, optional] VARIANT* MatchAllWordForms,
[in, optional] VARIANT* Forward,
[in, optional] VARIANT* Wrap,
[in, optional] VARIANT* Format,
[in, optional] VARIANT* ReplaceWith,
[in, optional] VARIANT* Replace,
[in, optional] VARIANT* MatchKashida,
[in, optional] VARIANT* MatchDiacritics,
[in, optional] VARIANT* MatchAlefHamza,
[in, optional] VARIANT* MatchControl,
[out, retval] VARIANT_BOOL* prop);'
==================
This is the code I used to get the above:
==================
word := IDispatch createObject: 'Word.Application'.
filename := 'C:\mydoc.doc'.
doc := (word getProperty: 'Documents')
invoke: 'Open' with: filename.
selection := word getProperty: 'Selection'.
find := selection getProperty: 'Find'.
"Evaluate the next line with Ctrl-D to see the IDL."
(find typeInfo methods detect: [:each | each name = 'Execute']) printIDL.
==================

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Word Automation II

Germán S. Arduino-2
Thanks you by the explanation!

Unfortunately I can't add corrections nor suggestions, I'm a totaly newbie
with this topic.

Again, thanks by your time and help.

Germán.


"Christopher J. Demers" <[hidden email]> escribió en el
mensaje news:[hidden email]...

> "German Arduino" <[hidden email]> wrote in message
> news:4238181e$[hidden email]...
>> Christopher J. Demers wrote:
>>>
>>> find invoke: 'Execute' withArguments: (OrderedCollection new add:
>>> VARIANT unspecified; add: VARIANT unspecified; add: VARIANT unspecified;
>>> add: VARIANT unspecified; add: VARIANT unspecified; add: VARIANT
>>> unspecified; add: VARIANT unspecified; add: VARIANT unspecified; add:
>>> VARIANT unspecified; add: VARIANT unspecified; add: 2"wdReplaceAll";
>>> yourself).
>>
>> I've tried and understood your VBA to Smalltalk translation, but can't
>> understand the previos paragraph nor how you figured out that this is the
>> right syntax.
>
> What I did here is I looked at either the Word help file, or the IDL
> (Interface Definition Language) spec for the Execute method on the Find
> object.  I saw that it took a whole bunch of arguments, but that all input
> arguments were optional.  The VBA code used a VBA trick called named
> arguments, I believe.  That way a VBA coder can easily send one named
> argument to a method that has lots of optional arguments without needing
> to pad all the optional arguments.  As far as I know (corrections
> appreciated) there is no equivalent to named arguments via dynamic COM
> code in Dolphin (there is a little irony here given the nature of
> Smalltalk).  So what I had to do was pad all of the optional arguments
> preceding the one I needed to pass with VARIANT unspecified.  It looks
> like some of the values the macro set on the Find object could have been
> passed to the Execute method instead. When I migrated the code from VBA to
> Smalltalk I just worked from the top down and I did a fairly direct
> translation of the generated Macro code. There may be more elegant ways to
> do this.
>
> This is the IDL code for the Execute method:
> ==================
> '[id(0x000001bc), helpcontext(0x09b001bc)]
> HRESULT __stdcall Execute(
> [in, optional] VARIANT* FindText,
> [in, optional] VARIANT* MatchCase,
> [in, optional] VARIANT* MatchWholeWord,
> [in, optional] VARIANT* MatchWildcards,
> [in, optional] VARIANT* MatchSoundsLike,
> [in, optional] VARIANT* MatchAllWordForms,
> [in, optional] VARIANT* Forward,
> [in, optional] VARIANT* Wrap,
> [in, optional] VARIANT* Format,
> [in, optional] VARIANT* ReplaceWith,
> [in, optional] VARIANT* Replace,
> [in, optional] VARIANT* MatchKashida,
> [in, optional] VARIANT* MatchDiacritics,
> [in, optional] VARIANT* MatchAlefHamza,
> [in, optional] VARIANT* MatchControl,
> [out, retval] VARIANT_BOOL* prop);'
> ==================
> This is the code I used to get the above:
> ==================
> word := IDispatch createObject: 'Word.Application'.
> filename := 'C:\mydoc.doc'.
> doc := (word getProperty: 'Documents')
> invoke: 'Open' with: filename.
> selection := word getProperty: 'Selection'.
> find := selection getProperty: 'Find'.
> "Evaluate the next line with Ctrl-D to see the IDL."
> (find typeInfo methods detect: [:each | each name = 'Execute']) printIDL.
> ==================
>
> Chris
>