Isolieren von Komponenten

Gut erstellte Komponenten beeinträchtigt weder die Umgebung der Hostinganwendung, noch werden Aktivierungskontexte durch sie verloren. Gut erstellte Komponenten führen ihre eigene Kontextverwaltung aus, anstatt sich auf die Umgebung der Hostinganwendung zu verlassen.

Der Autor der gehosteten Komponente ist in der besten Position, um genau zu wissen, welche anderen Assemblys die Komponente benötigt. Sich darauf zu verlassen, dass die Hostanwendung die richtige Umgebung für Ihre gehostete Komponente bereitstellt, ist eine wahrscheinliche Fehlerquelle. Erstellen Sie stattdessen ein Manifest für Ihre gehostete Komponente, das alle zugehörigen Abhängigkeiten angibt, und kompilieren Sie dann mit ISOLATION_AWARE_ENABLED. Dadurch wird sichergestellt, dass externe Aufrufe Ihrer Komponente isoliert werden und die richtigen Versionen verwenden. Da der Aktivierungskontext, den ISOLATION_AWARE_ENABLED verwendet, pro DLL ist, kann er sicher in mehreren DLLs verwendet werden, von denen jede ihr eigenes Manifest aufweist, das Abhängigkeiten aufruft.

Wenn es nicht möglich ist, mit ISOLATION_AWARE_ENABLED zu kompilieren, verwenden Sie eine Lösung wie die unter Verwenden von Rückrufen aus gehosteten Komponenten dargestellte Lösung.

Sie sollten Ihren eigenen Aktivierungskontext in allen Einstiegspunkten aktivieren, die die Hostinganwendung aufrufen kann, um sicherzustellen, dass Ihre gehostete Komponente vollständig mit dem richtigen Aktivierungskontext ausgeführt wird. Sie können ein C++-Hilfsobjekt verwenden, um das Ändern aller Einstiegspunkte zu erleichtern. Sie können beispielsweise eine C++-Klasse wie die folgende verwenden:

#include <windows.h>

class CActivationContext 
{
    HANDLE m_hActivationContext;

public:
    CActivationContext() : m_hActivationContext(INVALID_HANDLE_VALUE) 
    {
    }

    VOID Set(HANDLE hActCtx) 
    {
        if (hActCtx != INVALID_HANDLE_VALUE)
            AddRefActCtx(hActCtx);

        if (m_hActivationContext != INVALID_HANDLE_VALUE)
            ReleaseActCtx(m_hActivationContext);
        m_hActivationContext = hActCtx;
    }

    ~CActivationContext() 
    {
        if (m_hActivationContext != INVALID_HANDLE_VALUE)
            ReleaseActCtx(m_hActivationContext);
    }

    BOOL Activate(ULONG_PTR &ulpCookie) 
    {
        return ActivateActCtx(m_hActivationContext, &ulpCookie);
    }

    BOOL Deactivate(ULONG_PTR ulpCookie) 
    {
        return DeactivateActCtx(0, ulpCookie);
    }
};

class CActCtxActivator 
{
    CActivationContext &m_ActCtx;
    ULONG_PTR m_Cookie;
    bool m_fActivated;

public:
    CActCtxActivator(CActivationContext& src, bool fActivate = true) 
        : m_ActCtx(src), m_Cookie(0), m_fActivated(false) 
    {
        if (fActivate) {
            if (src.Activate(m_Cookie))
                m_fActivated = true;
        }
    }

    ~CActCtxActivator() 
    {
        if (m_fActivated) {
            m_ActCtx.Deactivate(m_Cookie);
            m_fActivated = false;
        }
    }
};

Dies kann dann in Ihrer Komponente verwendet werden, indem Sie eine globale Variable verwenden, um den Aktivierungskontext zu speichern, der an jedem Einstiegspunkt aktiviert werden soll. Auf diese Weise können Sie Ihre Komponente von Ihrer Hostinganwendung isolieren.

CActivationContext s_GlobalContext;

void MyExportedEntrypoint(void) 
{
    CActCtxActivator ScopedContext(s_GlobalContext);
    // Do whatever work here
    // Destructor automatically deactivates the context
}

void MyInitializerFunction() 
{
    HANDLE hActCtx;
    ACTCTX actctx = {sizeof(actctx)};
    hActCtx = CreateActCtx(&actctx);
    s_GlobalContext.Set(hActCtx);
    ReleaseActCtx(hActCtx);
    // The static destructor for s_GlobalContext destroys the
    // activation context on component unload.
}