Édition

Partage via


FAQ sur la relation contenant-contenu des contrôles ATL

Quelles sont les classes ATL qui facilitent la contenance de contrôles ActiveX ?

Le code d’hébergement de contrôle d’ATL ne vous oblige pas à utiliser de classes ATL ; Vous pouvez simplement créer une fenêtre « AtlAxWin80 » et utiliser l’API d’hébergement de contrôle si nécessaire (pour plus d’informations, consultez l’API ATL Control-Hosting. Toutefois, les classes suivantes facilitent l’utilisation des fonctionnalités de confinement.

Classe Description
CAxWindow Encapsule une fenêtre « AtlAxWin80 », fournissant des méthodes pour créer la fenêtre, créer un contrôle et/ou attacher un contrôle à la fenêtre et récupérer des pointeurs d’interface sur l’objet hôte.
CAxWindow2T Encapsule une fenêtre « AtlAxWinLic80 », fournissant des méthodes pour créer la fenêtre, créer un contrôle et/ou attacher un contrôle sous licence à la fenêtre et récupérer des pointeurs d’interface sur l’objet hôte.
CComCompositeControl Agit en tant que classe de base pour les classes de contrôle ActiveX basées sur une ressource de dialogue. Ces contrôles peuvent contenir d’autres contrôles ActiveX.
CAxDialogImpl Agit en tant que classe de base pour les classes de dialogue basées sur une ressource de dialogue. Ces dialogues peuvent contenir des contrôles ActiveX.
CWindow Fournit une méthode, GetDlgControl, qui retourne un pointeur d’interface sur un contrôle, en fonction de l’ID de sa fenêtre hôte. En outre, les wrappers d’API Windows exposés en CWindow général facilitent la gestion des fenêtres.

Qu’est-ce que l’API d’hébergement de contrôle ATL ?

L’API d’hébergement de contrôle d’ATL est l’ensemble de fonctions qui permet à n’importe quelle fenêtre d’agir en tant que conteneur de contrôle ActiveX. Ces fonctions peuvent être liées de manière statique ou dynamique à votre projet, car elles sont disponibles en tant que code source et exposées par ATL90.dll. Les fonctions d’hébergement de contrôle sont répertoriées dans le tableau ci-dessous.

Fonction Description
AtlAxAttachControl Crée un objet hôte, le connecte à la fenêtre fournie, puis attache un contrôle existant.
AtlAxCreateControl Crée un objet hôte, le connecte à la fenêtre fournie, puis charge un contrôle.
AtlAxCreateControlLic Crée un contrôle ActiveX sous licence, l’initialise et l’héberge dans la fenêtre spécifiée, comme AtlAxCreateControl.
AtlAxCreateControlEx Crée un objet hôte, le connecte à la fenêtre fournie, puis charge un contrôle (autorise également la configuration des récepteurs d’événements).
AtlAxCreateControlLicEx Crée un contrôle ActiveX sous licence, l’initialise et l’héberge dans la fenêtre spécifiée, comme AtlAxCreateControlLic.
AtlAxCreateDialog Crée une boîte de dialogue sans mode à partir d’une ressource de boîte de dialogue et retourne le handle de fenêtre.
AtlAxDialogBox Crée une boîte de dialogue modale à partir d’une ressource de dialogue.
AtlAxGetControl Retourne le pointeur d’interface IUnknown du contrôle hébergé dans une fenêtre.
AtlAxGetHost Retourne le pointeur d’interface IUnknown de l’objet hôte connecté à une fenêtre.
AtlAxWinInit Initialise le code d’hébergement de contrôle.
AtlAxWinTerm Annule l’initialisation du code d’hébergement de contrôle.

Les HWND paramètres des trois premières fonctions doivent être une fenêtre existante de (presque) n’importe quel type. Si vous appelez l’une de ces trois fonctions explicitement (généralement, vous n’aurez pas besoin de passer un handle à une fenêtre qui agit déjà en tant qu’hôte (si vous le faites, l’objet hôte existant ne sera pas libéré).

Les sept premières fonctions appellent implicitement AtlAxWinInit .

Remarque

L’API d’hébergement de contrôle constitue la base de la prise en charge d’ATL pour l’endiguement du contrôle ActiveX. Toutefois, il est généralement peu nécessaire d’appeler ces fonctions directement si vous tirez parti ou utilisez pleinement les classes wrapper d’ATL. Pour plus d’informations, consultez les classes ATL qui facilitent l’endiguement du contrôle ActiveX.

Qu’est-ce que AtlAxWin100 ?

AtlAxWin100 est le nom d’une classe de fenêtre qui permet de fournir la fonctionnalité d’hébergement de contrôle d’ATL. Lorsque vous créez une instance de cette classe, la procédure de fenêtre utilise automatiquement l’API d’hébergement de contrôle pour créer un objet hôte associé à la fenêtre et le charger avec le contrôle que vous spécifiez comme titre de la fenêtre.

Quand dois-je appeler AtlAxWinInit ?

AtlAxWinInit inscrit la classe de fenêtre « AtlAxWin80 » (plus quelques messages de fenêtre personnalisés) afin que cette fonction soit appelée avant d’essayer de créer une fenêtre hôte. Toutefois, vous n’avez pas toujours besoin d’appeler cette fonction explicitement, car les API d’hébergement (et les classes qui les utilisent) appellent souvent cette fonction pour vous. Il n’y a pas de mal à appeler cette fonction plusieurs fois.

Qu’est-ce qu’un objet hôte ?

Un objet hôte est un objet COM qui représente le conteneur de contrôle ActiveX fourni par ATL pour une fenêtre particulière. L’objet hôte sous-classe la fenêtre de conteneur afin qu’elle puisse refléter les messages au contrôle, elle fournit les interfaces conteneur nécessaires à utiliser par le contrôle et expose les interfaces IAxWinHostWindow et IAxWinAmbientDispatch pour vous permettre de configurer l’environnement du contrôle.

Vous pouvez utiliser l’objet hôte pour définir les propriétés ambiantes du conteneur.

Puis-je héberger plusieurs contrôles dans une seule fenêtre ?

Il n’est pas possible d’héberger plusieurs contrôles dans une seule fenêtre hôte ATL. Chaque fenêtre hôte est conçue pour contenir exactement un contrôle à la fois (cela permet un mécanisme simple pour gérer la réflexion des messages et les propriétés ambiantes par contrôle). Toutefois, si vous avez besoin de l’utilisateur pour voir plusieurs contrôles dans une seule fenêtre, il est simple de créer plusieurs fenêtres hôtes en tant qu’enfants de cette fenêtre.

Puis-je réutiliser une fenêtre hôte ?

Il n’est pas recommandé de réutiliser les fenêtres hôtes. Pour garantir la robustesse de votre code, vous devez lier la durée de vie de votre fenêtre hôte à la durée de vie d’un seul contrôle.

Quand dois-je appeler AtlAxWinTerm ?

AtlAxWinTerm annule l’inscription de la classe de fenêtre « AtlAxWin80 ». Vous devez appeler cette fonction (si vous n’avez plus besoin de créer des fenêtres hôtes) une fois que toutes les fenêtres hôtes existantes ont été détruites. Si vous n’appelez pas cette fonction, la classe de fenêtre est annulée automatiquement lorsque le processus se termine.

Hébergement de contrôles ActiveX à l’aide d’ATL AXHost

L’exemple de cette section montre comment créer AXHost et comment héberger un contrôle ActiveX à l’aide de différentes fonctions ATL. Il montre également comment accéder aux événements de contrôle et de récepteur (à l’aide d’IDispEventImpl) à partir du contrôle hébergé. L’exemple héberge le contrôle Calendar dans une fenêtre principale ou dans une fenêtre enfant.

Notez la définition du USE_METHOD symbole. Vous pouvez modifier la valeur de ce symbole pour varier entre 1 et 8. La valeur du symbole détermine la façon dont le contrôle sera créé :

  • Pour les valeurs paires de USE_METHOD, l’appel pour créer la sous-classe hôte une fenêtre et le convertit en hôte de contrôle. Pour les valeurs impaires, le code crée une fenêtre enfant qui agit en tant qu’hôte.

  • Pour les valeurs comprises USE_METHOD entre 1 et 4, l’accès au contrôle et au récepteur des événements est effectué dans l’appel qui crée également l’hôte. Les valeurs comprises entre 5 et 8 interrogent l’hôte pour les interfaces et raccordent le récepteur.

Voici un résumé :

USE_METHOD Host Contrôler l’accès et le récepteur d’événements Fonction illustrée
1 Fenêtre enfant Une étape CreateControlLicEx
2 Fenêtre principale Une étape AtlAxCreateControlLicEx
3 Fenêtre enfant Une étape CreateControlEx
4 Fenêtre principale Une étape AtlAxCreateControlEx
5 Fenêtre enfant Plusieurs étapes CreateControlLic
6 Fenêtre principale Plusieurs étapes AtlAxCreateControlLic
7 Fenêtre enfant Plusieurs étapes CreateControl
8 Fenêtre principale Plusieurs étapes 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;   
   }
}