Condividi tramite


Isolamento dei componenti

I componenti ben creati non perturbiscono l'ambiente dell'applicazione di hosting, né perdono contesti di attivazione. I componenti ben creati eseguono la propria gestione del contesto anziché basarsi sull'ambiente dell'applicazione host.

L'autore del componente ospitato è nella posizione migliore per sapere esattamente quali altri assembly richiedono il componente. Basarsi sull'applicazione host per fornire l'ambiente corretto per il componente ospitato è una probabile origine di errori. Creare invece un manifesto per il componente ospitato che specifica tutte le relative dipendenze e quindi compilarlo usando ISOLATION_AWARE_ENABLED. Ciò garantisce che le chiamate esterne effettuate dal componente siano isolate e usino le versioni corrette. Poiché il contesto di attivazione usato da ISOLATION_AWARE_ENABLED è per DLL, è possibile usarlo in più DLL, ognuna con il proprio manifesto che chiama le dipendenze.

Se non è possibile eseguire la compilazione con ISOLATION_AWARE_ENABLED, usare una soluzione come quella presentata in Uso di callback da componenti ospitati.

È consigliabile attivare il proprio contesto di attivazione in tutti i punti di ingresso che l'applicazione host può chiamare per garantire che il componente ospitato venga eseguito interamente con il contesto di attivazione corretto. È possibile usare un oggetto helper C++ per facilitare la modifica di tutti i punti di ingresso. Ad esempio, è possibile usare una classe C++, ad esempio:

#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;
        }
    }
};

Può quindi essere usato nel componente, usando una variabile globale per archiviare il contesto di attivazione che deve essere attivato in ogni punto di ingresso. In questo modo, è possibile isolare il componente dall'applicazione di hosting.

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.
}