IUnknown


IUnknown

All COM objects must implement the IUnknown interface. Any object that implements this interface must implement the functions shown below.
Todos los objetos COM deben implementar la interface IUnknown. Cualquier objeto que implemente esta interface debe implementar las funciones que se muestran debajo.

IUnknown.h
class IUnknown
{
public:
     virtual HRESULT STDMETHODCALLTYPE QueryInterface(
          REFIID riid, // [in]
          __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) = 0; // [iid_is][out]
     virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
     virtual ULONG STDMETHODCALLTYPE Release() = 0;
};


AddRef

AddRef and Release are use to control the life time of an object. The first time AddRef is called, an internal counter (an integer value) is set to one, and the object is created. Every time AddRef is called, the internal counter value is incremented in one, and the function returns the number of objects that are currently using the interface. The AddRef function prevent that an object be prematurely destroyed. See the files Product.h and Product.cpp that illustrates how to implement the IUnknown interface.
AddRef y Release son usadas para controlar el tiempo de vida de un objeto. La primera vez que AddRef es llamado, un contador (un valor del tipo entero) se fija en uno, y el objeto se crea. Cada vez que AddRef se llama, el valor del contador interno se incrementa en uno, y la función regresa el número de objetos que están usando la interface. La función AddRef evita que un objeto se destruya prematuramente. Vea los archivos Product.h y Product.cpp que ilustran como implementar la interface IUnknown.

Release

When a program does not need an interface anymore, it calls the Release function. Every time Release is called, the internal counter value is decrement by one, and the function returns the number of objects that are using the interface. When this value reaches zero the object destroys itself. A typical error is forgetting to call the Release function. When using smart pointers, you do have to worry about calling Release, because this function is automatically called.
Cuando un programa ya no necesita una interface manda llamar la función Release. Cada vez que se llama Release, el valor del contador interno se disminuye en uno, y la función regresa el número de objetos que están usando la interface. Cuando este valor llega a cero el objeto se destruya así mismo. Cuando se usan los punteros inteligentes, usted no tiene que preocuparse por llamar la función Release, ya que ésta es llamada automáticamente.

QueryInterface

QueryInterface is used to request an interface (set of functions) to the object. If the object implements the interface, it returns a pointer to the interface and a value of S_OK is also returned. If the object does not implement the interface, it returns a NULL pointer and a value of E_NOINTERFACE. QueryInterface calls internally AddRef to know that other object is using its object interface. When the other object does not need the interface, it must call Release.
QueryInterface es usada para solicitar una interface (grupo de funciones) al objeto. Si el objeto implementa la interface, este regresa un puntero a la interface y un valor de S_OK es también devuelto. Si el objeto no implementa la interface, este regresa un puntero NULL y un valor de E_NOINTERFACE. QueryInterface llama internamente AddRef para saber que otro objeto está usando su interface. Cuando el otro objeto ya no necesita la interface, este debe llamar Release.

Product.h
class Product : public IUnknown
{
public:
     Product();
     ~Product();
     //_______________________________ IUnknown
     STDMETHOD (QueryInterface) (REFIID iid, void**ppvObject);
     STDMETHOD_(ULONG, AddRef) ();
     STDMETHOD_(ULONG, Release) ();
     //
     unsigned int refCount;
};


Product.cpp
//_____________________________________________________________ IUnknown
STDMETHODIMP_ (ULONG) Product::AddRef()
{     
     if (refCount == 0)
     {
          this = new Product;
     }
     refCount++;
     return refCount;
}

STDMETHODIMP Product::QueryInterface(REFIID iid, void** ppvObject)
{
     *ppvObject = NULL;

     if (iid == IID_IOleClientSite) *ppvObject = (IOleClientSite*)this;
     else if (iid == IID_IUnknown) *ppvObject = (IUnknown*)(IDispatch*)this;
     else if (iid == IID_IOleWindow) *ppvObject = (IOleWindow*)(IOleInPlaceSiteWindowless*)this;
     else if (iid == IID_IAdviseSink) *ppvObject = (IAdviseSink*)this;
     else if (iid == IID_IDispatch) *ppvObject = (IDispatch*)this;
     else if (iid == IID_IServiceProvider) *ppvObject = (IServiceProvider*)this;
     else if (iid == IID_IOleControlSite) *ppvObject = (IOleControlSite*)this;
     else if (iid == IID_IOleInPlaceSite) *ppvObject = (IOleInPlaceSite*)this;
     else if (iid == IID_IOleInPlaceSiteEx) *ppvObject = (IOleInPlaceSiteEx*)this;
     else if (iid == IID_IOleInPlaceSiteWindowless) *ppvObject = (IOleInPlaceSiteWindowless*)this;
     //
     else if (iid == IID_IOleInPlaceFrame) *ppvObject = (IOleInPlaceFrame*)this;
     else if (iid == IID_IOleInPlaceUIWindow) *ppvObject = (IOleInPlaceUIWindow*)this;
     else if (iid == IID_IOleContainer) *ppvObject = (IOleContainer*)this;
     else if (iid == IID_IParseDisplayName) *ppvObject = (IParseDisplayName*)this;
     else if (iid == IID_IBindHost) *ppvObject = (IBindHost*)this;

     if (*ppvObject)
     {
          AddRef();
          return S_OK;
     }
     return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG)Product::Release()
{
      if (--refCount==0)
      {
           delete this;
           return 0;
      }
      return refCount;
}


