Freigeben über


Erstellen eines C++-Add-Ins für Outlook 2010

Zusammenfassung: In diesem Artikel wird gezeigt, wie Sie in C++ ein nicht verwaltetes Add-In erstellen, mit dem die Benutzeroberfläche von Microsoft Outlook 2010 angepasst wird. Sie erfahren, wie Sie die Menübandkomponente der Microsoft Office Fluent-Benutzeroberfläche anpassen und Outlook 2010 benutzerdefinierte Formularbereiche hinzufügen.

Letzte Änderung: Mittwoch, 14. September 2011

Gilt für: Office 2010 | Outlook 2010

Inhalt dieses Artikels
Einführung in das Erstellen von Add-ins in Outlook
Erstellen eines C++-Add-Ins
Hinzufügen eines Menübands und einer Menübandschaltfläche
Formularbereiche
Hinzufügen der Bing-Suchfunktionen
Schlussbemerkung
Weitere Ressourcen

Klicken Sie hier, um den Code abzurufenOutlook 2010-Beispiel: Erstellen eines C++-Add-Ins

Inhalt

  • Einführung in das Erstellen von Add-ins in Outlook

  • Erstellen eines C++-Add-Ins

  • Hinzufügen eines Menübands und einer Menübandschaltfläche

  • Formularbereiche

  • Hinzufügen der Bing-Suchfunktionen

  • Schlussbemerkung

  • Weitere Ressourcen

Einführung in das Erstellen von Add-ins in Outlook

Microsoft Outlook verfügt über ein umfangreiches Modell zum Erstellen von Add-Ins, mit denen Benutzern das tägliche Arbeiten mit Outlook deutlich erleichtert werden kann. Zum Erstellen von Outlook-Add-Ins können Sie Microsoft Office-Entwicklungstools in Microsoft Visual Studio 2010 (oder die Microsoft Visual Studio-Tools für Office für frühere Versionen von Visual Studio) verwenden, eine Reihe verwalteter Bibliotheken, Objektmodellen von Outlook und Microsoft Office basieren. Alternativ können Sie nicht verwalteten Code (das heißt C++) verwenden.

Hinweis

Von Microsoft Visual C++ wird die Entwicklung von Projekten in nicht verwaltetem C++ sowie in verwaltetem C++ mithilfe von Common Language Runtime (CLR) unterstützt. In diesem Artikel bezieht sich C++ auf die nicht verwaltete Version der Sprache und verwaltetes C++ auf Visual C++, das auf CLR basiert.

In der folgenden Liste werden Gründe aufgeführt, die für die Verwendung von C++ im Gegensatz zu C# oder Visual Basic (den beiden Sprachoptionen, die für Office-Entwicklungstools in Visual Studio zur Verfügung stehen) zum Erstellen von Add-Ins sprechen.

  • Leistung

    Mit einem nicht verwalteten Add-In können Sie im Allgemeinen eine bessere Leistung erzielen als mit einem in einer verwalteten Sprache geschriebenen Add-In. Der Code wird möglicherweise, abhängig vom Code und von den verwendeten Algorithmen, schneller ausgeführt. Außerdem wird ein nicht verwaltetes Add-In schneller geladen, da CLR nicht geladen werden muss. Wenn mit dem Add-In große Datenmengen in und aus Outlook verschoben werden, können Sie mit einer nicht verwalteten Version ebenfalls eine bessere Leistung erzielen, da die Daten nicht bei jedem Aufruf die Grenze zwischen systemeigen und verwaltet überqueren müssen (wird auch als Marshaling bezeichnet).

  • Größe der Verteilungspakete und weniger Abhängigkeiten

    Bei einem nicht verwalteten Add-In müssen die Benutzer keine erforderlichen Komponenten wie beispielsweise CLR installieren.

    Hinweis

    Wenn vom Add-In 32-Bit- und 64-Bit-Versionen von Outlook unterstützt werden, müssen Sie für jede Version einen separaten Build erstellen.

  • MAPI-Unterstützung (Messaging-API)

    Wenn MAPI vom Add-In direkt verwendet werden muss, müssen Sie C++ verwenden. MAPI-Aufrufe direkt aus verwaltetem Code werden nicht unterstützt.

  • Versionsverwaltung

    Obwohl in .NET Framework mehrere Versionen einer Assembly zulässig sind, können Sie mit der Laufzeit der Visual Studio-Tools für Office nur eine Assembly pro Version der Visual Studio-Tools für Office oder Office-Entwicklungstools in Visual Studio 2010 verwenden. Bei nicht verwaltetem Code können Sie mit der Versionsverwaltung größere Flexibilität erzielen.

Hinweis

Dieser Artikel ist für fortgeschrittene Entwickler gedacht, die über Erfahrung im Entwickeln von Anwendungen in C++ verfügen. Auf die Details allgemeiner Verfahren in Visual Studio wird nicht zwangsläufig eingegangen.

Die Bing-API wird in diesem Artikel nur als Beispiel für die Bereitstellung von Funktionen auf einer benutzerdefinierten Benutzeroberfläche verwendet. Sie können die benutzerdefinierte Schaltfläche im Menüband der Outlook-Prüfung mit einer API wie beispielsweise dem Outlook-Objektmodell verbinden. Wenn Sie in Ihrer Anwendung die Bing-API verwenden, muss der Code mit der zurzeit unterstützten Version von Bing kompatibel sein. Weitere Informationen finden Sie im Bing Developer Center.

Erstellen eines C++-Add-Ins

Wenn Sie sich für die Erstellung eines Outlook-Add-Ins in C++ entschieden haben, müssen Sie als Erstes mit den folgenden Verfahren eine C++-Bibliotheksanwendung erstellen.

Hinweis

Das zu diesem Artikel gehörende Codebeispiel können Sie unter Outlook 2010-Beispiel: Erstellen eines C++-Add-Ins herunterladen.

Schritt 1: Erstellen eines neuen ATL-Projekts

  1. Öffnen Sie Microsoft Visual Studio 2010.

  2. Zeigen Sie im Menü Datei auf Neu, und klicken Sie auf Projekt.

  3. Wählen Sie im Dialogfeld Neues Projekt die Vorlage ATL-Projekt aus dem Knoten Visual C++ aus.

  4. Geben Sie dem Projekt den Namen NativeAddIn. Mit ATL erhalten Sie eine gute Infrastruktur für die Verwendung des Outlook-Add-In-Modells, das auf COM basiert.

  5. Klicken Sie auf OK, um den ATL-Projekt-Assistenten zu öffnen.

  6. Klicken Sie auf Fertig stellen, um für dieses Projekt die Standardeinstellungen zu verwenden.

Schritt 2: Hinzufügen eines neuen Objekts

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektknoten, zeigen Sie auf Hinzufügen, und klicken Sie dann auf Klasse.

  2. Wählen Sie im Dialogfeld Klasse hinzufügen aus der Liste die Vorlage Einfaches ATL-Objekt aus, und klicken Sie dann auf Hinzufügen.

  3. Geben Sie im ATL-Assistenten für einfache Objekte in das Textfeld Kurzer Name die Zeichenfolge Connect ein. Dies ist der Name der Klasse, die vom Add-In implementiert wird. Die Verwendung von Connect ist als Konvention beim Erstellen von Add-In-Klassen allgemein bekannt.

  4. Geben Sie NativeAddin.Connect in das Textfeld ProgID ein, und lassen Sie die zusätzlichen Informationen vom Assistenten ausfüllen.

  5. Klicken Sie auf Fertig stellen.

Schritt 3: Implementieren von Schnittstellen

Verwenden Sie als Nächstes die ATL-Assistenten, um die notwendigen Schnittstellen für das Add-In zu implementieren.

  1. Nachdem Sie die Klasse erstellt haben, wechseln Sie zur Registerkarte Klassenansicht. (Wenn die Registerkarte nicht angezeigt wird, klicken Sie im Menü Ansicht auf Klassenansicht, oder drücken Sie STRG+UMSCHALTTASTE+C).

  2. Erweitern Sie im Fenster Klassenansicht den Knoten NativeAddIn.

  3. Klicken Sie mit der rechten Maustaste auf den Knoten CConnect, der die gerade erstellte Klasse darstellt, zeigen Sie auf Hinzufügen, und klicken Sie dann auf Schnittstelle implementieren.

    Hinweis

    Möglicherweise müssen Sie Visual Studio schließen und erneut öffnen, damit der Knoten CConnect angezeigt wird. Dabei handelt es sich um ein bekanntes Problem in der Beta 2-Version von Visual Studio 2010.

  4. Wählen Sie im Dialogfeld Assistent zum Implementieren von Schnittstellen im Feld Verfügbare Typbibliotheken die Option Microsoft Add-In Designer <1.0> aus.

  5. Wählen Sie im Listenfeld Schnittstellen die Option _IDTExtensbility2 aus, und klicken Sie auf die Schaltfläche >, um die Schnittstelle der Liste Schnittstellen implementieren hinzuzufügen.

  6. Klicken Sie auf Fertig stellen.

_IDTExtensibility2 ist die Schnittstelle, die von allen Office-Add-Ins implementiert werden muss. Mit dieser Schnittstelle werden die Interaktionen zwischen dem Add-In und dem Host (in diesem Fall Outlook) definiert. Die Hauptinteraktion findet beim ersten Laden des Add-Ins statt, wenn von Outlook die OnConnection-Methode aufgerufen wird. Mit dieser Methode erhalten Sie Zugriff auf das Outlook-Objektmodell, speichern Verweise auf die Schnittstellenzeiger und fügen Anpassungen hinzu.

