Udostępnij przez


Izolowanie składników

Dobrze utworzone składniki nie zakłócają środowiska aplikacji hostującej ani nie powodują wycieku kontekstów aktywacji. Dobrze utworzone składniki wykonują własne zarządzanie kontekstem, a nie polegają na środowisku aplikacji hostingu.

Autor hostowanego składnika jest w najlepszej sytuacji, aby dokładnie wiedzieć, które inne zespoły są wymagane przez składnik. Poleganie na aplikacji hosta w celu zapewnienia prawidłowego środowiska dla hostowanego składnika jest prawdopodobnym źródłem błędów. Zamiast tego utwórz manifest dla hostowanego składnika, który określa wszystkie jego zależności, a następnie skompiluj przy użyciu ISOLATION_AWARE_ENABLED. Dzięki temu zewnętrzne wywołania wykonywane przez składnik są izolowane i używają poprawnych wersji. Ponieważ kontekst aktywacji używany przez ISOLATION_AWARE_ENABLED jest powiązany z każdą biblioteką DLL, można go bezpiecznie używać w wielu bibliotekach DLL, z których każda ma własny manifest określający zależności.

Jeśli nie można skompilować z ISOLATION_AWARE_ENABLED, należy użyć rozwiązania takiego jak to przedstawione w Korzystanie z wywołań zwrotnych z hostowanych komponentów.

Należy aktywować własny kontekst aktywacji we wszystkich punktach wejścia, które aplikacja hostingowa może wywołać, aby upewnić się, że hostowany składnik działa całkowicie z prawidłowym kontekstem aktywacji. Możesz użyć obiektu pomocniczego języka C++, aby ułatwić zmianę wszystkich punktów wejścia. Można na przykład użyć klasy C++, takiej jak:

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

Można go następnie użyć w składniku, używając zmiennej globalnej do przechowywania kontekstu aktywacji, który powinien zostać aktywowany w każdym punkcie wejścia. W ten sposób można odizolować składnik od aplikacji hostingowej.

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