Obtaining an interface to a running Automation server
In many cases rather than create a new object in your application you may want to control an object that is already running or has been created by another application. Automation servers that allow this type of access register their running objects with OLE to indicate that the objects are loaded in memory. f90VB provides function GetActiveOleObject that can check the OLE’s table of running objects for a specific Automation server. If the server is loaded, GetActiveOleObject returns a pointer to its IDispatch interface. This process is illustrated in Example 6.2. The program implements a simple search/replace utility that can be used to change the text of the active document in Word. Obviously, attempting to run this utility when you don’t have an open Word document wouldn’t make any sense, so instead of creating a new instance of Word the example requests an interface to the Word instance that is currently running.
Example 6.2
program Example62
!Example shows how to use f90VB to automate Word
!Copyright (C) 1999-2000, Canaima Software, Inc.
!Illustrates:
! - Creating an new object
! - Getting an interface to an active object
! - Setting/retrieving property values
! - Executing object methods
! - Passing optional arguments to a method
use f90VBDefs
use f90VBBStrings
use f90VBVariants
use f90VBAutomation
implicit none
!Variants containing main objects
type(VARIANT)::Word, Document, SelObj
!Variants used to stored temporal objects and collections
type(VARIANT)::VarTmp
integer(HRESULT_KIND)::iRet
character(len=255)::TmpStr
type(VARIANT)::WrdToFind,WrdReplace
type(EXCEPINFO)::EInfo
!Initialize Ole
iRet = OleInitialize()
!If Word is already running, then get an interface
!to the running instance. Otherwise exit with
!an error message
Word = GetActiveOleObject('Word.Application',iRet)
if (iRet.ne.S_OK) goto 900
!Get a reference to the active document. If there
!is no active document, exit with an error message
Document=PropertyGet(Word,'ActiveDocument', EInfo=EInfo, iRet=iRet)
if (iRet.ne.S_OK) goto 1000
!read the words to find and replace
print *,'Enter the word to replace:'
read(*,*) TmpStr
WrdToFind = VariantCreate(VT_BSTR,trim(TmpStr))
print *,'Enter the word to use as replacement:'
read(*,*) TmpStr
WrdReplace = VariantCreate(VT_BSTR,trim(TmpStr))
!Get a find/replace object for the whole document
SelObj = PropertyGet(Document,'Content.Find', EInfo=EInfo, iRet=iRet)
if (iRet.ne.S_OK) goto 1000
!Set the text to find
call PropertyPut(SelObj,'Text',WrdToFind, EInfo=EInfo,iRet=iRet)
if (iRet.ne.S_OK) goto 1000
!Set the text to use as replacement
call PropertyPut(SelObj,'Replacement.Text',WrdReplace, &
EInfo=EInfo, iRet=iRet)
if (iRet.ne.S_OK) goto 1000
!Execute the find/replace for all occurrences of the word to replace
!(i.e. pass the value 2 in argument 11 of the method
VarTmp = ExecMethod(SelObj,'Execute',EmptyParam(),EmptyParam(), &
EmptyParam(),EmptyParam(),EmptyParam(),EmptyParam(), &
EmptyParam(),EmptyParam(),EmptyParam(),EmptyParam(), &
VariantCreate(VT_INT,2),EInfo=EInfo,iRet=iRet)
if (iRet.ne.S_OK) goto 1000
!We are done
goto 2000
900 continue
print *,'You must have an instance of Word for Windows'
print *,'running for this example to work'
1000 continue
print *, 'The following Errors were detected:'
print *, 'HRESULT:',iRet
call StrCopy(EInfo%bstrDescription,TmpStr)
print *,TmpStr
2000 continue
!clear variants containing BStrings
call VariantClear(WrdToFind)
call VariantClear(WrdReplace)
call ExceptionClear(Einfo)
!release references to objects
call Release(SelObj)
call Release(Document)
call Release(Word)
!Uninitialize Ole
call OLEUninitialize()
stop
end
As you have probably noticed, there are many new things in this example that we have not explained yet. Don’t worry, we’ll go through them in the following sections. At this point, what is important is that you see how function GetActiveOleObject was used, instead of CreateOleObject.
The other point worth mentioning is that this is the first time we use function PropertyGet. This function requests the value of an object’s property. It works in a similar way to PropertyPut. The first argument is the variant containing the object reference, the second argument is the name of the property. If this is an indexed property, then you can pass the index(es) as the third, forth, etc. arguments. Property values are always returned as variants. Properties can be normal numbers, but many objects also return other objects as properties. This is explained in more detail in the section that discusses collections and object hierarchies.
Obtaining information about errors and exceptions