Office Addins Maken in Delphi 2005
In Delphi Win32 kennen we al enige tijd de Servers-tab in het component-palette. Deze componenten zijn wrappers rond COM-interfaces. Op deze manier is het mogelijk om automation toe te passen op een Office-applicatie. Je kunt daarmee de Office-applicatie vanuit je eigen Delphi applicatie sturen. Het is echter ook mogelijk om addins te maken voor Office-producten. In dit artikel kijk ik naar een manier om dit te doen in Delphi.NET.
PIAs
Microsoft heeft voor .NET een equivalent voor de componenten op de Servers-tab die we al kennen. Dit zijn managed assemblies die de typedefinities van het COM-interface van de Office-applicaties in zich hebben. Met deze types kun je Office-applicaties aansturen, maar ook gebruik maken van de addin-mogelijkheden.
Deze assemblies hebben de naam PIA: Primary InterOp Assembly. Ze worden overigens in de GAC (Global Assembly Cache) geïnstalleerd wanneer je een volledige installatie van een Office-product doet. Een PIA wordt gesigned door de uitgever van de applicatie waar hij voor is.
Visueel
Een COM addin is een in-process COM-server, die de IDTExensibility2-interface implementeert. Deze interface zit in de Msaddndr.dll library. Een klasse die deze interface implementeert moet 5 methods ondersteunen.
Als je de SDK van een Office-applicatie installeert - die je bij Microsoft kunt downloaden - dan heb je in Visual Studio de mogelijkheid om via de Project-wizard een Office AddIn te maken. Hierbij worden de PIAs gebruikt. De wizard gebruikt een template die je veel tikwerk bespaart, maar de addin moet nog wel helemaal in code worden opgezet.
In Delphi 2005 hebben we (nog) niet de mogelijkheid om hiervoor een wizard te gebruiken. Dit zou nog meer uitzoeken en codekloppen gaan opleveren.
Er is echter een eenvoudiger manier: Add-In Express.NET, of kortweg ADX.NET.
Met ADX.NET kun je het visuele gedeelte van je addin in de IDE opzetten. Daarnaast wordt er een klasse voor je gegenereerd die het IDTExensibility2-interface al helemaal implementeert. Je hoeft je zodoende alleen bezig houden met de functionele aspecten van je addin, zonder dat je druk hoeft te maken over hoe dit op de achtergrond werkt. Een prima voorbeeld van encapsulation.
Microsoft heeft voor .NET een equivalent voor de componenten op de Servers-tab die we al kennen
Met ADX.NET - er is overigens ook een VCL versie - kun je alleen het visuele gedeelte van de addin ontwikkelen. In het manipuleren van de Office-applicatie voorziet ADX.NET niet, daar gebruiken we de PIAs direct voor.
Ik vond het overigens prettig om te merken dat de installer van ADX.NET verschillende ontwikkelomgevingen detecteert. Met 1 licentie heb je zodoende naast Delphi ook Visual Studio support.
Nieuw Project
Als voorbeeld ga ik in dit artikel een addin maken die tekst in Word van een animatie kan voorzien. Ik maak een nieuw project aan door File -> New -> Other the kiezen:

ADX.NET ondersteunt drie typen addins:
- COM: een extensie van de Office-applicatie door middel van b.v. een extra toolbar of floating window.
- SmartTag: een addin die een bepaalde tekst herkent in een Office-applicatie. De gebruiker kan door rechts-klikken op de tekst bij de functionaliteit van de addin komen.
- Excel RTD (RealTimeData) server: hiermee kun je RealTime data ter beschikking stellen aan Excel (b.v. aandelenkoersen). De gebruiker kan deze data door middel van een formule in Excel opnemen.
In dit geval kies ik voor de COM-addin.

Een wizard verschijnt, waarin je een naam en locatie aangeeft. Als je op finish drukt, wordt er een unit gegenereerd met een klasse afgeleid van ADXAddinModule, een MarshalByRefObject afgeleide, waar de afhandeling naar het COM-interface ingekapseld is. Het GUID-attribute wordt al boven de klasse gezet en de register- en unregister-methods zijn al geïmplementeerd.
Om een referentie naar de PIA te krijgen kies je Add Reference en Interop.Word.DLL. In de uses clause neem je Word op.
SupportedApps

De unit heeft een visuele representatie, zodat je properties met de object-inspector kunt opgeven. Met de SupportedApps stel je in welke Office producten je wilt ondersteunen. Je kunt ook meerdere Office applicaties tegelijk ondersteunen, alleen zul je hier wel rekening moeten houden bij het casten naar het interface, zoals je later zult zien.
CommandBars

