Upravit

Sdílet prostřednictvím


Nejčastější dotazy k používání kontejnerů ovládacích prvků v knihovně ATL

Jaké třídy ATL umožňují používat kontejnery ovládacích prvků ActiveX?

Kód ATL pro hostování řízení nevyžaduje použití žádné třídy ATL; Můžete jednoduše vytvořit okno AtlAxWin80 a v případě potřeby použít rozhraní API pro hostování ovládacích prvků (další informace najdete v tématu Co je rozhraní API pro řízení a hostování ATL. Následující třídy však usnadňují používání funkcí zahrnutí.

Třída Popis
CAxWindow Zabalí okno "AtlAxWin80" a poskytuje metody pro vytvoření okna, vytvoření ovládacího prvku nebo připojení ovládacího prvku k okně a načtení ukazatelů rozhraní na objekt hostitele.
CAxWindow2T Zabalí okno "AtlAxWinLic80" , poskytuje metody pro vytvoření okna, vytvoření ovládacího prvku nebo připojení licencovaného ovládacího prvku k okně a načtení ukazatelů rozhraní na objekt hostitele.
CComCompositeControl Funguje jako základní třída pro třídy ovládacích prvků ActiveX na základě prostředku dialogového okna. Tyto ovládací prvky mohou obsahovat další ovládací prvky ActiveX.
CAxDialogImpl Funguje jako základní třída pro třídy dialogových oken založených na prostředku dialogového okna. Taková dialogová okna můžou obsahovat ovládací prvky ActiveX.
CWindow Poskytuje metodu GetDlgControl, která vrátí ukazatel rozhraní na ovládací prvek, vzhledem k ID jeho hostitelského okna. Kromě toho obálky rozhraní API systému Windows zpřístupněné CWindow obecně usnadňují správu oken.

Co je API pro hostování ovládacích prvků ATL?

Rozhraní API pro hostování ovládacích prvků ATL je sada funkcí, které umožňují, aby jakékoli okno fungovalo jako kontejner ovládacího prvku ActiveX. Tyto funkce můžou být staticky nebo dynamicky propojené s vaším projektem, protože jsou dostupné jako zdrojový kód a zveřejněné ATL90.dll. Funkce pro hostování ovládacích prvků jsou uvedené v následující tabulce.

Function Popis
AtlAxAttachControl Vytvoří hostitelský objekt, připojí ho k zadanému okně a pak připojí existující ovládací prvek.
AtlAxCreateControl Vytvoří hostitelský objekt, připojí ho k zadanému okně a pak načte ovládací prvek.
AtlAxCreateControlLic Vytvoří licencovaný ovládací prvek ActiveX, inicializuje ho a hostuje ho v zadaném okně, podobně jako AtlAxCreateControl.
AtlAxCreateControlEx Vytvoří hostitelský objekt, připojí ho k zadanému okně a pak načte ovládací prvek (umožňuje také nastavit jímky událostí).
AtlAxCreateControlLicEx Vytvoří licencovaný ovládací prvek ActiveX, inicializuje ho a hostuje ho v zadaném okně, podobně jako AtlAxCreateControlLic.
AtlAxCreateDialog Vytvoří bezmodální dialogové okno z prostředku dialogového okna a vrátí popisovač okna.
AtlAxDialogBox Vytvoří modální dialogové okno z prostředku dialogového okna.
AtlAxGetControl Vrátí ukazatel rozhraní IUnknown ovládacího prvku hostovaného v okně.
AtlAxGetHost Vrátí ukazatel rozhraní IUnknown objektu hostitele připojeného k oknu.
AtlAxWinInit Inicializuje kód pro hostování ovládacích prvků.
AtlAxWinTerm Neinicializuje kód pro hostování ovládacích prvků.

Parametry HWND v prvních třech funkcích musí být existujícím oknem (téměř) jakéhokoli typu. Pokud explicitně zavoláte některou z těchto tří funkcí (obvykle nebudete muset), nepředávejte popisovač do okna, které už funguje jako hostitel (pokud to uděláte, stávající hostitelský objekt nebude uvolněn).

Prvních sedm funkcí volá AtlAxWinInit implicitně.

Poznámka:

Rozhraní API pro hostování ovládacích prvků tvoří základ podpory ovládacích prvků ACTIVEX pro zahrnutí ovládacího prvku ActiveX. Tyto funkce je však obvykle potřeba volat přímo, pokud využijete nebo plně využijete třídy obálky KNIHOVNY ATL. Další informace naleznete v tématu , které třídy ATL usnadňují zahrnutí ovládacích prvků ActiveX.

Co je AtlAxWin100?

AtlAxWin100 je název třídy okna, která pomáhá poskytovat funkce ATL pro hostování ovládacích prvků. Když vytvoříte instanci této třídy, procedura okna automaticky použije rozhraní API pro hostování ovládacích prvků k vytvoření hostitelského objektu přidruženého k tomuto okně a načte ho ovládacím prvku, který zadáte jako název okna.

Kdy potřebuji volat AtlAxWinInit?

AtlAxWinInit zaregistruje třídu okna AtlAxWin80 (plus několik vlastních zpráv oken), takže tato funkce musí být volána, než se pokusíte vytvořit okno hostitele. Tuto funkci ale nemusíte vždy volat explicitně, protože rozhraní API pro hostování (a třídy, které je používají), tuto funkci často volají za vás. Při volání této funkce více než jednou nedojde k žádné škodě.

Co je hostitelský objekt?

Hostitelský objekt je objekt COM, který představuje kontejner ovládacího prvku ActiveX zadaný atL pro konkrétní okno. Hostitelský objekt podtřídí okno kontejneru, aby bylo možné odrážet zprávy ovládacímu prvku, poskytuje potřebná rozhraní kontejneru, která má ovládací prvek používat, a zveřejňuje rozhraní IAxWinHostWindow a IAxWinAmbientDispatch , aby bylo možné nakonfigurovat prostředí ovládacího prvku.

Objekt hostitele můžete použít k nastavení okolních vlastností kontejneru.

Můžu v jednom okně hostovat několik ovládacích prvků?

V jednom okně hostitele ATL není možné hostovat více než jeden ovládací prvek. Každé okno hostitele je navržené tak, aby vždy drželo přesně jeden ovládací prvek (to umožňuje jednoduchý mechanismus pro zpracování reflexe zpráv a okolních vlastností ovládacího prvku). Pokud ale potřebujete, aby uživatel viděl více ovládacích prvků v jednom okně, je jednoduché vytvořit několik hostitelských oken jako podřízených položek tohoto okna.

Můžu opakovaně použít okno hostitele?

Nedoporučujeme opakovaně používat okna hostitele. Pokud chcete zajistit odolnost kódu, měli byste svázat životnost okna hostitele s životností jednoho ovládacího prvku.

Kdy potřebuji volat Call AtlAxWinTerm?

AtlAxWinTerm zruší registraci třídy okna AtlAxWin80 . Tuto funkci byste měli zavolat (pokud už nepotřebujete vytvářet okna hostitele) po zničení všech existujících hostitelských oken. Pokud tuto funkci nezavoláte, třída okna se po ukončení procesu automaticky zruší registrace.

Hostování ovládacích prvků ActiveX pomocí ATL AXHost

Ukázka v této části ukazuje, jak vytvořit AXHost a jak hostovat ovládací prvek ActiveX pomocí různých funkcí ATL. Ukazuje také, jak získat přístup k událostem ovládacího prvku a jímky (pomocí IDispEventImpl) z hostovaného ovládacího prvku. Ukázka hostuje ovládací prvek Kalendář v hlavním okně nebo v podřízeném okně.

Všimněte si definice symbolu USE_METHOD . Hodnotu tohoto symbolu můžete změnit tak, aby se lišily od 1 do 8. Hodnota symbolu určuje způsob vytvoření ovládacího prvku:

  • U sudých hodnot USE_METHODvolání pro vytvoření podtřídy hostitele okno a převede ho na hostitele ovládacího prvku. Pro liché hodnoty vytvoří kód podřízené okno, které funguje jako hostitel.

  • U hodnot USE_METHOD mezi 1 a 4 se přístup k řízení a jímce událostí provádí ve volání, které také vytvoří hostitele. Hodnoty v rozsahu 5 až 8 dotazují hostitele na rozhraní a zahodí jímku.

Tady je souhrn:

USE_METHOD Hostitelský počítač Řízení přístupu a jímky událostí Demonstrována funkce
0 Podřízené okno Jeden krok CreateControlLicEx
2 Hlavní okno Jeden krok AtlAxCreateControlLicEx
3 Podřízené okno Jeden krok CreateControlEx
4 Hlavní okno Jeden krok AtlAxCreateControlEx
5 Podřízené okno Více kroků CreateControlLic
6 Hlavní okno Více kroků AtlAxCreateControlLic
7 Podřízené okno Více kroků CreateControl
8 Hlavní okno Více kroků 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;   
   }
}