Bearbeiten

Fragen und Antworten zur ATL-Steuerelementkapselung

Welche ATL-Klassen machen die Kapselung von ActiveX-Steuerelementen verfügbar?

Der ATL-Steuerelementhostingcode erfordert keine ATL-Klassen; Sie können einfach ein "AtlAxWin80" -Fenster erstellen und bei Bedarf die Steuerelementhosting-API verwenden (weitere Informationen finden Sie unter What Is the ATL Control-Hosting API. Die folgenden Klassen erleichtern jedoch die Verwendung der Eindämmungsfeatures.

Klasse Beschreibung
CAxWindow Umschließt ein "AtlAxWin80" -Fenster, das Methoden zum Erstellen des Fensters, das Erstellen eines Steuerelements und/oder das Anfügen eines Steuerelements an das Fenster sowie das Abrufen von Schnittstellenzeigern auf dem Hostobjekt bereitstellt.
CAxWindow2T Umschließt ein "AtlAxWinLic80" -Fenster, das Methoden zum Erstellen des Fensters, das Erstellen eines Steuerelements und/oder das Anfügen eines lizenzierten Steuerelements an das Fenster sowie das Abrufen von Schnittstellenzeigern auf dem Hostobjekt bereitstellt.
CComCompositeControl Dient als Basisklasse für ActiveX-Steuerelementklassen basierend auf einer Dialogressource. Solche Steuerelemente können andere ActiveX-Steuerelemente enthalten.
CAxDialogImpl Dient als Basisklasse für Dialogklassen basierend auf einer Dialogressource. Solche Dialogfelder können ActiveX-Steuerelemente enthalten.
CWindow Stellt eine Methode, GetDlgControl, bereit, die einen Schnittstellenzeiger für ein Steuerelement zurückgibt, vorausgesetzt, die ID des Hostfensters. Darüber hinaus erleichtern die Windows-API-Wrapper, die von CWindow der Allgemeinen Fensterverwaltung verfügbar gemacht werden.

Was ist die API des ATL-Steuerelementhostings?

Die ATL-Steuerelementhosting-API ist der Satz von Funktionen, mit denen jedes Fenster als ActiveX-Steuerelementcontainer fungieren kann. Diese Funktionen können statisch oder dynamisch mit Ihrem Projekt verknüpft werden, da sie als Quellcode verfügbar sind und von ATL90.dll verfügbar gemacht werden. Die Steuerelementhostingfunktionen sind in der folgenden Tabelle aufgeführt.

Function Beschreibung
AtlAxAttachControl Erstellt ein Hostobjekt, verbindet es mit dem angegebenen Fenster und fügt dann ein vorhandenes Steuerelement an.
AtlAxCreateControl Erstellt ein Hostobjekt, verbindet es mit dem angegebenen Fenster und lädt dann ein Steuerelement.
AtlAxCreateControlLic Erstellt ein lizenziertes ActiveX-Steuerelement, initialisiert es und hostet es im angegebenen Fenster, ähnlich wie AtlAxCreateControl.
AtlAxCreateControlEx Erstellt ein Hostobjekt, verbindet es mit dem angegebenen Fenster und lädt dann ein Steuerelement (ermöglicht auch das Einrichten von Ereignissenken).
AtlAxCreateControlLicEx Erstellt ein lizenziertes ActiveX-Steuerelement, initialisiert es und hostet es im angegebenen Fenster, ähnlich wie AtlAxCreateControlLic.
AtlAxCreateDialog Erstellt ein Dialogfeld ohne Modus aus einer Dialogressource und gibt das Fensterhandle zurück.
AtlAxDialogBox Erstellt ein modales Dialogfeld aus einer Dialogressource.
AtlAxGetControl Gibt den IUnknown-Schnittstellenzeiger des steuerelements zurück, das in einem Fenster gehostet wird.
AtlAxGetHost Gibt den IUnknown-Schnittstellenzeiger des hostobjekts zurück, das mit einem Fenster verbunden ist.
AtlAxWinInit Initialisiert den Steuerelementhostingcode.
AtlAxWinTerm Hebt die Initialisierung des Steuerelementhostingcodes auf.

Die HWND Parameter in den ersten drei Funktionen müssen ein (fast) beliebiges Fenster sein. Wenn Sie eine dieser drei Funktionen explizit aufrufen (in der Regel nicht erforderlich), übergeben Sie kein Handle an ein Fenster, das bereits als Host fungiert (wenn Sie dies tun, wird das vorhandene Hostobjekt nicht freigegeben).

Die ersten sieben Funktionen rufen AtlAxWinInit implizit auf.

Hinweis

Die Steuerelementhosting-API bildet die Grundlage der Unterstützung von ATL für die Eindämmung von ActiveX-Steuerelementen. In der Regel ist es jedoch wenig erforderlich, diese Funktionen direkt aufzurufen, wenn Sie die Wrapperklassen von ATL nutzen oder vollständig nutzen. Weitere Informationen finden Sie unter Welche ATL-Klassen die Eindämmung von ActiveX-Steuerelementen erleichtern.

Was ist AtlAxWin100?

AtlAxWin100 ist der Name einer Fensterklasse, die die Funktionalität des ATL-Steuerelementhostings bereitstellt. Wenn Sie eine Instanz dieser Klasse erstellen, verwendet die Fensterprozedur automatisch die Steuerelementhosting-API, um ein dem Fenster zugeordnetes Hostobjekt zu erstellen und mit dem Steuerelement zu laden, das Sie als Titel des Fensters angeben.

Wann muss ich AtlAxWinInit aufrufen?

AtlAxWinInit registriert die "AtlAxWin80"- Fensterklasse (plus ein paar benutzerdefinierte Fenstermeldungen), sodass diese Funktion aufgerufen werden muss, bevor Sie versuchen, ein Hostfenster zu erstellen. Sie müssen diese Funktion jedoch nicht immer explizit aufrufen, da die Host-APIs (und die Klassen, die sie verwenden) diese Funktion häufig für Sie aufrufen. Es gibt keinen Schaden daran, diese Funktion mehrmals aufzurufen.

Was ist ein Hostobjekt?

Ein Hostobjekt ist ein COM-Objekt, das den activeX-Steuerelementcontainer darstellt, der von ATL für ein bestimmtes Fenster bereitgestellt wird. Das Hostobjekt unterklassig das Containerfenster, sodass es Nachrichten an das Steuerelement wiedergeben kann, es stellt die erforderlichen Containerschnittstellen bereit, die vom Steuerelement verwendet werden sollen, und macht die IAxWinHostWindow - und IAxWinAmbientDispatch-Schnittstellen verfügbar, damit Sie die Umgebung des Steuerelements konfigurieren können.

Sie können das Hostobjekt verwenden, um die Umgebungseigenschaften des Containers festzulegen.

Kann ich in einem Fenster mehrere Steuerelemente hosten?

Es ist nicht möglich, mehrere Steuerelemente in einem einzelnen ATL-Hostfenster zu hosten. Jedes Hostfenster ist so konzipiert, dass jeweils genau ein Steuerelement gehalten wird (dies ermöglicht einen einfachen Mechanismus für die Behandlung von Nachrichtenreflektionen und Umgebungseigenschaften pro Steuerung). Wenn Der Benutzer jedoch mehrere Steuerelemente in einem einzelnen Fenster sehen muss, ist es einfach, mehrere Hostfenster als untergeordnete Elemente dieses Fensters zu erstellen.

Kann ich ein Hostfenster wiederverwenden?

Es wird nicht empfohlen, Hostfenster wiederzuverwenden. Um die Stabilität des Codes sicherzustellen, sollten Sie die Lebensdauer des Hostfensters auf die Lebensdauer eines einzelnen Steuerelements binden.

Wann muss ich AtlAxWinInit aufrufen?

AtlAxWinTerm hebt die Registrierung der "AtlAxWin80"- Fensterklasse auf. Sie sollten diese Funktion aufrufen (wenn Sie keine Hostfenster mehr erstellen müssen), nachdem alle vorhandenen Hostfenster zerstört wurden. Wenn Sie diese Funktion nicht aufrufen, wird die Registrierung der Fensterklasse automatisch aufgehoben, wenn der Prozess beendet wird.

Hosten von ActiveX-Steuerelementen mit ATL AXHost

Das Beispiel in diesem Abschnitt zeigt, wie AXHost erstellt und ein ActiveX-Steuerelement mithilfe verschiedener ATL-Funktionen gehostet wird. Außerdem wird gezeigt, wie Sie über das gehostete Steuerelement auf die Steuerelement- und Sinkereignisse (mit IDispEventImpl) zugreifen. Im Beispiel wird das Kalendersteuerelement in einem Standard-Fenster oder in einem untergeordneten Fenster gehostet.

Beachten Sie die Definition des USE_METHOD Symbols. Sie können den Wert dieses Symbols ändern, um zwischen 1 und 8 zu variieren. Der Wert des Symbols bestimmt, wie das Steuerelement erstellt wird:

  • Für gerade nummerierte Werte des USE_METHODAufrufs zum Erstellen der Hostunterklassen eines Fensters und konvertiert ihn in einen Steuerelementhost. Bei ungeraden Werten erstellt der Code ein untergeordnetes Fenster, das als Host fungiert.

  • Für Werte zwischen USE_METHOD 1 und 4 erfolgt der Zugriff auf das Steuerelement und das Sinken von Ereignissen im Aufruf, der auch den Host erstellt. Werte zwischen 5 und 8 abfragen den Host nach Schnittstellen und verbinden die Spüle.

Dies ist eine Zusammenfassung:

USE_METHOD Host Steuern des Zugriffs und des Sinkens von Ereignissen Veranschaulichte Funktion
1 Untergeordnetes Fenster Ein Schritt CreateControlLicEx
2 Hauptfenster Ein Schritt AtlAxCreateControlLicEx
3 Untergeordnetes Fenster Ein Schritt CreateControlEx
4 Hauptfenster Ein Schritt AtlAxCreateControlEx
5 Untergeordnetes Fenster Mehrere -Schritte CreateControlLic
6 Hauptfenster Mehrere -Schritte AtlAxCreateControlLic
7 Untergeordnetes Fenster Mehrere -Schritte CreateControl
8 Hauptfenster Mehrere -Schritte 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;   
   }
}