隔離元件

撰寫良好的元件不會干擾裝載應用程式的環境,也不會洩漏啟用內容。 撰寫良好的元件會執行自己的內容管理,而不是依賴裝載應用程式的環境。

裝載元件的作者最適合知道元件所需的其他元件。 依賴主應用程式來為您的託管元件提供正確的環境,可能是錯誤的來源。 相反地,請為裝載的元件建立資訊清單,以指定其所有相依性,然後使用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.
}