Schritt 4: Einrichten des Ladens des Add-Ins in Outlook

  1. Öffnen Sie die Datei Connect.h.

  2. Ändern Sie alle Methoden so, dass S_OK anstelle von E_NOTIMPL zurückgegeben wird. Da alle diese Methoden von Outlook aufgerufen werden, ist es wichtig, dass ein erfolgreiches Ergebnis zurückgegeben wird.

  3. Fügen Sie der OnConnection-Methode Code hinzu, damit Sie überprüfen können, ob das Add-In von Outlook geladen wird. Fügen Sie wie im folgenden Code einen Aufruf für MessageBoxW hinzu.

    STDMETHOD(OnConnection)(LPDISPATCH Application, 
        ext_ConnectMode ConnectMode, 
        LPDISPATCH AddInInst, 
        SAFEARRAY * * custom)
    {
        MessageBoxW(NULL,L"OnConnection",L"Native Addin",MB_OK);
        return S_OK;
    }
    

Dies reicht für den Anfang. Bevor das Add-In jedoch tatsächlich in Outlook geladen werden kann, müssen Sie weitere Metadateninformation zum Add-In bereitstellen, das heißt zum Vorhandensein und zum Laden des Add-Ins. Diese Informationen müssen Sie in der Windows-Registrierung platzieren. Da in das ATL-Projekt bereits ein Registrierungsskript eingebettet ist (zum Platzieren der allgemeinen COM-Metadaten in der Registrierung), können Sie Ihre Outlook-spezifischen Metadaten einfach diesem Skript hinzufügen, um die Daten ebenfalls der Registrierung hinzuzufügen.

Schritt 5: Einfügen von Outlook-spezifischen Metadaten für das Add-In in die Windows-Registrierung

  1. Öffnen Sie den Projektmappen-Explorer.

  2. Erweitern Sie den Ordner Ressourcendateien, und öffnen Sie die Datei Connect.rgs.

  3. Fügen Sie der Datei das folgende Registrierungsskript hinzu.

    HKCU
    {
        NoRemove Software
        {
            NoRemove Microsoft
            {
                NoRemove Office
                {
                    NoRemove Outlook
                    {
                        NoRemove Addins
                        {
                            NativeAddin.Connect
                            {
                                val Description = s 'Sample Addin'
                                val FriendlyName = s 'Sample Addin'
                                val LoadBehavior = d 3
                            }
                        }
                    }
                }
            }
        }
    }
    

Mit diesem Registrierungseintrag wird Outlook informiert, dass das Add-In geladen werden soll, und aus dem LoadBehavior-Schlüssel geht hervor, dass das Add-In automatisch geladen werden soll. Wenn Sie jetzt das Projekt erstellen, werden die richtigen Registrierungsschlüssel in der Registrierung platziert, und das Add-In ist fast bereit zum Laden.

Schritt 6: Ermitteln des geeigneten Builds für das Add-In

Jetzt müssen Sie ermitteln, ob Sie die 32-Bit- oder 64-Bit-Version von Outlook ausführen. Die Office-Installation befindet sich im Verzeichnis Laufwerk:\Programme\Microsoft Office, wenn Sie 32-Bit-Windows ausführen, bzw. im Verzeichnis Laufwerk:\Programme (x86)\Microsoft Office, wenn Sie die 32-Bit-Version von Outlook unter einer 64-Bit-Version von Windows ausführen. Wenn Sie die 32-Bit-Version von Outlook ausführen, sind Sie fertig; Sie können das Add-In erstellen und dann Outlook öffnen.

Wenn Sie die 64-Bit-Version von Outlook ausführen, müssen Sie das Projekt so ändern, dass das Add-In mit dem 64-Bit-Compiler erstellt wird. In der 64-Bit-Version von Outlook werden 32-Bit-Add-Ins nicht geladen.

Führen Sie diese Schritte aus, um das Add-In für die 64-Bit-Version von Outlook zu erstellen:

  1. Öffnen Sie den Konfigurations-Manager, indem Sie mit der rechten Maustaste im Projektmappen-Explorer auf den Lösungsknoten klicken und dann auf Konfigurations-Manager klicken.

  2. Wählen Sie im Konfigurations-Manager im Feld Aktive Projektmappenplattform die Option Neu aus, um eine neue Plattformeinstellung für das Projekt NativeAddin zu erstellen.

  3. Wählen Sie im Dialogfeld Neue Projektmappenplattform als neue Plattform die Option x64 aus, und klicken Sie dann auf OK.

  4. Klicken Sie im Dialogfeld Konfigurations-Manager auf Schließen.

  5. Erstellen Sie die Lösung erneut, bevor Sie Outlook zu öffnen versuchen.

Beim Öffnen von Outlook sollte das Meldungsfeld angezeigt werden, das mit der folgenden Codezeile in der OnConnection-Methode generiert wird.

MessageBoxW(NULL, L"OnConnection", L"Native_Addin", MB_OK);
    return S_OK;

Das Meldungsfeld wird in Abbildung 1 gezeigt.

Abbildung 1. "NativeAddIn" mit Meldungsfeld beim Start

Von 'NativeAddIn' wird beim Start ein Meldungsfeld angezeigt

Sie können das Debuggen erleichtern, in dem Sie die Projekteigenschaften so ändern, dass Outlook beim Debuggen des Projekts geladen wird.

Schritt 7 (optional): Ändern der Projekteigenschaften, sodass Outlook geladen wird, um das Debuggen zu erleichtern

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und klicken Sie dann auf Eigenschaften.

  2. Erweitern Sie Konfigurationseigenschaften in der Strukturansicht im linken Bereich, und wählen Sie dann den Knoten Debugging aus.

  3. Wählen Sie für die Eigenschaft Befehl im rechten Bereich in dem Kombinationsfeld, das angezeigt wird, wenn Sie rechts neben die Eigenschaft klicken, die Option Durchsuchen aus.

  4. Navigieren Sie auf dem Computer zur Datei Outlook.exe (auch hier hängt der Pfad vom Betriebssystem ab und davon, ob Sie die 32-Bit- oder 64-Bit-Version von Outlook ausführen).

Bevor Sie fortfahren, sollten Sie den Aufruf von MessageBoxW in der OnConnection-Methode aus der CConnect-Implementierung entfernen (oder auskommentieren). Das wiederholte Schließen des Dialogfelds bei jeder Ausführung wird beim Erstellen und Debuggen recht ermüdend. Es empfiehlt sich, den Aufruf auszukommentieren, da Sie, falls später beim Laden oder Debuggen Probleme auftreten, den Kommentar jederzeit zu Testzwecken entfernen können, um sicherzustellen, dass das Add-In geladen wird (bzw. um festzustellen, dass das Add-In nicht geladen wird).

Hinzufügen eines Menübands und einer Menübandschaltfläche

Nachdem Sie nun das Add-In erstellt haben und das Add-In zum Laden bereit ist, möchten Sie wahrscheinlich zusätzliche Funktionen hinzufügen. Häufig wird als Anpassung dem Outlook-Menüband eine Registerkarte hinzugefügt, der wiederum Registerkartengruppen und Schaltflächen hinzugefügt werden.

Hierzu müssen Sie eine weitere Schnittstelle implementieren: IRibbonExtensibility. IRibbonExtensibility ist eine ziemlich einfache Schnittstelle, da nur eine Methode (GetCustomUI) vorhanden ist. GetCustomUI verfügt über eine BSTR-Zeichenkette als Ausgabeparameter, die XML enthalten sollte, die mit dem Schema der Microsoft Office Fluent-Benutzeroberfläche formatiert ist. Die XML wird dann verwendet, um weitere Menübandelemente im Host (in diesem Fall Outlook) hinzuzufügen.

IRibbonExtensibility befindet sich in einer anderen Typbibliothek als der, die Sie vorhin hinzugefügt haben. Daher müssen Sie diese Typbibliothek in das Projekt aufnehmen. Dies ist ein guter Zeitpunkt, die Headerdatei StdAfx.h zu bereinigen, um das Projekt für verschiedene Plattformen und Computer etwas robuster zu machen.

Wenn Sie die Datei StdAfx.h öffnen (siehe Abbildung 2), sehen Sie, dass der ATL-Assistent zum Implementieren von Schnittstellen einen absoluten Pfad in die #import-Anweisung einfügt (dadurch wird die Typbibliothek beim Kompilieren des Projekts in eine C++-/COM-Headerdatei konvertiert). Für Ihren Computer ist das richtig, aber wenn Sie das Projekt gemeinsam mit einem anderen Entwickler nutzen möchten, verwendet dieser möglicherweise einen anderen Pfad. Der Pfad kann sich auch ändern, wenn Sie zwischen einem 32-Bit- und einem 64-Bit-System wechseln.

Abbildung 2. Datei "StdAfx.h" mit der "#import"-Anweisung des Assistenten

Datei 'StdAfx.h' mit der #import-Anweisung des Assistenten

Sie können die #import-Anweisung robuster gestalten, indem Sie anstatt auf den Pfad auf die LIBID LIBID (Library Identifier, Bibliothekenkennung oder GUID) der Typbibliothek verweisen. Außerdem sollten Sie eine zweite Importanweisung für die Office-Typbibliothek einschließen (die die IRibbonExtensibility-Schnittstelle enthält). Dadurch wird die #import-Anweisung erheblich robuster, und durch Hinzufügen von rename_namespace können Sie Probleme umgehen, die auftreten können, wenn nach dem Importieren der Typbibliotheken Namenkonflikte auftreten.

In den folgenden Verfahren wird gezeigt, wie Sie ein Menüband und eine Menübandschaltfläche hinzufügen.

