TN039: Implementação de automação do 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.sistema autônomo resultado, alguns procedimentos e tópicos podem estar desatualizado ou incorreto.Para obter informações mais recentes, é recomendável que você procurar o tópico de interesse no índice de documentação online. |
Visão geral da interface de IDispatch OLE
The IDispatch interface é o meio ao quais aplicativos expõem métodos e propriedades tais poderá fazer com que outros aplicativos, sistema autônomo o Visual BASIC ou outras linguagens, usar sistema autônomo recursos do aplicativo. A parte mais importante dessa interface é o IDispatch:: Invoke função.MFC usa "mapas de distribuição" implementarIDispatch:: Invoke.O MAP de despacho fornece as informações de implementação do MFC no layout ou "forma" de suaCCmdTarget-derivadas de classes, de modo que ele pode manipular diretamente as propriedades do objeto, ou telefonar funções de membro dentro de seu objeto para satisfazer IDispatch:: Invoke solicitações.
Em sua maioria, 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 tem se preocupar com detalhes técnicos subjacentes.
Há casos, entretanto, onde é necessário compreender o que a MFC está fazendo nos bastidores.Esta nota abordará como a estrutura atribui DISPID s para funções de membro e propriedades.Conhecimento de algoritmo de MFC usa para a atribuição de DISPID sistema autônomo só é necessário quando você precisa conhecer sistema autônomo IDs, por exemplo, quando você cria "uma biblioteca de tipos" para objetos do aplicativo.
Atribuição MFC DISPID
Embora o usuário participante de automação (um Visual Basic usuário, por exemplo), visualiza sistema autônomo nomes real da automação habilitada propriedades e métodos em seu código (sistema autônomo obj.ShowWindow), a implementação de IDispatch:: Invoke não recebe sistema autônomo nomes real.Por motivos de otimização, ele recebe um DISPID, que é de 32 bit "magic cookie" que descreve o método ou propriedade a ser acessado.Esses DISPID valores de são retornados do IDispatch implementação por outro método, chamado IDispatch::GetIDsOfNames.Um aplicativo cliente de automação chamará GetIDsOfNames uma vez para cada membro ou uma propriedade que pretende acessar e armazenar em cache-los para posteriores chamadas para IDispatch:: Invoke.Dessa forma, a pesquisa de seqüência caro apenas é feita uma vez por uso de objeto, em vez de uma vez por IDispatch:: Invoke telefonar.
MFC determina o DISPID s para cada método e propriedade baseada em duas coisas:
A distância da parte superior do MAP de despacho (1 relativo)
A distância do MAP de despacho de mais classe derivada (0 relativo)
The DISPID é dividido em duas partes.The LOWORD of the DISPID contém o elemento, a distância da parte superior do MAP de despacho.The HIWORD contém a distância entre a maioria classe 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()
sistema autônomo você pode ver, há duas classes, que expõem interfaces de automação OLE.Uma dessas classes é derivada de Outros e, portanto, aproveita a funcionalidade da classe base, incluindo a parte de automação OLE ("x" e "y" propriedades no caso).
MFC será gerar DISPID sistema autônomo para classe CDispPoint da seguinte maneira:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Como as propriedades não são uma classe base, a HIWORD of the DISPID é sempre zero (a distância entre a maioria classe derivada CDispPoint é zero).
MFC gerará DISPID sistema autônomo para classe CDisp3DPoint da seguinte maneira:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
A propriedade Z é fornecida um DISPID com um zero HIWORD, pois ele é definido na classe que está expondo as propriedades, CDisp3DPoint.Como as propriedades X e Y são definidas na classe base, a HIWORD of the 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 MAP, mesmo se há entradas no MAP com explícita DISPID (consulte a próxima seção para obter informações sobre o _ID o versõesDISP_PROPERTY e DISP_FUNCTION macros). |
Avançados recursos de MAP de despacho MFC
Há um número de recursos adicionais que não oferece suporte a ClassWizard com esta versão do Visual C++.ClassWizard suporta DISP_FUNCTION, DISP_PROPERTY, e DISP_PROPERTY_EX que defina um método, propriedade de membro de variável e propriedade de função de membro get/conjunto, respectivamente. Esses recursos normalmente são 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 suportado 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 está armazenada.pfnAfterSet
Nome da função de membro para chamar quando a propriedade é alterada.vtPropType
Um valor que especifica 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 foi 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 de membro usada para obter a propriedade.memberSet
Nome da função de membro usada para conjunto a propriedade.vtPropType
Um valor que especifica o tipo da propriedade.vtsParams
Uma seqüência de caracteres de espaço separados VTS_ para cada parâmetro.
Comentários
Muito semelhante a DISP_PROPERTY_EX macro, essa macro define uma propriedade acessada com funções de membro get e conjunto separadas. Essa macro, no entanto, permite que você especifique uma lista de parâmetros para a propriedade.Isso é útil para implementar propriedades que estão indexadas ou parâmetros definidas de alguma Outros maneira.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 conjunto 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 de membro usada para obter a propriedade.pfnSet
Nome da função de membro usada para conjunto a propriedade.memberName
O nome da variável membro para mapear para a propriedadevtPropType
Um valor que especifica 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 macros avançadas têm os mesmos nomes, exceto esse ID é acrescentado ao nome do macro (por exemploDISP_PROPERTY_ID) e a ID é determinada pelo parâmetro especificado logo após o pszName parâmetro. Para obter mais informações sobre essas macros, consulte AFXDISP.H.The _ID entradas devem ser colocadas no participante do MAP de despacho.Elas afetarão o automáticoDISPID geração da mesma forma sistema autônomo um não-_ID versão da macro seria (a DISPID sistema autônomo 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 irá 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 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, sistema autônomo a DISPID_NEWENUM coleção).
Recuperar a interface IDispatch para um COleClientItem
Muitos servidores oferecerá suporte a automação dentro de seus objetos de documento, junto com a funcionalidade de servidor OLE.Para acessar essa interface de automação, é necessário acessar diretamente o COleClientItem::m_lpObject variável de membro.O código a seguir recuperará o IDispatch interface de um objeto derivado de COleClientItem. Você pode incluir o código abaixo no seu aplicativo se encontrar essa funcionalidade necessários:
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 fortemente tipado. Se usá-lo diretamente, certifique-se de que você chamar sua Versão membro quando através com o ponteiro do (a COleDispatchDriver Destrutor faz isso por padrão).