TN064:在 ActiveX 控件的单元模型线程处理
备注
以下技术声明,则它在联机文档,首先包括了不更新。因此,某些过程和主题可能已过时或不正确。有关最新信息,建议您搜索议题在联机文档的索引。
此方法声明解释如何在 Activex 控件的单元模型线程处理。 请注意单元模型线程处理在 Visual C++ 4.2 版或更高版本只支持。
什么是单元模型线程处理?
单元模型是路由到支持嵌入对象,如 Activex 控件,在一个多线程的容器应用程序中。 尽管应用程序可以有多个线程,一个嵌入对象的每个实例将分配给一个 “单元,”在一个线程只将要执行的操作。 换言之,所有在同一线程调用该控件的实例将发生。
但是,该相同类型的控件的不同实例可以分配给不同的单元。 对此共享数据的,因此,如果控件的多个实例共享任何数据共同的 (例如,静态或全局数据),然后访问需要由同步对象保护,如临界区。
有关单元 (sta) 线程模型的全部详细信息,请参见 OLE 程序员参考 中的 进程和线程。
在支持单元模型线程处理?
支持单元模型线程的控件可用于还支持单元模型的多线程的容器应用程序。 如果未启用单元模型线程处理,您将限制潜在您的控件可以使用的设置容器。
特别是,如果它们具有极少代码或甚至不共享数据,启用单元模型线程处理对于大多数控件非常容易。
保护共享数据
如果控件使用共享数据,如静态成员变量,因为访问应保护数据。临界区阻止多个线程同时修改数据。 因此若要设置临界区,声明类 CCriticalSection 的静态成员变量在控件的类。 使用此临界区对象的 Lock 和 解锁 成员函数,无论在何处的代码访问共享数据。
考虑,例如,需要维护字符串由所有实例共享的控件类。 此字符串在变量静态的成员可以维护和由临界区来保护。 控件的类声明将包含以下内容:
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();
...
}
注册一个单元模型识别控件
支持单元模型线程的控件应通过添加命名值指示在注册表中此功能, “ThreadingModel”与 “单元的”值的类 ID 注册表项在 类 ID\InprocServer32 项下。 若要使此密钥将自动注册您的控件,则通过在第六个参数的 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 的早期版本生成,则现有代码将具有布尔值作为第六个参数。 如果为现有参数为 true,将其更改为afxRegInsertable | afxRegApartmentThreading。 如果为现有参数是错误的,将其更改为afxRegApartmentThreading。
如果控件不遵循单元模型线程处理的规则,则不能通过此参数的 afxRegApartmentThreading 。