Schritt 1: Bereinigen der Datei "StdAfx.h"

  1. Öffnen Sie die Datei StdAfx.h.

  2. Entfernen Sie die #import-Anweisung, und ersetzen Sie diese durch den folgenden Code.

    #import "libid:AC0714F2-3D04-11D1-AE7D-00A0C90F26F4"\
    auto_rename auto_search raw_interfaces_only rename_namespace("AddinDesign")
    
    // Office type library (i.e., mso.dll).
    #import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52"\
        auto_rename auto_search raw_interfaces_only rename_namespace("Office")
    using namespace AddinDesign;
    using namespace Office;
    

Nun nehmen Sie manuelle Änderungen an der CConnect-Klasse vor, um Interaktionen mit dem Menüband zu unterstützen.

Schritt 2: Ändern der "CConnect"-Klasse, um Interaktionen mit dem Menüband zu unterstützen

  1. Öffnen Sie die Datei Connect.h.

    Nun fügen Sie typedef-Deklarationen für die verschiedenen Schnittstellen hinzu, mit deren Hilfe Sie spätere Aufgaben vereinfachen werden.

  2. Suchen Sie die IDispatchImpl-Deklaration der CConnect-Klasse für _IDTExtensibility2 (siehe Abbildung 3), und machen Sie daraus eine typedef-Deklaration mit dem Namen IDTImpl.

    Abbildung 3. Vom Assistenten generierte "IDispatchImpl"-Deklaration

    Vom Assistenten generierte IDispatchImpl-Deklaration

  3. Fügen Sie eine ähnliche typedef-Deklaration mit dem Namen RibbonImpl für IRibbonExtensibility hinzu, und fügen Sie diese dann der Liste der Basisklassen für CConnect hinzu. Anschließend sollte die Klasse wie der folgende Code aussehen.

    typedef IDispatchImpl<_IDTExtensibility2, &__uuidof(_IDTExtensibility2), &__uuidof(__AddInDesignerObjects), /* wMajor = */ 1>
    IDTImpl;
    
    typedef IDispatchImpl<IRibbonExtensibility, &__uuidof(IRibbonExtensibility), &__uuidof(__Office), /* wMajor = */ 2, /* wMinor = */ 5>
    RibbonImpl;
    
    class ATL_NO_VTABLE CConnect :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CConnect, &CLSID_Connect>,
    public IDispatchImpl<IConnect, &IID_IConnect, &LIBID_NativeAddinLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDTImpl,
    public RibbonImpl
    
  4. Fügen Sie die folgende Schnittstelle der ATL-COM-Zuordnung hinzu.

    COM_INTERFACE_ENTRY(IRibbonExtensibility)
    
  5. Ändern Sie alle Methoden, einschließlich derer, für die Sie noch keine echte Funktionalität hinzufügen, so, dass S_OK anstelle von E_NOT_IMPL zurückgegeben wird.

Schritt 3: Implementieren von "IRibbonExtensibility"

Fügen Sie die Implementierung für IRibbonExtensibility hinzu. Diese sollte ungefähr wie der folgende Code aussehen.

public:
STDMETHOD(GetCustomUI)(BSTR RibbonID, BSTR * RibbonXml)
{
    if(!RibbonXml)
        return E_POINTER;
    *RibbonXml = CComBSTR("XML GOES HERE");  
    return S_OK;
}

Nun müssen Sie entscheiden, wo die Menüband-XML gespeichert werden soll. Eine Möglichkeit besteht darin, die XML direkt in den Code einzubetten. Praktischer wäre es jedoch, die XML dem Projekt als Ressource hinzuzufügen.

Schritt 4: Einrichten der Menüband-XML als Ressource für das Projekt

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt NativeAddIn, zeigen Sie auf Hinzufügen, und klicken Sie dann auf Neues Element.

  2. Wählen Sie im Dialogfeld Neues Element hinzufügen die Vorlage XML-Datei aus, und geben Sie dem Element den Namen RibbonManifest.xml.

  3. Klicken Sie auf Hinzufügen, um das Element dem Projekt hinzuzufügen.

Die Menüband-XML ist relativ einfach. Die XML enthält ein ribbon-Element und ein tab-Element, das mehrere tab-Elemente enthalten kann. Eine Registerkarte in einem Menüband kann eine Gruppe enthalten, und jede Gruppe kann Schaltflächen enthalten. In Abbildung 4 wird gezeigt, wie sich dadurch die Benutzeroberfläche des Outlook-Menübands ergibt. Gruppen werden durch rote Rechtecke gekennzeichnet und Schaltflächen durch blaue Ovale.

Abbildung 4. Registerkarte, Gruppen und Schaltflächen im Outlook-Menüband

Registerkarte, Gruppen und Schaltflächen im Outlook-Menüband

Nun müssen Sie eine neue Registerkarte, eine neue Gruppe und eine neue Schaltfläche erstellen.

Schritt 5: Angeben der XML für eine neue Registerkarte, eine neue Gruppe und eine neue Schaltfläche

Öffnen Sie die Datei RibbonManifest.xml, und fügen Sie die folgende XML hinzu.

<customUI xmlns="https://schemas.microsoft.com/office/2006/01/customui">
    <ribbon>
        <tabs>
            <tab id="Bing" label="Bing">
                <group id="BingGroup" label="Bing Group">
                    <button id="NewCustomButton" 
                        imageMso="WebPagePreview" 
                        size="large" 
                        label="Search Bing" 
                        onAction="ButtonClicked"/>
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

Wie in Schritt 4 eingerichtet wird die Datei RibbonManifest.xml als Ressource gespeichert, sodass Sie die XML über die IRibbonExtensibility::GetCustomUI-Methode zurückgeben können.

Schritt 6: Implementieren von "IRibbonExtensibility::GetCustomUI" zum Zurückgeben von XML

  1. Zeigen Sie im Menü Ansicht auf Weitere Fenster, und klicken Sie dann auf Ressourcenansicht, um zur Ressourcenansicht für dieses Projekt zu wechseln.

  2. Erweitern Sie den Knoten NativeAddIn, klicken Sie mit der rechten Maustaste auf den KnotenNativeAddIn.rc, und klicken Sie dann auf Ressource hinzufügen.

  3. Klicken Sie im Dialogfeld Ressource hinzufügen auf die Schaltfläche Importieren.

  4. Ändern Sie den Dateityp rechts unten im Dialogfeld in Alle Dateien, wählen Sie in der Dateiliste die Datei RibbonManifest.xml aus, und klicken Sie dann auf Öffnen.

  5. Geben Sie im Dialogfeld Benutzerdefinierter Ressourcentyp dem Ressourcentyp den Namen XML, und klicken Sie dann auf OK.

  6. Jetzt benötigen Sie Code, mit dem die XML-Ressource tatsächlich verarbeitet werden kann. Diesen Code können Sie selbst implementieren, oder Sie können der CConnect-Klasse den folgenden Code hinzufügen.

    HRESULT HrGetResource(int nId, 
        LPCTSTR lpType, 
        LPVOID* ppvResourceData,       
        DWORD* pdwSizeInBytes)
    {
        HMODULE hModule = _AtlBaseModule.GetModuleInstance();
        if (!hModule)
            return E_UNEXPECTED;
        HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(nId), lpType);
        if (!hRsrc)
            return HRESULT_FROM_WIN32(GetLastError());
        HGLOBAL hGlobal = LoadResource(hModule, hRsrc);
        if (!hGlobal)
            return HRESULT_FROM_WIN32(GetLastError());
        *pdwSizeInBytes = SizeofResource(hModule, hRsrc);
        *ppvResourceData = LockResource(hGlobal);
        return S_OK;
    }
    
    BSTR GetXMLResource(int nId)
    {
        LPVOID pResourceData = NULL;
        DWORD dwSizeInBytes = 0;
        HRESULT hr = HrGetResource(nId, TEXT("XML"), 
            &pResourceData, &dwSizeInBytes);
        if (FAILED(hr))
            return NULL;
        // Assumes that the data is not stored in Unicode.
        CComBSTR cbstr(dwSizeInBytes, reinterpret_cast<LPCSTR>(pResourceData));
        return cbstr.Detach();
    }
    
    SAFEARRAY* GetOFSResource(int nId)
    {
        LPVOID pResourceData = NULL;
        DWORD dwSizeInBytes = 0;
        if (FAILED(HrGetResource(nId, TEXT("OFS"), 
            &pResourceData, &dwSizeInBytes)))
            return NULL;
        SAFEARRAY* psa;
        SAFEARRAYBOUND dim = {dwSizeInBytes, 0};
        psa = SafeArrayCreate(VT_UI1, 1, &dim);
        if (psa == NULL)
            return NULL;
        BYTE* pSafeArrayData;
        SafeArrayAccessData(psa, (void**)&pSafeArrayData);
        memcpy((void*)pSafeArrayData, pResourceData, dwSizeInBytes);
        SafeArrayUnaccessData(psa);
        return psa;
    }
    
  7. Fügen Sie den folgenden Code hinzu, um die Implementierung von IRibbonExtensibility::GetCustomUI abzuschließen, sodass die eigentliche XML zurückgegeben wird.

    STDMETHOD(GetCustomUI)(BSTR RibbonID, BSTR * RibbonXml)
    {
        if(!RibbonXml)
            return E_POINTER;
        *RibbonXml = GetXMLResource(IDR_XML1);
        return S_OK;
    }
    

Wenn Sie das Add-In erstellen und Outlook ausführen, sollten die hinzugefügte Registerkarte, die Gruppe und die Schaltfläche wie in Abbildung 5 angezeigt werden.

