Beim Fernsteuern von Office-Anwendungen ist generell Vorsicht angesagt. Das gilt aber insbesondere, wenn die Fernsteuerung aus .Net heraus erfolgt. Wieviel Vor- und Umsicht tatsächlich notwendig ist, mußten wir in der letzten Phase vor Auslieferung der ersten Version einer WinForms-Anwendung kürzlich schmerzlich erfahren. Um diesen Schmerz anderen Entwicklern in Zukunft zu ersparen, hier ein paar “Lessons Learned”:

COM/COM Interop – Kurze Einführung

COM ist lange, lange Jahre Microsofts Objektmodell gewesen und was die Menge an existierendem COM-Code anbelangt auch sehr erfolgreich. Das später dazugekommene DCOM zur verteilten Komponentenentwicklung (als Gegenstück zu CORBA) war aus mancherlei Gründen weniger erfolgreich und Microsoft bastelte bald an einer neuen Variante. Diese neue Variante entwickelte sich intern schnell weiter und es wurde daraus das, was wir heute unter der “.Net-Plattform” kennen. Es ist also kein Wunder, daß Microsoft einige Anstrengung unternommen hat, die alte COM-Welt nicht einfach zu vergessen und damit die unzähligen existierenden Komponenten unbrauchbar zu machen. Stattdessen ist tief in .Net die Möglichkeit integriert, COM-Objekten (beinahe) so zu verwenden wie native .Net-Komponenten. Dieser Mechanismus wird “COM Interop” genannt.
Es gibt jedoch einen entscheidenden Unterschied zwischen beiden Modellen: .Net-Code ist sogenannter “managed Code”, wird von einer Runtime, der sogenannten CLR (Common Language Runtime) verwaltet, was in etwa der Java VM entspricht. Zu den Aufgaben dieser Runtime gehört unter anderem die Speicherverwaltung, auch Garbage Collection (GC) genannt. In .Net (wie in Java) hat man als Entwickler wenig Kontrolle darüber, wie, wann und ob überhaupt der GC nicht mehr benötigte Objekte freigibt und damit auch von diesen benutzte Ressourcen. Ganz anders bei COM. Der überwiegende Teil der COM-Komponenten wurde sicher in C/C++ erstellt, also in unmanaged Code. Hier ist der Entwickler selbst für Speicher-Allokation und -Freigabe zuständig. Treffen diese beiden Welten aufeinander stellt sich die Frage, wer denn nun die Verwaltung der COM-Objekte übernimmt. Nach wie vor kann man das als Entwickler von .Net-Code der CLR bzw. dem GC überlassen. Aber da sind wir auch schon bei dem nächsten Problem:

Wenn man in .Net eine Referenz auf eine COM-Bibliothek anlegt, wird ein sogenannter RCW (Runtime Callable Wrapper) erstellt, eine Art Proxy für das COM-Objekt. Hier findet das Marshalling der Daten statt. Pro COM-Objekt gibt es immer nur einen RCW, unabhängig von der Anzahl der Instanzen. Hierbei spielt das sogenannte “Appartment Model” eine Rolle. Unter COM gibt es verschiedener solcher Modelle, im wesentlichen die beiden MTA und STA, Multi Threaded Appartment und Single Threaded Appartment. Das Appartment besagt, ob eine COM-Komponente von verschiedenen Threads (MTA) oder nur von einem einzigen (STA) angesprochen werden kann. Um diese beiden Varianten in .Net abzubilden, hat dort jeder Thread ebenfalls eines der beiden Appartments, default ist “MTA”. Durch ein Attribut an der Main()-Methode wird das Appartment aber eigentlich immer auf STA gestellt, um Probleme mit eben diesen STA-COM-Objekten zu vermeiden.

Pitfalls

