コンポーネントの分離

適切に作成されたコンポーネントは、ホスティング アプリケーションの環境を乱したり、アクティブ化コンテキストをリークしたりしません。 適切に作成されたコンポーネントは、ホスティング アプリケーションの環境に依存するのではなく、独自のコンテキスト管理を実行します。

ホストされるコンポーネントの作成者は、コンポーネントに必要な他のアセンブリを正確に把握するのに最適な位置にあります。 ホスト されたコンポーネントに適切な環境を提供するためにホスト アプリケーションに依存することは、おそらくエラーの原因です。 代わりに、すべての依存関係を指定するホストされたコンポーネントのマニフェストを作成し、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.
}