TN039: Implementação de automação de MFC/OLE
Observação |
---|
A seguinte nota técnica 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 desatualizado ou incorreto.As informações mais recentes, é recomendável que você procure o tópico de interesse no índice de documentação on-line. |
Visão geral da Interface de IDispatch OLE
O IDispatch interface é o meio pelo qual os aplicativos expõem métodos e propriedades como outros aplicativos, como Visual BASIC ou em outros idiomas, podem fazer uso de recursos do aplicativo.A parte mais importante dessa interface é a IDispatch:: Invoke função.MFC usa "mapas de despacho" implementar IDispatch:: Invoke.O mapa de expedição fornece as informações de implementação do MFC no layout ou "forma" de seu CCmdTarget-derivadas de classes, que ele diretamente pode manipular as propriedades do objeto ou chamar membro funções dentro de seu objeto para satisfazer IDispatch:: Invoke solicitações.
Na maior parte, ClassWizard e MFC cooperam para ocultar a maioria dos detalhes de automação OLE do programador de aplicativo.O programador concentra-se na funcionalidade real para expor no aplicativo e não precisa se preocupar com detalhes técnicos subjacentes.
Há casos, contudo, onde é necessário compreender o MFC está fazendo nos bastidores.Esta nota abordará como a estrutura atribui DISPIDs para funções de membro e propriedades.Conhecimento do algoritmo para atribuir o MFC usa DISPIDs só é necessário quando você precisa conhecer as identificações, como, por exemplo, quando você cria uma biblioteca de tipos"" para objetos do aplicativo.
Atribuição de DISPID MFC
Embora o usuário final de automação (um Visual Basic de usuário, por exemplo), vê os nomes reais de automação habilitada propriedades e métodos em seu código (como obj.ShowWindow), a implementação de IDispatch:: Invoke não recebe os nomes reais.Por motivos de otimização, ele recebe um DISPID, que é o 32 bits "mágico cookie" que descreve o método ou propriedade a ser acessado.Esses DISPID valores são retornados do IDispatch implementação por outro método, chamado IDispatch::GetIDsOfNames.Um aplicativo de cliente de automação chamará GetIDsOfNames uma vez para cada membro ou propriedade que pretende acessar e cache para posteriores chamadas para IDispatch:: Invoke.Dessa forma, a pesquisa de seqüência cara é realizada apenas uma vez por uso de objeto, em vez de uma vez por IDispatch:: Invoke chamar.
MFC determina o DISPIDs para cada método e propriedade com base em duas coisas:
A distância da parte superior do mapa de expedição (1 relativo)
A distância do mapa de expedição da classe mais derivado (0 relativo)
O DISPID dividida em duas partes.O LOWORD do DISPID contém o primeiro componente, a distância da parte superior do mapa de despacho.O HIWORD contém a distância entre a classe mais derivada.Por exemplo:
class CDispPoint : public CCmdTarget
{
public:
short m_x, m_y;
...
DECLARE_DISPATCH_MAP()
...
};
class CDisp3DPoint : public CDispPoint
{
public:
short m_z;
...
DECLARE_DISPATCH_MAP()
...
};
BEGIN_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, CDispPoint)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()
Como você pode ver, há duas classes, que exponham interfaces de automação de OLE.Uma dessas classes é derivada de outro e, portanto, 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:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Desde que as propriedades não estão em uma classe base, o HIWORD do DISPID é sempre zero (a distância entre a classe mais derivada de CDispPoint é zero).
MFC gerará DISPIDs para classe CDisp3DPoint da seguinte maneira:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
A propriedade z é dado um DISPID com um zero HIWORD como é definido na classe que é expor as propriedades, CDisp3DPoint.Como as propriedades x e y são definidas na classe base, o HIWORD do DISPID é 1, pois a classe na qual essas propriedades são definidas é a uma distância de uma derivação da classe mais derivada.
Observação |
---|
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 o ID versões do DISP_PROPERTY e DISP_FUNCTION macros). |
Avançados recursos de mapa de expedição do MFC
Há um número de recursos adicionais que ClassWizard não oferece suporte com esta versão do Visual C++.Suporta ClassWizard DISP_FUNCTION, DISP_PROPERTY, e DISP_PROPERTY_EX que definem um método, propriedade de membro de variável e propriedade de função de membro get/set, respectivamente.Esses recursos normalmente são todos necessários 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_NOTIFY, e DISP_PROPERTY_PARAM.
DISP_PROPERTY_NOTIFY — Descrição da Macro
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType
)
Comentários
Parâmetros
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.
Comentários
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 não retorna nada e sem parâmetros, 'void OnPropertyNotify()'.Ele será chamado depois de a variável de membro tiver sido modificada.
DISP_PROPERTY_PARAM — Descrição da Macro
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
Comentários
Parâmetros
theClass
Nome da classe.pszName
Nome externo da propriedade.memberGet
Nome da função membro usada para obter a propriedade.memberSet
Nome da função membro usada para definir a propriedade.vtPropType
Um valor especificando o tipo da propriedade.vtsParams
Uma seqüência de caracteres de espaço separados VTS_ para cada parâmetro.
Comentários
Assim como o DISP_PROPERTY_EX macro, essa macro define uma propriedade acessada com funções de membro Get e Set separadas.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 forma.Os parâmetros serão sempre colocados em primeiro lugar, seguido pelo novo valor da propriedade.Por exemplo:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
seria correspondem para obter e definir funções de membro:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID — 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
)
Comentários
Parâmetros
theClass
Nome da classe.pszName
Nome externo da propriedade.dispid
DISPID fixo para a propriedade ou método.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 propriedadevtPropType
Um valor especificando o tipo da propriedade.vtsParams
Uma seqüência de caracteres de espaço separados VTS_ para cada parâmetro.
Comentários
Essas macros permitem que você especifique um DISPID em vez de permitir que o MFC automaticamente o atribuir.Essas avançadas macros têm os mesmos nomes, exceto que ID é acrescentada ao nome da macro (por exemploDISP_PROPERTY_ID) e a identificação é determinada pelo parâmetro especificado logo após o pszName parâmetro.Consulte AFXDISP.H para obter mais informações sobre essas macros.O ID entradas devem ser colocadas no final do mapa de despacho.Elas irão afetar automáticas DISPID geração da mesma forma como um não-ID versão da macro seria (o DISPIDs são determinadas pela posição).Por exemplo:
BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()
MFC gerará DISPIDs para classe CDisp3DPoint da seguinte maneira:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Especificando um fixo DISPID é útil para manter a compatibilidade com uma interface dispatch previamente existentes ou implementar determinadas propriedades ou métodos definidos pelo sistema (normalmente indicado por um negativo DISPID, como o DISPID_NEWENUM coleção).
Recuperar a Interface IDispatch para um COleClientItem
Muitos servidores oferecerá suporte a automação dentro de seus objetos de documento, juntamente com a funcionalidade do servidor OLE.Para obter acesso a esta interface de automação, é necessário acessar diretamente o COleClientItem::m_lpObject variável de membro.O código a seguir irá recuperar o IDispatch interface para um objeto derivado de COleClientItem.Você pode incluir o código abaixo em seu aplicativo se você achar necessário essa funcionalidade:
LPDISPATCH CMyClientItem::GetIDispatch()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
Run(); // must be running
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0("Warning: Link is not connected!\n");
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch)
!= NOERROR)
{
TRACE0("Warning: does not support IDispatch!\n");
return NULL;
}
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
Interface dispatch retornado por essa função pode ser usada diretamente ou anexada a um COleDispatchDriver para acesso de tipo seguro.Se você usá-lo diretamente, certifique-se de que você chamar seu Release membro quando através com o ponteiro (o COleDispatchDriver destruidor faz isso por padrão).