Solange man direkt aus dem Haupt-Thread mit COM-Objekten arbeitet und das nicht exzessiv, hat man eigentlich keine Probleme. Die eigentliche Arbeit wird einem von der CLR bzw. dem RCW abgenommen. Fängt man jedoch an, etwas komplexere Aufgaben zu erledigen und dies auch durch Einsatz von Multi-Threading wird es schnell unangenehm. Bei den ersten etwas umfangreicheren Tests einer unserer WinForms-Anwendungen zeigte sich, daß es zu sehr unschönen Effekten kommen kann. In bestimmten Fällen werden dort zwei Hintergrund-Threads erzeugt, die jeweils über COM Outlook fernsteuern. Leider stürzte die Anwendung dabei auf einigen Rechnern regelmäßig nach einigen hundert Aktionen ab. Manchmal mit einer “MemoryAccessViolation” und manchmal einfach ohne irgendeine Nachricht, da war die Anwendung einfach mal eben weg. Wenn wir das Glück hatten, zumindest eine Fehlermeldung zu bekommen, deutete der Stacktrace auf ein Problem in der Anzeigekomponente, genauer gesagt im TreeView hin. Tagelange Suche nach Problemen dort zeigte aber keinerlei Auffälligkeiten in diesem Teil des Codes.
Da das Problem auf zumindest einem Rechner mehr oder weniger deterministisch auftrat deutete das Bauchgefühl relativ schnell auf COM-Interop hin. Nach tagelangen Recherchen ergaben folgende Maßnahmen eine Lösung:

  • Sicherstellung, daß immer nur ein Thread mit den Outlook COM-Objekten arbeitet (mittels “lock()”-Statements)
  • Sicherstellung, daß der ausführende Thread das Appartment-Modell des COM-Objektes verwendet (in diesem Fall STA). Daraus folgt auch, daß man leider keine ThreadPools verwenden kann, da diese mit MTA-Threads arbeiten und man das Appartment nachträglich nicht ändern kann.
  • Sicherstellung, daß jedes im Code erzeugte COM-Objekt (durch “new”) durch einen Aufruf von “Marshal.ReleaseComObject()” freigegeben wird, bevor der GC aktiv werden muß. Sicherstellen kann man das durch “try/finally”-Blöcke.

Ich hoffe, diese Informationen werden irgendwann einmal jemandem helfen, die Fehler, die wir gemacht haben, zu vermeiden. Vielleicht helfen sie ja mir selbst beim nächsten Projekt… 🙂

Hin und wieder ist es notwendig, in einem Ordner Dateien gleichen Namens zu speichern. Da das unter Windows (und den meisten anderen Betriebssystemen auch) nicht geht, muß man sich was einfallen lassen. Gängige Praxis vieler Anwendungen ist es dabei, dem Dateinamen ein Zeichen mit einer Zahl anzuhängen, wenn es den Originalnamen schon gab. Z.B. wird die Datei “Neues Dokument.txt” zu “Neues Dokument~1.txt”, dann “Neues Dokument~2.txt” usw.

Der folgende Code-Snippet erzeugt für einen gegebenen Dateinamen genau solche einen eindeutigen Namen mit der kleinstmöglichen Zahl.

public static String getUniqueFileName(String tempFileName, String extension, String extensionSeparator, String suffixSeparator)
{
  String tempFileNameNew; 
  if (extension == null || extension.length() == 0)
  {
    tempFileNameNew = tempFileName;
  } 
  else
  {
    tempFileNameNew = tempFileName + extensionSeparator + extension;
  } 

  File file = new File(tempFileNameNew);
  int suffix = 1; 

  while (file.isFile())
  {
    if (extension == null || extension.length() > 0)
    {
      tempFileNameNew = tempFileName + suffixSeparator + String.valueOf(suffix);
    }
    else
    {
      tempFileNameNew = tempFileName + suffixSeparator + String.valueOf(suffix) + extensionSeparator + extension;
    } 

    file = new File(tempFileNameNew);
    suffix++;
  }

  return tempFileNameNew;
}

Möglicher Aufruf wäre also:

String newFilename = getUniqueFileName("Neues Textdokument", "txt", ".", "~");

