テクニカル ノート 64: ActiveX コントロールにおけるアパートメント モデルのスレッド処理
Note
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。 結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。 最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
このテクニカル ノートでは、ActiveX コントロールでアパートメント モデルのスレッド処理を有効にする方法について説明します。 アパートメント モデルのスレッド処理は、Visual C++ バージョン 4.2 以降でのみサポートされていることに注意してください。
アパートメント モデルのスレッド化とは
アパートメント モデルは、マルチスレッドのコンテナー アプリケーション内で ActiveX コントロールなどの埋め込みオブジェクトをサポートするためのアプローチです。 アプリケーションには複数のスレッドが存在する場合がありますが、埋め込みオブジェクトの各インスタンスは 1 つの "アパートメント" に割り当てられ、1 つのスレッドでのみ実行されます。 つまり、コントロールのインスタンスへのすべての呼び出しは、同じスレッド上で行われます。
ただし、同じ種類のコントロールの異なるインスタンスを異なるアパートメントに割り当てることができます。 したがって、コントロールの複数のインスタンスが共通のデータ (たとえば、静的データまたはグローバルデータ) を共有している場合、この共有データへのアクセスは、クリティカル セクションなどの同期オブジェクトによって保護される必要があります。
アパートメントスレッドモデルの詳細については、「OLE プログラマーリファレンス」の「プロセスとスレッド」を参照してください。
アパートメント モデルのスレッド処理をサポートする理由
アパートメント モデルのスレッド処理をサポートするコントロールは、アパートメント モデルもサポートするマルチスレッドのコンテナー アプリケーションで使用できます。 アパートメント モデルのスレッド処理を有効にしない場合は、コントロールを使用できるコンテナーの可能性のあるセットを制限します。
ほとんどのコントロールでは、特に共有データがほとんどまたはまったくない場合は、アパートメントモデルのスレッド処理を簡単に有効にすることができます。
共有データの保護
コントロールで静的メンバー変数などの共有データを使用する場合、複数のスレッドが同時にデータを変更できないようにするには、そのデータへのアクセスがクリティカル セクションで保護されている必要があります。 この目的のためにクリティカルセクションを設定するには、コントロールのクラスでクラス CCriticalSection
の静的メンバー変数を宣言します。 コードが共有データにアクセスするすべての場所で、このクリティカルセクション オブジェクトの Lock
および Unlock
メンバー関数を使用します。
たとえば、すべてのインスタンスで共有される文字列を保持する必要があるコントロール クラスを考えてみます。 この文字列は、静的メンバー変数に保持し、クリティカル セクションによって保護することができます。 コントロールのクラス宣言には、次のものが含まれます:
class CSampleCtrl : public COleControl
{
...
static CString _strShared;
static CCriticalSection _critSect;
};
クラスの実装には、次の変数の定義が含まれます:
int CString CSampleCtrl::_strShared;
CCriticalSection CSampleCtrl::_critSect;
_strShared
静的メンバーへのアクセスは、クリティカルセクションで保護できます:
void CSampleCtrl::SomeMethod()
{
_critSect.Lock();
if (_strShared.Empty())
_strShared = "<text>";
_critSect.Unlock();
...
}
アパートメントモデルに対応したコントロールの登録
アパートメントモデルのスレッド処理をサポートするコントロールは、class id\InprocServer32キーの下にあるクラス ID レジストリエントリに "アパートメント" という値を持つ名前付きの値 "ThreadingModel" を追加することによって、この機能をレジストリで示す必要があります。 このキーがコントロールに自動的に登録されるようにするには、6番目のパラメーターの afxRegApartmentThreading フラグを AfxOleRegisterControlClass
に渡します。
BOOL CSampleCtrl::CSampleCtrlFactory::UpdateRegistry(BOOL bRegister)
{
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_SAMPLE,
IDB_SAMPLE,
afxRegApartmentThreading,
_dwSampleOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid,
m_lpszProgID);
}
コントロール プロジェクトが Visual C++ バージョン 4.1 以降の ControlWizard で生成された場合、このフラグは既にコード内に存在しています。 スレッド モデルを登録するために変更は必要ありません。
以前のバージョンの ControlWizard によってプロジェクトが生成された場合、既存のコードには 6 番目のパラメーターとしてブール値が設定されます。 既存のパラメーターが TRUE の場合は、afxRegInsertable | afxRegApartmentThreading に変更します。 既存のパラメーターが FALSE の場合は、afxRegApartmentThreading に変更します。
コントロールがアパートメント モデルのスレッド処理の規則に従っていない場合は、このパラメーターで afxRegApartmentThreading を渡さないようにする必要があります。