Abbildung 5. Hinzugefügte Registerkarte, Gruppe und Schaltfläche im Outlook-Menüband

Hinzugefügte Registerkarte, Gruppe und Schaltfläche im Outlook-Menüband

Nun müssen Sie Code hinzufügen, über den eine Aktion ausgeführt wird, wenn Benutzer auf die Schaltfläche Bing durchsuchen klicken. (Den Code für die eigentliche Bing-Such-API implementieren Sie später.)

Im Gegensatz zu vielen anderen Rückrufumgebungen wird in Office, einschließlich Outlook, anstelle einer benutzerdefinierten Schnittstelle unter Verwendung von Verbindungspunkten IDispatch für Rückrufe an die IRibbonExtensibility-Implementierung verwendet. Von Ihrem Objekt muss ein DISPID-Element von GetIDsofName zurückgegeben werden, wenn der Wert des onAction-Attributs (in diesem Fall ButtonClicked) von der Menüband-XML übergeben wird. Außerdem muss die IDispatch::Invoke-Methode entsprechend auf DISPID reagieren. Für die Methode wird außerdem ein Eingabeparameter benötigt, bei dem es sich um einen IDispatch-Zeiger handelt.

Ab hier wird der Code etwas komplizierter, da Sie eine tiefere Ebene in ATL verwenden müssen, als Sie normalerweise für die Implementierung eines einfachen COM-Add-Ins verwenden müssten.

An dieser Stelle müssen Sie zuerst eine COM-Schnittstelle mit einer ButtonClicked-Methode erstellen.

Schritt 7: Deklarieren einer COM-Schnittstelle mit einer "ButtonClicked"-Methode

  1. Öffnen Sie die IDL-Datei (NativeAddIn.idl) für das Projekt.

  2. Fügen Sie die Schnittstelle hinzu. Dabei muss es sich um eine doppelte Schnittstelle handeln, und Sie sollten einen eindeutigen DISPID-Wert für das id-Attribut auswählen. Dadurch sollen DISPID-Konflikte zu einem späteren Zeitpunkt vermieden werden. Die Deklaration in der Datei NativeAddIn.idl sollte wie der folgende Code aussehen.

    [
        object,
        uuid(CE895442-9981-4315-AA85-4B9A5C7739D8),
        dual,
        nonextensible,
        helpstring("IRibbonCallback Interface"),
        pointer_default(unique)
    ]
    interface IRibbonCallback : IDispatch{
        [id(42),helpstring("Button Callback")]
        HRESULT ButtonClicked([in]IDispatch* ribbonControl);
    };
    
  3. Legen Sie IRibbonCallback als Standardschnittstelle für Ihre Klasse fest, indem Sie IConnect ersetzen.

    coclass Connect
    {
        [default] interface IRibbonCallback;
    };
    

Nachdem die Schnittstelle deklariert und die Standardschnittstelle festgelegt ist, können Sie festlegen, dass die Schnittstelle von der CConnect-Klasse implementiert wird.

Schritt 8: Implementieren der Schnittstelle

  1. Fügen Sie die folgende Deklaration am Anfang der Datei Connect.h hinzu.

    typedef IDispatchImpl<IRibbonCallback, &__uuidof(IRibbonCallback)> 
    CallbackImpl;
    

    Das Hinzufügen von typedef erleichtert die Implementierung der IDispatch::Invoke-Methode zu einem späteren Zeitpunkt.

  2. Fügen Sie die Schnittstelle der Basishierarchie der CConnect-Klasse hinzu. Die Klasse sollte jetzt wie der folgende Code aussehen.

    class ATL_NO_VTABLE CConnect :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CConnect, &CLSID_Connect>,
    public IDispatchImpl<IConnect, &IID_IConnect, &LIBID_NativeAddInLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDTImpl,
    public RibbonImpl,
    public CallbackImpl
    
  3. Fügen Sie die Schnittstelle der ATL-COM-Zuordnung hinzu, und ersetzen Sie die _IDTExtensibility2-Schnittstelle im Eintrag COM_INTERFACE_ENTRY2. Die COM-Zuordnung sollte wie folgt aussehen.

    BEGIN_COM_MAP(CConnect)
        COM_INTERFACE_ENTRY2(IDispatch, IRibbonCallback)
        COM_INTERFACE_ENTRY(IConnect)
        COM_INTERFACE_ENTRY(_IDTExtensibility2)
        COM_INTERFACE_ENTRY(IRibbonExtensibility)
        COM_INTERFACE_ENTRY(IRibbonCallback)
    END_COM_MAP()
    
  4. Implementieren Sie die IRibbonCallback::ButtonClicked-Methode. Fügen Sie den folgenden Code hinzu, um ein Meldungsfeld zu öffnen, damit Sie sich vergewissern können, dass der Rückruf funktionsfähig ist.

    STDMETHOD(ButtonClicked)(IDispatch* ribbon)
    {
        MessageBoxW(NULL,L"Button Clicked!",L"NativeAddin",MB_OK);
        return S_OK;
    }
    

Damit dieser Rückruf funktionsfähig ist, ist noch ein weiterer Schritt erforderlich: Sie müssen die Implementierung von IDispatch::Invoke außer Kraft setzen. Hierfür gibt es einige Möglichkeiten wie beispielsweise das folgende Verfahren. Beachten Sie, dass es sich dabei jedoch nicht um eine allgemein geeignete Methode zum Verfügbarmachen mehrerer benutzerdefinierter Schnittstellen durch IDispatch handelt.

Schritt 9: Außerkraftsetzen der Implementierung von "IDispatch::Invoke"

  1. Fügen Sie der CConnect-Klasse den folgenden Code hinzu:

    STDMETHOD(Invoke)(DISPID dispidMember, 
        const IID &riid, 
        LCID lcid, 
        WORD wFlags, 
        DISPPARAMS *pdispparams, 
        VARIANT *pvarResult, 
        EXCEPINFO *pexceptinfo, 
        UINT *puArgErr)
    {
        HRESULT hr=DISP_E_MEMBERNOTFOUND;
        if(dispidMember==42)
        {
            hr  = CallbackImpl::Invoke(dispidMember, 
                riid, 
                lcid, 
                wFlags,       
                pdispparams, 
                pvarResult, 
                pexceptinfo, 
                puArgErr);
        }
        if (DISP_E_MEMBERNOTFOUND == hr)
            hr = IDTImpl::Invoke(dispidMember, 
                riid, 
                lcid, 
                wFlags, 
                pdispparams, 
                pvarResult, 
                pexceptinfo, 
                puArgErr);
        return hr;
    }
    

    Mit diesem Code wird ermittelt, ob der dispidMember-Parameter für den Rückruf (in diesem Fall 42) eindeutig ist. Wenn dies der Fall ist, wird die CallbackImpl::Invoke-Methode aufgerufen. Anderenfalls wird die IDTImpl::Invoke-Methode aufgerufen, da es sich dabei um die einzige andere IDispatch-Schnittstelle handelt, die Sie im Moment benötigen.

An dieser Stelle können Sie das Add-In erstellen. Wenn Sie auf die benutzerdefinierte Schaltfläche im neuen Menüband klicken, sollte ein Meldungsfeld angezeigt werden.

Formularbereiche

Eine weitere Möglichkeit zum Hinzufügen einer Benutzeroberfläche zu Outlook ist das Hinzufügen benutzerdefinierter Formularbereiche. Mit benutzerdefinierten Formularbereichen können Sie einen Bereich mit Steuerelementen in einer Outlook-Prüfung platzieren. Sie können diese Formularbereiche an verschiedenen Stellen in der Prüfung platzieren und beispielsweise auch das gesamte Dialogfeld ersetzen.

Zum Abschließen dieses Add-ins fügen Sie dem Formular einen Formularbereich hinzu, der zum Anzeigen von E-Mail-Elementen verwendet wird. Der Formularbereich wird ein Webbrowser-Steuerelement enthalten. Für die Integration eines Formularbereichs in das Add-In werden ähnliche Schritte verwendet wie zum Hinzufügen der Menüband-Benutzeroberfläche. Fügen Sie mit den folgenden Verfahren benutzerdefinierte Formularbereiche hinzu.

Zunächst müssen Sie die notwendigen Typbibliotheken integrieren. In diesem Fall integrieren Sie drei Typbibliotheken: eine für Microsoft Word (da Word in Outlook zum Bearbeiten von E-Mail-Nachrichten verwendet wird), eine für Outlook (damit Sie für das Outlook-Objektmodell programmieren können) und eine für Formularbereiche.

Schritt 1: Importieren der notwendigen Typbibliotheken

Fügen Sie der Datei StdAfx.h die folgenden #import-Anweisungen hinzu.

#import "libid:00020905-0000-0000-C000-000000000046"\
auto_rename auto_search raw_interfaces_only rename_namespace("Word")

// Outlook type library (i.e., msoutl.olb).
#import "libid:00062FFF-0000-0000-C000-000000000046"\
auto_rename auto_search raw_interfaces_only rename_namespace("Outlook")

// Forms type library (i.e., fm20.dll).
#import "libid:0D452EE1-E08F-101A-852E-02608C4D0BB4"\
auto_rename auto_search raw_interfaces_only  rename_namespace("Forms")
using namespace Word;
using namespace Outlook;

using namespace Forms;

Nun implementieren Sie die _FormRegionStartup-Schnittstelle.

