A presente nota aborda como adicionar suporte de interface dupla em um aplicativo de servidor com base em MFC automação OLE. O ACDUAL exemplo mostra o suporte de interface dupla, e o código de exemplo nesta nota faz de ACDUAL. As macros descritas nesta nota, tais como DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , e IMPLEMENT_DUAL_ERRORINFO , fazem parte do exemplo de ACDUAL e pode ser encontrado em MFCDUAL.H.
Interfaces duplos
Apesar de automação OLE permite que você implemente uma interface de IDispatch , uma interface VTBL ou uma interface dupla (que engloba ambos), a Microsoft recomenda que você implemente interfaces duplos para todos os objetos de automação OLE expostos. Interfaces duplos têm vantagens significativas sobre IDispatch-somente ou somente VTBL interfaces:
Adicionando suporte de Interface dupla para uma classe CCmdTarget-com
Uma interface dupla é realmente apenas uma interface personalizada derivada de IDispatch. A maneira mais simples de implementar o suporte de interface dupla em um CCmdTarget-classe com base é necessário primeiro implementar a expedição normal de interface em sua classe usando o MFC e ClassWizard e, em seguida, adicionar a interface Personalizar posteriormente. A maior parte do tempo, sua implementação de interface Personalizar simplesmente delegará volta para a implementação do MFC IDispatch.
Em primeiro lugar, modificar o arquivo ODL para seu servidor definir interfaces duplos para seus objetos. Para definir uma interface dupla, você deve usar uma instrução de interface, em vez da DISPINTERFACE declaração de que os assistentes do Visual C++ geram. Em vez de remover o existente DISPINTERFACE declaração, adicionar uma Novo instrução de interface. Mantendo o DISPINTERFACE formulário, você pode continuar a usar ClassWizard para adicionar métodos e propriedades para o objeto, mas você deve adicionar os equivalentes de propriedades e métodos para sua instrução de interface.
Uma instrução de interface para uma interface dupla deve ter OLEAUTOMATION e atributos DUAL , e a interface deve ser derivada de IDispatch. Você pode usar o exemplo GUIDGEN para criar um IID da interface dual
[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), / / IID_IDualAClick
oleautomation,
dupla
]
IDualAClick de interface: IDispatch
{
}
Uma vez que a instrução de interface no lugar, começar a adicionar entradas para os métodos e propriedades. Para interfaces duplos, você precise reorganizar as listas de parâmetro para que seus métodos e funções do acessador de propriedade na interface dupla retornam um HRESULT e passam seu valores de retorno como parâmetros com os atributos [retval,out] . Lembre-se que propriedades, você precisará adicionar uma leitura ( propget ) e escrever ( propput ) função com o mesmo id de acesso. Por exemplo:
[propput, id(1)] Texto HRESULT ([in] BSTR newText);
[propget, id(1)] Texto HRESULT ([out, retval] BSTR * retval)
Depois de suas propriedades e métodos são definidas, você precisará adicionar uma referência para a instrução de interface na sua declaração coclass. Por exemplo:
[uuid(4B115281-32F0-11cf-AC85-444553540000)]
coclass docume&nto
{
nbsp; dispinterface IAClick;
interface [padrão] IDualAClick;
}
Depois que seu arquivo ODL foi atualizado, use o mecanismo de mapa de interface do MFC para definir uma classe de implementação para a interface dupla em sua classe de objeto e fazer as entradas correspondentes no mecanismo de QueryInterface do MFC. Você precisa de uma entrada no INTERFACE_PART bloco para cada entrada na instrução de interface da EAD, além de entradas para uma interface de distribuição. Cada entrada de EAD com o atributo propput tem uma função chamada put_propertyname . Cada entrada com o atributo propget tem uma função chamadaget_propertyname.
Para definir uma classe de implementação para a interface dupla, adicionar um DUAL_INTERFACE_PART bloco para sua definição de classe do objeto. Por exemplo:
BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)
STDMETHOD(put_text) (THIS_ BSTR newText);
STDMETHOD(get_Text) (THIS_ BSTR FAR * retval);
STDMETHOD(put_x) (THIS_ newX curto);
STDMETHOD(get_x) (THIS_ curto FAR * retval);
STDMETHOD(put_y) (THIS_ newY curto);
STDMETHOD(get_y) (THIS_ curto FAR * retval);
STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint FAR * newPosition);
STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint FAR * extremo * retval);
STDMETHOD(RefreshWindow)(this);
STDMETHOD(SetAllProps) (THIS_ curto x, y curto, texto BSTR);
STDMETHOD(ShowWindow)(this);
END_DUAL_INTERFACE_PART(DualAClick)
Para se conectar a interface dupla do MFC mecanismo de QueryInterface , adicionar um INTERFACE_PART entrada de mapa de interface
BEGIN_INTERFACE_MAP (CAutoClickDoc, CDocument)
INTERFACE_PART (CAutoClickDoc, DIID_IAClick, expedição)
INTERFACE_PART (CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()
Em seguida, você precisará preencher a implementação da interface. A maior parte do tempo, você será capaz de delegar a implementação do MFC de IDispatch . Por exemplo:
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::AddRef()
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::Release()
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalRelease();
}
STDMETHODIMP CAutoClickDoc::XDualAClick::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfoCount(
UINT FAR* pctinfo)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetTypeInfoCount(pctinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfo(
UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetIDsOfNames(
REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
LCID lcid, DISPID FAR* rgdispid)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames,
lcid, rgdispid);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::Invoke(
DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
ASSERT(lpDispatch != NULL);
return lpDispatch->Invoke(dispidMember, riid, lcid,
wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr);
}
Para os métodos e funções do acessador de propriedade do objeto, você precisará preencher na implementação. Suas funções de método e propriedade geralmente podem delegar volta para os métodos gerados usando ClassWizard. No entanto, se você definir as propriedades para acessar variáveis diretamente, você precisará gravar o código para obter/coloque o valor para a variável. Por exemplo:
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC automaticamente converte de Unicode BSTR para / / Ansi CString, se necessário...
pThis - > m_str = newText;
retornar NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
/ / MFC automaticamente converte de Ansi de CString para / / Unicode BSTR, se necessário...
pThis - > m_str.SetSysString(retval);
retornar NOERROR;
}
Passar ponteiros de Interface dupla
Não é simples, especialmente se você precisará chamar CCmdTarget::FromIDispatchpassar o ponteiro de interface dupla. Assinatura deIDispatch só funciona em ponteiros de IDispatch do MFC. Uma maneira de contornar esse problema é para consultar para obter o conjunto original de ponteiro de IDispatch para cima pelo MFC e passar esse ponteiro para funções que precisam dele. Por exemplo
STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position (
nbsp; IDualAutoClickPoint FAR * newPosition)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH lpDisp = NULL;
newPosition - > falha de QueryInterface (IID_IDispatch, (LPVOID *) & lpDisp);
pThis - > SetPosition(lpDisp);
lpDisp - > Release();
retornar NOERROR;
}
Antes de passar um ponteiro voltar através do método de interface dupla, você talvez precise convertê-lo do MFC IDispatch ponteiro para o ponteiro de interface dupla. Por exemplo:
STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position (
nbsp; IDualAutoClickPoint FAR * extremo * retval)
{
METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
LPDISPATCH lpDisp;
lpDisp = pThis - > GetPosition ();
lpDisp - > falha de QueryInterface (IID_IDualAutoClickPoint, (LPVOID *) retval);
retornar NOERROR;
}
Registrar a biblioteca de tipos do aplicativo
AppWizard não gera código para registrar a biblioteca de tipos do aplicativo servidor OLE automação com o sistema. Embora existam outras formas de registrar a biblioteca de tipos, é conveniente ter o aplicativo registrar a biblioteca de tipos quando ele está atualizando suas informações de tipo OLE, ou seja, sempre que o aplicativo é executado autônomo.
Para registrar a biblioteca de tipos do aplicativo sempre que o aplicativo é executado autônomo:
InitInstance função, localizar a chamada COleObjectFactory:: UpdateRegistryAll. Após essa chamada, adicionar uma chamada para AfxOleRegisterTypeLib, especificando o LIBID correspondente à sua biblioteca de tipo, juntamente com o nome da biblioteca tipo/ / Quando um aplicativo de servidor é iniciado autônomo, é uma boa idéia
/ / para atualizar o registro do sistema, caso ele tenha sido danificado.
m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
COleObjectFactory::UpdateRegistryAll();
/ / DUAL_SUPPORT_START
/ / Certifique-se a biblioteca de tipos está registrada ou interface dupla não vai funcionar.
AfxOleRegisterTypeLib(AfxGetInstanceHandle(), LIBID_ACDual, _T("AutoClik.TLB"));
/ / DUAL_SUPPORT_END
Modificando as configurações de compilação do projeto para acomodar alterações de biblioteca de tipo
Para modificar um projeto Compilação configurações para que um arquivo de cabeçalho que contém definições de UUID é gerado por MkTypLib sempre que a biblioteca de tipos é reconstruída
Para adicionar as definições de UUID de arquivo de cabeçalho gerado pelo MkTypLib para seu projeto:
/ / initIIDs.c: define IIDs para interfaces duplos
/ / Este não deve ser construído com cabeçalho pré-compilado.
# include lt;ole2.h >
# include <initguid.h>
# include "acdual.h"
Especificando o nome de classe de objeto correto na biblioteca de tipos
Os assistentes fornecidos com Visual C++ incorretamente usam o nome de classe de implementação para especificar o coclass no arquivo ODL do servidor para classes OLE createable. Enquanto isso vai funcionar, o nome da classe de implementação provavelmente não é o nome de classe que você deseja que os usuários do seu objeto para usar. Para especificar o nome correto, abra o arquivo ODL, localize cada instrução coclass e substituir o nome da classe de implementação com o nome correto de externo.
Observe que quando a instrução coclass é alterada, os nomes de variável de CLSIDs no arquivo de cabeçalho gerado pelo MkTypLib irão alterar em conformidade. Você precisará atualizar seu código para usar os novos nomes das variáveis.
Manipulação de exceções e Interfaces de erro de automação
Seu objeto de automação métodos e funções do acessador de propriedade podem lançar exceções. Se assim for, você deve lidar com eles em sua implementação de interface dupla e passar informações sobre a exceção Voltar ao controlador através da interface de manipulação de erros de automação OLE, IErrorInfo. Essa interface fornece informações de erro detalhadas, contextual através de interfaces de IDispatch e VTBL. Para indicar que um manipulador de erro está disponível, você deve implementar a interface de ISupportErrorInfo.
Para ilustrar o mecanismo de manipulação de erros, assuma que as funções gerado pelo ClassWizard usadas para implementar o suporte de envio padrão lançam exceções. Implementação do MFC do IDispatch:: Invoke normalmente captura essas exceções e converte-los para um EXCEPTINFO estrutura que é retornado por meio da chamada de Invoke . No entanto, quando a interface VTBL é usada, você é responsável para a captura de exceções. Como exemplo de proteger os seus métodos de interface dupla
STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
TRY_DUAL(IID_IDualAClick)
{
/ / MFC automaticamente converte de Unicode BSTR para / / Ansi CString, se necessário...
pThis - > m_str = newText;
retornar NOERROR;
}
CATCH_ALL_DUAL
}
CATCH_ALL_DUALse encarrega de retornar o código de erro correta quando ocorre uma exceção. CATCH_ALL_DUALconverte uma exceção MFC em informações sobre manipulação de erro de automação OLE usando a interface do ICreateErrorInfo . (Um exemplo CATCH_ALL_DUAL macro está no arquivo MFCDUAL.H na exemplo ACDUAL . A função que ele chama para lidar com exceções, DualHandleException , está no arquivo MFCDUAL.CPP.) CATCH_ALL_DUALdetermina o código de erro de retorno com base no tipo de exceção que ocorreu
hr = MAKE_HRESULT (SEVERITY_ERROR, FACILITY_ITF, nbsp; (e - > m_wCode + 0x200))
Isso cria um HRESULT específicos para a interface que causou a exceção. O código de erro é compensado por 0x200 para evitar quaisquer conflitos com s HRESULTdefinidos pelo sistema para interfaces OLE padrão.
E_OUTOFMEMORY é retornado.E_UNEXPECTED é retornado.Para indicar que o manipulador de erro de automação OLE é usado, você também deve implementar a interface de ISupportErrorInfo.
Primeiro, adicione código à sua definição de classe de automação para mostrar que ele oferece suporte a ISupportErrorInfo.
Em segundo lugar, adicione código ao mapa de interface da sua classe de automação para associar a classe de implementação de ISupportErrorInfo com mecanismo de QueryInterface do MFC. O INTERFACE_PART declaração coincide com a classe definida para ISupportErrorInfo.
Finalmente, implementar a classe definida para oferecer suporte a ISupportErrorInfo.
(O ACDUAL exemplo contém três macros para ajudar a fazer estes três passos, DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , e IMPLEMENT_DUAL_ERRORINFO , tudo contido em MFCDUAL.H.)
O exemplo a seguir implementa uma classe definida para oferecer suporte a ISupportErrorInfo. CAutoClickDocé o nome de sua classe de automação e IID_IDualAClick é o IID da interface que é a fonte de erros relatados através do objeto de erro de automação OLE:
STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() {
nbsp; METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) retornar pThis - > ExternalAddRef();
} CAutoClickDoc::XSupportErrorInfo::Release() STDMETHODIMP_(ULONG) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) retornar pThis - > ExternalRelease();
} CAutoClickDoc::XSupportErrorInfo::QueryInterface STDMETHODIMP (REFIID iid, LPVOID * ppvObj) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) retornar pThis - > ExternalQueryInterface (& iid, ppvObj);
} CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo STDMETHODIMP (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) retorno (iid = = IID_IDualAClick)? S_OK: S_FALSE;
}
Técnico anotações por número |nbsp; &Notas técnicas por categoria