Tip
Because smart pointers can be used to simplify pointers in COM, in some cases, programmers do not need to know about the functions: AddRef, Release and QueryInterface. The code below shows how to declare an IUnknown smart pointer. Basically, the word Ptr is appended at the end of the interface name as shown in the code.
Debido a que los punteros inteligentes pueden ser usados para simplificar los punteros en COM, en algunos casos, los programadores no necesitan tener conocimiento de las funciones: AddRef, Release y QueryInterface. El código de abajo muestra como declarar un puntero inteligente para la interface IUnknown. Básicamente se le concatena la final de la interface la palabra Ptr como se ilustra en el código.

Program.cpp
// A smart pointer is declared by appending Ptr to the name of the interface
void Program::Window_Open(Win::Event& e)
{
     ::CoInitialize(NULL);
     IUnknownPtr p = NULL;
     // __________________ Do something with the pointer



     p = NULL;
     //__________________ Be sure to set the pointer to NULL before calling ::CoUninitialize
     ::CoUninitialize();
}


Tip
If you put the CoInitialize function in the constructor of the class, and the CoUninitialize function in the destructor of the class, you do need to set the pointer to NULL before the function completes as shown below.
Si usted coloca la función CoInitialize en el constructor de una clase, y la función CoUninitialize en el destructor de una clase, usted no necesita fijar el puntero a NULL antes de que la función complete como se muestra debajo.

Program.cpp
void Program::Program()
{
     ::CoInitialize(NULL);
}

void Program::Window_Open(Win::Event& e)
{

     IUnknownPtr p = NULL;


}

void Program::~Program()
{
     ::CoUninitialize();
}


Tip
Smart pointers hide the function QueryInterface of the IUnkown interface inside the casting operator of the class. The code shown below illustrates how to get an ITypeInfo interface using smart pointers.
Los punteros inteligentes esconden la función QueryInterface de la interface IUnknown dentro del operador de conversión de la clase. El código de abajo muestra cómo conseguir una interface ITypeInfo usando un puntero inteligente.

Program.cpp
void Program::Program()
{
     ::CoInitialize(NULL);
}

void Program::Window_Open(Win::Event& e)
{
     try
     {
          IUnknownPtr Application;
          Application.CreateInstance(L"Word.Application");
          //
          ITypeInfoPtr typeInfo = Application; // QueryInterface is called internally
          //__________________ Do something with the typeInfo interface

     }
     catch(...)
     {
     }
}

void Program::~Program()
{
     ::CoUninitialize();
}


Tip
It is always a good idea to use a try-catch block to catch any exception that the code may produce. For instance, if the object does not support the ITypeInfo interface, an exception will be thrown crashing the program.
Siempre es una buena idea usar un bloque try-catch para capturar cualquier excepción que el código pueda producir. Por ejemplo, si el objeto no ofrece la interface ITypeInfo, una excepción se aventará haciendo que el programa se salga con un error grave.

Tip
You must remember that an interface is a set of functions (skills), therefore when an interface is requested using QueryInterface , the programmer is requesting a set of functions that are going to be used.
Hay que recordar que una interface es una colección de funciones (habilidades) y por lo tanto cuando se solicita una interface usando QueryInterface se está solicitando una colección de funciones con la esperanza de mandarlas llamar.

Tip
For instance, if cooking is needed the QueryInterface function is called requesting the IChef interface. If QueryInterface returns S_OK, then it is possible to call any function that IChef has. If the QueryInterface returns E_NOINTERFACE, then we should try to request another interface.
Por ejemplo si desea cocinar se debe mandar llamar QueryInterface solicitando la interface IChef. Si QueryInterface regresa S_OK entonces se pueden llamar todas las funciones que implemente la interface IChef. Si QueryInterface regresa E_NOINTERFACE entonces se debe intentar solicitar otra interface.

Tip
The advantage of IUnknown is that it offers great flexibility in the future without any restriction. For instance, in future versions of piece of software it is possible to request interfaces that were not previously implemented. However, it is possible to implement these interfaces later, thus some interface that returned E_NOINTERFACE when resquested using QueryInterface, may now return S_OK.
La ventaja de IUnknown es que ofrece mucha flexibilidad hacia el futuro sin restricciones. Por ejemplo, en versiones futuras de una pieza de software se pueden solicitar interfaces que aún no están implementadas. Sin embargo, es posible implementar estas interfaces posteriormente así que interfaces que previamente al llamar QueryInterface regresaban E_NOINTERFACE ahora pueden regresar S_OK.

© Copyright 2000-2021 Wintempla selo. All Rights Reserved. Jul 22 2021. Home