Über unsMediaKontaktImpressum
Ralf Nebelo 16. Mai 2014

MS Office: App-Entwicklung für Office-Anwendungen

Hinter dem neuen Befehl Apps für Microsoft Office im Menüband Einfügen von Excel 2013 verbirgt sich ein radikal neues Erweiterungskonzept, das Apps an die Stelle von Makros setzen und Webtechniken und Cloud-Dienste direkt in die Bedienoberflächen aller Office-Anwendungen (und ihrer jeweiligen Web-App-Versionen) integrieren will.

Obwohl sich Apps für Microsoft Office (oder kürzer: Office-Apps) auch lokal bereitstellen lassen – was wir in diesem Artikel anhand von zwei Beispielen demonstrieren werden –, erhält man sie vorzugsweise im Office Store. Das ist ein gleichfalls neuer Online-Shop, den man direkt aus den MS Office-Anwendungen heraus erreicht.

Der Office Store präsentiert das bislang vorwiegend englischsprachige App-Angebot in übersichtlicher Form und reduziert die Installation des gewählten Helferleins auf wenige Mausklicks. Die schnelle Verfügbarkeit macht Office-Apps für Anwender und damit natürlich auch für Entwickler attraktiv. Grund genug also, sich mit den Grundlagen der neuen Office-Apps vertraut zu machen.

MS Office-Programmierung: Bestandteile einer Office-App

Eine Office-App ist im Grunde eine normale Webanwendung, die aber nicht auf einem Server im Internet, sondern in Office „gehostet“ und angezeigt wird. Die typische Office-App besteht aus den folgenden Komponenten:

  • Webseite: Dabei handelt es sich um eine (halbwegs) normale HTML-Datei, die man wie jede andere Webseite auch mit Steuerelementen aus dem HTML-, ASP.NET-, Silverlight- oder Flash-Fundus bestücken kann. Das Aussehen der Webseite kann der Entwickler über standardmäßige Webtechniken wie HTML5, XML und CSS3 bestimmen. Die Webseite bildet die Bedienoberfläche der Office-App.
  • Skriptdatei: Das ist zumeist eine JavaScript-Datei, die den Programmcode der App enthält und damit für die „Action“ zuständig ist. Wie bei regulären Webanwendungen wird die Verbindung zwischen Webseite und Skriptdatei häufig über das onclick-Attribut der Steuerelemente hergestellt. Es weist dem jeweiligen Steuerelement eine Ereignisroutine in der Skriptdatei zu. Der Code darin bestimmt, was beim Anklicken des Steuerelements geschieht. Grundsätzlich lässt sich die gewünschte Funktionalität einer Office-App aber nicht nur über eine externe Skriptdatei, sondern über jede Art der client- oder serverseitigen Programmierung bereitstellen. Das kann im einfachsten Fall ein in die Webseite eingebettetes Skript sein, in anspruchsvolleren Szenarien eine komplexe ASP.NET-Anwendung. Über REST-APIs kann eine Office-App so gut wie jeden Web-Service zur Informationsbeschaffung anzapfen.
  • Icon-Datei (optional): Diese BMP-, GIF-, EXIF-, JPG-, PNG- oder TIFF-Datei enthält das Icon der Office-App, das eine Größe von 32 mal 32 Pixel aufweisen muss. Fehlt die Icon-Datei oder weist sie eine andere Bildgröße auf, erhält die App ein monochromes Standard-Icon zugewiesen.
  • OfficeStyles.css (optional): Diese Datei stellt das Stylesheet für die Office-App bereit und weist allen Bestandteilen der Webseite die Office-typischen Schriftarten und Formatierungen zu.
  • Manifestdatei: Diese XML-Datei ist das Bindeglied zwischen den einzelnen App-Elementen. Die Manifestdatei verrät der Office-Anwendung unter anderem, wo die Webseiten- und die Icon-Datei (falls vorhanden) zu finden sind. Darüber hinaus definiert sie die Einstellungen der App, ihre Fähigkeiten und Rechte.
  • JavaScript-API für Office: Diese von Microsoft bereitgestellte und online verfügbare Bibliothek (die eine JavaScript-Datei ist) stellt die Verbindung zwischen der Office-Anwendung und der App-Webseite her. Die Bibliothek sorgt dafür, dass die App unter anderem auf Inhalte des Dokuments zugreifen oder mit der als Host fungierenden Office-Anwendung kommunizieren kann. Die Risiken einer solchen Interaktion zwischen Anwendung und App will Microsoft insbesondere durch eine sorgsame Trennung der beiden klein halten. Dazu sperrt der Hersteller die HTML-Datei in ein Webbrowser-Control und lässt dieses in einem von der Host-Anwendung unabhängigen Prozess ausführen. Zu den weiteren Sicherheitsmaßnahmen gehört eine restriktive Laufzeitumgebung. Die überwacht jede Interaktion über Prozessgrenzen hinweg und gestattet Zugriffe auf die Daten und die Bedienoberfläche der Office-Anwendung grundsätzlich nur über asynchrone Methoden, die den Office-Prozess weder ausbremsen noch zum Entgleisen bringen können.

Die Auflistung der App-Elemente lässt bereits erahnen, dass die Entwicklung von Office-Apps vorzugsweise in die Zuständigkeit erfahrener Webentwickler fällt. Klassische Office-Entwickler, die sich „nur“ mit VBA und eventuell noch mit den Visual Studio Tools for Office auskennen, werden sich in einer neuen Programmierwelt zurechtfinden müssen. Aus diesem Grund kann der vorliegende Artikel auch kaum mehr als eine Einführung in das Thema sein. Für das Verständnis der folgenden Ausführungen und Codepassagen sind grundlegende HTML-, XML- und JavaScript-Kenntnisse erforderlich. Wer weiterführende Infos benötigt, findet diese auf Microsofts Portal für Office-App-Entwickler [1].

