Bilder in Excel 2010 per VBA einfügen

Was bei Excel 2003 noch funktionierte

Call ActiveSheet.Pictures.Insert("C:\Temp\Image.jpg")

schlägt bei Excel 2010 fehl. Stattdessen muss hier Folgendes getan werden:

Dim targetRange as Range
Set targetRange = Range("B2")

Dim pictureShape as Shape
Set pictureShape = ActiveSheet.Shapes.AddPicture( _
    "C:\Temp\Image.jpg", _
    False, True, _
    targetRange.Left, _
    targetRange.Top, _
    targetRange.Width, _
    targetRange.Height)

Anschließend muss dann nur noch das neue Shape auf die gewünschte Größe skaliert werden.

Was ist neu an HTML5?

HTML5 entfernt ein paar selten benutzte (oder auch durch CSS nutzlos gewordene) Tags und führt einige neue ein. Diese neuen Tags dienen in der Regel entweder der besseren (semantischen) Strukturierung von Dokumenten oder unterstützen multi-mediale Webseiten.

Zu den neuen Tags gehören u.a.:

  • <header> definiert einen Kopfbereich
  • <footer> definiert einen Fußbereich
  • <aside> definiert einen Seitenbereich
  • <section> umschließt einen Abschnitt
  • <article> kennzeichnet einen Artikel
  • <nav> kennzeichnet die Links der Navigations
  • <audio> kennzeichnet Audio-Inhalte
  • <video> kennzeichnet Video-Inhalte
  • <canvas> ermöglicht freies Zeichnen per JavaScript

Besondere Beachtung, zumindest im Hinblick auf die Entwicklung von Browserspielen, verdient <canvas> – was damit möglich ist, verdeutlicht das Spiel Cut the Rope.

Unobtrusive Javascript mit jQuery

Unobtrusive – unaufdringlich, zurückhaltend, dezent – meint hier den unauffälligen Einsatz von Javascript. Statt den HTML-Code mit Javascript zu spicken, wird der Code zum einen ausgelagert und zum anderen nicht explizit an HTML-Elemente gebunden, sondern implizit durch das Setzen entsprechender Attribute. Insgesamt führt dieser Ansatz zu einer besseren Trennung von UI Design (HTML) und Verhalten (Javascript) und einer besseren Wiederverwertbarkeit des geschriebenen Codes.

Gerade beim (ersten) Einsatz von jQuery neigt man u.U. dazu, für spezifische GUI-Elemente spezifisches Verhalten zu programmieren, statt allgemeingültigere Ansätze zu verfolgen. Oft wird der Code entsprechend mit diesem spezifischen Javascript durchsetzt.

Die beiden Beispiele finden sich online unter http://demo.jochenlinnemann.de/foundation/xp/unobtrusive

Beispiel: jQueryUI

<a href="#" id="DialogStarter">Zeige Dialog</a>
<div id="SampleDialog" title="Hinweis">
    <p>Hallo, Welt!</p>
</div>

Der obige HTML-Ausschnitt könnte durch das folgende Javascript mit Leben erfüllt werden:

<script type="text/javascript">
    $(function () {
        $("#SampleDialog").dialog({ autoOpen: false });
        $("#DialogStarter").button().click(function() {
            $("#SampleDialog").dialog("open");
        });
    });
</script>

Dieser Quelltext macht nichts Besonderes, ist aber spezifisch für den obigen HTML-Ausschnitt geschrieben. Es wäre wesentlich schöner, wenn man durch einfache Deklaration ein Verhalten an ein HTML-Element binden könnte. In meinem Beispiel verwende ich das Attribut „class“, um das grundlegende Verhalten zu steuern:

<a href="#" class="jsButton">Zeige Dialog</a>
<div id="SampleDialog" title="Hinweis" class="jsDialog">
    <p>Hallo, Welt!</p>
</div>

Ein passendes, allgemeingültiges Skript kann nun „jsButton“ und „jsDialog“ mit einem entsprechenden Verhalten belegen. Dieser Code kann bequem in eine *.js-Datei ausgelagert werden. Hier sei er der Einfachheit halber in einem <script>-Tag eingefasst:

<script type="text/javascript">
    $(function () {
        $(".jsDialog").dialog({ autoOpen: false });
        $(".jsButton").button();
    });
</script>

Für den Button fehlt jetzt noch eine Möglichkeit, das Verhalten genau zu spezifizieren. Dazu verwende ich in diesem Beispiel selbstdefinierte HTML5-„data-„-Attribute:

<a href="#" class="jsButton"
   data-js-target="#SampleDialog"
   data-js-action="dialog"
   data-js-param="open">Zeige Dialog</a>

Die Erweiterung des Javascripts bringt dann das gewünschte Verhalten:

