TN064: modelo Apartment Threading em controles ActiveX

Observação

A nota técnica a seguir não foi atualizada desde que foi incluída pela primeira vez na documentação online. Como resultado, alguns procedimentos e tópicos podem estar desatualizados ou incorretos. Para obter as informações mais recentes, é recomendável que você pesquise o tópico de interesse no índice de documentação online.

Esta nota técnica explica como habilitar o threading de modelo de apartamento em um controle ActiveX. Observe que o threading de modelo de apartamento só tem suporte nas versões 4.2 ou posteriores do Visual C++.

O que é o threading de modelo de apartamento?

O modelo de apartamento é uma abordagem para dar suporte a objetos inseridos, como controles ActiveX, em um aplicativo de contêiner com multithread. Embora o aplicativo possa ter vários threads, cada instância de um objeto inserido será atribuída a um "apartamento", que será executado em apenas um thread. Em outras palavras, todas as chamadas em uma instância de um controle ocorrerão no mesmo thread.

No entanto, diferentes instâncias do mesmo tipo de controle podem ser atribuídas a apartamentos diferentes. Portanto, se várias instâncias de um controle compartilharem dados em comum (por exemplo, dados estáticos ou globais), o acesso a esses dados compartilhados precisará ser protegido por um objeto de sincronização, como uma seção crítica.

Para obter detalhes completos sobre o modelo de threading de apartamento, consulte Processos e Threads na Referência do Programador OLE.

Por que dar suporte ao threading de modelo de apartamento?

Controles que dão suporte ao threading de modelo de apartamento podem ser usados em aplicativos de contêiner com multithread que também dão suporte ao modelo de apartamento. Se você não habilitar o threading de modelo de apartamento, você limitará o conjunto de contêineres potencial nos qual seu controle pode ser usado.

Habilitar o threading de modelo de apartamento é fácil na maioria dos controles, especialmente se eles tiverem pouco ou nenhum dado compartilhado.

Proteger dados compartilhados

Se o controle usa dados compartilhados, como uma variável de membro estático, o acesso a esses dados deve ser protegido com uma seção crítica para impedir que mais de um thread modifique os dados ao mesmo tempo. Para configurar uma seção crítica para essa finalidade, declare uma variável de membro estático de classe CCriticalSection na classe do controle. Use as funções de membro Lock e Unlock deste objeto de seção crítica onde quer que seu código acesse os dados compartilhados.

Considere, por exemplo, uma classe de controle que precisa manter uma cadeia de caracteres compartilhada por todas as instâncias. Essa cadeia de caracteres pode ser mantida em uma variável de membro estático e protegida por uma seção crítica. A declaração de classe do controle conteria o seguinte:

class CSampleCtrl : public COleControl
{
...
    static CString _strShared;
    static CCriticalSection _critSect;
};

A implementação da classe incluiria definições para essas variáveis:

int CString CSampleCtrl::_strShared;
CCriticalSection CSampleCtrl::_critSect;

O acesso ao membro estático _strShared pode ser protegido pela seção crítica:

void CSampleCtrl::SomeMethod()
{
    _critSect.Lock();
if (_strShared.Empty())
    _strShared = "<text>";
    _critSect.Unlock();

...
}

Registrar um controle com reconhecimento de modelo de apartamento

Os controles que dão suporte ao threading de modelo de apartamento devem indicar essa funcionalidade no registro, adicionando o valor nomeado "ThreadingModel" com um valor de "Apartment" na entrada do registro de ID de classe na chaveinprocServer32\ da ID da classe. Para fazer com que essa chave seja registrada automaticamente para o controle, transfira o sinalizador afxRegApartmentThreading no sexto parâmetro para 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);

}

Se o projeto de controle foi gerado pelo ControlWizard no Visual C++ versão 4.1 ou posterior, esse sinalizador já faz parte do seu código. Nenhuma alteração é necessária para registrar o modelo de threading.

Se o projeto foi gerado por uma versão anterior do ControlWizard, o código existente terá um valor booliano como o sexto parâmetro. Se o parâmetro existente for TRUE, altere para afxRegInsertable | afxRegApartmentThreading. Se o parâmetro existente for FALSE, altere para afxRegApartmentThreading.

Se o controle não seguir as regras para threading de modelo de apartamento, você não deve transferir afxRegApartmentThreading nesse parâmetro.

Confira também

Observações técnicas por número
Observações técnicas por categoria