Изоляция компонентов
Хорошо созданные компоненты не оказывают влияния на среду приложения, и не допускают утечки контекстов активации. Хорошо созданные компоненты выполняют собственное управление контекстом, а не зависят от среды приложения размещения.
Автор размещенного компонента находится в лучшем положении, чтобы точно знать, какие другие сборки требует компонент. Использование ведущего приложения для предоставления правильной среды для размещенного компонента является вероятным источником ошибок. Вместо этого создайте манифест для размещенного компонента, указывающего все его зависимости, а затем скомпилируйте с помощью 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.
}