Sdílet prostřednictvím


Izolování komponent

Dobře vytvořené komponenty nenarušují prostředí hostitelské aplikace ani neunikají informace o kontextu aktivace. Dobře vytvořené komponenty provádějí vlastní správu kontextu místo toho, aby se spoléhaly na prostředí hostitelské aplikace.

Autor hostované komponenty je v nejlepší pozici, abyste přesně věděli, která další sestavení komponenta vyžaduje. Spoléhat se na hostitelskou aplikaci, aby poskytla správné prostředí hostované komponenty, je pravděpodobně zdrojem chyb. Místo toho vytvořte manifest pro hostované komponenty, který určuje všechny jeho závislosti, a pak zkompilujte pomocí ISOLATION_AWARE_ENABLED. Tím se zajistí izolace vnějších volání provedených vaší komponentou a použití správných verzí. Vzhledem k tomu, že kontext aktivace, který ISOLATION_AWARE_ENABLED používá, je bezpečný k použití v několika knihovnách DLL, přičemž každá z nich má vlastní manifest, který vyjmenovává závislosti.

Pokud není možné zkompilovat s ISOLATION_AWARE_ENABLED, použijte řešení, jako to uvedené v Použití zpětného volání z hostovaných komponent.

Ve všech vstupních bodech, které hostitelské aplikace může volat, byste měli aktivovat svůj vlastní kontext aktivace, abyste zajistili, že hostovaná komponenta běží zcela se správným kontextem aktivace. Pomocí pomocného objektu jazyka C++ můžete usnadnit změnu všech vstupních bodů. Můžete například použít třídu C++, například:

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

To se pak dá použít ve vaší komponentě pomocí globální proměnné k uložení kontextu aktivace, který by se měl aktivovat v každém vstupním bodu. Tímto způsobem můžete izolovat komponentu od hostitelské aplikace.

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