Gehören Sie auch zu den “Information Junkies”? Den nach ständig neuen Informationen Gierenden, denen, die immer auf dem neusten technischen Stand sein wollen? Ja? Trösten Sie sich, Sie sind nicht alleine! Die Blogger-Szene als wahrscheinlich größte Selbsthilfegruppe der Welt fördert immer wieder gewinnbringende Einsichten in den Seelenhaushalt von Leidensgenossen zutage. Und hin und wieder auch einmal tröstende, aufbauende Worte. So gefunden auf dem Blog von Coding Horror:

Via SecretGeek:

  • You do NOT have to refactor all your code.
  • You do NOT have to keep up with the latest news from microsoft, and know everythnig there is to know about longhorn, whidbey, avalon, XAML, indigo and star wars III.
  • You do not have to have perfectly de-coupled tiers in your technology independent SOA software.
  • You do not have to comply to every standard, achieve the perfect balance between maintainability and performance. Usability and familiarity.
  • You don’t have to do “first things first every day”
  • You DO NOT have to memorize and understand every patten the gang of four have catalogued.
  • You do NOT have to read every technical blog, print out every technical article and learn every technical thing there is to learn.
  • You are beautiful just the way you are.
  • You are brilliant, interesting, wise and fun to be around.
  • You rock.

Und? Geht es Ihnen schon besser? Der wohl erste Schritt zur Besserung. Und vom gleichen Blog-Eintrag zitiert auch gleich noch ein paar Tips, um auch in Zukunft den Tag ohne die Informationsdroge zu überstehen:

Kathy Sierra has a few suggestions to combat Information Anxiety:

  • Find the best aggregators
  • Get summaries
  • Cut redundancy
  • Unsubscribe from as many things as possible
  • Recognize black holes (gaming, slashdot, etc)
  • Pick categories for balance; include some from outside your main field
  • Be more realistic about what you’re likely to get to; throw the rest out
  • In anything you need to learn, find someone who can tell you what is
    • Need to know
    • Should know
    • Nice to know
    • Edge case
    • Useless

Wenn Sie jedoch – wie ich – zu der Sorte Mensch gehören, die zu allem Überfluß auch noch unter “Aufschieberitis” leiden, wird es doppelt schlimm. Da hilft zumindest langfristig auch nicht, daß sich das Fachwort für “Aufschieberitis”, “Prokrastination”, deutlich mehr nach Krankheit als nach Charakterschwäche anhört. Es gibt jedoch ein relativ wirksames Mittel, das zwei Fliegen mit einer Klappe schlägt: Ziehen Sie den Netzwerkstecker, schalten Sie Ihr WLAN ab, verkaufen Sie Ihre UMTS-Karte und Ihren Blackberry, seien Sie Offline! Zumindest für eine gewisse Zeit des Tages, in der Sie sich wichtiger, schon oft aufgeschobener Aufgaben annehmen wollen. Wenn Sie – wie ich – regelmäßig längere Strecken mit dem Zug fahren: noch besser. Es gibt wohl kaum einen Ort, an dem ich so produktiv bin wie im Zug. Vielleicht sollte man – solange es noch nicht zu spät ist – eine Eingabe bei der Deutschen Bahn gegen die geplante Einführung von Internetzugängen auf Fernverkehrsstrecken machen. Die negativen Auswirkungen auf die wirtschaftliche Entwicklung wären kaum abzuschätzen!

Gute Besserung! 🙂

Immer mal wieder ist es notwendig zu wissen, welche Ports auf einem Rechner abgehört werden und damit belegt sind. Um das herauszufinden, kann man sich unter Windows (für Mac-Nutzer hier) einfacher DOS-Boardmittel bedienen. Der folgende Befehl auf der Kommandozeile ausgeführt liefert eine Liste aller abgehörten Ports:

netstat -ano | find /i “Abhören”

In meinem Fall resultiert daraus die folgende Ausgabe:

