Editar

Compartir a través de


Preguntas más frecuentes sobre contención de controles ATL

¿Qué clases ATL facilitan la contención de controles ActiveX?

El código de hospedaje de controles de ATL no requiere que se usen clases ATL; simplemente puede crear una ventana "AtlAxWin80" y usar la API de hospedaje de controles si es necesario (para obtener más información, consulte ¿Qué es la API de hospedaje de controles ATL?. Pero las siguientes clases facilitan el uso de las características de independencia.

Clase Descripción
CAxWindow Ajusta una ventana "AtlAxWin80", proporcionando métodos para crear la ventana, crear un control o adjuntar un control a la ventana y recuperar punteros de interfaz en el objeto host.
CAxWindow2T Ajusta una ventana "AtlAxWinLic80", proporcionando métodos para crear la ventana, crear un control o adjuntar un control con licencia a la ventana y recuperar punteros de interfaz en el objeto host.
CComCompositeControl Actúa como una clase base para las clases de control ActiveX basadas en un recurso de diálogo. Estos controles pueden contener otros controles ActiveX.
CAxDialogImpl Actúa como una clase base para las clases de diálogo basadas en un recurso de diálogo. Estos diálogos pueden contener controles ActiveX.
CWindow Proporciona un método, GetDlgControl, que devolverá un puntero de interfaz en un control, dado el id. de su ventana host. Además, los contenedores de la API de Windows expuestos por CWindow normalmente facilitan la administración de ventanas.

¿Qué es la API de hospedaje de controles ATL?

La API de hospedaje de controles de ATL es el conjunto de funciones que permite que cualquier ventana actúe como un contenedor de control ActiveX. Estas funciones se pueden vincular al proyecto de forma estática o dinámica, ya que están disponibles como código fuente y expuestas por ATL90.dll. Las funciones de hospedaje de controles se enumeran en la tabla siguiente.

Función Descripción
AtlAxAttachControl Crea un objeto host, lo conecta a la ventana proporcionada y, después, adjunta un control existente.
AtlAxCreateControl Crea un objeto host, lo conecta a la ventana proporcionada y, después, carga un control.
AtlAxCreateControlLic Crea un control ActiveX con licencia, lo inicializa y lo hospeda en la ventana especificada, igual que AtlAxCreateControl.
AtlAxCreateControlEx Crea un objeto host, lo conecta a la ventana proporcionada y, después, carga un control (también permite configurar receptores de eventos).
AtlAxCreateControlLicEx Crea un control ActiveX con licencia, lo inicializa y lo hospeda en la ventana especificada, igual que AtlAxCreateControlLic.
AtlAxCreateDialog Crea un cuadro de diálogo sin modelo a partir de un recurso de diálogo y devuelve el manipulador de ventana.
AtlAxDialogBox Crea un cuadro de diálogo modal a partir de un recurso de diálogo.
AtlAxGetControl Devuelve el puntero de interfaz IUnknown del control hospedado en una ventana.
AtlAxGetHost Devuelve el puntero de interfaz IUnknown del objeto host conectado a una ventana.
AtlAxWinInit Inicializa el código de hospedaje de controles.
AtlAxWinTerm Anula la inicialización del código de hospedaje de controles.

Los parámetros HWND de las tres primeras funciones deben ser una ventana existente de (casi) cualquier tipo. Si llama explícitamente a cualquiera de estas tres funciones (normalmente, no tendrá que hacerlo), no pase un manipulador a una ventana que ya actúe como host (si lo hace, el objeto host existente no se liberará).

Las siete primeras funciones llaman a AtlAxWinInit de forma implícita.

Nota:

La API de hospedaje de controles constituye la base de la compatibilidad de ATL con la independencia de control ActiveX. Pero no suele ser necesario llamar a estas funciones directamente si se aprovechan o se usan las clases contenedoras de ATL por completo. Para obtener más información, consulte ¿Qué clases ATL facilitan la contención de control ActiveX?

¿Qué es AtlAxWin100?

AtlAxWin100 es el nombre de una clase de ventana que ayuda a proporcionar la funcionalidad de hospedaje de controles de ATL. Al crear una instancia de esta clase, el procedimiento de ventana usará de forma automática la API de hospedaje de controles para crear un objeto host asociado a la ventana y cargarlo con el control que especifique como título de la ventana.

¿Cuándo es necesario llamar a AtlAxWinInit?

AtlAxWinInit registra la clase de ventana "AtlAxWin80" (más un par de mensajes de ventana personalizados), por lo que se debe llamar a esta función antes de intentar crear una ventana host. Pero no siempre es necesario llamar explícitamente a esta función, ya que las API de hospedaje (y las clases que las usan) suelen llamar a esta función de forma automática. No pasa nada si llama a esta función más de una vez.

¿Qué es un objeto host?

Un objeto host es un objeto COM que representa el contenedor de control ActiveX proporcionado por ATL para una ventana determinada. El objeto host baja la clase de la ventana contenedora para que pueda reflejar los mensajes en el control, proporciona las interfaces de contenedor necesarias que usará el control y expone las interfaces IAxWinHostWindow e IAxWinAmbientDispatch para permitirle configurar el entorno del control.

Puede usar el objeto host para establecer las propiedades ambientales del contenedor.

¿Puedo hospedar más de un control en una única ventana?

No es posible hospedar más de un control en una sola ventana host ATL. Cada ventana host está diseñada para contener exactamente un control a la vez (esto permite un mecanismo sencillo para controlar la reflexión de mensajes y las propiedades ambientales por control). Pero si necesita que el usuario vea varios controles en una sola ventana, crear varias ventanas host como elementos secundarios de esa ventana es muy sencillo.

¿Puedo volver a usar una ventana host?

No se recomienda reusar las ventanas host. Para garantizar la solidez del código, debe vincular la duración de la ventana del host a la duración de un solo control.

¿Cuándo es necesario llamar a AtlAxWinTerm?

AtlAxWinTerm anula el registro de la clase de ventana "AtlAxWin80". Debe llamar a esta función (si ya no necesita crear ventanas host) después de que se hayan destruido todas las ventanas host existentes. Si no llama a esta función, se anulará automáticamente el registro de la clase de ventana cuando finalice el proceso.

Hospedaje de controles ActiveX mediante ATL AXHost

En el ejemplo de esta sección se muestra cómo crear AXHost y cómo hospedar un control ActiveX mediante varias funciones ATL. También se muestra cómo acceder a los eventos de control y receptor (mediante IDispEventImpl) desde el control hospedado. El ejemplo hospeda el control Calendar en una ventana principal o en una ventana secundaria.

Observe la definición del símbolo USE_METHOD. Puede cambiar el valor de este símbolo para que varíe entre 1 y 8. El valor del símbolo determina cómo se creará el control:

  • Para los valores de número par de USE_METHOD, la llamada para crear el host baja de clase a una ventana y la convierte en un host de control. En el caso de los valores impares, el código crea una ventana secundaria que actúa como host.

  • Para los valores de USE_METHOD entre 1 y 4, el acceso al control y al receptor de eventos se realiza en la llamada que también crea el host. Los valores entre 5 y 8 consultan al host para las interfaces y enlazan el receptor.

A continuación, se muestra un resumen:

USE_METHOD Host Control del acceso y del receptor de eventos Función demostrada
1 Ventana secundaria Un paso CreateControlLicEx
2 Ventana principal Un paso AtlAxCreateControlLicEx
3 Ventana secundaria Un paso CreateControlEx
4 Ventana principal Un paso AtlAxCreateControlEx
5 Ventana secundaria Varios pasos CreateControlLic
6 Ventana principal Varios pasos AtlAxCreateControlLic
7 Ventana secundaria Varios pasos CreateControl
8 Ventana principal Varios pasos AtlAxCreateControl
// Your project must be apartment threaded or the (AtlAx)CreateControl(Lic)(Ex)
// calls will fail.
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
#include <atlwin.h>
#include <atlhost.h>

// Value of g_UseMethod determines the function used to create the control.
int g_UseMethod = 0; // 1 to 8 are valid values
bool ValidateUseMethod() { return (1 <= g_UseMethod) && (g_UseMethod <= 8); }

#import "PROGID:MSCAL.Calendar.7" no_namespace, raw_interfaces_only

// Child window class that will be subclassed for hosting Active X control
class CChildWindow : public CWindowImpl<CChildWindow>
{
public:
   BEGIN_MSG_MAP(CChildWindow)
   END_MSG_MAP()
};

class CMainWindow : public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>,
   public IDispEventImpl<1, CMainWindow, &__uuidof(DCalendarEvents), &__uuidof(__MSACAL), 7, 0>
{
public :

   CChildWindow m_wndChild;
   CAxWindow2 m_axwnd;
   CWindow m_wndEdit;

   static ATL::CWndClassInfo& GetWndClassInfo()
   {
      static ATL::CWndClassInfo wc =
      {
         { 
            sizeof(WNDCLASSEX), 
            CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, 
            StartWindowProc,
            0, 0, NULL, NULL, NULL, 
            (HBRUSH)(COLOR_WINDOW + 1), 
            0, 
            _T("MainWindow"), 
            NULL 
         },
         NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
      };
      return wc;
   }
   
   BEGIN_MSG_MAP(CMainWindow)
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
   END_MSG_MAP()

   BEGIN_SINK_MAP(CMainWindow)
      SINK_ENTRY_EX(1, __uuidof(DCalendarEvents), DISPID_CLICK, OnClick)
   END_SINK_MAP()

   // Helper to display events
   void DisplayNotification(TCHAR* pszMessage)
   {
      CWindow wnd;
      wnd.Attach(GetDlgItem(2));
      
      wnd.SendMessage(EM_SETSEL, (WPARAM)-1, -1);
      wnd.SendMessage(EM_REPLACESEL, 0, (LPARAM)pszMessage);
   }
   
   // Event Handler for Click
   STDMETHOD(OnClick)()
   {
      DisplayNotification(_T("OnClick\r\n"));
      return S_OK;
   }

   LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
   {
      HRESULT hr = E_INVALIDARG;

      _pAtlModule->Lock();

      RECT rect;
      GetClientRect(&rect);
      
      RECT rect2;
      rect2 = rect;
      
      rect2.bottom -=200;
      
      // if g_UseMethod is odd then create AxHost directly as the child of the main window
      if (g_UseMethod & 0x1) 
      {
         m_axwnd.Create(m_hWnd, rect2, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 1);
      }
      // if g_UseMethod is even then the AtlAx version is invoked.
      else
      {
         // Create a child window.
         // AtlAx functions will subclass this window.
         m_wndChild.Create(m_hWnd, rect2, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 1);
         // Attach the child window to the CAxWindow so we can access the 
         // host that subclasses the child window.
         m_axwnd.Attach(m_wndChild);
      }

      if (m_axwnd.m_hWnd != NULL)
      {
         CComPtr<IUnknown> spControl;

         // The calls to (AtlAx)CreateControl(Lic)(Ex) do the following:
         // Create Calendar control. (Passing in NULL for license key. 
         //   Pass in valid license key to the Lic functions if the 
         //   control requires one.)
         // Get the IUnknown pointer for the control.
         // Sink events from the control.
         
         // The AtlAx versions subclass the hWnd that is passed in to them 
         //   to implement the host functionality.

         // The first 4 calls accomplish it in one call.
         // The last 4 calls accomplish it using multiple steps.

         switch (g_UseMethod)
         {
            case 1:
            {
               hr = m_axwnd.CreateControlLicEx(
                  OLESTR("MSCAL.Calendar.7"), 
                  NULL, 
                  NULL, 
                  &spControl, 
                  __uuidof(DCalendarEvents), 
                  (IUnknown*)(IDispEventImpl<1, CMainWindow, 
                     &__uuidof(DCalendarEvents), &__uuidof(__MSACAL), 7, 0>*)this
               );
               break;
            }
            case 2:
            {
               hr = AtlAxCreateControlLicEx(
                  OLESTR("MSCAL.Calendar.7"), 
                  m_wndChild.m_hWnd, 
                  NULL, 
                  NULL, 
                  &spControl, 
                  __uuidof(DCalendarEvents), 
                  (IUnknown*)(IDispEventImpl<1, CMainWindow, 
                     &__uuidof(DCalendarEvents), &__uuidof(__MSACAL), 7, 0>*)this, 
                  NULL
               );
               break;
            }
            case 3:
            {
               hr = m_axwnd.CreateControlEx(
                  OLESTR("MSCAL.Calendar.7"), 
                  NULL, 
                  NULL, 
                  &spControl, 
                  __uuidof(DCalendarEvents), 
                  (IUnknown*)(IDispEventImpl<1, CMainWindow, 
                     &__uuidof(DCalendarEvents), &__uuidof(__MSACAL), 7, 0>*)this
               );
               break;
            }
            case 4:
            {
               hr = AtlAxCreateControlEx(
                  OLESTR("MSCAL.Calendar.7"), 
                  m_wndChild.m_hWnd, 
                  NULL, 
                  NULL, 
                  &spControl, 
                  __uuidof(DCalendarEvents), 
                  (IUnknown*)(IDispEventImpl<1, CMainWindow, 
                     &__uuidof(DCalendarEvents), &__uuidof(__MSACAL), 7, 0>*)this
               );
               break;
            }
            // The following calls create the control, obtain an interface to 
            // the control, and set up the sink in multiple steps.
            case 5:
            {
               hr = m_axwnd.CreateControlLic(
                  OLESTR("MSCAL.Calendar.7")
               );
               break;
            }
            case 6:
            {
               hr = AtlAxCreateControlLic(
                  OLESTR("MSCAL.Calendar.7"), 
                  m_wndChild.m_hWnd, 
                  NULL, 
                  NULL
               );
               break;
            }
            case 7:
            {
               hr = m_axwnd.CreateControl(
                  OLESTR("MSCAL.Calendar.7")
               );
               break;
            }
            case 8:
            {
               hr = AtlAxCreateControl(
                  OLESTR("MSCAL.Calendar.7"), 
                  m_wndChild.m_hWnd , 
                  NULL, 
                  NULL
               );
               break;
            }
         }

         // have to obtain an interface to the control and set up the sink
         if (g_UseMethod > 4)
         {
            if (SUCCEEDED(hr))
            {
               hr = m_axwnd.QueryControl(&spControl);
               if (SUCCEEDED(hr))
               {
                  // Sink events form the control
                  DispEventAdvise(spControl, &__uuidof(DCalendarEvents));
               }
            }
         }

         if (SUCCEEDED(hr))
         {
            // Use the returned IUnknown pointer.
            CComPtr<ICalendar> spCalendar;
            hr = spControl.QueryInterface(&spCalendar);
            if (SUCCEEDED(hr))
            {
               spCalendar->put_ShowDateSelectors(VARIANT_FALSE);
            }
         }
      }

      rect2 = rect;
      rect2.top = rect.bottom - 200 + 1;
      m_wndEdit.Create(_T("Edit"), m_hWnd, rect2, NULL, WS_CHILD | WS_VISIBLE | 
         WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0, 2);
      return 0;
   }

   LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL&)
   {
      _pAtlModule->Unlock();
      return 0;
   }
};

