TN039: Implementação de automação MFC/OLE

Visão geral da Interface de IDispatch OLE

A interface de IDispatch é os meios pelos quais aplicativos expõem métodos e propriedades tais que outros aplicativos, como Visual BASIC, ou outros idiomas, podem fazer usam de recursos do aplicativo. A parte mais importante dessa interface é IDispatch:: Invoke função. MFC usa "mapas de expedição" para implementar IDispatch:: Invoke. O mapa de expedição fornece as informações de implementação do MFC no layout ou "forma" de seu CCmdTarget-classes derivadas, tal que ele possa diretamente manipular as propriedades do objeto, ou chamar membro funções dentro de seu objeto para satisfazer às solicitações do IDispatch:: Invoke.

Na maior parte, ClassWizard e MFC cooperarem para ocultar a maioria dos detalhes de automação de OLE do programador de aplicativo. O programador concentra-se na funcionalidade real para expor no aplicativo e não tem que preocupar-se sobre o encanamento subjacente.

Há casos, no entanto, em que é necessário compreender o MFC está fazendo nos bastidores. Esta anotação irá abordar como a estrutura atribui DISPIDs a propriedades e funções de membro. Conhecimento do algoritmo que MFC usa para atribuição de DISPIDs só é necessário quando você precisa conhecer as identificações, como quando você cria uma biblioteca de"tipo" para objetos do seu aplicativo.

Atribuição de DISPID MFC

Embora o usuário final de automação (Visual Basic utilizador, por exemplo), vê os nomes reais da automação habilitada propriedades e métodos em seu código (por exemplo, obj.ShowWindow), a implementação de IDispatch:: Invoke não recebe os nomes reais. Por motivos de otimização, ele recebe um DISPID, que é um 32-bit "mágico cookie" que descreve o método ou propriedade a ser acessado. Esses valores DISPID são retornados da implementação IDispatch por outro método, chamado IDispatch:: GetIDsOfNames. Um aplicativo de cliente de automação irá chamar GetIDsOfNames uma vez para cada membro ou propriedade que pretende acessar e armazenar em cache-los para chamadas posteriores para IDispatch:: Invoke. Desta forma, a pesquisa de Cadeia de caracteres caro é feita apenas uma vez por uso de objeto, em vez de uma vez por IDispatch:: Invoke chamada.

MFC determina o s DISPIDpara cada método e propriedade com base em duas coisas:

O DISPID é dividido em duas partes. O LOWORD do DISPID contém o primeiro componente, a distância da parte superior do mapa de distribuição. O HIWORD contém a distância entre a classe mais derivada. Por exemplo:

classe CDispPoint: público CCmdTarget
{
público:
 nbsp;  curto m_x, m_y;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

classe CDisp3DPoint da: CDispPoint pública
{
público:
    m_y curto;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

BEGI&N_DISPATCH_MAP (CDispPoint, CCmdTarget)
    DISP_PROPERTY (CDispPoint, "x", m_x, VT_I2)
    DISP_PROPERTY (CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()

BEGIN_DISPATCH_MAP (CDisp3DPoint da, CDispPoint)
    DISP_PROPERTY (CDisp3DPoint da, "z", m_z, VT_I2)
END_DISPATCH_MAP()

Como você pode ver, há duas classes, os quais expõem interfaces de automação de OLE. Uma dessas classes é derivada de outro e, assim, aproveita a funcionalidade da classe base, incluindo a parte de automação OLE ("x" e "y" Propriedades neste caso).

MFC gerará DISPIDs para classe CDispPoint da seguinte maneira:

propriedade X    (DISPID) 0 X 00000001
Propriedade Y (DISPID) 0 x 00000002

Como as propriedades não estão em uma classe base, o HIWORD do DISPID é sempre zero (a distância entre a classe mais derivada para CDispPoint é zero).

MFC gerará DISPIDs para classe CDisp3DPoint da seguinte maneira:

propriedade Z    (DISPID) 0 X 00000001
Propriedade X (DISPID) 0x00010001
Propriedade Y (DISPID) 0x00010002

A propriedade z é dado um DISPID com um zero HIWORD desde que ele é definido na classe que é expor as propriedades, CDisp3DPoint da. Uma vez que as propriedades x e y são definidas em uma classe base, o HIWORD do DISPID é 1, uma vez que a classe na qual essas propriedades são definidas está a uma distância de uma derivação da classe mais derivada.

&Notanbsp;  O LOWORD sempre é determinado pela posição no mapa, mesmo se há entradas no mapa com explícito DISPID (consulte a próxima seção para obter informações sobre as versões de ID do DISP_PROPERTY e DISP_FUNCTION macros).

Avançados recursos de mapa de expedição MFC

Há uma série de recursos adicionais que ClassWizard não tem suporte nesta versão do Visual C++. ClassWizard oferece suporte a macro DISP_PROPERTY_EX , que definem um método, propriedade de membro de variável e propriedade de função de membro get/set, respectivamente, DISP_PROPERTYe DISP_FUNCTION. Esses recursos são, geralmente, tudo o que é necessário para criar a maioria dos servidores de automação.

As seguintes macros adicionais podem ser usadas quando as macros ClassWizard suportada não são adequadas: DISP_PROPERTY_NOTIFYe DISP_PROPERTY_PARAM.

DISP_PROPERTY_NOTIFY — Descrição da Macro

DISP_PROPERTY_NOTIFY (theClass, pszName, memberName, pfnAfterSet, vtPropType)

theClass

Nome da classe.

pszName

Nome externo da propriedade.

memberName

Nome da variável de membro no qual a propriedade é armazenada.

pfnAfterSet

Nome da função de membro para chamar quando a propriedade é alterada.

vtPropType

Um valor especificando o tipo da propriedade.

&Notanbsp;  Essa macro é muito parecido com DISP_PROPERTY, exceto que ele aceita um argumento adicional. O argumento adicional, pfnAfterSet, deve ser uma função de membro que retorna nada e sem parâmetros, 'void OnPropertyNotify()'. Ele será chamado depois que a variável de membro tiver sido modificada.

DISP_PROPERTY_PARAM — Descrição da Macro

DISP_PROPERTY_PARAM (theClass, pszName, pfnGet, pfnSet, vtPropType, vtsParams)

theClass

Nome da classe.

pszName

Nome externo da propriedade.

memberGet

Nome da função membro usada para obter a propriedade.

conjunto de membros

Nome da função membro usada para definir a propriedade.

vtPropType

Um valor especificando o tipo da propriedade.

vtsParams

Uma Cadeia de caracteres de espaço separados VTS _ para cada parâmetro.

&Notanbsp;  Muito como a macro macro DISP_PROPERTY_EX , essa macro define uma propriedade acessada com separado Get e Set funções de membro. Essa macro, no entanto, permite que você especifique uma lista de parâmetro para a propriedade. Isso é útil para implementar propriedades que são indexadas ou parametrizadas de alguma outra forma. Os parâmetros serão sempre colocados em primeiro lugar, seguido pelo novo valor para a propriedade. Por exemplo:

DISP_PROPERTY_PARAM (CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)

corresponderia a obter e definir funções de membro:

CMyObject::GetItem(short row, short col) LPDISPATCH
void CMyObject::SetItem (linha pequeno, curto col, LPDISPATCH newValue)

DISP_XXXX_ID — As descrições de Macro

DISP_FUNCTION_ID (theClass pszName dispid, pfnMember, vtRetVal, vtsParams)

DISP_PROPERTY_ID (theClass, pszName, dispid, memberName, vtPropType)

DISP_PROPERTY_NOTIFY_ID (theClass pszName dispid, memberName, pfnAfterSet, vtPropType)

DISP_PROPERTY_EX_ID (theClass pszName dispid, pfnGet, pfnSet, vtPropType)

DISP_PROPERTY_PARAM_ID (theClass, pszName, dispid, pfnGet, pfnSet, vtPropType, vtsParams)

theClass

Nome da classe.

pszName

Nome externo da propriedade.

dispid

O DISPID fixo para o método ou propriedade.

pfnGet

Nome da função membro usada para obter a propriedade.

pfnSet

Nome da função membro usada para definir a propriedade.

memberName

O nome da variável membro para mapear a propriedade

vtPropType

Um valor especificando o tipo da propriedade.

vtsParams

Uma Cadeia de caracteres de espaço separados VTS _ para cada parâmetro.

&Notanbsp;  Essas macros permitem que você especifique um DISPID em vez de permitir que o MFC atribuir automaticamente um. Estas avançadas macros têm os mesmos nomes, exceto que ID é acrescentada ao nome da macro (por exemplo, DISP_PROPERTY_ID) e a identificação é determinada pelo parâmetro especificado apenas após o pszName parâmetro. Consulte AFXDISP.H para obter mais informações sobre essas macros. As entradas de ID devem ser colocadas no final do mapa de distribuição. Elas irão afetar a geração de automática DISPID da mesma forma como um não-ID versão da macro seria (o s DISPIDsão determinadas pela posição). Por exemplo:

BEGI&N_DISPATCH_MAP (CDisp3DPoint da, CCmdTarget)
 nbsp;  DISP_PROPERTY (CDisp3DPoint da, "y", m_y, VT_I2)
    DISP_PROPERTY (CDisp3DPoint da, "z", m_z, VT_I2)
    DISP_PROPERTY_ID (CDisp3DPoint da, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()

MFC gerará DISPIDs para classe CDisp3DPoint da seguinte maneira:

propriedade X    (DISPID) 0X00020003
Propriedade Y (DISPID) 0 x 00000002
Propriedade Z (DISPID) 0 x 00000001

Especificando um fixo DISPID é útil para manter compatibilidade com versões anteriores para uma interface dispatch previamente existentes, ou para implementar determinado sistema definido métodos ou propriedades (normalmente indicadas por um negativo DISPID, como a coleção DISPID_NEWENUM ).

Recuperar a Interface de IDispatch para um COleClientItem

Número de servidores oferecerá suporte automação dentro de seus objetos de documento, juntamente com a funcionalidade de servidor OLE. Para ter acesso a essa interface de automação, é necessário acessar diretamente a variável de membro COleClientItem::m_lpObject . O código a seguir irá recuperar a interface de IDispatch para um objeto derivado de COleClientItem. Você pode incluir o código abaixo em seu aplicativo se você encontrar esta funcionalidade necessários

CMyClientItem::GetIDispatch() LPDISPATCH
{
 nbsp;  ASSERT_VALID(this);
    ASSERT (m_lpObject! = NULL);

LPUNKNOWN lpUnk = m_lpObject;

Run ();    / / deve estar sendo executado

LPOLELINK lpOleLink = NULL;
    se (m_lpObject - > falha de QueryInterface (IID_IOleLink, (LPVOID FAR *) & lpOleLink) = = NOERROR)
    {
        ASSERT (lpOleLink! = NULL);
        lpUnk = NULL;
        se (lpOleLink - > GetBoundSource(&lpUnk)! = NOERROR)
        {
            TRACE0 ("aviso: Link não está ligado! \n");
            lpOleLink - > Release();
            retornar NULL;
        }
        ASSERT (lpUnk! = NULL);
    }

LPDISPATCH lpDispatch = NULL;
    se (lpUnk - > falha de QueryInterface (IID_IDispatch & lpDispatch)! = NOERROR)
    {
        TRACE0 ("aviso: não dá suporte a IDispatch! \n");
        retornar NULL;
    }

ASSERT (lpDispatch! = NULL);
    retornar lpDispatch;
}

A interface dispatch retornado dessa função, em seguida, pode ser usada diretamente ou anexada a um COleDispatchDriver para acessar de tipo seguro. Se você usá-lo diretamente, certifique-se de que você chamar seu membro de lançamento quando através com o ponteiro (o destruidor COleDispatchDriver faz isso por padrão).

Técnico anotações por número |nbsp; &Notas técnicas por categoria

Index