C:\Programme\Support Tools>netstat -ano | find /i "Abhören"
TCP    0.0.0.0:21          0.0.0.0:0  ABHÖREN         1408
TCP    0.0.0.0:25          0.0.0.0:
0 ABHÖREN         1408
TCP    0.0.0.0:80          0.0.0.0:
0 ABHÖREN         1408
TCP    0.0.0.0:135         0.0.0.0:
0 ABHÖREN         1048
TCP    0.0.0.0:443         0.0.0.0:
0 ABHÖREN         1408
TCP    0.0.0.0:445         0.0.0.0:
0 ABHÖREN         4
TCP    0.0.0.0:987         0.0.0.0:
0 ABHÖREN         11344
TCP    0.0.0.0:1048        0.0.0.0:
0 ABHÖREN         1408
TCP    0.0.0.0:2869        0.0.0.0:
0 ABHÖREN         1924
TCP    0.0.0.0:3389        0.0.0.0:
0 ABHÖREN         992
TCP    0.0.0.0:5051        0.0.0.0:
0 ABHÖREN         1832
TCP    0.0.0.0:19226       0.0.0.0:
0 ABHÖREN         3952
TCP    0.0.0.0:23761       0.0.0.0:
0 ABHÖREN         664
TCP    127.0.0.1:1082      0.0.0.0:
0 ABHÖREN         3308
TCP    127.0.0.1:1118      0.0.0.0:
0 ABHÖREN         2948
TCP    127.0.0.1:4664      0.0.0.0:
0 ABHÖREN         4020
TCP    127.0.0.1:6083      0.0.0.0:
0 ABHÖREN         3592
TCP    127.0.0.1:31595     0.0.0.0:
0 ABHÖREN         304
TCP    192.168.136.1:139   0.0.0.0:
0 ABHÖREN         4
TCP    192.168.154.1:139   0.0.0.0:
0 ABHÖREN         4
TCP    192.168.213.22:139  0.0.0.0:
0 ABHÖREN         4

Unter englischem Betriebssystem muß man “abhören” durch “listening” ersetzen. Die letzte Spalte der Ausgabe gibt dabei (Windows XP oder höher vorausgesetzt) die ID des Prozesses an, der den jeweiligen Port blockiert. Um nun herauszufinden, welche Anwendung dahintersteckt, öffnet man den Taskmanager (taskmgr) und läßt sich auf dem Tab “Prozesse” die Prozess-ID mit ausgeben. Dazu wählt man im Menü “Ansicht” den Punkt “Spalten auswählen” und markiert “PID”. So läßt sich im obigen Beispiel herausfinden, daß hinter der PID 1408 der Prozess “inetinfo.exe” steckt, also der Micosoft IIS. Wer hätte das gedacht… 😉

UPDATE: Für Mac-Nutzer gibt es ebenfalls eine Lösung: “Belegte Ports anzeigen – Mac Version