MS Office-Programmierung: Typen von Office-Apps

Es gibt drei Typen von Office-Apps, die man nach dem Erscheinungsort der App-Oberfläche (die ja von der App-Webseite bereitgestellt wird) unterscheidet:

  • Aufgabenbereich-App: Diese Office-App zeigt sich im Aufgabenbereich der Office-Anwendung am rechten Rand des Dokumentfensters. Apps dieser Art eignen sich insbesondere dazu, dem Anwender kontextbezogene Informationen und Funktionen – für die Suche oder das Übersetzen von Inhalten beispielsweise – zu liefern.
  • Inhalt-App: Diese Office-App erscheint ähnlich wie ein Excel-Diagramm als abgegrenzter Bereich innerhalb des Dokuments. Inhalt-Apps eignen sich vor allem für die Visualisierung von Daten oder die Wiedergabe von YouTube-Videos und anderen Internetmedien. Microsofts Suchmaschine Bing stellt Excel-Anwendern unter anderem eine Aufgabenbereich-App (hinten) sowie eine Inhalt-App zur Verfügung.
  • Mail-App: Sie klinkt sich in Outlook-Formulare ein und stellt dem Anwender dort maß- geschneiderte Infos und Funktionen bereit, die sich auf das jeweils angezeigte Outlook- Element – eine Nachricht, eine Besprechungsanfrage oder einen Termin etwa – beziehen. Mail-Apps funktionieren nur im Zusammenspiel mit Exchange 2013, normale POP- und IMAP-Konten werden nicht unterstützt.

Während Mail-Apps quasi naturgemäß auf Outlook festgelegt sind, sollten Inhalt- und Aufgabenbereich-Apps von der Konzeption her eigentlich in allen Office-Anwendungen nutzbar sein, die der Bearbeitung von Dokumenten dienen. Momentan unterstützt aber nur Excel beide App-Typen, während sich PowerPoint, Project und Word 2013 nur mit Aufgabenbereich-Apps erweitern lassen. Die Tabelle zeigt den aktuellen Stand, der sich jedoch jederzeit ändern kann.

MS Office-Programmierung: App-Typen nach Anwendungesbereich

Anwendung Aufgabenbereich-App Inhalt-App Mail-App
Access 2013 - - -
Excel 2013 + + -
Excel-Web-App - + -
Outlook 2013 - - +
Outlook-Web-App - - +
PowerPoint 2013 + - -
PowerPoint-Web-App - - -
Project 2013 + - -
Word 2013 + - -
Word-Web-App - - -

Anders als ein konventionelles Office-Add-in, das man für jede Applikation separat entwickeln muss, lässt sich eine App aber sehr leicht so gestalten, dass sie mit demselben Code in jeder Office-Anwendung funktioniert, die den jeweiligen App-Typ unterstützt.

MS Office-Programmierung: Werkzeuge für die App-Entwicklung

Auch wenn die App-Entwicklung einiges Wissen über Webtechniken erfordert, so benötigt man doch erfreulich wenig Handwerkszeug dafür: Ein schlichter Texteditor genügt für den Anfang (und die Realisierung der nachfolgenden Beispiel-Apps).

Allerdings sollte man es auch nicht übertreiben, indem man sich mit dem Windows-eigenen Notepad begnügt. Wesentlich angenehmer lässt es sich beispielsweise mit Notepad++ arbeiten, da es unter anderem mehrere Fenster für die Bearbeitung der verschiedenen Projektdateien unterstützt. Die Download-Adresse für das nützliche Open-Source-Werkzeug lautete zuletzt wie folgt [2].

Wer es komfortabler mag, verwendet die Napa Office 365 Development Tools. Dabei handelt es sich um eine webbasierte Entwicklungsumgebung, mit der Sie im Browser Projekte erstellen, Code schreiben und Ihre Apps ausführen können. Weitere Informationen finden Sie hier [3].

Das mit Abstand komfortabelste, leistungsfähigste, aber auch teuerste Werkzeug zum Erstellen einer Office-App ist Visual Studio 2012. Die Entwicklungsumgebung verfügt über eine spezielle App für Office-Projektvorlage, die dem Entwickler viele Handgriffe, die er ansonsten manuell erledigen müsste, erspart. Darüber hinaus beschleunigt Visual Studio die App-Entwicklung mit einer Projektmappe, die eine vorkonfigurierte Manifestdatei, Skript-bibliotheken, Stylesheets sowie HTML- und JavaScript-Ausgangsdateien enthält.

MS Office-Programmierung: Beispiel 1 - Einfache Anwendung

