TN038: Implementação do MFC/OLE IUnknown
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. |
A essência do OLE 2 é o "OLE componente objeto Model", ou COM.COM define um padrão para objetos como cooperação se comunicar com um outro.Isso inclui os detalhes do que um "objeto" aparência, incluindo como os métodos são distribuídos em um objeto.COM também define uma classe base, a partir da qual todas as classes compatível COM são derivadas.Essa classe base é IUnknown.Embora o IUnknown interface é conhecido sistema autônomo uma classe C++, COM não é específico para qualquer um idioma — pode ser implementado em C, PASCAL ou qualquer Outros linguagem que suporte o layout de um objeto COM binário.
OLE refere-se a todas sistema autônomo classes derivadas de IUnknown sistema autônomo "interfaces". Isso é uma distinção importante, desde a "interface", sistema autônomoIUnknown não carrega com ele nenhuma implementação.Ele simplesmente define o protocolo que objetos se comunicar, não as especificidades do que fazem essas implementações.Isso é razoável para um sistema que permite flexibilidade máxima.É função do MFC para implementar um comportamento padrão para programas do C++/MFC.
Para compreender a implementação do MFC de IUnknownVocê deve primeiro compreender o que esta interface é .Uma versão simplificada do IUnknown é definida abaixo:
class IUnknown
{
public:
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
Observação: |
---|
Detalhe determinada convenção de chamada necessária, sistema autônomo __stdcall são deixados check-out para esta ilustração. |
The AddRef e Versãofunções de membro controlam o gerenciamento de memória do objeto.COM usa um esquema de contagem de referência para manter o controle dos objetos.Um objeto é referenciado nunca diretamente sistema autônomo faria em C++.Em vez disso, os objetos COM sempre são referenciados através de um ponteiro.Para liberar o objeto quando o proprietário é concluído usando-Versão membro é chamado (em oposição a usando o operador excluir, sistema autônomo seria concluído para um objeto C++ tradicional).A mecanismo de contagem de referência permite várias referências a um único objeto a serem gerenciado.Uma implementação de AddRef e Versão mantém uma contagem de referência no objeto — o objeto não é excluído até que sua contagem de referência chega a zero.
AddRef e Versão são bastante simples de um ponto de vista da implementação.Esta é uma implementação simples:
ULONG CMyObj::AddRef()
{
return ++m_dwRef;
}
ULONG CMyObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
The QueryInterface função de membro é um pouco mais interessante. Não é muito interessante tenha um objeto cujas somente funções de membro são AddRef e Versão — seria legal informar o objeto para fazer mais coisas que IUnknown fornece.Isso é onde QueryInterface é útil. Ele permite que você obtenha uma "interface" diferente no mesmo objeto.Essas interfaces são obtidas geralmente IUnknown e adicionar funcionalidades adicionais, adicionando novas funções de membro.Interfaces COM nunca tem variáveis de membro declaradas na interface do, e todas sistema autônomo funções de membro são declaradas sistema autônomo essencialmente virtual.Por exemplo,
class IPrintInterface : public IUnknown
{
public:
virtual void PrintObject() = 0;
};
Para obter um IPrintInterface se você tiver apenas um IUnknown, telefonar IUnknown::QueryInterface usando o IID of the IPrintInterface.An IID é um número de 128 bit que identifica com exclusividade a interface.Há um IID para cada interface que você ou OLE definem.If pUnk é um ponteiro para um IUnknown objeto, o código para recuperar um IPrintInterface dele pode ser:
IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface,
(void**)&pPrint) == NOERROR)
{
pPrint->PrintObject();
pPrint->Release();
// release pointer obtained via QueryInterface
}
Que parece bastante fácil, mas como você implementa um objeto que suporte o IPrintInterface e IUnknown interface?Nesse caso é simples, pois o IPrintInterface é derivada diretamente de IUnknown — implementando IPrintInterface, IUnknown automaticamente é suportado.Por exemplo:
class CPrintObj : public CPrintInterface
{
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
virtual void PrintObject();
};
sistema autônomo implementações de AddRef e Versão deve ser exatamente o mesmo implementado acima.CPrintObj::QueryInterface poderia ter esta aparência:
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
sistema autônomo você pode ver, se o identificador de interface (IID) é reconhecido, um ponteiro é retornado para seu objeto; caso contrário, ocorrerá um erro.Observe também que um bem-sucedida QueryInterface resultados em um implícita AddRef. Obviamente, também seria necessário implementar CEditObj::Print.É simples porque o IPrintInterface foi derivado diretamente o IUnknown interface.No entanto se você quisesse oferecer suporte a duas interfaces diferentes, ambos derivado de IUnknown, considere o seguinte:
class IEditInterface : public IUnkown
{
public:
virtual void EditObject() = 0;
};
Embora haja várias maneiras diferentes de implementar uma classe com suporte para ambos os IEditInterface and IPrintInterface, incluindo o uso de C++ herança múltipla, esta nota se concentrará no uso de classes aninhadas para implementar essa funcionalidade.
class CEditPrintObj
{
public:
CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD m_dwRef;
class CPrintObj : public IPrintInterface
{
public:
CEditPrintObj* m_pParent;
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_printObj;
class CEditObj : public IEditInterface
{
public:
CEditPrintObj* m_pParent;
virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_editObj;
};
A implementação completa está incluída abaixo:
CEditPrintObj::CEditPrintObj()
{
m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef()
{
return ++m_dwRef;
}
CEditPrintObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = &m_printObj;
AddRef();
return NOERROR;
}
else if (iid == IID_IEditInterface)
{
*ppvObj = &m_editObj;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG CEditPrintObj::CEditObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CEditObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
ULONG CEditPrintObj::CPrintObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CPrintObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CPrintObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
Observe que a maioria do IUnknown implementação é colocada no CEditPrintObj classe em vez de duplicar o código no CEditPrintObj::CEditObj e CEditPrintObj::CPrintObj.Isso reduz a quantidade de código e evita erros.O ponto principal aqui é que da interface IUnknown é possível chamar QueryInterface para recuperar qualquer interface que o objeto pode suporte, e de cada uma dessas interfaces é possível fazer o mesmo. Isso significa que todos os QueryInterface funções disponível em cada interface devem se comportar exatamente da mesma maneira. Em ordem para esses objetos incorporados chamar a implementação em "objeto externo", um ponteiro de back é usado (m_pParent).O ponteiro m_pParent é inicializado durante o construtor CEditPrintObj.Em seguida, você implementaria CEditPrintObj::CPrintObj::PrintObject e CEditPrintObj::CEditObj::EditObject também.Um bit de código foi adicionado ao adicionar um recurso — a capacidade de edição o objeto.Felizmente, é bastante incomum de interfaces para que apenas uma função de membro único (embora ele acontecer) e nesse caso, EditObject e PrintObject geralmente poderiam ser combinadas em uma única interface.
Ou seja, muita explicação e muito código para um cenário simples.As classes do MFC/OLE fornecem uma alternativa mais simples.A implementação do MFC usa uma técnica semelhante à forma dispostas mensagens do Windows com mapas de mensagem.Esse recurso é chamado Mapas de interface e é abordado na próxima seção.
Mapas de interface do MFC
MFC/OLE inclui uma implementação de "Interface mapas" semelhante a "Mapas de mensagem" e "Mapas de despacho" do MFC em conceito e execução.sistema autônomo principais recursos de mapas de interface do MFC são:
Uma implementação padrão de IUnknown, incorporados a CCmdTarget classe.
Manutenção de contagem de referência, modificada por AddRef e Versão
Implementação de QueryInterface orientados a dados
Além disso, mapas de interface suportam os seguintes recursos avançados:
Suporte para a criação de objetos COM agregáveis
Suporte para o uso de objetos agregados na implementação de um objeto COM
A implementação é extensível e hookable
Para obter mais informações sobre agregação, consulte o Referência do programador de OLE.
Suporte de MAP de interface do MFC está enraizada no CCmdTarget classe. CCmdTarget"tem um"referência contagem, bem sistema autônomo todas sistema autônomo funções de membro associadas com o IUnknown implementação (a contagem de referência por exemplo está em CCmdTarget). Para criar uma classe que ofereça suporte a OLE COM, você deve derivar uma classe de CCmdTarget e use várias macros, bem sistema autônomo funções de membro de CCmdTarget para implementar sistema autônomo interfaces desejadas. Implementação do MFC usa classes aninhadas para definir cada implementação de interface muito semelhante ao exemplo acima.Isso é mais fácil com uma implementação padrão de IUnknown, bem sistema autônomo um número de macros que elimine alguns códigos repetitivos.
Para implementar uma classe usando a interface do MFC mapas
Derivar uma classe direta ou indiretamente de CCmdTarget.
Use o DECLARE_INTERFACE_MAP função na definição de classe derivada.
Para cada interface que você deseja dar suporte, use o BEGIN_INTERFACE_PART and END_INTERFACE_PART macros na definição de classe.
No arquivo de implementação, use o BEGIN_INTERFACE_MAP e END_INTERFACE_MAP macros para definir o MAP de interface da classe.
Para cada IID suportado, use o INTERFACE_PART macro entre o BEGIN_INTERFACE_MAP e END_INTERFACE_MAPas macros para MAP que IID para um específico "parte" de sua classe.
Implemente cada uma das classes aninhadas que representam as interfaces que você dá suporte.
Use o METHOD_PROLOGUE macro para acessar o pai CCmdTarget-derivados do objeto.
AddRef, Versão, and QueryInterface pode delegado para o CCmdTarget implementação dessas funções)ExternalAddRef, ExternalRelease, and ExternalQueryInterface).
Exemplo CPrintEditObj acima poderia ser implementado da seguinte maneira:
class CPrintEditObj : public CCmdTarget
{
public:
// member data and member functions for CPrintEditObj go here
// Interface Maps
protected:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(EditObj, IEditInterface)
STDMETHOD_(void, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART(PrintObj, IPrintInterface)
STDMETHOD_(void, PrintObject)();
END_INTERFACE_PART(PrintObj)
};
A declaração acima cria uma classe derivada de CCmdTarget. The DECLARE_INTERFACE_MAP macro informa a estrutura que essa classe terá um MAP de interface personalizada.Além disso, a BEGIN_INTERFACE_PART and END_INTERFACE_PART macros definem classes aninhadas, nesse caso com nomes CEditObj e CPrintObj (o X é usado somente para diferenciar as classes aninhadas de global classes que começam com "C" e as classes de interface que começam com "I").Dois membros aninhados dessas classes são criados: m_CEditObj e m_CPrintObj, respectivamente.As macros declarar automaticamente o AddRef, Versão, and QueryInterface funciona; portanto você apenas declarar as funções específicas para esta interface: EditObject e PrintObject (o OLE macro STDMETHOD é usado sistema autônomo assim que _stdcall e palavras-chave virtual são fornecidas conforme apropriado para a plataforma de destino).
Para implementar o MAP de interface para esta classe:
BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
Isso conecta a IID IID_IPrintInterface m_CPrintObj e IID_IEditInterface com m_CEditObj respectivamente.The CCmdTarget implementação do QueryInterface (CCmdTarget::ExternalQueryInterface) usa este MAP para retornar ponteiros m_CPrintObj e m_CEditObj quando solicitado.Não é necessário incluir uma entrada para IID_IUnknown; o estrutura usam a interface primeira no MAP (no caso, m_CPrintObj) quando a IID_IUnknown é solicitada.
Embora o BEGIN_INTERFACE_PART macro automaticamente declarado o AddRef, Versão and QueryInterface funções para você, você ainda precisará implementá-los:
ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
// code to "Edit" the object, whatever that means...
}
A implementação de CEditPrintObj::CPrintObj, seria semelhante às definições acima para CEditPrintObj::CEditObj.Embora seria possível criar uma macro que pode ser usada para gerar automaticamente essas funções (mas anteriormente no desenvolvimento do MFC/OLE esse era o caso), é difícil conjunto pontos de interrupção quando uma macro gera mais de uma linha de código.Por esse motivo, esse código é expandido manualmente.
Usando a implementação da estrutura de mapas de mensagem, há várias coisas que não eram necessárias para fazer:
Implementar QueryInterface
Implementar AddRef e versão
Declarar um desses métodos internos em ambas as interfaces
Além disso, a estrutura usa internamente mapas de mensagem.Assim, você pode derivar de uma estrutura de classe, digamos que COleServerDoc, já que oferece suporte a certas interfaces e fornece substituições ou adições nas interfaces fornecidos pela estrutura do. Isso é ativado pelo fato de que a estrutura oferece suporte total ao herança uma interface mapear de uma classe base — essa é a razão por que BEGIN_INTERFACE_MAP Obtém, sistema autônomo seu segundo parâmetro, o nome da classe base.
Observação: |
---|
Em geral não é possível reutilizar a implementação de implementações internas do MFC das interfaces OLE por herança a especialização incorporada da interface da versão do MFC.Não é possível porque o uso do METHOD_PROLOGUE macro para obter acesso a que contém CCmdTarget-objeto derivado implica um deslocamento fixo do objeto incorporado do CCmdTarget-derivados do objeto. Isso significa, por exemplo, que você não pode derivar um XMyAdviseSink incorporado de implementação do MFC no COleClientItem::XAdviseSink, como XAdviseSink depende de estar em um deslocamento específico da parte superior do COleClientItem objeto. |
Observação: |
---|
Você pode, entretanto, delegado para a implementação do MFC para todas as funções que você deseja que o comportamento do padrão do MFC.Isso é concluído na implementação do MFC IOleInPlaceFrame (XOleInPlaceFrame) no COleFrameHook classe (delega para m_xOleInPlaceUIWindow para muitas funções).Esse design foi escolhido para reduzir o dimensionar do tempo de execução de objetos que implementam várias interfaces; elimina a necessidade de um ponteiro back (sistema autônomo m_pParent forma foi usado na seção anterior). |
Agregação e mapas de interface
Em além oferecendo suporte a objetos COM autônomos, MFC também dá suporte à agregação.Agregação propriamente dito é muito complexo um tópico para discutir aqui; consulte o Referência do programador de OLE para obter mais informações sobre agregação.Esta nota simplesmente descreve o suporte para agregação incorporada os mapas de estrutura e interface.
Há duas maneiras de usar agregação: (1) (2) usando um objeto COM que oferece suporte à agregação e a implementação de um objeto que pode ser agregado por outra.Esses recursos podem ser denominados "usando um objeto agregado"e "tornar um objeto agregável".MFC oferece suporte a ambos.
Usando um objeto agregado
Para usar um objeto agregado, há precisa ser uma maneira de vincular o agregado para o mecanismo de QueryInterface.Em Outros palavras, o objeto agregado deve comportamento sistema autônomo se fosse parte nativa de seu objeto.Então, como esta ligação na interface do MFC está mapeado mecanismo?Juntamente com o INTERFACE_PART macro, onde um objeto aninhado é mapeado para um IID, também é possível declarar um objeto agregado sistema autônomo parte do seu CCmdTarget classe derivada. Para fazer isso, a INTERFACE_AGGREGATE macro é usada.Isso permite que você especificar uma variável de membro (que deve ser um ponteiro para um IUnknown ou classe derivada), que é ser integrado ao mecanismo de MAP de interface.Se o ponteiro for nulo não quando CCmdTarget::ExternalQueryInterface é telefonar ed, a estrutura será automatitelefonary telefonar QueryInterface membro funcionar se o IID solicitada não é um do nativo IIDs com suporte a CCmdTarget objeto propriamente dito.
Para usar a macro INTERFACE_AGGREGATE
Declare uma variável de membro (um IUnknown *) que contém um ponteiro para o objeto agregado.
Incluir um INTERFACE_AGGREGATE macro em MAP de interface que se refere à variável de membro por nome.
Em algum momento (geralmente durante CCmdTarget::OnCreateAggregates), inicialize a variável de membro para algo Outros de nulo.
Por exemplo:
class CAggrExample : public CCmdTarget
{
public:
CAggrExample();
protected:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
// "native" interface part macros may be used here
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
// wire up aggregate with correct controlling unknown
m_lpAggrInner = CoCreateInstance(CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID*)&m_lpAggrInner);
if (m_lpAggrInner == NULL)
return FALSE;
// optionally, create other aggregate objects here
return TRUE;
}
BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
// native "INTERFACE_PART" entries go here
INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
The m_lpAggrInner é inicializada no construtor para nulo. A estrutura irá ignorar uma variável de membro nulo de implementação padrão de QueryInterface. OnCreateAggregates é um mercadoria lugar para realmente criar os objetos agregados.Você terá que telefonar-lo explicitamente se você estiver criando o objeto fora da implementação do MFCCOleObjectFactory. O motivo para criar agregações no CCmdTarget::OnCreateAggregates , bem sistema autônomo o uso de CCmdTarget::GetControllingUnknown se tornará aparente quando criar objetos agregáveis é discutido.
Essa técnica, terá seu objeto de todas as interfaces que o objeto agregado suporte além de suas interfaces nativas.Se você quiser apenas um subconjunto de interfaces que oferece suporte a agregação, você pode substituir CCmdTarget::GetInterfaceHook.Isso lhe permite hookability muito baixo nível, semelhante a QueryInterface. Normalmente, você quer todas as interfaces que oferece suporte à agregação.
Fazer uma implementação do objeto Aggregatable
Para um objeto a ser agregáveis, a implementação de AddRef, Versão, and QueryInterfacedeve delegado para "desconhecido controle". Em outras palavras, para que ela seja parte do objeto, ele deve delegado AddRef, Versão, and QueryInterface para um objeto diferente, também derivado de IUnknown.Este "controlar desconhecido" é fornecido para o objeto quando ele é criado, ou seja, ele é fornecido para a implementação doCOleObjectFactory. Implementar isso executa uma pequena quantidade de sobrecarga e em alguns casos não é desejável, modo MFC torna isso opcional.Para ativar um objeto a ser agregáveis, chame CCmdTarget::EnableAggregation do construtor do objeto.
Se o objeto também usa agregados, você deve também estar certo de passar o correto "controlar desconhecido" para os objetos agregados.Geralmente este IUnknown ponteiro é passado para o objeto quando a agregação é criada.Por exemplo, o parâmetro pUnkOuter é o "controle desconhecido" para objetos criados comCoCreateInstance. O ponteiro "Controlando desconhecido" correto pode ser recuperado chamandoCCmdTarget::GetControllingUnknown.O valor retornado da função, no entanto, inválido durante o construtor.Por esse motivo, é recomendável que você crie seus agregados somente em uma substituir de CCmdTarget::OnCreateAggregates, onde o retorno de valor de GetControllingUnknown é confiável, mesmo se criado a partir do COleObjectFactory implementação.
Também é importante que o objeto manipular a contagem de referência correto quando adicionando ou liberando contagens de referência artificial.Para garantir que isso seja o caso, sempre telefonar ExternalAddRef and ExternalRelease em vez de InternalRelease e InternalAddRef. É raro telefonar InternalRelease ou InternalAddRef em uma classe que oferece suporte à agregação.
Material de referência
Uso avançado de OLE, sistema autônomo definir suas próprias interfaces ou substituindo a implementação da estrutura das interfaces OLE requer o uso do mecanismo subjacente de MAP de interface.
Esta seção aborda cada macro e as APIs que são usadas para implementar esses recursos avançados.
CCmdTarget::EnableAggregation — Descrição da função
voidEnableAggregation();
Comentários
telefonar Essa função no construtor da classe derivada para suporte a agregação de OLE para objetos desse tipo.Esta opção prepara uma implementação IUnknown especial que é necessária para objetos agregáveis.
CCmdTarget::ExternalQueryInterface — Descrição da função
DWORDExternalQueryInterface(
constvoidFAR*lpIID,
LPVOIDFAR*ppvObj
);
Comentários
Parâmetros
lpIID
Um ponteiro oposto para um IID (o primeiro argumento de QueryInterface)ppvObj
Um ponteiro para um IUnknown * (segundo argumento para QueryInterface)
Comentários
telefonar Essa função na implementação do IUnknown para cada interface implementa sua classe.Essa função permite a implementação padrão orientados por dados de QueryInterface com base no MAP de interface do seu objeto.É necessário converter o valor retornado para um HRESULT.Se o objeto é agregado, essa função será telefonar "IUnknown controlador" em vez de usar o MAP da interface local.
CCmdTarget::ExternalAddRef — Descrição da função
DWORDExternalAddRef();
Comentários
telefonar Essa função na implementação do IUnknown::AddRef para cada interface implementa sua classe.O valor retornado é a nova contagem de referência no objeto CCmdTarget.Se o objeto é agregado, essa função será telefonar "IUnknown controlador" em vez de manipular a contagem de referência local.
CCmdTarget::ExternalRelease — Descrição da função
DWORD ExternalRelease();
Comentários
Chamar essa função em sua implementação de IUnknown::versão para cada interface de sua classe implementa.O valor retornado indica a nova contagem de referência no objeto.Se o objeto é agregado, essa função será telefonar "IUnknown controlador" em vez de manipular a contagem de referência local.
DECLARE_INTERFACE_MAP — Descrição da macro
DECLARE_INTERFACE_MAP
Comentários
Usar essa macro em qualquer classe derivada de CCmdTarget que terá um MAP de interface. Usado em grande parte da mesma forma sistema autônomo DECLARE_MESSAGE_MAP. Invocação essa macro deve ser colocada na definição de classe, geralmente em um arquivo de cabeçalho (.H).Uma classe com DECLARE_INTERFACE_MAP deverá definir o MAP de interface no arquivo de implementação (.CPP) com o BEGIN_INTERFACE_MAP e END_INTERFACE_MAP macros.
BEGIN_INTERFACE_PART e END_INTERFACE_PART — descrições de macro
BEGIN_INTERFACE_PART(
localClass,
iface
);
END_INTERFACE_PART(
localClass
)
Comentários
Parâmetros
localClass
O nome da classe que implementa a interfaceiface
O nome da interface que essa classe implementa
Comentários
Para cada interface que implementará sua classe, você precisa ter um BEGIN_INTERFACE_PART and END_INTERFACE_PART emparelhar.Essas macros definir uma classe local derivada da interface da OLE que você define, bem sistema autônomo uma variável de membro incorporado dessa classe.The AddRef, Versão, and QueryInterface os membros são declarados automaticamente. Você deve incluir as declarações para as outras funções de membro que fazem parte da interface que está sendo implementada (essas declarações são colocadas entre o BEGIN_INTERFACE_PART and END_INTERFACE_PART macros).
The iface argumento é a interface OLE que você deseja implementar o, por exemplo, IAdviseSink, or IPersistStorage (ou sua própria interface personalizada).
The localClass argumento é o nome da classe local que será definido.Um ' X ' automaticamente será ser anexado ao nome.Essa convenção de nomeclatura é usada para evitar colisões com classes global de mesmo nome.Além disso, o nome do membro incorporado, igual a localClass nome, exceto 'm_x' sistema autônomo prefixo.
Por exemplo:
BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange)(DWORD, LONG);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
define uma classe local chamada XMyAdviseSink derivado IAdviseSink e um membro da classe na qual é declarada chamado m_xMyAdviseSink.Note:
Observação: |
---|
As linhas que começam com STDMETHOD_ essencialmente são copiados do OLE2.H e ligeiramente modificado.Copiando-os de OLE2.H pode reduzir os erros que são difíceis de resolver. |
BEGIN_INTERFACE_MAP e END_INTERFACE_MAP — descrições de macro
BEGIN_INTERFACE_MAP(
theClass,
baseClass
)END_INTERFACE_MAP
Comentários
Parâmetros
theClass
A classe na qual o MAP de interface é a serem definidasbaseClass
A classe da qual theClass deriva.
Comentários
The BEGIN_INTERFACE_MAP e END_INTERFACE_MAP as macros são usadas no arquivo de implementação para definir, na verdade, o MAP de interface. Para cada interface implementada, há um ou mais INTERFACE_PART invocações de macro. Para cada função agregada que usa a classe, há um INTERFACE_AGGREGATE macro chamada.
INTERFACE_PART — Descrição da macro
INTERFACE_PART(
theClass,
iid,
localClass
)
Comentários
Parâmetros
theClass
O nome da classe que contém o MAP de interface.iid
The IID que deve ser mapeado para a classe incorporada.localClass
O nome da classe local (menos 'X').
Comentários
Essa macro é usada entre o BEGIN_INTERFACE_MAP macro e o END_INTERFACE_MAP macro para cada interface que oferecerá suporte a seu objeto. Ele permite que você MAP um IID a um membro da classe indicada por theClass e localClass.'m_x' será adicionado ao localClass automaticamente.Observe que mais de um IID pode ser associado a um único membro.Isso é muito útil quando você estiver implementando somente uma interface "mais derivados" e deseja fornecer todas sistema autônomo interfaces intermediárias.Um mercadoria exemplo disso é o IOleInPlaceFrameWindow interface.Sua hierarquia tem esta aparência:
IUnknown
IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
Se um objeto implementa IOleInPlaceFrameWindow, um cliente pode QueryInterface em qualquer dessas interfaces: IOleUIWindow, IOleWindow, or IUnknown, além da interface "mais derivada" IOleInPlaceFrameWindow (o realmente estiver implementando um).Para lidar com isso, você pode usar mais de um INTERFACE_PART macro mapear cada interface base para o IOleInPlaceFrameWindow interface:
no arquivo de definição de classe:
BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)
no arquivo de implementação da classe:
BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
A estrutura se encarrega de IUnknown porque sempre é necessária.
INTERFACE_PART — Descrição da macro
INTERFACE_AGGREGATE(
theClass,
theAggr
)
Comentários
Parâmetros
theClass
O nome da classe que contém o MAP de interfacetheAggr
O nome da variável membro a ser agregados.
Comentários
Essa macro é usada para informar a estrutura que a classe está usando um objeto agregado.Deve ser exibido entre o BEGIN_INTERFACE_PART and END_INTERFACE_PART macros.Um objeto agregado é um objeto separado, derivado de IUnknown.Usando um agregado e o INTERFACE_AGGREGATE macro, você pode fazer todas as interfaces que o suporta agregação parece ser diretamente suportado pelo objeto.The theAggr argumento é simplesmente o nome de uma variável de membro de sua classe que é derivada de IUnknown (direta ou indiretamente).All INTERFACE_AGGREGATE macros devem seguir o INTERFACE_PART macros quando colocados em um MAP de interface.