Isolamento dei componenti
I componenti ben creati non perturbiscono l'ambiente dell'applicazione di hosting, né perdono contesti di attivazione. I componenti ben creati eseguono la propria gestione del contesto anziché basarsi sull'ambiente dell'applicazione host.
L'autore del componente ospitato è nella posizione migliore per sapere esattamente quali altri assembly richiedono il componente. Basarsi sull'applicazione host per fornire l'ambiente corretto per il componente ospitato è una probabile origine di errori. Creare invece un manifesto per il componente ospitato che specifica tutte le relative dipendenze e quindi compilarlo usando ISOLATION_AWARE_ENABLED. Ciò garantisce che le chiamate esterne effettuate dal componente siano isolate e usino le versioni corrette. Poiché il contesto di attivazione usato da ISOLATION_AWARE_ENABLED è per DLL, è possibile usarlo in più DLL, ognuna con il proprio manifesto che chiama le dipendenze.
Se non è possibile eseguire la compilazione con ISOLATION_AWARE_ENABLED, usare una soluzione come quella presentata in Uso di callback da componenti ospitati.
È consigliabile attivare il proprio contesto di attivazione in tutti i punti di ingresso che l'applicazione host può chiamare per garantire che il componente ospitato venga eseguito interamente con il contesto di attivazione corretto. È possibile usare un oggetto helper C++ per facilitare la modifica di tutti i punti di ingresso. Ad esempio, è possibile usare una classe C++, ad esempio:
#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;
}
}
};
Può quindi essere usato nel componente, usando una variabile globale per archiviare il contesto di attivazione che deve essere attivato in ogni punto di ingresso. In questo modo, è possibile isolare il componente dall'applicazione di hosting.
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.
}