Die Arbeit an unserer ersten Beispiel-App beginnt mit dem Anlegen einer Ordnerstruktur, die die diversen Projektdateien aufnimmt. Dazu benötigen Sie eine Netzwerkfreigabe, die auf einem Rechner Ihres Firmen- respektive Heimnetzes oder einer Netzwerkfestplatte (NAS) liegen kann. Lokale Festplatten kommen nicht in Betracht, da Office 2013 für Speicherortangaben ausschließlich echte URLs (ohne „file:///“-Präfix) akzeptiert.

Fügen Sie der Netzwerkfreigabe zunächst ein neues Stammverzeichnis für die App-Entwicklung hinzu, das Sie mit OfficeApps benennen. Dieses Stammverzeichnis dient unter anderem der Aufnahme der Manifestdatei(en) (und ist damit gleichzeitig auch der Manifestordner). Fügen Sie dem Stammverzeichnis einen Unterordner namens SimpleApp hinzu, der die Heimat der Beispiel-App bildet.

Die Webseite von SimpleApp

Zunächst erstellen Sie die Webseite der Beispiel-App, indem Sie eine HTML-Datei mit folgendem Inhalt anlegen (die erste Zeile bitte weglassen, sie verweist nur auf den Speicherort der Datei auf der Buch-CD). Speichern Sie die HTML-Datei anschließend unter dem Namen SimpleApp.html im Unterordner SimpleApp.

<! 15\OfficeApps\SimpleApp\SimpleApp.html >
<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
    <link rel="stylesheet" type="text/css" 
        href="../OfficeStyles.css" />
    <script src="SimpleApp.js"></script>
    </head>
    <body>
    <input type="text" value=https://www.hanser-fachbuch.de/fachbuch 
        id="TextBox1" style="margin-top: 10px; width: 280px" />
    <input type="button" value="Öffnen" id="Button1" onclick= 
        "doAction()" style="margin-top: 10px; margin-right: 10px; padding: 0px; width: 100px;" />
    </body>
</html>

Wer sich mit HTML ein wenig auskennt, erkennt rasch, dass sich die Struktur dieser App-Webseite kaum von jeder anderen Webseite unterscheidet. Erklärungsbedürftig ist allenfalls das zweite meta-Element innerhalb des HTML-Kopfs, das den Internet Explorer zur bevorzugten Rendering-Engine erhebt.

Das link-Element stellt einen Verweis auf das Stylesheet OfficeStyles.css im übergeordneten Verzeichnis (..\) her. Da diese CSS-Datei ziemlich umfangreich ist, kopieren Sie sie der Einfachheit halber von der Buch-CD in Ihren neu angelegten OfficeApps-Ordner, wo sie künftig allen Apps zur Verfügung steht.

Das script-Element erhebt die Datei SimpleApp.js im gleichen Verzeichnis in den Rang der zuständigen Skriptdatei.

Die Anweisungen innerhalb des body-Blocks statten die Webseite mit zwei HTML-Controls aus, einer Textbox und einem Button. In der Textbox erscheint die Webadresse „https://www.hanser-fachbuch.de/fachbuch“ als Vorgabewert, dem Button wird per onclick-Attribut eine Funktion namens „doAction“ als Ereignisroutine für das Anklicken zugewiesen.

MS Office-Programmierung: Skriptdatei der SimpleApp

Die oben erwähnte doAction-Funktion bildet den einzigen Inhalt der nachfolgend abgebildeten Skriptdatei SimpleApp.js. Speichern Sie diese – genau wie die HTML-Datei zuvor – im Unterordner SimpleApp. Die erste Zeile können Sie beim Abtippen wieder weglassen.

/* 15\OfficeApps\SimpleApp\SimpleApp.js */
function doAction() {
    var url = document.getElementById("TextBox1").value
    window.location.href = url; }

Der Inhalt der doAction-Funktion ist schnell erklärt. Die erste Anweisungszeile liest den aktuellen Inhalt der Textbox, bei dem es sich um eine gültige Webadresse handeln sollte, in die Variable url ein. Die zweite Zeile öffnet dann ein Browserfenster, das den Inhalt der entsprechenden Internetseite anzeigt.

Die Manifestdatei von SimpleApp

Die Manifestdatei unserer Beispiel-App hat folgenden Inhalt (erste Zeile bitte wieder weglassen):

<! 15\OfficeApps\SimpleApp.xml >
<?xml version="1.0" encoding="utf-8"?>
<OfficeApp xmlns=
    "http://schemas.microsoft.com/Office/appforOffice/1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:type="TaskPaneApp">
    <Id>08afd7fe-1631-42f4-84f1-5ba51e242f11</Id>
    <Version>1.0</Version>
    <ProviderName>Ralf Nebelo</ProviderName>
    <DefaultLocale>EN-US</DefaultLocale>
    <DisplayName DefaultValue="SimpleApp"/>
    <Description DefaultValue="Meine erste Office-App"/>
    <IconUrl DefaultValue=
      "\\MYBOOKDATA\Public\OfficeApps\SimpleApp\SimpleApp.png"/>

    <Capabilities>
        <Capability Name="Document"/>
        <Capability Name="Workbook"/>
    </Capabilities>

    <DefaultSettings>
        <SourceLocation DefaultValue=
          "\\MYBOOKDATA\Public\OfficeApps\SimpleApp\SimpleApp.html"/>
    </DefaultSettings>
    <Permissions>ReadWriteDocument</Permissions>
</OfficeApp>

Speichern Sie diese Manifestdatei unter dem Namen SimpleApp.xml im Stammverzeichnis (respektive Manifestordner) OfficeApps.

Im Normalfall werden Manifestdateien nicht lokal gespeichert. Das ist nur für die Dauer der Programmierung der Fall oder wenn die App ausschließlich für Teilnehmer des eigenen Heim- oder Firmennetzwerks gedacht ist. Möchte man eine App in Microsofts eingangs erwähntem Office Store veröffentlichen (und sie damit weltweit für alle Office-Anwender verfügbar machen), so leitet man das Manifest im Rahmen eines offiziellen Anmelde- und Prüfverfahrens an Microsoft weiter. Informationen darüber finden Sie hier.

Die HTML-Datei und alle weiteren Bestandteile der App gehören dann auf einen öffentlich erreichbaren Webserver, dessen Adresse im Manifest zu vermerken ist.

Der konstruktive Inhalt der abgedruckten Manifestdatei beginnt mit einem XML-Element namens OfficeApp, das neben dem verwendeten XML-Schema gleich auch den App-Typus definiert. Letzteres fällt in die Zuständigkeit des Attributs xsi:type, das im Falle einer Aufgabenbereich-App den Wert „TaskPaneApp“ enthält. Bei einer Inhalt- oder Mail-App würden die Attributwerte „ContentApp“ beziehungsweise „MailApp“ lauten.

Das Id-Element benennt die GUID der App, die man als eine Art Seriennummer bezeichnen könnte. Diese sollte für jede App neu generiert werden, was sich unter anderem mit dem Online GUID Generator [4] erledigen lässt. Im jeweiligen Verbreitungsraum der App (Office Store oder Netzwerk) muss die GUID auf jeden Fall eindeutig sein. Ist sie das nicht, taucht die App gar nicht erst im Auswahldialog der Office-Anwendung auf. Weniger kritisch ist der Inhalt des Version-Elements, das die Versionsnummer des Codegebildes angibt.

Die XML-Elemente DisplayName und Description definieren den Namen der App sowie eine Beschreibung ihrer Funktion, der Name des Entwicklers lässt sich im Element ProviderName verewigen. IconUrl verweist auf den Speicherort der Icon-Datei. Dabei handelt es sich im konkreten Fall um die Projektdatei SimpleApp.png, die Sie von der Buch-CD in den Projektordner SimpleApp kopieren sollten.

Die Icon-Datei wird nur sichtbar, wenn Sie die hinter DefaultValue angegebene URL an Ihre konkreten Gegebenheiten anpassen. Dabei müssen Sie stets absolute Angaben machen; relative URLs wie in der Webseitendatei sind in der Manifestdatei nicht zulässig.

Im Abschnitt Capabilities bestimmt das Manifest, mit welchen Office-Dokumenten die App zusammenarbeiten kann. Dabei steht „Document“ für ein Word-Dokument, „Workbook“ für eine Excel-Arbeitsmappe, „Project“ für ein Microsoft-Project-Projekt und „MailBox“ für ein Outlook-Postfach. Das Element Permissions weist der App die Rechte für den Umgang mit den aufgeführten Office-Dokumenten zu. Der Wert ReadWriteDocument erlaubt hier Lese- und Schreibzugriffe und bildet das Maximum an zuweisbaren Rechten. Weitere Abstufungen wären WriteDocument (nur Schreiben), ReadDocument (nur Lesen) und Restricted, die der App gar keinen Zugriff gewährt.

Das Element SourceLocation im Abschnitt DefaultSettings schließlich verweist auf den Speicherort der App-eigenen Webseite. Auch hier müssen Sie die angegebene (absolute!) URL an Ihre Gegebenheiten anpassen.

Vertrauenswürdige App-Kataloge

Die Office-Anwendungen laden lokal gespeicherte Apps grundsätzlich nur aus einem „Vertrauenswürdigen App-Katalog“, wobei es sich um den Ordner handelt, in dem die Manifestdateien gespeichert sind. Im Fall unserer Beispiel-App wäre das also der Ordner OfficeApps.

Um diesen Ordner nun in den Status der Vertrauenswürdigkeit zu erheben, starten Sie Excel 2013 und wählen Datei | Optionen. Klicken Sie links auf Trust Center und danach auf die Schaltfläche Einstellungen für das Trust Center. Markieren Sie links Vertrauenswürdige App-Kataloge und tragen Sie den UNC-Pfad des Ordners in das Textfeld „Katalog-URL“ ein – er sollte die Form „\\server\freigabe\manifestordner“ haben. Im Fall unseres Entwicklungsrechners lautet der Pfad:
\\MYBOOKDATA\Public\OfficeApps

Bleibt zu erwähnen, dass Sie auch diesen Pfad Ihren Gegebenheiten entsprechend ändern müssen. Wählen Sie dann KATALOG HINZUFÜGEN. Das Listenfeld enthält jetzt einen neuen Eintrag mit einem Kontrollkästchen dahinter („Im Menü anzeigen“). Das müssen Sie unbedingt einschalten, da Ihre Apps ansonsten nicht im Auswahldialog erscheinen. Anschließend schließen Sie alle Dialoge mit OK und starten Excel neu.

App-Start

Die Beispiel-App ist jetzt betriebsbereit und kann zum ersten Mal gestartet werden. Wählen Sie EINFÜGEN | APPS FÜR OFFICE, wobei Sie nicht auf das Icon, sondern auf dessen Pfeilsymbol klicken. Nach einem Klick auf ALLE ANZEIGEN und dann auf FREIGEGEBENE ORDNER sollte das Dialogfeld einen Eintrag namens „SimpleApp“ enthalten, dessen Icon aus einem Smiley besteht. Fehlt der Eintrag, empfiehlt sich ein Klick auf die Schaltfläche AKTUALISIERUNG, um die Anzeige auf den neuesten Stand zu bringen. Der Rest ist simpel: Markieren Sie „SimpleApp“, und wählen Sie EINFÜGEN. Wenn alles geklappt hat, erscheint die App nun am rechten Rand des Excel-Fensters. Inhaltlich bietet sie nicht viel: Sie können eine Webadresse eingeben und die entsprechende Seite dann mit einem Klick auf den Button in Ihrem Standard-Browser öffnen. SimpleApp halt!

Wenn die App einmal erfolgreich gestartet wurde, erscheint sie künftig im Schnellstartmenü des Apps für OFFICE-Symbols, das Sie mit einem Klick auf das Pfeilsymbol öffnen können.

MS Office-Programmierung: Das JavaScript-API für Office

SimpleApp ist zwar schon eine „echte“ App für Office, hat mit Office-Programmierung aber noch nicht viel zu tun. Sie ist absolut isoliert und kann anders als jedes VBA-Makro weder mit der Host-Anwendung kommunizieren noch Daten mit dem aktuellen Dokument austauschen.

Für diese Formen der Interaktion benötigt man das JavaScript-API für Office. Dabei handelt es sich um eine relativ umfangreiche Funktionsbibliothek, die auf einem Microsoft-Server liegt und damit online verfügbar ist (natürlich kann man die JavaScript-Datei auch herunterladen und lokal abspeichern). 

API-Anatomie

Das JavaScript-API stellt der Office-App ein ziemlich überschaubares Objektmodell für den programmierten Zugriff auf die Host-Anwendung und den Datenaustausch mit dem Dokument zur Verfügung. Eine vollständige Dokumentation finden Sie hier [6]. An der Spitze des Objektmodells steht das Office-Objekt. Es repräsentiert das API und verweist mit seiner context-Eigenschaft auf ein gleichnamiges Objekt, das den Laufzeitkontext der App verkörpert. Dieses Objekt wiederum stellt die Verbindung zum Document-Objekt her, welches Zugriff auf das konkrete Dokument gewährt und bei Aufgabenbereich- oder Inhalt-Apps stets im Mittelpunkt des Interesses steht. Bevor das Objektmodell nutzbar ist, muss das API initialisiert werden. Dazu setzt man die folgende Anweisung an den Anfang der Skriptdatei:
Office.initialize = function (reason) { }

Die Zeile installiert zugleich einen Ereignis-Handler, der beim Laden der App ausgeführt wird. Den kann man mit Code füllen, um eigene Initialisierungen vorzunehmen oder auf unterschiedliche Startbedingungen zu reagieren. So könnte es etwa von Interesse sein, ob die App erstmals eingefügt wurde oder bereits im Dokument vorhanden war. Zur Beantwortung der Frage sollte man den von Office übergebenen reason-Parameter auswerten. Das kann folgendermaßen aussehen:

Office.initialize = function (reason) {
if (reason == "inserted")
    showText("App wurde neu eingefuegt");
if (reason == "documentOpened")
    showText("App wurde mit Dokument geoeffnet");
}
function showText(text)
document.getElementById("TextBox1").value = text;
{

Auf Dokumentenereignisse reagieren

Alternativ lässt sich die Office.initialize-Routine auch nutzen, um einen Handler für Dokumentenereignisse – die Änderung der Auswahl beispielsweise – einzurichten. Dazu benutzt man die addHandlerAsync-Methode des Document-Objekts und übergibt ihr eine Office.EventType- Konstante, die das gewünschte Ereignis definiert, sowie den Namen der Routine, die das Ereignis behandeln soll. Das Beispiel

Office.initialize = function (reason) {
  Office.context.document.addHandlerAsync(
   Office.EventType.DocumentSelectionChanged, myHandler);
}
function myHandler(eventArgs) {
  showText("Auswahl geaendert");
}
erklärt die Routine myHandler zum offiziellen Event-Handler für das DocumentSelection-Changed-Ereignis. Das tritt in Excel auf, sobald der Anwender eine andere Zelle innerhalb des Arbeitsblatts aktiviert. In Word wirkt sowohl das Verschieben der Schreibmarke als auch das Markieren von Inhalten als Event-Trigger.

Rückgabe von markiertem Text

Wer nicht nur auf eine Änderung der Auswahl reagieren, sondern auch auf deren Inhalt zugreifen will, verwendet die getSelectedDataAsync-Methode des Document-Objekts und übergibt ihr eine passende Office.CoercionType-Konstante.

Die bestimmt den sogenannten Koersionstyp, das ist der Datentyp, den die Methode zurückgeben soll. Dabei kann es sich im einfachsten Fall um den reinen Text der Auswahl handeln, der sich wie folgt ermitteln lässt:

Office.context.document.getSelectedDataAsync(
    Office.CoercionType.Text, function(result) {
        if (result.status == "succeeded")
            showText(result.value);
        else
            showText(result.error.message);
    }
);
Die Methode greift auf den Inhalt der Auswahl zu und retourniert das Objekt result an die eingeschlossene function-Routine. Die überprüft zunächst die status-Eigenschaft des Objekts. Enthält diese den Text „succeeded“, war der Abruf des Auswahltextes erfolgreich. Eine leere status-Variable oder der Text „failed“ deuten auf einen Fehler hin, dessen Beschreibung dann in result.error.message steckt.

Rückgabe von mehreren markierten Werten

Neben simplem Text unterstützt das JavaScript-API noch weitere Rückgabetypen: Matrix und Table beispielsweise. Diese eignen sich für die Rückgabe respektive das Festlegen von tabellarischen Daten, wobei eine Table Kopfzeilen enthalten kann, eine Matrix nicht.

Die drei bislang genannten Typen funktionieren in allen App-tauglichen Office-Anwendungen. Table- oder Matrix-Daten stehen also nicht nur in Excel zur Verfügung, was man erwarten würde, sondern beispielsweise auch in Word, wo es ja ebenfalls Tabellen gibt.

Das JavaScript-API wandelt Daten, die nicht im passenden Typ vorliegen, in den meisten Fällen automatisch um. Sollte der Entwickler also einen Text anfordern, der Anwender aber einen Bereich mit mehreren Tabellenzellen markiert haben, so liefert das API dennoch einen Text zurück – in Form eines tabulatorseparierten Strings nämlich, der die Werte aller ausgewählten Zellen enthält.

Wer keinen Sammel-String, sondern jeden markierten Zellwert einzeln verarbeiten möchte, fordert den Typ Matrix beim Aufruf der getSelectedDataAsync-Methode ausdrücklich an:

Office.context.document.getSelectedDataAsync(
    Office.CoercionType.Matrix, function(result){
        if (result.status == "succeeded")
        showData(result.value);
    }
);

Die value-Eigenschaft des result-Objekts enthält dann im Erfolgsfall ein zweidimensionales Array mit den markierten Zellwerten. Die kann die aufgerufene showData-Funktion wie folgt mit zwei verschachtelten for-Schleifen zur Anzeige bringen:

function showData(data) {
    var text = "";
    for (var y = 0 ; y < data.length; y++) {
        for (var x = 0; x < data[y].length; x++) {
            text += data[y][x] + ", ";
        }
    }
    document.getElementById("TextBox1").value = text;
}

Markierte Dokumentinhalte ändern

Soll die Office-App den Inhalt der Auswahl nicht nur lesen, sondern aktiv verändern, wählt man die setSelectedDataAsync-Methode und übergibt ihr im einfachsten Fall einen Text, der die Dokumentauswahl ersetzt:
Office.context.document.setSelectedDataAsync("Neuer Text");
Im Fall von Word ersetzt der Text den Inhalt der Markierung, im Fall von Excel wird stets der komplette Inhalt der aktiven Zelle ausgetauscht, auch wenn der Anwender nur einen Teil davon markiert hat. Soll die App die Inhalte mehrerer Zellen ändern, die Teil der aktuellen Auswahl sind, definiert man zunächst ein passendes Array, das die neuen Werte enthält:
var arr = [['a', 'b'],['c', 'd'],['e', 'f']];
Dieses Array leitet man dann nebst einem weiteren Argument zur Festlegung der Datentyps Matrix an die setSelectedDataAsync-Methode weiter. Das Beispiel
Office.context.document.setSelectedDataAsync(arr, {coercionType: 'matrix'});

füllt einen zwei Spalten breiten und drei Zeilen hohen Tabellenbereich, dessen obere linke Ecke die aktive Zelle bildet, mit den Buchstaben „a“ bis „f“.

Das deutlich spektakulärere Einfügen von Bildern gelingt ausschließlich im Office-eigenen Textprogramm Word. In Excel ist es bislang nicht vorgesehen.

Entwicklerdefinierte Dokumentinhalte ändern

Über die vom Anwender festgelegte Auswahl hinaus können Office-Apps auch mit Regionen eines Dokuments interagieren, die der Entwickler bestimmt. Dazu muss die Region allerdings einen eindeutigen Namen besitzen, was im Fall von Excel auf benannte oder als Tabelle/Liste formatierte Arbeitsblattbereiche, in Word unter anderem auf Inhaltssteuerelemente zutrifft.

Für den Zugriff auf eine solche Region generiert die App zunächst eine „Bindung“, über die sie dann den Inhalt der Region sowohl lesen als auch ändern kann. Dazu stehen ihr die Methoden getDataAsync und setDataAsync zur Verfügung, die ähnlich funktionieren wie die zuvor vorgestellten Methoden getSelectedDataAsync und setSelectedDataAsync für den Umgang mit Markierungsinhalten. Die verfügbaren Datentypen sind in beiden Fällen identisch.

Die zuvor schon erwähnte JavaScript-API-Dokumentation [5] enthält ausführliche Infos über den Zugriff auf Regionen.

Auf die Dokumentdatei zugreifen

Neben der Interaktion mit markierten Dokumentinhalten und benannten Regionen erlaubt das JavaScript-API auch einen programmierten Zugriff auf die Dokumentdatei. Den erhält man mit Hilfe der getFileAsync-Methode. Damit kann man das Dokument beispielsweise versenden oder im Firmennetzwerk veröffentlichen. Zugang zum gesamten Dokumentinhalt liefert die Methode aber nicht.

Auch hier müssen wir Sie auf die JavaScript-API-Dokumentation [5] verweisen. Eine ausführliche Behandlung des Themas würde den Rahmen einer Einführung sprengen.

MS Office-Programmierung: Beispiel 2 - Komplexe Anwendung

Ein zweites Beispielprojekt soll den Einsatz des JavaScript-API und den dadurch ermöglichten Datenaustausch zwischen Anwendung und App demonstrieren. Es übernimmt einen in Celsius angegebenen Temperaturwert aus der aktuellen Zelle und rechnet diesen wahlweise in Kelvin oder Fahrenheit um. Ein Mausklick fügt das Ergebnis dann wieder in die aktuelle Zelle ein.

Wenn Sie dieses Beispielprojekt praktisch nachvollziehen möchten, fügen Sie dem Office- Apps-Stammordner zunächst einen neuen Unterordner namens ComplexApp hinzu. Dort speichern Sie die folgende HTML-Datei, die die Webseite der App bildet, unter dem Namen ComplexApp.html ab:

<! 15\OfficeApps\SimpleApp\ComplexApp.html >
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
        <link rel="stylesheet" type="text/css" 
          href="../OfficeStyles.css" />
        <script src=
          "https://az88874.vo.msecnd.net/api/1.0/Office.js"></script>
        <script src="ComplexApp.js"></script>
    </head>
    <body>
        <div>
            Aktuelle Auswahl: <br>
            <input type="text" value="" id="txtValue"
              style="width: 254px" />
            <input type="button" value="Celsius in Kelvin"
              id="btnToKelvin" onclick="convertKelvin()"
              style="margin-top: 5px; width: 258px" />
            <input type="button" value="Celsius in Fahrenheit"
              id="btnToFahrenheit" onclick= "convertFahrenheit()"
              style="margin-top: 5px; width: 258px" />
            <hr width="258" align="left">
            Ergebnis: <br>
            <input type="text" value="" id="txtResult"
              style="width: 254px" />
            <input type="button" value="Ergebnis einfügen"
              id="btnInsert" onclick= "insertResult()"
              style="margin-top: 5px; width: 258px" />
        </div>
        <div>
            <hr width="258" align="left">
            Meldung: <br>
            <textarea id="txtMessage" rows="6"></textarea>
            <hr width="210" align="left">
        </div>
    </body>
</html>

Der head-Bereich der Webseite unterscheidet sich kaum von seinem Gegenstück in Simple- App.html. Einziger Unterschied ist das zweite script-Element, das den Verweis auf das JavaScript-API herstellt.

Innerhalb des body-Blocks sind die Unterschiede größer. Die Anweisungen dort fügen der Webseite gleich zwei Textboxen, drei Buttons und ein mehrzeiliges Textarea-Control aus dem HTML-Fundus hinzu. Die erste Textbox (id=“txtValue“) zeigt den Inhalt der aktuell markierten Zelle, die zweite (id=“txtResult“) das Ergebnis, das nach dem Klick auf die oberen beiden Buttons (id=“btnToKelvin“ und id=“btnToFahrenheit“) berechnet wird. Button Nummer Drei (id=“btnInsert“) überträgt das Ergebnis zurück in das Dokument. Das Textarea-Control schließlich (id=“txtMessage“) ist für die Anzeige möglicher Fehlermeldungen zuständig.

Die Skriptdatei von ComplexApp

Die Skriptdatei der Beispiel-App trägt den Namen ComplexApp.js und ist ebenfalls im Unterordner ComplexApp zu speichern.

/* 15\OfficeApps\SimpleApp\ComplexApp.js */
Office.initialize = function (reason) {
    Office.context.document.addHandlerAsync(
      Office.EventType.DocumentSelectionChanged, myHandler);
}

function myHandler(eventArgs) {
    showMessage("");

    Office.context.document.getSelectedDataAsync(
        Office.CoercionType.Text, function (result) {
        if (result.status == "succeeded")
          document.getElementById("txtValue").value = result.value;
        else
          showMessage(result.error.message);
    });
}

function convertKelvin() {
    var celsius =
      parseFloat(document.getElementById("txtValue").value)
    var kelvin = celsius + 273.15

    document.getElementById("txtResult").value = kelvin
}

function convertFahrenheit() {
    var celsius =
      parseFloat(document.getElementById("txtValue").value)
    var fahrenheit = (celsius * 1.8) + 32

    document.getElementById("txtResult").value = fahrenheit
}

function insertResult() {
    showMessage("");

    var correctedResult =
      document.getElementById("txtResult").value.replace(".", ",")
    
    Office.context.document.setSelectedDataAsync(correctedResult,
        function (result) {
        if (result.status == "failed")
           showMessage(result.error.message);
    });
}

function showMessage(message) {
    document.getElementById("txtMessage").value = message;
}

Die Office.initialize-Zeile, die ja beim Laden der App automatisch aufgerufen wird, erklärt die Funktion myHandler zum zuständigen Event-Handler, der bei jeder Änderung der Dokument- auswahl ausgeführt wird. Die Funktion ermittelt dann den Wert der aktuellen Zelle mit Hilfe der API-Funktion getSelectedDataAsync und trägt diesen in die Textbox mit der ID txtValue ein.

Das Anklicken des obersten Buttons fällt in die Zuständigkeit der convertKelvin-Routine. Diese liest den Wert der Textbox txtValue, addiert die Zahl 273,15 dazu und trägt das Ergebnis in die Textbox txtResult ein.

Bei convertFahrenheit verhält es sich ähnlich. Die Routine tritt beim Anklicken des zweiten Buttons von oben in Aktion. Sie liest ebenfalls den Wert der Textbox txtValue, multipliziert diesen aber mit 1,8 und rechnet 32 hinzu, ehe sie das Ergebnis in die Textbox txtResult überträgt.

Ein Klick auf den dritten Button schließlich ruft die insertResult-Routine auf den Plan. Diese ermittelt den momentanen Wert der Textbox txtResult, tauscht einen eventuell darin befindlichen Dezimalpunkt gegen das hierzulande übliche Dezimalkomma aus und überträgt das Ergebnis mit Hilfe der setSelectedDataAsync-Methode des JavaScript-API in die markierte Zelle.

Die Manifestdatei von ComplexApp

Die Manifestdatei unserer zweiten Beispiel-App hat folgenden Inhalt und ist unter dem Namen ComplexApp.xml im Stamm-/Manifestordner OfficeApps zu speichern. Wie schon im ersten Beispiel, so sind auch hier die verwendeten (absoluten) URLs, die auf die Speicherorte der Webseiten- und der Icon-Datei verweisen, an die eigenen Gegebenheiten anzupassen.

<! 15\OfficeApps\ComplexApp.xml >
<?xml version="1.0" encoding="utf-8"?>
<OfficeApp xmlns=
  "http://schemas.microsoft.com/Office/appforOffice/1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:type="TaskPaneApp">
    <Id>08afd7fe-1631-42f4-84f1-5ba51e242f12</Id>
    <Version>1.0</Version>
    <ProviderName>Ralf Nebelo</ProviderName>
    <DefaultLocale>EN-US</DefaultLocale>
    <DisplayName DefaultValue="ComplexApp"/>
    <Description DefaultValue="Meine zweite Office-App"/>
    <IconUrl DefaultValue=
      "\\MYBOOKDATA\Public\OfficeApps\ComplexApp\ComplexApp.png"/>
    <Capabilities>
        <Capability Name="Document"/>
        <Capability Name="Workbook"/>
    </Capabilities>

    <DefaultSettings>
        <SourceLocation DefaultValue=
          "\\MYBOOKDATA\Public\OfficeApps\ComplexApp\ComplexApp.html"/>
    </DefaultSettings>
    <Permissions>ReadWriteDocument</Permissions>
</OfficeApp>

ComplexApp anzeigen und nutzen

Zum Starten der Beispiel-App wählen Sie EINFÜGEN | APPS FÜR OFFICE, wobei Sie wiederum nicht auf das Icon, sondern auf dessen Pfeilsymbol klicken. Nach einem Klick auf ALLE ANZEIGEN und dann auf FREIGEGEBENE ORDNER sollte das Dialogfeld einen Eintrag namens „ComplexApp“ enthalten, dessen Icon aus einem Stern besteht. Fehlt der Eintrag, klicken Sie auf AKTUALISIERUNG, um die Anzeige auf den neuesten Stand zu bringen. Anschließend markieren Sie „ComplexApp“ und wählen EINFÜGEN. Die App sollte nun am rechten Rand des Excel-Fensters erscheinen. Testen Sie sie, indem Sie ein paar Temperaturwerte in das Arbeitsblatt schreiben und diese anschließend der Reihe nach anklicken. Der jeweilige Zellwert erscheint dann in der TEXTBOX AKTUELLE AUSWAHL der ComplexApp. Nach einem Klick auf CELSIUS IN CALVIN beziehungsweise CELSIUS IN FAHRENHEIT sollte das Ergebnis der Umrechnung in der Textbox "Ergebnis" auftauchen, von wo aus Sie es mit einem Klick auf ERGEBNIS EINFÜGEN in die aktuelle Zelle übertragen können.

MS Office-Programmierung: Zusammenfassung

Mit Office-Apps will Microsoft die Grenzen seines Büropakets mit Hilfe von Webtechniken erweitern. Die Idee ist nicht schlecht. Solange aber nur Excel sowohl Aufgabenbereich- als auch Inhalt-Apps unterstützt und solange viele Office-Anwendungen überhaupt noch nicht App-tauglich gemacht wurden, weist das Konzept noch große Lücken auf. Die findet man auch im JavaScript-API für Office. Das bildet in der vorliegenden Version 1.0 nur eine sehr schmale Brücke zur Host-Anwendung, da es der App zu wenige Möglichkeiten bietet, Informationen in das Dokument einzufügen. Den meisten Apps bleibt derzeit nur der Weg über die aktuelle Auswahl. Der Zugriff auf andere Dokumentregionen mit Hilfe von Bindungen ist in der Praxis verbaut, da er vorbereitete Dokumente erfordert, die der Entwickler selbst mit den notwendigen Bereichsnamen versehen hat. Die typische Office-App erkennt, was der User gerade eintippt oder markiert, und beschafft ihm dazu passende Infos, Übersetzungen, Karten oder Grafiken aus dem Internet – was durchaus nützlich ist. Makros und insbesondere Add-ins, die mit VSTO und den unerschöpflichen .NET-Bibliotheken realisiert wurden, können das aber auch – und darüber hinaus noch sehr viel mehr. Sie besitzen unbegrenzten Zugang auf jeden Dokumentbestandteil, können Office-Anwendungen nach Belieben steuern, Programme starten, auf die Hardware und das Dateisystem zugreifen, Funktionen des Windows-API nutzen und vieles mehr, was einer in Office integrierten Webanwendung verwehrt ist. Daher werden Office-Apps die klassischen Makros und Add-ins auch sicher nicht ersetzen, sondern allenfalls ergänzen. Davon abgesehen muss man dem App-Konzept aber auch klare Vorteile attestieren:
  • den unkomplizierten und voll in die Office-Anwendung integrierten Installationsmechanismus beispielsweise,
  • den Office Store, der für Transparenz im App-Angebot sorgt und Entwicklern eine zentrale und weltweite Vermarktungsplattform bietet,
  • eine konkurrenzlos hohe Codekompatibilität, die Apps in mehreren Office-Anwendungen funktionieren lässt und nicht zuletzt
  • ein deutliches Plus an Sicherheit, das der Welt nach den Makroviren hoffentlich jede Form von „App-Viren“ ersparen wird

Quellen

  1. Microsoft-Portal für Office-App-Entwickler
  2. Download-Adresse Notepad++
  3. Veröffentlichen von Apps für Microsoft Office
  4. Online Guide Generator
  5. JavaScript-API für Office v1.1

Autor

Ralf Nebelo

Ralf Nebelo arbeitet schon seit vielen Jahren als Buch- und Zeitschriftenautor und ist ständiger Mitarbeiter der c‘t. Sein Spezialgebiet ist die Office-Programmierung.
>> Weiterlesen
Kommentare (0)

Neuen Kommentar schreiben