Schritt 2: Implementieren der "_FormRegionStartup"-Schnittstelle

  1. Fügen Sie die folgende typedef für IDispatchImpl am Anfang der Datei Connect.h hinzu.

    typedef IDispatchImpl<_FormRegionStartup, &__uuidof(_FormRegionStartup), &__uuidof(__Outlook), /* wMajor = */ 9, /* wMinor = */ 4>
    FormImpl;
    
  2. Fügen Sie die FormImpl-Definition der CConnect-Klasse hinzu. Die endgültige CConnect-Deklaration sollte wie der folgende Code aussehen.

    class ATL_NO_VTABLE CConnect :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CConnect, &CLSID_Connect>,
    public IDispatchImpl<IConnect, &IID_IConnect, &LIBID_NativeAddinLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDTImpl,
    public RibbonImpl,
    public CallbackImpl,
    public FormImpl
    
  3. Da Sie im letzten Abschnitt IDispatch::Invoke außer Kraft gesetzt haben, müssen Sie der Methode den folgenden Code für die Behandlung der neuen Schnittstelle hinzufügen.

    STDMETHOD(Invoke)(DISPID dispidMember, 
        const IID &riid, 
        LCID lcid, 
        WORD wFlags, 
        DISPPARAMS *pdispparams, 
        VARIANT *pvarResult,  
        EXCEPINFO *pexceptinfo, 
        UINT *puArgErr)
    {
        HRESULT hr=DISP_E_MEMBERNOTFOUND;
        if(dispidMember==42)
        {
            hr  = CallbackImpl::Invoke(dispidMember, 
                riid, 
                lcid, 
                wFlags, 
                pdispparams, 
                pvarResult, 
                pexceptinfo, 
                puArgErr);
        }
        if (DISP_E_MEMBERNOTFOUND == hr)
            hr = IDTImpl::Invoke(dispidMember, 
                riid, 
                lcid, 
                wFlags, 
                pdispparams, 
                pvarResult, 
                pexceptinfo, 
                puArgErr);
        if (DISP_E_MEMBERNOTFOUND == hr)
            hr = FormImpl::Invoke(dispidMember, 
                riid, 
                lcid, 
                wFlags, 
                pdispparams, 
                pvarResult, 
                pexceptinfo, 
                puArgErr);
        return hr;
    }
    
  4. Fügen Sie _FormRegionStartup der ATL-COM-Schnittstellenzuordnung hinzu.

    BEGIN_COM_MAP(CConnect)
        COM_INTERFACE_ENTRY2(IDispatch, IRibbonCallback)
        COM_INTERFACE_ENTRY(IConnect)
        COM_INTERFACE_ENTRY(_IDTExtensibility2)
        COM_INTERFACE_ENTRY(IRibbonExtensibility)
        COM_INTERFACE_ENTRY(IRibbonCallback)
        COM_INTERFACE_ENTRY(_FormRegionStartup)
    END_COM_MAP()
    
  5. Fügen Sie die Implementierung von _FormRegionStartup hinzu.

    public:
    STDMETHOD(GetFormRegionStorage)(BSTR FormRegionName, 
        LPDISPATCH Item, 
        long LCID, 
        OlFormRegionMode FormRegionMode, 
        OlFormRegionSize FormRegionSize, 
        VARIANT * Storage)
    {
        V_VT(Storage) = VT_ARRAY | VT_UI1;
        V_ARRAY(Storage) = GetOFSResource(IDR_OFS1);
        return S_OK;
    }
    
    STDMETHOD(BeforeFormRegionShow)(_FormRegion * FormRegion)
    {
        if(m_pFormRegionWrapper)
            delete m_pFormRegionWrapper;
        m_pFormRegionWrapper = new FormRegionWrapper();
        if (!m_pFormRegionWrapper)
            return E_OUTOFMEMORY;
        return m_pFormRegionWrapper->HrInit(FormRegion);
    }
    
    STDMETHOD(GetFormRegionManifest)(BSTR FormRegionName, 
        long LCID, 
        VARIANT * Manifest)
    {
        V_VT(Manifest) = VT_BSTR;
        BSTR bstrManifest = GetXMLResource(IDR_XML2);
        V_BSTR(Manifest) = bstrManifest;
        return S_OK;
    }
    
    STDMETHOD(GetFormRegionIcon)(BSTR FormRegionName, 
        long LCID, 
        OlFormRegionIcon Icon, 
        VARIANT * Result)
    {
        return S_OK;
    }
    
    private:
    FormRegionWrapper* m_pFormRegionWrapper;
    
  6. Ändern Sie FinalConstruct, um m_pFormRegionWrapper zu initialisieren.

    HRESULT FinalConstruct()
    {
        m_pFormRegionWrapper = NULL;
        return S_OK;
    }
    

Die Implementierung enthält eine Methode (_FormRegionStartup::GetFormRegionManifest), die mit IRibbonExtensibility::GetCustomUI vergleichbar ist. Die GetFormRegionManifest-Methode muss außerdem Outlook-spezifische XML zurückgeben, mit der Outlook Informationen zum hinzuzufügenden Formularbereich erhält.

Schritt 3: Angeben der Anzeige des Formularbereichs in XML

  1. Fügen Sie dem Projekt eine weitere XML-Datei hinzu. Geben Sie dieser den Namen FormManifest.xml.

  2. Fügen Sie der Datei die folgende XML hinzu.

    <FormRegion xmlns="https://schemas.microsoft.com/office/outlook/12/formregion.xsd">
        <name>Native</name>
        <formRegionType>adjoining</formRegionType>
        <formRegionName>Search Bing</formRegionName>
        <hidden>true</hidden>
        <ribbonAccelerator>I</ribbonAccelerator>
        <showInspectorCompose>true</showInspectorCompose>
        <showInspectorRead>true</showInspectorRead>
        <showReadingPane>false</showReadingPane>
        <addin>NativeAddin.Connect</addin>
    </FormRegion>
    
  3. Wechseln Sie zur Ressourcenansicht für das Projekt (zeigen Sie im Menü Ansicht auf Weitere Fenster, und klicken Sie dann auf Ressourcenansicht).

  4. Erweitern Sie den Knoten NativeAddIn, klicken Sie mit der rechten Maustaste auf den KnotenNativeAddIn.rc, und klicken Sie dann auf Ressource hinzufügen.

  5. Klicken Sie im Dialogfeld Ressource hinzufügen auf die Schaltfläche Importieren.

  6. Ändern Sie den Dateityp rechts unten im Dialogfeld in Alle Dateien, wählen Sie in der Dateiliste die Datei FormManifest.xml aus, und klicken Sie dann auf Öffnen.

  7. Geben Sie im Dialogfeld Benutzerdefinierter Ressourcentyp dem Ressourcentyp den Namen XML, und klicken Sie dann auf OK.

Zum Abschließen dieser Implementierung müssen Sie die Hilfsklasse (FormRegionWrapper) erstellen, die von der _FormRegionStartup-Schnittstelle zum Verwalten des Formularbereichs (und zum Aufrufen der Bing-API) verwendet wird.

