注
次のテクニカル ノートは、最初にオンライン ドキュメントに含まれてから更新されていません。 その結果、一部の手順やトピックが古くなっているか、正しくない可能性があります。 最新情報については、オンライン ドキュメント インデックスで関心のあるトピックを検索することをお勧めします。
このテクニカル ノートでは、ActiveX コントロールでアパートメント モデルスレッドを有効にする方法について説明します。 アパートメント モデルのスレッド処理は、Visual C++ バージョン 4.2 以降でのみサポートされることに注意してください。
「Apartment-Model スレッド」とは何ですか
アパートメント モデルは、マルチスレッド コンテナー アプリケーション内で ActiveX コントロールなどの埋め込みオブジェクトをサポートするためのアプローチです。 アプリケーションには複数のスレッドがある場合がありますが、埋め込みオブジェクトの各インスタンスは 1 つの "アパートメント" に割り当てられ、1 つのスレッドでのみ実行されます。 つまり、コントロールのインスタンスへのすべての呼び出しは、同じスレッドで行われます。
ただし、同じ種類のコントロールの異なるインスタンスを異なるアパートメントに割り当てることができます。 そのため、コントロールの複数のインスタンスが共通のデータ (静的データやグローバル データなど) を共有する場合、この共有データへのアクセスは、重要なセクションなどの同期オブジェクトによって保護される必要があります。
アパートメント スレッド モデルの詳細については、「OLE プログラマ リファレンス」の「プロセスとスレッド」を参照してください。
Apartment-Model スレッド処理をサポートする理由
アパートメント モデルのスレッド処理をサポートするコントロールは、アパートメント モデルもサポートするマルチスレッド コンテナー アプリケーションで使用できます。 アパートメント モデルのスレッド処理を有効にしない場合は、コントロールを使用できるコンテナーの潜在的なセットを制限します。
特に共有データがほとんどまたはまったくない場合は、ほとんどのコントロールでアパートメント モデルのスレッド処理を簡単に有効にできます。
共有データの保護
コントロールで静的メンバー変数などの共有データを使用する場合は、複数のスレッドが同時にデータを変更できないように、そのデータへのアクセスをクリティカル セクションで保護する必要があります。 この目的のためにクリティカル セクションを設定するには、コントロールのクラスでクラス 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();
...
}
アパートメントモデルに対応したコントロールの登録
アパートメント モデルのスレッド処理をサポートするコントロールは、クラス ID\InprocServer32 キーの下に、クラス ID レジストリ エントリに値 "Apartment" を持つ名前付き値 "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 を 渡してはなりません。