<script type="text/javascript">
    $(function () {
        $(".jsButton").button().click(function () {
            var target = $(this).attr("data-js-target");
            var action = $(this).attr("data-js-action");
            var param = $(this).attr("data-js-param");

            if (target && action && param) $(target)[action](param);
            else if (target && action) $(target)[action]();
        });
    });
</script>

Beispiel: Ajax

Auf ähnliche Weise lässt sich auch das Verhalten von Links ändern, so dass zum Beispiel kein Seitenwechsel stattfindet, sondern Inhalte aus einer anderen Seite gezielt nachgeladen werden, um in der aktuellen Seite zu erscheinen.

<a href="unob-full.html" class="jsButton"
   onclick="$('#Content').load($(this).attr('href')
   + ' #ProductDetails > *');
   event.preventDefault();">Lade komplettes HTML</a>
<div id="Content" class="ui-widget">
</div>

In „Unobtrusive“-Schreibweise würde daraus:

<a href="unob-full.html" class="jsButton ajaxLink"
   data-ajax-target="#Content"
   data-ajax-source="#ProductDetails">Lade komplettes HTML</a>
<div id="Content" class="ui-widget">
</div>

Und das zugehörige Javascript sähe wie folgt aus (und könnte ebenfalls in eine *.js-Datei ausgelagert werden):

<script type="text/javascript">
    $(function () {
        $(".ajaxLink")
        .click(function (event) {
            var target = $(this).attr("data-ajax-target");
            var href = $(this).attr("href");

            if (target && href) {
                var source = $(this).attr("data-ajax-source");
                $(target).load(href + (source ? " " + source + " > *" : ""));
            }

            event.preventDefault();
        });
    });
</script>

jQuery Mobile

Sowohl das jQueryUI- als auch das Ajax-Beispiel lassen sich in der Umsetzung von jQuery Mobile in der einen oder anderen Form wiederfinden; dort wird grundlegendes Verhalten durch „data-role“ und das Nachladen von Inhalten durch „data-ajax“ gesteuert. Letzteres wird standardmäßig als „true“ angenommen, wodurch das Laden aller verlinkten Seiten per Ajax-Request erfolgt.

ASP.NET-Runtime in der eigenen Applikation aufrufen

Nachdem die ASP.NET-Runtime in die eigene Applikation eingebunden wurde, können nun Aufrufe an diese weitergeleitet werden. Dazu ist „lediglich“ ein Aufruf der Methode HttpRuntime.ProcessRequest() nötig. Damit dieser aber durchgeführt werden kann, muss eine Implementierung der abstrakten Klasse System.Web.HttpWorkerRequest her. .NET bietet mit System.Web.Hosting.SimpleWorkerRequest eine solche Basisimplementierung, die hier erst einmal ausreichen soll – einfach den Konstruktor mit den drei Parametern aufrufen und das neue Objekt übergeben:

HttpWorkerRequest workerRequest = new SimpleWorkerRequest(page, query, output);
HttpRuntime.ProcessRequest(workerRequest);

Bei dem Page-Parameter darf kein führender Slash angegeben werden, während beim Query-Parameter das führende Fragezeichen weggelassen werden muss. Für einfachste Anwendungen kann der Output-Parameter eine Instanz vom Typ System.IO.StringWriter aufnehmen.

Ein kompletter Aufruf könnte dann im „client-seitigen“ Teil der Anwendung wie folgt aussehen:

MyApplicationHost myHost = MyApplicationHost.CreateWebHost(
    "/", Path.Combine(Environment.CurrentDirectory, "SampleWebApp"));
using (StringWriter writer = new StringWriter())
{
    myHost.ProcessRequest("Default.aspx", "q=Where are you?&a=I am here!", writer);
    EmbeddedWebBrowser.DocumentText = writer.ToString();
}

EmbeddedWebBrowser stellt dabei eine Instanz des System.Windows.Forms.WebBrowser-Controls dar.

ASP.NET-Runtime in die eigene Applikation einbinden

Im Laufe der letzten Jahre habe ich des Öfteren die ASP.NET-Runtime in Desktop-Applikationen integriert, sei es um ein komplexes HTML-Reporting umzusetzen oder um eine .NET 2.0-Anwendung Web Services veröffentlichen zu lassen. Nicht zuletzt der Wunsch nach einem kleinen, „eigenen Webserver“ hat meine Beschäftigung mit dem Thema vorangetrieben. Im Folgenden will ich kurz dokumentieren, was sich bis heute als meine „Best Practice“-Lösung herauskristallisiert hat.

Die wichtigste Erkenntnis war für mich, dass die Runtime in eine eigene AppDomain geladen werden muss und so von der restlichen Anwendung isoliert wird – das hat Vor- und Nachteile (bspw. kann die Runtime-AppDomain nach Gebrauch einfach entladen werden, auf der anderen Seite müssen Daten aus der Anwendung über eine AppDomain-Grenze transportiert werden, um im „Web-Bereich“ genutzt werden zu können). Es gibt zwar Mittel und Wege eine vorhandene AppDomain so zu manipulieren, dass sie die Runtime aufnehmen und ausführen kann, aber in der Praxis hat sich dies für mich nicht als sinnvoll erwiesen.