class CHostActiveXModule : public CAtlExeModuleT<CHostActiveXModule>
{
public :

   CMainWindow m_wndMain;

   // Create the Main window
   HRESULT PreMessageLoop(int nCmdShow)
   {
      HRESULT hr = CAtlExeModuleT<CHostActiveXModule>::PreMessageLoop(nCmdShow);
      if (SUCCEEDED(hr))
      {
         AtlAxWinInit();
         hr = S_OK;
         RECT rc;
         rc.top = rc.left = 100;
         rc.bottom = rc.right = 500;
         m_wndMain.Create(NULL, rc, _T("Host Calendar") );
         m_wndMain.ShowWindow(nCmdShow);         
      }
      return hr;
   }

   // Clean up. App is exiting.
   HRESULT PostMessageLoop()
   {
      AtlAxWinTerm();
      return CAtlExeModuleT<CHostActiveXModule>::PostMessageLoop();
   }
};

CHostActiveXModule _AtlModule;

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
   UNREFERENCED_PARAMETER(hInstance);
   UNREFERENCED_PARAMETER(hPrevInstance);

   g_UseMethod = _ttoi(lpCmdLine);

   if (ValidateUseMethod())
   {
      return _AtlModule.WinMain(nCmdShow);
   }
   else
   {
      return E_INVALIDARG;   
   }
}