Изоляция компонентов

Хорошо созданные компоненты не могут влиять на среду размещенного приложения и не пропускают контексты активации. Хорошо созданные компоненты выполняют собственное управление контекстом, а не зависят от среды приложения размещения.

Автор размещенного компонента находится в лучшем положении, чтобы точно знать, какие другие сборки требуются компоненту. Использование ведущего приложения для обеспечения правильной среды для размещенного компонента является вероятным источником ошибок. Вместо этого создайте манифест для размещенного компонента, который указывает все его зависимости, а затем выполните компиляцию с помощью ISOLATION_AWARE_ENABLED. Это гарантирует, что внешние вызовы, выполняемые вашим компонентом, будут изолированы и используют правильные версии. Так как контекст активации, используемый ISOLATION_AWARE_ENABLED, предназначен для каждой библиотеки DLL, его можно безопасно использовать в нескольких библиотеках DLL, каждый из которых имеет собственный манифест, вызывающий зависимости.

Если компиляция с помощью ISOLATION_AWARE_ENABLED невозможна, используйте решение, аналогичное тому, которое представлено в разделе Использование обратных вызовов из размещенных компонентов.

Необходимо активировать собственный контекст активации во всех точках входа, которые может вызывать приложение размещения, чтобы обеспечить полностьюе выполнение размещенного компонента с правильным контекстом активации. Вспомогательный объект C++ можно использовать для упрощения изменения всех точек входа. Например, можно использовать класс C++, такой как:

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

Затем его можно использовать в компоненте с помощью глобальной переменной для хранения контекста активации, который должен быть активирован в каждой точке входа. Таким образом можно изолировать компонент от размещаемого приложения.

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