Door met rechts te klikken kun je diverse CommandBars toevoegen. Meerdere CommandBars binnen een addin behoren tot de mogelijkheden.
Ik kies voor Add CommandBar. ExplorerCommandBar en InspectorCommandBar zijn specifiek voor Outlook. Je kunt deze activeren voor specifieke items die geselecteerd worden in de Explorer of de Inspector van Outlook.

Interessante properties van de ADXCommandBar klasse zijn:
- Position: werkt analoog aan de Align property van een visuele component in Delphi Win32. AdxMsoBarFloating (default), adxMsoBarLeft, adxMsoBarRight, adxMsoBarTop, adxMsoBarBottom behoren tot de mogelijkheden, maar ook de interessantere adxMsoBarPopup en adxMsoBarMenuBar.
- Protection: hiermee kun je het gebruik van je CommandBar beperken, b.v. via adxMsoBarNoMove.
- Controls: de collectie van controls die je in de CommandBar wilt hebben met keuze uit button, combobox, edit, dropdownlist en popup. In het voorbeeld gebruik ik een combobox.
De controls hebben bijna alle gebruikelijke properties en een event. Bij de combobox heet het event Change.
Gezien het feit dat de diverse interfaces van de PIAs zeer uitgebreid zijn, ben je op dit punt aangewezen op de uitgebreide documentatie op de MSDN-site van Microsoft en/of op de good old class completion
Implementatie
Buiten het feit dat ADXAddinModule een HostApplication-property heeft die de Office-applicatie voorstelt waar je Addin onder draait, helpt ADX.NET je op dit punt niet.
Gezien het feit dat de diverse interfaces van de PIAs zeer uitgebreid zijn, ben je op dit punt aangewezen op de uitgebreide documentatie op de MSDN-site van Microsoft en/of op de good old class completion.
HostApplication is een property van het type TObject. Deze zul je moeten typecasten naar het interface. Voor het gemak voeg ik hiervoor een functie toe aan mijn klasse:
function TAddinModule.WordHost: Word._Application;
begin
Result := HostApplication as Word._Application;
end;
De implementatie van het Change event ziet er zo uit:
procedure TAddinModule.AnimationComboBox_Change(
sender: System.Object);
var
Effect: Integer;
ActiveWindow: Word.Window;
SelObj: Word.Selection;
begin
Effect := AnimationComboBox.ListIndex;
ActiveWindow := WordHost().ActiveWindow;
try
if ActiveWindow <> nil then
begin
SelObj := ActiveWindow.Selection as
Word.Selection;
try
if SelObj <> nil then
case effect of
1:
SelObj.Font.Animation :=
Word.WdAnimation.wdAnimationNone;
2:
SelObj.Font.Animation :=
Word.WdAnimation.
wdAnimationBlinkingBackground;
3:
SelObj.Font.Animation :=
Word.WdAnimation.wdAnimationLasVegasLights;
4:
SelObj.Font.Animation :=
Word.WdAnimation.
wdAnimationMarchingBlackAnts;
5:
SelObj.Font.Animation :=
Word.WdAnimation.wdAnimationMarchingRedAnts;
6:
SelObj.Font.Animation :=
Word.WdAnimation.wdAnimationShimmer;
7:
SelObj.Font.Animation :=
Word.WdAnimation.wdAnimationSparkleText;
end;
finally
Marshal.ReleaseComObject(SelObj);
end;
end;
finally
Marshal.ReleaseComObject(ActiveWindow);
end;
end;
Alle zaken waar Word voor staat worden “geleverd” via het interface. De implementatie ervan zit in de COM-server.
De aanroep naar Marshal.ReleaseComObject is belangrijk, omdat dit ervoor zorgt dat de COM- instantie achter het proxy object verdwijnt, waardoor deze door de garbage collector wordt opgeruimd.
Registreren

De addin, een DLL, moet na het compileren geregistreerd worden in de registry van Windows, zodat de Office-applicatie “ziet” dat er een addin is. Dit kan binnen Delphi onder het Run menu. Buiten Delphi kun je met bijv. InstallShield of een eigen gemaakt installatie programma de klasse registreren door de class method Register aan te roepen.
Resultaat
Na registratie is het alleen nog een kwestie van Word starten. De gebruiker kan zelf de addin in of uitschakelen in het Tools-menu.

Meer info