Schritt 4: Erstellen einer Hilfsklasse zum Verwalten des Formularbereichs und zum Aufrufen der Bing-API

  1. Fügen Sie der Headerdatei StdAfx.h die folgenden #include-Anweisungen hinzu.

    #include <msxml2.h>//msxml for parsing the Bing results
    #include <Mshtml.h>//mshtml for controlling the web browser control
    #include <Winhttp.h>//for making the HTTP calls to Bing
    #include <atlstr.h>//for CString
    #include <atlsafe.h>//for the ATL Safearray helper classes
    
  2. Fügen Sie Winhttp.lib und Msxml2.lib den Linkerabhängigkeiten hinzu. Klicken Sie hierzu mit der rechten Maustaste auf das Projekt, und klicken Sie dann auf Eigenschaften. Erweitern Sie im Dialogfeld Eigenschaften den Knoten Linker, und wählen Sie dann Eingabe aus. Klicken Sie auf das Dropdownfeld neben Zusätzliche Abhängigkeiten und dann auf Bearbeiten. Geben Sie in das Dialogfeld Zusätzliche Abhängigkeiten auf separaten Zeilen die Zeichenfolgen winhttp.lib und msxml2.lib ein, und klicken Sie dann auf OK.

  3. Erstellen Sie eine neue Headerdatei mit dem Namen FormRegionWrapper.h, und fügen Sie dieser den folgenden Code hinzu.

    #pragma once
    #include "stdafx.h"
    #include <vector>
    #include <algorithm>
    
    /*!-----------------------------------------------------------------------
    FormRegionWrapper - Used to help track all the form regions and to 
    listen to some basic events such as the send button click and close.
    -----------------------------------------------------------------------!*/
    class FormRegionWrapper;
    typedef 
    IDispEventSimpleImpl<2, FormRegionWrapper, &__uuidof(FormRegionEvents)>
    FormRegionEventSink;
    const DWORD dispidEventOnClose = 0xF004;
    class FormRegionWrapper : public FormRegionEventSink
    {
        public:
            HRESULT HrInit(_FormRegion* pFormRegion);
            void Show();
            void SearchSelection();
            void Search(BSTR term);
        private:
            static _ATL_FUNC_INFO VoidFuncInfo; 
        public:
            BEGIN_SINK_MAP(FormRegionWrapper)
            SINK_ENTRY_INFO(2, __uuidof(FormRegionEvents), 
                dispidEventOnClose,    
                OnFormRegionClose, 
                &VoidFuncInfo)
            END_SINK_MAP()
            void __stdcall OnFormRegionClose();
        private:
            CComPtr<_FormRegion> m_spFormRegion;
            CComPtr<_MailItem> m_spMailItem;
            CComPtr<IWebBrowser> m_spWebBrowser;
    };
    
  4. Erstellen Sie eine C++-Datei (CPP) mit dem Namen FormRegionWrapper.cpp, und fügen Sie dieser den folgenden Code hinzu.

    #include "stdafx.h"
    #include "FormRegionWrapper.h"
    using namespace ATL;
    
    #define ReturnOnFailureHr(h) { hr = (h); ATLASSERT(SUCCEEDED((hr))); if (FAILED(hr)) return hr; }
    
    // Macro that calls a COM method that returns an HRESULT value.
    #define CHK_HR(stmt)        do { hr=(stmt); if (FAILED(hr)) ; } while(0)
    // Macro to verify memory allocation.
    #define CHK_ALLOC(p)        do { if (!(p)) { hr = E_OUTOFMEMORY; ; } } while(0)
    // Macro that releases a COM object if not NULL.
    #define SAFE_RELEASE(p)     do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0)
    /*!-----------------------------------------------------------------------
    FormRegionWrapper implementation
    -----------------------------------------------------------------------!*/
    _ATL_FUNC_INFO FormRegionWrapper::VoidFuncInfo = {CC_STDCALL, VT_EMPTY, 0, 0}; 
    
    HRESULT FormRegionWrapper::HrInit(_FormRegion* pFormRegion)
    {
        HRESULT hr = S_OK;
        m_spFormRegion = pFormRegion;
        FormRegionEventSink::DispEventAdvise(m_spFormRegion);
        CComPtr<IDispatch> spDispatch;
        ReturnOnFailureHr(pFormRegion->get_Form(&spDispatch));
        CComPtr<Forms::_UserForm> spForm;
        ReturnOnFailureHr(spDispatch->QueryInterface(&spForm));
        CComPtr<Forms::Controls> spControls;
        ReturnOnFailureHr(spForm->get_Controls(&spControls));
        CComPtr<Forms::IControl> spControl;
        CComBSTR bstrWBName(L"_webBrowser");
        spControls->_GetItemByName(bstrWBName.Detach(),&spControl);
        ReturnOnFailureHr(spControl->QueryInterface<IWebBrowser>
            (&m_spWebBrowser));
        spControl.Release();
        CComPtr<IDispatch> spDispItem;
        ReturnOnFailureHr(pFormRegion->get_Item(&spDispItem));
        ReturnOnFailureHr(spDispItem->QueryInterface(&m_spMailItem));
        return hr;
    }
    
    void FormRegionWrapper::Show()
    {
        if(m_spFormRegion)
        {
            m_spFormRegion->Select();
        }
    }
    
    void FormRegionWrapper::SearchSelection()
    {
        if (m_spMailItem)
        {
            CComPtr<_Inspector> pInspector;
            m_spMailItem->get_GetInspector(&pInspector);
            CComPtr<IDispatch> pWordDispatch;
            pInspector->get_WordEditor(&pWordDispatch);
            CComQIPtr<Word::_Document> pWordDoc(pWordDispatch);
            CComPtr<Word::_Application> pWordApp;
            pWordDoc->get_Application(&pWordApp);
            CComPtr<Word::Selection> pSelection;
            pWordApp->get_Selection(&pSelection);
            if(pSelection)
            {
                CComBSTR text;
                pSelection->get_Text(&text);
                Search(text);
            }
        }
    }
    
    void FormRegionWrapper::Search(BSTR term)
    {
        if(m_spWebBrowser)
        {
            CComBSTR html("<html><body><H1>You searched for:");
            html.AppendBSTR(term);
            html.Append("</H1></body></html>");
            CComPtr<IDispatch> docDispatch;
            m_spWebBrowser->get_Document(&docDispatch);
            if(docDispatch==NULL)
            {
                VARIANT vDummy;
                vDummy.vt=VT_EMPTY;
                m_spWebBrowser->Navigate
                    (L"about:blank",&vDummy,&vDummy,&vDummy,&vDummy);
                m_spWebBrowser->get_Document(&docDispatch);
            }
            if(docDispatch!=NULL)
            {
                CComPtr<IHTMLDocument2> doc;
                HRESULT hr = 
                    docDispatch.QueryInterface<IHTMLDocument2>(&doc);
                if(hr==S_OK)
                {
                    SAFEARRAY *psaStrings = 
                        SafeArrayCreateVector(VT_VARIANT, 0, 1);
                    VARIANT *param;
                    HRESULT hr = 
                        SafeArrayAccessData(psaStrings, (LPVOID*)&param);
                    param->vt = VT_BSTR;
                    param->bstrVal = html.Detach();
                    hr = SafeArrayUnaccessData(psaStrings);
                    doc->write(psaStrings);
                    SafeArrayDestroy(psaStrings);
                }
            }
        }
    }
    
    void FormRegionWrapper::OnFormRegionClose()
    {
        if (m_spMailItem)
        {
            m_spMailItem.Release();
        }
        if (m_spFormRegion)
        {
            FormRegionEventSink::DispEventUnadvise(m_spFormRegion);
            m_spFormRegion.Release();
        }
    }
    

    Hinweis

    Zur Vereinfachung sind in dieser Datei mehrere Klassen enthalten; in einer echten Anwendung würden Sie jedoch jede Klasse in einer eigenen Datei platzieren.

  5. Fügen Sie der Headerdatei Connect.h eine #include-Anweisung für FormRegionWrapper.h hinzu.

  6. Ändern Sie die ButtonClicked-Rückrufmethode, um die SearchSelection-Methode der FormRegion-Membervariablen (m_pFormRegion) aufzurufen, indem Sie den folgenden Code hinzufügen.

    STDMETHOD(ButtonClicked)(IDispatch* ribbon)
    {
        if(m_pFormRegionWrapper)
        {
            m_pFormRegionWrapper->SearchSelection();
        }
        return S_OK;
    }
    

Sie haben die XML für Outlook erstellt, um den Formularbereich anzuzeigen, und den Code, über den der Formularbereich ausgeführt werden soll. Nun erstellen Sie den Formularbereich selbst.

Schritt 5: Erstellen des Formularbereichs und Hinzufügen eines Steuerelements in Outlook

  1. Aktivieren Sie in Outlook die Registerkarte Entwickler im Menüband. Klicken Sie nacheinander auf die Registerkarte Datei, auf Optionen und auf Menüband anpassen. Aktivieren Sie unter Menüband anpassen das Kontrollkästchen Entwickler, um die Registerkarte Entwickler zu aktivieren, und klicken Sie dann auf OK.

  2. Wenn Sie die Registerkarte Entwickler aktiviert haben, öffnen Sie diese, und klicken Sie auf die Schaltfläche Ein Formular entwerfen.

  3. Wählen Sie das Formular Nachricht aus, und klicken Sie dann auf Öffnen.

    Welches Formular Sie im Dialogfeld Formular entwerfen auswählen, spielt in diesem Fall keine Rolle, da Sie letztendlich den Formularbereich aus diesem Dialogfeld exportieren.

  4. Wenn der Formular-Designer angezeigt wird, klicken Sie auf die Schaltfläche Neuer Formularbereich. Damit wird ein neuer Formularbereich erstellt und im Vordergrund des Formular-Designers angezeigt.

  5. Klicken Sie auf die Schaltfläche Steuerelement-Toolbox, damit die Steuerelemente angezeigt werden, die Sie dem Formular hinzufügen können.

  6. Fügen Sie ein benutzerdefiniertes Steuerelement hinzu. Klicken Sie in der Toolbox mit der rechten Maustaste auf eine beliebige Stelle auf der Registerkarte Steuerelemente, und klicken Sie dann auf Benutzerdefinierte Steuerelemente. Wählen Sie unter Verfügbare Steuerelemente die Option Microsoft Webbrowser aus, und klicken Sie dann auf OK.

    Das WebBrowser-Steuerelement eignet sich gut für diesen Fall, da es leicht möglich ist, eine Liste mit Bing-Suchergebnissen in diesem Steuerelement anzuzeigen. Sie können auch Hyperlinks in das Steuerelement einfügen; Outlook-Endbenutzer können auf einen Link im Steuerelement klicken und so zur entsprechenden Seite im Browser gelangen.

  7. Fügen Sie das -WebBrowser-Steuerelement dem Formular hinzu, indem Sie das Steuerelement aus der Toolbox in den Formularbereich ziehen. Passen Sie die Größe des Steuerelements so an, dass dieses die gesamte Fläche des Formularbereichs belegt.

  8. Ändern Sie den Namen des hinzugefügten Steuerelements in _webBrowser. Klicken Sie hierzu mit der rechten Maustaste auf das Steuerelement, und klicken Sie dann auf Eigenschaften. Die präzise Benennung des Steuerelements ist wichtig, da der Code in der FormRegionWrapper-Klasse die Steuerelemente nach Namen abruft (bei denen es sich einfach um Zeichenfolgen handelt).

  9. Wechseln Sie aus ästhetischen Gründen zur Registerkarte Layout der Eigenschaften des WebBrowser-Steuerelements, und legen Sie die Eigenschaften Horizontal und Vertikal auf Mit Formular vergrößern/verkleinern fest. Das Formular sollte ungefähr so wie in Abbildung 6 aussehen.

    Abbildung 6. Formularbereich mit hinzugefügtem Steuerelement

    Formularbereich mit hinzugefügtem Steuerelement

  10. Speichern Sie den Formularbereich als OFS-Datei. (Beim OFS-Dateiformat handelt es sich um eine binäre Datei, die von Outlook für Formularbereiche verwendet wird.) Klicken Sie hierzu auf die Schaltfläche Bereich speichern und dann aufFormularbereich speichern unter. Geben Sie den Dateinamen WebBrowser.ofs an, und speichern Sie die Datei im Projektverzeichnis für NativeAddIn.

