Isolando componentes
Componentes bem criados não perturbam o ambiente do aplicativo de hospedagem nem vazam contextos de ativação. Os componentes bem criados executam seu próprio gerenciamento de contexto em vez de depender do ambiente do aplicativo de hospedagem.
O autor do componente hospedado está na melhor posição para saber exatamente quais outros assemblies o componente requer. Confiar no aplicativo host para fornecer o ambiente correto para o componente hospedado é uma provável fonte de erros. Em vez disso, crie um manifesto para o componente hospedado que especifica todas as dependências e compile usando ISOLATION_AWARE_ENABLED. Isso garante que as chamadas externas feitas pelo componente sejam isoladas e usem as versões corretas. Como o contexto de ativação que ISOLATION_AWARE_ENABLED usa é por DLL, é seguro usar em várias DLLs, cada uma com seu próprio manifesto chamando dependências.
Se não for possível compilar com ISOLATION_AWARE_ENABLED, use uma solução como a apresentada em Usando retornos de chamada de componentes hospedados.
Você deve ativar seu próprio contexto de ativação em todos os pontos de entrada que o aplicativo de hospedagem pode chamar para garantir que o componente hospedado seja executado inteiramente com o contexto de ativação correto. Você pode usar um objeto auxiliar C++ para facilitar a alteração de todos os pontos de entrada. Por exemplo, você pode usar uma classe C++, como a seguinte:
#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;
}
}
};
Em seguida, isso pode ser usado em seu componente, usando uma variável global para armazenar o contexto de ativação que deve ser ativado em cada ponto de entrada. Dessa forma, você pode isolar seu componente do aplicativo de hospedagem.
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.
}