Aus einem privaten Projekt heraus entsprang die Anforderung, die Entfernung zwischen zwei (deutschen) Postleitzahlen zu berechnen. Dank der freien Geo-Informationen des OpenGeoDb-Projektes (http://opengeodb.hoppe-media.com/index.php) und einer einfachen Formel (http://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c5115/) war die Umsetzung relativ einfach. Die Einfachheit der Methode (z.B. wird bei der Berechnung angenommen, bei der Erde handele es sich um eine perfekte Kugel) führt verständlicherweise dann auch nur zu Näherungswerten, die für viele Anwendungen allerdings ausreichen sollten.

Eine mögliche Anwendung ist die Umkreissuche innerhalb einer Datenbank, z.B. Filialen eines Unternehmens im Umkreis von 15 km von meinem Wohnort. Der im angehängten Beispielprojekt umgesetzte Algorithmus ist allerdings sehr(, sehr) einfach und geht jeweils die komplette Liste aller Postleitzahlen durch, was auf einer Website mit vielen Anfragen dieser Art zu Performance-Problemen führen kann.

Das angehängte Projekt ist in C# unter .Net 2.0 realisiert und dient nur Demonstrationszwecken, es gibt keine Dokumentation, keine Fehlerbehandlung und (natürlich) keine Gewährleistung. Der Code wird “as-is” angeboten und kann in eigenen Projekten verwendet werden.

Geo.zip (259,24 KB)

[Updated: 2006-10-31]

  • Effective management of knowledge requires hybrid solutions of people and technology. [Thomas H. Davenport]
  • Leaders can energise learning by rewarding when it happens. [Warren Bennis/Nanus, 1985]
  • Wir ertrinken in einer Informationsflut und hungern trotzdem nach Wissen. [Rutherford D. Rogers, Bibliotheksvorstand, Yale, 1985]
  • Lernen ist wie Schwimmen gegen den Strom. Sobald man aufhört, treibt man zurück. [Benjamin Britten]
  • Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information? [T.S. Eliot, 1888-1965]
  • Wer will, daß ihm die anderen sagen, was sie wissen, der muß ihnen sagen, was er selbst weiß. Das beste Mittel Informationen zu erhalten, ist, Informationen zu geben. [Nicoló Michialvelli]
  • Nothing is ever changed except by marking it obsolete. [Bucky Fuller]
  • Knowledge constantly makes itself obsolete, with the result that today’s advanced knowledge is tomorrow’s ignorance. The only competitive advantage of the developed countries is in the supply of knowledge workers. [Peter F. Drucker]
  • Knowledge can be found most of all in the heads of the employees. Therefore we motivate our employees to record and to share knowledge[Heinrich von Pierer, Siemens]
  • However, knowledge remains to be knowledge as long as it is not practised. Wisdom, on the other hand, is gained but of practice and stays with the individual[Masaaki Imai]
  • Every profit center is a knowledge center.[Thomas Middelhof, Bertelsmann]
  • Wissen ist der entscheidende Produktionsfaktor unserer Zeit [Fredmund Malik]
  • If you do know how to get there, it’s not a stretch target [Jack Welch]
  • Kopfarbeit oder Wissensarbeit nimmt massiv an Bedeutung zu. Das Management von Kopfarbeitern verlangt nach neuen Führungsgrundsätzen, weil in der Wissensgesellschaft der Mensch den Job organisiert. [Fredmund Malik]
  • What is the value of a thought, based on a lifetime of experiences? [Karl E. Sveiby]
  • Communications is human nature; Knowledge sharing is human nurture.” [Alison Tucker, Buckman Laboratories]
  • Knowledge management is the strategy and processes to enable the creation and flow of relevant knowledge throughout the business to create organisational, customer and consumer value.” [David Smith, Unilever]
  • Knowledge Management is the broad process of locating, organising, transferring, and using the information and expertise within an organisation. The overall knowledge management process is supported by four key enablers: leadership, culture, technology, and measurement.” [American Productivity and Quality Center]
  • Knowledge is information that is relevant, actionable, and at least partially based on experience.” [Dorothy Leonard]
  • Knowledge can mean information, awareness, knowing, cognition, sapience, cognisance, science, experience, skill, insight, competence, know-how, practical ability, capability, learning, wisdom, certainty, and so on. The definition depends on the context in which the term is used.” [Karl-Erik Sveiby <../../wm/links/links.html>, The New Organizational Wealth]
  • Knowledge is content in context to produce an actionable understanding.” [Dr. Robert Bauer, Xerox Parc]
  • Knowledge management is all that there is in our company. We live and die on our intellectual property…acquiring knowledge quickly…moving it around the company very quickly…it’s all about knowledge transfer; starting with the customer. [Lew Platt]
  • In organizations KM has moved from ‘project’ to ‘ perspective’. [Thomas A. Stewart]
  • Knowledge is experience. Everything else is just information. [Albert Einstein]
  • The knowledge of the world is only to be acquired in the world, and not in a closet. [Lord Chesterfield]
  • Take a look at your culture before launching a knowledge initiative [Davenport, Prusak 1998]
  • What’s happened here is 90% culture change. You need to change the way you relate one another. If you don’t do that, you won’t succeed. [CEO of Buckman Laboratories]
  • In a knowledge economy everybody is a volunteer [Peter F. Drucker]
  • Wir ertrinken in Informationen, aber uns dürstet nach Wissen. [John Naisbitt]
  • Imagination is more important than knowledge [Albert Einstein]
  • Man kann dem Volk wohl Gehorsam befehlen, aber kein Wissen. [Konfuzius]
  • There is nothing so practical as a good theory [Kurt Lewin]
  • Believe nothing, no matter whre you read it, or who said it, no matter if I have said it, unless it agrees with your own reason and your own common sense [Buddha]
  • No amount of sophistication is going to allay the fact that all your knowledge is about the past and all your decisions are about the future. [Ian E. Wilson]
  • Ein Satz hat Sinn nur im Kontext. [Ludwig Wittgenstein]
  • Was wir wissen ist ein Tropfen, was wir nicht wissen ein Ozean [Sir Isaac Newton, 1643-1727]
  • What gets measured, gets done. If you are looking for quick ways to change how an organisation behaves, change the measurement system [Mason Haire]
  • Wovon ich aber gar nicht weiß, was es ist, wie soll ich davon irgendeine Beschaffenheit wissen [Platon]
  • Ich weiß, daß ich nichts weiß. [Sokrates]
  • Continuous improvement requires a commitment to learnin. [David Garvin]
  • Knowledge Capital is the chief ingredient of a new economy [Thomas A. Stewart]
  • The secret of success is …managing the creation of new knowledge. [Ikujiro Nonaka]
  • Success for a corporation lies … in its intellectual and systems capabilities [James Brian Quinn]
  • The essence of managment is to make knowledge productive. [Peter F. Drucker]
  • Knowledge is all important … It’s the source of most value-added. [Tom Peters]
  • When it comes to knowledge management, culture trumps all other factors. [Larry Prusak]
  • Those who are not confused today have not understood the problem. [Jack Welsh, Ex-CEO GE]
  • Wissen ist Macht [Francis Bacon, 1561-1626]
  • Nichts ist so erschreckend, wie nicht wissen und doch handeln. [J. W. von Goethe]
  • An investment in knowledge always pays the best interest. [Benjamin Franklin]
  • Knowledge is not power, it is only potential power that becomes real through use. [Dorothy Riley]
  • Nicht wissen wollen ist die erste intellektuelle Todsünde, nicht wissen lassen die zweite. [Otto Galo]
  • Wissen hat seinen Ort zwischen zwei Ohren, nicht zwischen zwei Modems. [Fredmund Malik]
  • Gebildet ist, wer weiß, wo er findet, was er nicht weiß. [Georg Simmel]
  • Wissen, das nicht in Handeln mündet, ist interessant, aber nicht relevant. [H.-J. Quadbeck-Seeger]
  • Die Investition in Wissen zahlt die besten Zinsen. [Benjamin Franklin]
  • In a knowledge economy everybody is a volunteer. [Peter F. Drucker]
  • The essence of management is to make knowledge productive. [Peter F. Drucker]
  • Knowledge is content in context to produce an actionable understanding [Robert Bauer]
  • In an economy where the only certainty is uncertainty, the one sure source of lasting competitive advantage is knowledge. [Nonaka]
  • Wenn Prozesse der Blutkreislauf eines Unternehmens sind, dann ist Wissen der Sauerstoff, der die Organisation antreibt. [http://www.km-a.net/5/artikel/245/245.html]
  • §$%$&§&$§!”

    So, das mußte jetzt erst einmal raus. Ihr habt schon einmal längere Texte in Microsoft Word geschrieben und Bilder verwendet? Dann habt Ihr verstanden! Es hat mich kostbare Stunden meines Lebens gekostet herauszufinden, warum ich trotz Informatikstudiums ohne weitere Hilfe nicht in der Lage war, Bilder in meine Diplomarbeit einzubinden, mit Unterschriften zu versehen, frei zu positionieren und selbige dann im Abbildungsverzeichnis auftauchen zu lassen. In der vagen Hoffnung, wenigstens einem auf dieser weiten Welt (ok, zumindest der deutsch-sprachigen) meinen Krampf ersparen zu können, hier einige Tips und Tricks:

    Verwendet nie exakte Angaben für den Zeilenabstand bei Absätzen! Exakte Zeilenabstände verhindern wirkungsvoll das Einbinden von Bildern, jedenfalls von dem Teil des Bildes, der über den exakt angegebenen Zeilenabstand hinausragt. Siehe nachstehenden Screenshot:

    Verwendet nie eine andere Layout-Angabe für Bilder als “Inline”. Ohne weitere Tricks sind die Bilder dann nicht frei positionierbar, doch dazu später. Der Grund für diese Einschränkung ist ein neues “Feature” seit Office 2000, der “Draw Layer“. Dieser Layer ist für die Aufnahme von Nicht-Inline-Bildern gedacht und selbst nicht Bestandteil des Dokumentenkörpers. Das wiederum heißt, daß Objekte auf diesem Layer nicht in die Aufzählung bei zum Beispiel Abbildungsverzeichnissen einfließen (was übrigens der eigentliche Auslöser für meine Lösungssuche war)!

    Die Lösung: Soweit auf frei positionierbare Bilder verzichtet werden kann, ist es vergleichsweise einfach:

    • Sicherstellen, daß kein exakter Zeilenabstand angegeben ist.
    • Bild einfügen
    • Sicherstellen, daß als Layout-Angabe “Inline” eingestellt ist.
    • Mit der rechten Maustaste auf das Bild klicken und “Caption…” auswählen.

    Wenn es frei postitionierbare Bilder sein sollen (und mal ehrlich, es muß fast immer sein), wird es komplizierter:

    • Die ersten vier Schritte aus der vorherigen Lösung wiederholen
    • Beide Elemente, Bild und Bildunterschrift markieren
    • Frame (dt.: Positionsrahmen) hinzufügen
    • Nach Belieben mit rechts den Frame anklicken und bei “Border and Shadings…” den schwarzen Rahmen entfernen.

    Ihr wißt nicht, was ein Frame/Positionsrahmen ist und schon gar nicht, wie man ihn hinzufügt? Ging mir genauso. Er ist ein Relikt aus Word 97-Zeiten aber nach Aussagen von Microsoft MVPs in so ziemlich allen Fällen der Textbox (die als Ersatz für den Positionsrahmen gilt) überlegen. Da er ein Relikt ist, hat Microsoft ihn gut versteckt. Es gibt im wesentlichen zwei Möglichkeiten:

    • Statt eines Frames eine Textbox hinzufügen, Textbox bearbeiten (Rechts-Klick auf “Format Textbox”), Reiter “Textbox” auswählen, den Button “Convert to Frame” anklicken und die Sicherheitswarnung bestätigen.
    • Wem das zu komliziert ist (und mir ist das deutlich zu kompliziert), kann mit Rechtsklick auf eine der Symbolleisten die mir bis dato unbekannte Leiste “Forms” auswählen und von der den Button “Insert Frame” auswählen.
    • Eine dritte Möglichkeit wäre, dem Menü “Insert” dauerhaft den Eintrag “Insert Frame” hinzuzufügen. Dazu klickt man mit rechts auf eine der Symbolleiten und wählt “Customize” aus. Dann wählt man auf dem “Commands”-Reiter unter “Categories” den Eintrag “All commands” und zieht den Eintrag “InsertFrame” per Drag and Drop in das “Insert”-Menü.

    War doch ganz einfach, oder?! ;-( Meine bisherige Begeisterung für Microsoft und seine ansonsten genial einfach zu bedienenden Anwendungen hat heute stark gelitten!

    PS: Ich habe leider nur ein englisches Office 2003 installiert, daher kann ich nicht zu allen Menüpunkten eine Übersetzung liefern.