Schritt 6: Verbinden des Formularbereichs mit "NativeAddIn"

  1. Gehen Sie zurück zu Visual Studio 2010, und erweitern Sie den Knoten NativeAddIn in der Ressourcenansicht. Klicken Sie mit der rechten Maustaste auf den Knoten NativeAddIn.rc, und klicken Sie dann auf Ressource hinzufügen.

  2. Klicken Sie im Dialogfeld Ressource hinzufügenImportieren.

  3. Ändern Sie den Dateityp rechts unten im Dialogfeld in Alle Dateien, wählen Sie in der Dateiliste die Datei WebBrowser.ofs aus, und klicken Sie dann auf Öffnen.

  4. Geben Sie dem Ressourcentyp den Namen OFS, und klicken Sie dann auf OK.

Wenn die _FormRegionStartup::GetFormRegionStorage-Methode in der Datei Connect.h aufgerufen wird, werden die Daten in der OFS-Datei an Outlook zurückgegeben. Bevor Sie das Add-In erstellen und testen, müssen Sie der Datei Connect.rgs weitere Einträge hinzufügen. Außerdem müssen Sie den Formularbereich in der Windows-Registrierung registrieren.

Schritt 7: Hinzufügen von Einträgen zur Registrierung

Fügen Sie in die Datei Connect.rgs den folgenden Code ein.

HKCU
{
    NoRemove Software
    {
        NoRemove Microsoft
        {
            NoRemove Office
            {
                NoRemove Outlook
                {
                    NoRemove Addins
                    {
                        NativeAddin.Connect
                        {
                            val Description = s 'Sample Addin'
                            val FriendlyName = s 'Sample Addin'
                            val LoadBehavior = d 3
                        }
                    }
                    NoRemove FormRegions
                    {
                        IPM.Note
                        {
                            val TestNativeCOMAddin = s '=NativeAddin.Connect'
                        }
                        IPM.Note.NativeAddin
                        {
                            val TestNativeCOMAddin = s '=NativeAddin.Connect'
                        }
                    }
                }
            }
        }
    }
}

Schritt 8: Erstellen und Testen des Add-Ins

  1. Erstellen Sie das Projekt.

  2. Öffnen Sie Outlook, und erstellen Sie eine neue E-Mail-Nachricht.

  3. Am Ende des Formulars für E-Mail-Nachrichten sollte der von Ihnen erstellte Formularbereich angezeigt werden. Markieren Sie Text in der Nachricht, und klicken Sie dann auf die Schaltfläche Bing durchsuchen. Das WebBrowser-Steuerelement sollte geändert werden, und der Suchbegriff sollte angezeigt werden (siehe Abbildung 7).

    Abbildung 7. Benutzerdefiniertes Menüband mit angezeigtem Formularbereich

    Benutzerdefiniertes Menüband mit angezeigtem Formularbereich

Hinzufügen der Bing-Suchfunktionen

Sie haben jetzt erfahren, wie Sie ein nicht verwaltetes Outlook-Add-In in C++ erstellen. Wenn Sie die Infrastruktur eingerichtet haben, können Sie spezifische Funktionen erstellen, die auf dieser Infrastruktur aufbauen.

Sie haben jetzt ein funktionsfähiges Outlook-Add-In, möchten aber möglicherweise weitere Funktionen hinzufügen. Dies ist im Hinblick auf das Erstellen nicht verwalteter Add-Ins für Outlook nicht Gegenstand dieses Artikels, eignet sich jedoch gut zum Veranschaulichen der produktübergreifenden Funktionalität. Bei Bedarf können Sie die folgenden Verfahren verwenden, um eine Bing-Suche einzuschließen, die auf in der E-Mail-Nachricht markierten Begriffen basiert.

Hinweis

Sie müssen sich im Bing Developer Center für eine Anwendungskennung anmelden, damit Sie diese Funktionalität hinzufügen können.

