隔离组件
编写良好的组件不会干扰托管应用程序的环境,也不会泄漏激活上下文。 编写良好的组件执行其自己的上下文管理,而不是依赖于托管应用程序的环境。
托管组件的作者处于最佳位置,确切地知道组件需要哪些其他程序集。 依赖主机应用程序为托管组件提供正确的环境可能是错误的源头。 相反,请为托管组件创建一个清单,该清单指定其所有依赖项,然后使用ISOLATION_AWARE_ENABLED进行编译。 这可确保将组件进行的外部调用隔离,并使用正确的版本。 由于ISOLATION_AWARE_ENABLED使用的激活上下文是每个 DLL,因此可以安全地在多个 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.
}