Laden der ASP.NET-Runtime

Das Laden der ASP.NET-Runtime beginnt mit der Klasse ApplicationManager aus dem Namespace System.Web.Hosting:

ApplicationManager appManager = ApplicationManager.GetApplicationManager();

Ist der Rückgabewert ungleich null,  kann in diesem Prozess mit dem Laden einer Ausführungsumgebung für eine Webanwendung begonnen werden.

Jetzt ist es prinzipiell nicht mehr schwer, einen physischen Pfad (das Basisverzeichnis der Webanwendung auf der Festplatte) auf einen virtuellen (der Pfad hinter der Adresse des Servers, z.B. http://domain.tld/virtual) abzubilden – dazu muss lediglich der Typ eine Objektes her, der IRegisteredObject implementiert, und mit dessen Instanz man später kommunizieren möchte, um die Runtime die gewünschten Aufgaben erledigen zu lassen. Sinnvollerweise sollte dieser Typ von MarshalByRefObject abgeleitet sein, da die Runtime in einer anderen AppDomain ausgeführt wird (siehe oben). Es besteht jetzt allerdings das Problem, dass dieser Typ sowohl in der aktuellen AppDomain, als auch in der ASP.NET-AppDomain bekannt sein muss, sein Assembly also in beiden AppDomains geladen ist/geladen werden kann. Dies ließe sich zum Beispiel dadurch bewerkstelligen, dass die entsprechende Assembly im bin-Verzeichnis der auszuführenden Webanwendung abgelegt wird oder aber jetzt hineinkopiert wird. Das finde ich allerdings wenig elegant und glücklicherweise gibt es einen anderen Weg:  System.Web.Compilation.BuildManagerHost. Dieser Typ wird nicht exportiert und kann deswegen nicht direkt zugegriffen werden. Da er aber Teil der Runtime ist, kann diese auf ihn zugreifen und ihn instanzieren:

Type buildManagerHostType = typeof(HttpRuntime).Assembly.GetType(
    "System.Web.Compilation.BuildManagerHost");
Object buildManagerHost = appManager.CreateObject(
    appId,
    buildManagerHostType,
    virtualPath,
    physicalPath,
    failIfExists);

Dabei bezeichnet die appId die auszuführende Anwendung eindeutig, man könnte also der Einfachheit halber bspw. eine Verknüpfung aus physischem und virtuellem Pfad als appId verwenden. Der Parameter failIfExists gibt desweiteren an, wie damit umgegangen werden soll, wenn das gewünschte Objekt schon existiert: bei true wird eine Ausnahme ausgelöst und bei false das bereits existierende Objekt zurückgegeben.

Die AppDomain ist nun bereit, die Runtime geladen…

Injizieren eigener Assemblies in die ASP.NET-Laufzeitumgebung

Dabei hilft nun die Methode RegisterAssembly() des zuvor registrierten BuildManagerHost:

Assembly myAssembly = typeof(MyApplicationHost).Assembly;
buildManagerHostType.InvokeMember(
    "RegisterAssembly",
    BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
    null,
    buildManagerHost,
    new Object[] { myAssembly.FullName, myAssembly.Location });

Der Typ MyApplicationHost ist nun die oben erwähnte Klasse, die uns später das Steuern der Runtime ermöglichen wird. Diese Klasse sollte von MarshalByRefObject abgeleitet sein und muss IRegisteredObject implementieren.

MyApplicationHost myHost = (MyApplicationHost)appManager.CreateObject(
    appId,
    typeof(MyApplicationHost),
    virtualPath,
    physicalPath,
    failIfExists);

In einem Folgeartikel zeige ich dann, wie nun Aufrufe an die Runtime durchgeführt werden.

Die verschiedenen ASP.NET Tags

Die folgenden ASP.NET Tags habe ich im Laufe der Zeit kennengelernt. Da es hin und wieder schwer fällt, die passende Doku zu finden, liste ich sie hier kurz auf.

<%@ … %> kennzeichnet ASP.NET-Direktiven
<% … %> umschließt einen serverseitig ausgeführten Code-Abschnitt
<%= … %> dient der direkten Ausgabe eines Wertes, der nicht weiter kodiert wird
<%: … %> dient der direkten Ausgabe eines Wertes, der durch HtmlEncode() kodiert wird
<%# … %> kommt bei der Datenbindung zum Einsatz und ermöglicht unter anderem den Einsatz der Eval-Funktion
<%– … –%> bietet die Möglichkeit serverseitiger Kommentierung
<%$ … %> umschließt einen ASP.NET Ausdruck, der Zugriff auf AppSettings, ConnectionStrings oder Resources erlaubt