So fügen Sie Bing-Suchfunktionen hinzu

  1. Ersetzen Sie den Code in der Datei FormsRegionWrapper.cpp durch den folgenden Code:

    #include "stdafx.h"
    #include "FormRegionWrapper.h"
    using namespace  ATL;
    
    #define ReturnOnFailureHr(h) { hr = (h); ATLASSERT(SUCCEEDED((hr))); if (FAILED(hr)) return hr; }
    
    // Macro that calls a COM method that returns an HRESULT value.
    #define CHK_HR(stmt)        do { hr=(stmt); if (FAILED(hr)) ; } while(0)
    
    // Macro to verify memory allocation.
    #define CHK_ALLOC(p)        do { if (!(p)) { hr = E_OUTOFMEMORY; ; } } while(0)
    
    // Macro that releases a COM object if not NULL.
    #define SAFE_RELEASE(p)     do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0)
    class AutoVariant : public VARIANT
    {
    public:
    
        AutoVariant()
        {
            VariantInit(this);
        }
    
        ~AutoVariant()
        {
            VariantClear(this);
        }
    
        HRESULT SetBSTRValue(LPCWSTR sourceString)
        {
            VariantClear(this);
            V_VT(this) = VT_BSTR;
            V_BSTR(this) = SysAllocString(sourceString);
            if (!V_BSTR(this))
            {
                return E_OUTOFMEMORY;
            }        
            return S_OK;
        }
    
        void SetObjectValue(IUnknown *sourceObject)
        {
            VariantClear(this);
            V_VT(this) = VT_UNKNOWN;
            V_UNKNOWN(this) = sourceObject;
            if (V_UNKNOWN(this))
            {
                V_UNKNOWN(this)->AddRef();
            }
        }
    };
    
    class BingHttpRequest
    {
    public:
    
        BingHttpRequest(){}
    
        void Complete()
        {  
            HRESULT hr = CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); 
            m_buffer.Append(m_tempBuffer);
            loadDOM(m_buffer);
            CoUninitialize();
        }
    
        void DoRequestSync(LPWSTR request,IWebBrowser* pWebBrowser)
        {
            m_WebBrowser = pWebBrowser;
            DWORD err =0;
            DWORD dwSize = 0;
            DWORD dwDownloaded = 0;
            LPSTR pszOutBuffer;
            HINTERNET hSession = ::WinHttpOpen(0,
                WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                WINHTTP_NO_PROXY_NAME,
                WINHTTP_NO_PROXY_BYPASS,
                0);
            HINTERNET hConnection  = ::WinHttpConnect(hSession,               
                L"api.bing.net",
                INTERNET_DEFAULT_PORT,
                0);
            CString lpstrRequest =  L"xml.aspx?Sources=
                web&AppID=70FA6D77B407BA830359D291DD4531800EA4DA38";
            lpstrRequest += L"&query=";
            lpstrRequest += request;
            HINTERNET hRequest = ::WinHttpOpenRequest(hConnection,
                L"GET",
                (lpstrRequest.GetString()),
                0, // use HTTP version 1.1
                WINHTTP_NO_REFERER,
                WINHTTP_DEFAULT_ACCEPT_TYPES,
                0); // flags
            if (!::WinHttpSendRequest(hRequest,
                WINHTTP_NO_ADDITIONAL_HEADERS,
                0, // headers length
                WINHTTP_NO_REQUEST_DATA,
                0, // request data length
                0, // total length
                (DWORD_PTR)this)) // context
            {
                err = GetLastError();
            }
            else
            { 
                bool result = WinHttpReceiveResponse( hRequest, NULL);
                do 
                {
                    // Check for available data.
                    dwSize = 0;
                    if (!WinHttpQueryDataAvailable( hRequest, &dwSize))
                        printf( "Error %u in WinHttpQueryDataAvailable.\n",
                            GetLastError());
                        // Allocate space for the buffer.
                        pszOutBuffer = new char[dwSize+1];
                    if (!pszOutBuffer)
                    {
                        printf("Out of memory\n");
                        dwSize=0;
                    }
                    else
                    {
                        // Read the Data.
                        ZeroMemory(pszOutBuffer, dwSize+1);
                        if (!WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, 
                            dwSize, &dwDownloaded))
                            printf("Error %u in WinHttpReadData.\n", 
                                GetLastError());
                        else
                        {
                            m_buffer.Append(pszOutBuffer);
                            printf("%s", pszOutBuffer);
                        }          
                        // Free the memory allocated to the buffer.
                        delete [] pszOutBuffer;
                    }
                } while (dwSize > 0);
                OutputDebugStringW(m_buffer);
                loadDOM(m_buffer);
            }
            WinHttpCloseHandle(hSession);
        }
    
        CComPtr<IWebBrowser> m_WebBrowser;
    
        HRESULT VariantFromString(PCWSTR wszValue, VARIANT &Variant)
        {
            HRESULT hr = S_OK;
            BSTR bstr = SysAllocString(wszValue);
            CHK_ALLOC(bstr);    
            V_VT(&Variant) = VT_BSTR;
            V_BSTR(&Variant) = bstr;
            return hr;
        }
    
        // Helper function to create a DOM instance. 
        HRESULT CreateAndInitDOM(IXMLDOMDocument2 **ppDoc)
        {
            HRESULT hr = CoCreateInstance(CLSID_DOMDocument, 
                NULL,     
                CLSCTX_INPROC_SERVER,  
                IID_IXMLDOMDocument2,
                (void**)ppDoc);
    
            return hr;
        }
    
        void loadDOM(BSTR xml)
        {
            OutputDebugStringW(xml);
            HRESULT hr = S_OK;
            IXMLDOMDocument2 *pXMLDom=NULL;
            IXMLDOMParseError *pXMLErr = NULL;
            BSTR bstrXML = NULL;
            BSTR bstrErr = NULL;
            VARIANT_BOOL varStatus;
            WCHAR ns[]= L"'xmlns:web=
                'https://schemas.microsoft.com/LiveSearch/2008/04/XML/web' " 
                L"'xmlns:search=
                'https://schemas.microsoft.com/LiveSearch/2008/04/XML/element' ";
            AutoVariant v;
            v.SetBSTRValue(L"xmlns:search=\
                "https://schemas.microsoft.com/LiveSearch/2008/04/XML/element\"
                ");
            CHK_HR(CreateAndInitDOM(&pXMLDom));    
            CHK_HR(pXMLDom->loadXML(xml, &varStatus));
            if (varStatus == VARIANT_TRUE)
            {
                CHK_HR(pXMLDom->get_xml(&bstrXML));
            }
            else
            {
                CHK_HR(pXMLDom->get_parseError(&pXMLErr));
                CHK_HR(pXMLErr->get_reason(&bstrErr));
                printf("Failed to load DOM from BING. %S\n", bstrErr);
            }
            CComPtr<IXMLDOMNodeList> resultNodes;
            pXMLDom->setProperty (L"SelectionNamespaces", 
            CComVariant(L"xmlns:search=\
                "https://schemas.microsoft.com/LiveSearch/2008/04/XML/element\"
                xmlns:web=\
                "https://schemas.microsoft.com/LiveSearch/2008/04/XML/web\""));
            pXMLDom->setProperty(L"SelectionLanguage", CComVariant("XPath"));
            CComPtr<IXMLDOMElement> doc;
            CHK_HR(pXMLDom->get_documentElement(&doc));
            hr =  doc->selectNodes(CComBSTR(L
                "//search:SearchResponse/web:Web/web:Results/web:WebResult"),
                &resultNodes);
            long length;
            if(resultNodes!=NULL)
            {
                resultNodes->get_length(&length);
                printf("Results node count %d",length);
                if(m_WebBrowser)
                {
                    CComBSTR html("<html><body><ul>");
                    CComPtr<IXMLDOMNode> pNode;
                    CComPtr<IXMLDOMNode> pTitleNode;
                    CComPtr<IXMLDOMNode> pUrlNode;
                    CComBSTR title;
                    CComBSTR url;
                    for(int i=0;i<length;i++)
                    {
                        resultNodes->get_item(i,&pNode);
                        pNode->get_firstChild(&pTitleNode);
                        pNode->selectSingleNode(CComBSTR(L"web:Url"),&pUrlNode);
                        if(pTitleNode!=NULL&&pUrlNode!=NULL)
                        {
                            html.Append("<li><a target=\"_blank\" href=\"");
                            pUrlNode->get_text(&url);
                            html.AppendBSTR(url);
                            html.Append("\">");
                            pTitleNode->get_text(&title);
                            html.AppendBSTR(title);
                            html.Append("</a></li>");
                        }
                        pNode.Release();
                        pUrlNode.Release();
                        pTitleNode.Release();
                    }
                    CComPtr<IDispatch> docDispatch;
                    m_WebBrowser->get_Document(&docDispatch);
                    if(docDispatch==NULL)
                    {
                        VARIANT vDummy;
                        vDummy.vt=VT_EMPTY;
                        m_WebBrowser->Navigate(L"about:blank",
                            &vDummy,&vDummy,&vDummy,&vDummy);
                        m_WebBrowser->get_Document(&docDispatch);
                        if(docDispatch!=NULL)
                        {
                            CComPtr<IHTMLDocument2> doc;
                            hr = docDispatch.QueryInterface
                                <IHTMLDocument2>(&doc);
                            if(hr==S_OK)
                            {
                                // Creates a new one-dimensional array.
                                SAFEARRAY *psaStrings =
                                    SafeArrayCreateVector(VT_VARIANT, 0, 1);
                                VARIANT *param;
                                HRESULT hr = SafeArrayAccessData(psaStrings,
                                    (LPVOID*)&param);
                                param->vt = VT_BSTR;
                                param->bstrVal = html.Detach();
                                hr = SafeArrayUnaccessData(psaStrings);
                                doc->write(psaStrings);
                                SafeArrayDestroy(psaStrings);
                            }
                            else
                            {
                                OutputDebugString(L
                                    "QI for IHtmlDocument2 failed");
                            }
                        }
                        else
                            OutputDebugString(L"DOC IS STILL NULL!!!!");
                    }
                }
                else
                {
                    printf("No nodes found");
                }
            }
        }
    
        LPSTR m_tempBuffer;
        CComBSTR m_buffer;
    };
    
    /*!-----------------------------------------------------------------------
        FormRegionWrapper implementation
    -----------------------------------------------------------------------!*/
    
    _ATL_FUNC_INFO FormRegionWrapper::VoidFuncInfo = {CC_STDCALL, VT_EMPTY, 0, 0}; 
    
    HRESULT FormRegionWrapper::HrInit(_FormRegion* pFormRegion)
    {
        HRESULT hr = S_OK;
        m_spFormRegion = pFormRegion;
        FormRegionEventSink::DispEventAdvise(m_spFormRegion);
        CComPtr<IDispatch> spDispatch;
        ReturnOnFailureHr(pFormRegion->get_Form(&spDispatch));
        CComPtr<Forms::_UserForm> spForm;
        ReturnOnFailureHr(spDispatch->QueryInterface(&spForm));
        CComPtr<Forms::Controls> spControls;
        ReturnOnFailureHr(spForm->get_Controls(&spControls));
        CComPtr<Forms::IControl> spControl;
        CComBSTR bstrWBName(L"_webBrowser");
        spControls->_GetItemByName(bstrWBName.Detach(),&spControl);
        ReturnOnFailureHr(spControl->QueryInterface
            <IWebBrowser>(&m_spWebBrowser));
        spControl.Release();
        CComPtr<IDispatch> spDispItem;
        ReturnOnFailureHr(pFormRegion->get_Item(&spDispItem));
        ReturnOnFailureHr(spDispItem->QueryInterface(&m_spMailItem));
        return hr;
    }
    
    void FormRegionWrapper::Show()
    {
        if(m_spFormRegion)
        {
            m_spFormRegion->Select();
        }
    }
    
    void FormRegionWrapper::SearchSelection()
    {
        if (m_spMailItem)
        {
            CComPtr<_Inspector> pInspector;
            m_spMailItem->get_GetInspector(&pInspector);
            CComPtr<IDispatch> pWordDispatch;
            pInspector->get_WordEditor(&pWordDispatch);
            CComQIPtr<_Document> pWordDoc(pWordDispatch);
            CComPtr<Word::_Application> pWordApp;
            pWordDoc->get_Application(&pWordApp);
            CComPtr<Word::Selection> pSelection;
            pWordApp->get_Selection(&pSelection);
            if(pSelection)
            {
                CComBSTR text;
                pSelection->get_Text(&text);
                Search(text);
            }
        }
    }
    
    void FormRegionWrapper::Search(BSTR term)
    {
        BingHttpRequest* r = new BingHttpRequest();
        r->DoRequestSync(term,m_spWebBrowser);
    }
    
    void FormRegionWrapper::OnFormRegionClose()
    {
        if (m_spMailItem)
        {
            m_spMailItem.Release();
        }
        if (m_spFormRegion)
        {
            FormRegionEventSink::DispEventUnadvise(m_spFormRegion);
            m_spFormRegion.Release();
        }
    }
    
  2. Nun können Sie debuggen oder Outlook starten. Öffnen Sie eine neue E-Mail-Nachricht. Geben Sie Text ein, wählen Sie den Text aus, und klicken Sie dann auf die Schaltfläche Bing durchsuchen. Die Anzeige sollte ungefähr wie in Abbildung 8 aussehen.

    Abbildung 8. Add-In mit integrierter Bing-Suche

    Add-in mit integrierter Bing-Suche

Schlussbemerkung

Sie haben gesehen, wie Sie in C++ ein Outlook-Add-In erstellen können, mit dem die _IDTExtensibility2-Schnittstelle implementiert wird. _IDTExtensibility2 sowie die Outlook-spezifischen Registrierungseinträge sind wichtig, damit das Add-In in der Outlook-Umgebung geladen wird.

Außerdem haben Sie dem Add-In Funktionen zum Anpassen der Outlook-Benutzeroberfläche hinzugefügt, indem Sie zwei allgemeine Erweiterbarkeitsmechanismen verwendet haben: ein benutzerdefiniertes Menüband und einen Formularbereich. Mit einem benutzerdefinierten Menüband können Sie dem Menüband Benutzeroberflächenelemente wie beispielsweise eine Schaltfläche hinzufügen und zulassen, dass das Add-In auf kontextbasierte Benutzeroberflächenereignisse reagiert. Mit einem benutzerdefinierten Formularbereich können Sie Outlook-Formularen Benutzeroberflächenelemente wie beispielsweise ein WebBrowser-Steuerelement hinzufügen.

Sie verfügen nun über die Infrastruktur eines Add-Ins, mit dem die Outlook-Benutzeroberfläche angepasst wird. Mit dieser Infrastruktur können Sie das Add-In weiter erweitern (beispielsweise indem Sie die Bing-Suchfunktionen verwenden), um dieses an Ihre Zwecke anzupassen.

Weitere Ressourcen

Weitere Informationen zu Outlook-Formularbereichen finden Sie in den folgenden Ressourcen:

Weitere Informationen zum Anpassen des Office Fluent-Menübands finden Sie in den folgenden Ressourcen: