Door alle media-aandacht voor de nieuwste technieken lijkt het ontwikkelen van applicaties met Microsoft Office een langzame dood te zijn gestorven. Niets is echter minder waar. Nog steeds worden er talloze oplossingen gebouwd met behulp van (onderdelen van) Office. Nog steeds is Office het meest geavanceerde RAD ontwikkelinstrument op de markt. Via o.a. automatisering is het mogelijk om zeer geavanceerde oplossingen te bouwen in relatief korte tijd.
In dit artikel laten we zien hoe we Microsoft Word via automatisering kunnen aansturen. We bekijken de verschillen tussen early en late binding en geven de voor- en nadelen van die twee methodes. Tussendoor laten we een aantal valkuilen zien en geven enkele tips voor de automatisering van Office objecten in het algemeen.
Word aanroepen
We gaan meteen van start om Word aan te roepen via automatisering. Hiervoor moeten we twee dingen doen. Ten eerste een "referentie" leggen naar de "Word Object Library". Ten tweede een paar regels code uitvoeren.
Referentie naar Word
Je opent de VBA editor in bijvoorbeeld Access 2000 (ALT+F11) en gaat naar menu: Extra/Referenties (in VB 6.0: Project/References). Je ziet dan een overzicht van alle beschikbare referenties. De geactiveerde referenties staan bovenaan met een vinkje aan. Als je wat verder naar beneden scrolt zie je ook Microsoft Word Object 10.0 Library staan.
Maar wacht eens … Word 10.0 verwijst toch naar Word 2002/XP en we zitten toch in Access 2000? Gaat dat wel goed? Nou … euh nee … da's vragen om problemen als je gebruikers alleen Office 2000 hebben. Gelukkig kunnen we via het knopje "Browse…" de type library van Word 2000 gaan zoeken. Browse naar de folder waar je Office 2000 hebt geïnstalleerd en selecteer het bestand "MSWORD9.OLB".
Zo, nu hebben we een correcte referentie naar Word 2000.
Als u slechts één versie van Office op uw PC heeft geïnstalleerd, dan heeft u dit probleem niet. Dan ziet u in het scherm met de beschikbare referenties meteen de juiste versie en klikt u meteen het vinkje aan.
Het maakt voor de voorbeelden in dit artikel niet uit welke versie van Word u gebruikt (97/2000/2002).
Goed, de referentie is gelegd, het is tijd om Word aan te roepen in de code.
Word starten met early binding
Zonder meteen in te gaan op de term "early binding" gaan we nu Word starten vanuit VB(A).
Public Function WordEarly()
Dim objWordApp As Word.Application
Set objWordApp = CreateObject("Word.application")
objWordApp.Visible = True
Set objWordApp = Nothing
End Function
We declareren de variable objWordApp expliciet als "Word.Application". Op de tweede regel wordt de variabele objWordApp werkelijk geïnstantieerd. We gebruiken hier de functie "CreateObject" voor.
De doorgewinterde (Office/VB) programmeur zal zich meteen afvragen waarom we niet "Set objWordApp = New Word.Application" gebruiken, want da's toch de standaard manier om een COM object te instantieren? In het knowledgebase artikel "Q244264" van Microsoft wordt geadviseerd om CreateObject te gebruiken voor het instantieren van Office objecten. Het heeft nog een ander voordeel dat in de volgende paragraaf duidelijk zal worden.
Op de volgende regel in de voorbeeld code zien we dat we Word zichtbaar maken. Als je Word namelijk via automatisering aanroept, dan is het in eerste instantie onzichtbaar. We moeten Word dus zelf zichtbaar maken voor de gebruiker. Tot slot wordt in de voorbeeldcode de variabele op "Nothing" gezet, om alle geheugen weer vrij te maken die door de variabel in gebruik is.
Hergebruik Word
Elke keer als de bovenstaande voorbeeldcode wordt uitgevoerd, wordt er weer een aparte Word applicatie opgestart. Als we dat een paar keer doen op een wat "magere" PC, dan krijgen we in no time de melding "Out of Memory", of op zijn minst gebruikers die klagen over hun trage programma/machine. In de meeste gevallen is het daarom beter om eerst te kijken of er al een Word applicatie actief is en vervolgens die applicatie te gebruiken voor je automatiseringssessie.
We breiden het eerste voorbeeld uit met de mogelijkheid om een openstaande Word applicatie te hergebruiken voor ons automatiseringsobject. We gaan met de functie "GetObject" proberen om onze variabele objWordApp aan een bestaande Word sessie te koppelen. Indien dit mislukt, dan openen we Word weer zoals in het eerste voorbeeld met "CreateObject".
Public Function WordEarly2()
Dim objWordApp As Word.Application
On Error Resume Next
'Probeer eerst of er al een instantie van Word open staat
Set objWordApp = GetObject(, "Word.application")
If Err.Number = 429 Then
'429 = ActiveX component can't create object
'Er is nog geen instantie van Word open
'We moeten zelf een instantie van Word openen
Set objWordApp = CreateObject("Word.application")
End If
On Error GoTo 0
objWordApp.Visible = True
objWordApp.Activate
Set objWordApp = Nothing
End Function
In het bovenstaande voorbeeld kunt u zien dat we de error handling op "resume next" zetten. We gaan vervolgens proberen om de variabele te linken aan een bestaande Word-sessie. Lukt dit niet, omdat er geen Word-sessie actief is, dan wordt er een fout 429 gegenereerd en moeten we zelf een Word-sessie starten. We zetten vervolgens de error handling weer uit (goto 0). We maken Word zichtbaar. Als er al een Word-sessie actief was, dan moet je ook nog zorgen dat Word de actieve applicatie wordt, anders houdt de applicatie waarin je de code uitvoert de focus.
In uw eigen applicatie moet u wel zorgen voor een betere foutafhandeling dan in het bovenstaande voorbeeld.
Word besturen
Tot nu toe hebben we alleen nog maar Word opgestart (zonder document zelfs). De hoogste tijd om Word echt te gaan "besturen".
We nemen weer het eerste voorbeeld waarin we een nieuwe Word-sessie openen. Vervolgens maken we een nieuw document aan en typen wat tekst in het nieuwe document. Tot slot roepen we het "Opslaan als" dialoog venster op en zorgen dat deze start in "C:\".
Public Function WordEarly3()
Dim objWordApp As Word.Application
Dim objWordDoc As Word.Document
Set objWordApp = CreateObject("Word.application")
Set objWordDoc = objWordApp.Documents.Add
With objWordDoc
.Range().Text = "Zeer geachte mensen," & _
vbNewLine & vbNewLine & _
"Word automatiseren is leuk!"
End With
objWordApp.Visible = True
With objWordApp.Dialogs(wdDialogFileSaveAs)
.Name = "C:\"
.Show
End With
Set objWordDoc = Nothing
Set objWordApp = Nothing
End Function
Het bovenstaande voorbeeld is nog steeds erg eenvoudig, maar laat al zien dat de mogelijkheden om Word te "besturen" zeer krachtig zijn. Feitelijk kunt u bijna alles wat in Word mogelijk is, automatiseren.
Late binding
Alle voorgaande voorbeelden maken gebruik van "early binding". Nu geven we een voorbeeldje van "late binding" en gaan dan verder in op de verschillen tussen early en late binding.
Public Function WordLate()
Dim objWordApp As Object
Set objWordApp = CreateObject("Word.application")
objWordApp.Visible = True
Set objWordApp = Nothing
End Function
Bovenstaande code is bijna identiek aan het eerste voorbeeld van dit artikel. Het enige verschil zit in de eerste regel. De variabele wordt nu als "Object" gedeclareerd in plaats van als "Word.Application".
Wat is dan verder het verschil met early binding? Het grote verschil is dat er bij late binding geen verbinding is met de Word Object Library tijdens het programmeren. U hoeft daarom bij late binding ook geen referentie te leggen naar een Word Object library, zoals we dat gedaan hebben in het begin van het artikel.
Nu kunnen we ook verklaren waarom de ene methode early binding heet en de andere late. Bij early binding wordt meteen bij de declaratie "verteld" naar wat voor soort object (Word applicatie) we willen refereren. Bij late binding gebeurt dat pas als we de code uitvoeren en de object variabele instantieren.
Beide methodes hebben zo hun voor- en nadelen.
Voor- en nadelen early vs late binding
De voordelen van early binding t.o.v. late binding zijn:
- sneller tijdens de uitvoer van de code
- events onderscheppen met "WithEvents"
- IntelliSense kan worden gebruikt
- de objectbrowser (F2) geeft het objectmodel weer (alle functies en eigenschappen van Word)
- automatische controle van de code tijdens het compileren
- context gevoelige Help gebruiken vanuit de VB(A) editor
- gebruik van ingebouwde constanten
En de voordelen van late binding t.o.v. earky binding zijn (of liever … is):
De conclusie lijkt gauw gemaakt: early binding wint. Dit is ook de conclusie van veel artikelen over dit onderwerp. Maar toch … in de praktijk kiezen we vaak voor late binding. Waarom?
Referentie hel
Een groot deel van de problemen met het automatiseren van Office componenten (en andere COM objecten) wordt veroorzaakt door referenties. Of beter gezegd, door het ontbreken van (de juiste) referenties.
In een aantal gevallen is dit weer op te lossen door de referenties steeds bij het opstarten te controleren en eventueel weer te leggen. Maar wat als de hele applicatie (bijv. Word) ontbreekt op de computer van de gebruiker? Bij het gebruik van early binding zal je programma een runtime fout geven en niet verder gaan. Ook is het opnieuw leggen van referenties niet altijd mogelijk (bijvoorbeeld niet in een Access .mde bestand).
Daarnaast geven bepaalde combinaties van referenties problemen. In onze praktijk hebben we bijvoorbeeld ondervonden dat Access 97 geen goede automatiseringsvriend is met Outlook 2000.
Vervelend is ook dat je programma soms stuk loopt op een stuk code dat helemaal niks met het automatiseringsobject heeft te maken. Dat maakt het vinden van deze problemen erg moeilijk.
Vroeg programmeren, laat opleveren
Het programmeren van bijvoorbeeld Word zonder IntelliSense en contextgevoelige help is toch wel een heel gemis. Hoe kunnen we nu het programmeergemak van early binding combineren met de voordelen van late binding?
Tijdens het programmeren gebruik je early binding: leg een referentie naar Word en declareer de objecten specifiek (objWord as Word.Application). Voordat je het programma oplevert aan je gebruikers, verbreek je de referentie en declareer je de objecten weer algemeen (objWord as Object).
Bijvoorbeeld:
Dim objWordApp As Object
'Dim objWordApp As Word.Application
Laat of vroeg?
Wat is nu beter, early of late binding?
Het antwoord is afhankelijk van het soort project en van de geïnstalleerde software van uw eindgebruikers. Gebruik early binding in een omgeving waar u inzicht heeft in de geïnstalleerde componenten die u wilt automatiseren. Gebruik late binding als u geen goed inzicht heeft in de te automatiseren software van uw eindgebruikers.
Ontwikkelt u een programma voor gebruikers die bijvoorbeeld allemaal Office XP hebben geïnstalleerd, maak dan gebruik van early binding. Maakt u bijvoorbeeld standaard software voor onbekende gebruikers, gebruik dan late binding.
Zorg in ieder geval voor een solide foutafhandeling. Voorkom dat er onzichtbare Word objecten blijven openstaan na een programmafout.
Wat nog meer?
De voorbeelden in dit artikel zijn wat eenvoudig gebleven, maar geven een goede basis om zelf aan de slag te gaan. Denk bijvoorbeeld eens aan het samenvoegen (mailmerge) van Word brieven met database gegevens. Daarnaast kun je ook de overige programma's van Microsoft Office middels automatisering geheel naar je hand zetten.
Conclusie
Microsoft Word (en de overige Office applicaties) zijn via automatisering relatief eenvoudig te integreren in uw projecten. Kies tijdens het ontwikkelen bewust voor late of early binding, zodat u niet voor verrassingen komt te staan bij de oplevering.