Edytuj

Udostępnij za pośrednictwem


Zawieranie kontrolek ALT — Często zadawane pytania

Które klasy ATL umożliwiają zawieranie kontrolek ActiveX?

Kod hostingu kontrolek atl nie wymaga używania żadnych klas ATL; Możesz po prostu utworzyć okno "AtlAxWin80" i w razie potrzeby użyć interfejsu API hostingu kontrolek (aby uzyskać więcej informacji, zobacz Co to jest interfejs API hostingu kontrolek ATL. Jednak następujące klasy ułatwiają korzystanie z funkcji zawierania.

Klasa opis
CAxWindow Opakowuje okno "AtlAxWin80" , udostępniając metody tworzenia okna, tworzenia kontrolki i/lub dołączania kontrolki do okna oraz pobierania wskaźników interfejsu w obiekcie hosta.
CAxWindow2T Opakowuje okno "AtlAxWinLic80" , udostępniając metody tworzenia okna, tworzenia kontrolki i/lub dołączania licencjonowanej kontrolki do okna i pobierania wskaźników interfejsu w obiekcie hosta.
CComCompositeControl Działa jako klasa bazowa dla klas kontrolek ActiveX na podstawie zasobu okna dialogowego. Takie kontrolki mogą zawierać inne kontrolki ActiveX.
CAxDialogImpl Działa jako klasa bazowa dla klas okien dialogowych na podstawie zasobu okna dialogowego. Takie okna dialogowe mogą zawierać kontrolki ActiveX.
CWindow Udostępnia metodę GetDlgControl, która zwróci wskaźnik interfejsu w kontrolce, biorąc pod uwagę identyfikator okna hosta. Ponadto otoki interfejsu API systemu Windows udostępniane przez CWindow zwykle ułatwiają zarządzanie oknami.

Co to jest interfejs API hostingu kontrolek ATL?

Interfejs API hostowania kontrolek ATL to zestaw funkcji, który umożliwia każdemu oknie działanie jako kontener kontrolek ActiveX. Te funkcje mogą być statycznie lub dynamicznie połączone z projektem, ponieważ są one dostępne jako kod źródłowy i udostępniane przez ATL90.dll. Funkcje hostingu kontrolek są wymienione w poniższej tabeli.

Function opis
AtlAxAttachControl Tworzy obiekt hosta, łączy go z podanym oknem, a następnie dołącza istniejącą kontrolkę.
AtlAxCreateControl Tworzy obiekt hosta, łączy go z podanym oknem, a następnie ładuje kontrolkę.
AtlAxCreateControlLic Tworzy licencjonowany formant ActiveX, inicjuje go i hostuje go w określonym oknie, podobnie jak AtlAxCreateControl.
AtlAxCreateControlEx Tworzy obiekt hosta, łączy go z podanym oknem, a następnie ładuje kontrolkę (umożliwia również skonfigurowanie ujścia zdarzeń).
AtlAxCreateControlLicEx Tworzy licencjonowany formant ActiveX, inicjuje go i hostuje go w określonym oknie, podobnie jak AtlAxCreateControlLic.
AtlAxCreateDialog Tworzy okno dialogowe bez moderowania z zasobu okna dialogowego i zwraca uchwyt okna.
AtlAxDialogBox Tworzy modalne okno dialogowe z zasobu okna dialogowego.
AtlAxGetControl Zwraca wskaźnik interfejsu IUnknown kontrolki hostowanej w oknie.
AtlAxGetHost Zwraca wskaźnik interfejsu IUnknown obiektu hosta połączonego z oknem.
AtlAxWinInit Inicjuje kod hostingu kontrolek.
AtlAxWinTerm Uninitializuje kod hostingu kontrolek.

HWND Parametry w pierwszych trzech funkcjach muszą być istniejącym oknem (prawie) dowolnego typu. Jeśli jawnie wywołasz dowolną z tych trzech funkcji (zazwyczaj nie musisz), nie przekaż uchwytu do okna, które działa już jako host (jeśli to zrobisz, istniejący obiekt hosta nie zostanie uwolniony).

Pierwsze siedem funkcji wywołuje niejawnie atlAxWinInit .

Uwaga

Interfejs API hostingu kontrolek stanowi podstawę obsługi formantów ActiveX przez atl. Jednak zwykle nie trzeba wywoływać tych funkcji bezpośrednio, jeśli korzystasz z klas otoki ATL lub korzystasz z nich w pełni. Aby uzyskać więcej informacji, zobacz Które klasy ATL ułatwiają zawieranie kontrolek ActiveX.

Co to jest klasa AtlAxWin100?

AtlAxWin100 to nazwa klasy okien, która pomaga zapewnić funkcje hostingu kontrolek ATL. Podczas tworzenia wystąpienia tej klasy procedura okna automatycznie użyje interfejsu API hostingu kontrolek do utworzenia obiektu hosta skojarzonego z oknem i załadowania go za pomocą kontrolki określonej jako tytuł okna.

Kiedy muszę tworzyć wywołanie klasy AtlAxWinInit?

AtlAxWinInit rejestruje klasę okien "AtlAxWin80" (plus kilka niestandardowych komunikatów okna), aby ta funkcja musiała zostać wywołana przed próbą utworzenia okna hosta. Jednak nie zawsze trzeba jawnie wywoływać tę funkcję, ponieważ interfejsy API hostingu (i klasy, które ich używają) często nazywają tę funkcję za Ciebie. Nie ma żadnych szkód w wywoływaniu tej funkcji więcej niż raz.

Co to jest obiekt hosta?

Obiekt hosta jest obiektem COM, który reprezentuje kontener sterowania ActiveX dostarczony przez ATL dla określonego okna. Podklasy obiektu hosta okno kontenera, dzięki czemu może odzwierciedlać komunikaty do kontrolki, udostępnia niezbędne interfejsy kontenera do użycia przez kontrolkę i uwidacznia interfejsy IAxWinHostWindow i IAxWinAmbientDispatch , aby umożliwić skonfigurowanie środowiska kontrolki.

Za pomocą obiektu hosta można ustawić właściwości otoczenia kontenera.

Czy mogę umieścić więcej niż jedną kontrolkę w jednym oknie?

Nie można hostować więcej niż jednej kontrolki w jednym oknie hosta ATL. Każde okno hosta jest przeznaczone do przechowywania dokładnie jednej kontrolki naraz (pozwala to na prosty mechanizm obsługi odbicia komunikatów i właściwości otoczenia dla poszczególnych kontrolek). Jeśli jednak chcesz, aby użytkownik widział wiele kontrolek w jednym oknie, wystarczy utworzyć wiele okien hosta jako elementów podrzędnych tego okna.

Czy mogę ponownie użyć okna hosta?

Nie zaleca się ponownego używania okien hostów. Aby zapewnić niezawodność kodu, należy powiązać okres istnienia okna hosta z okresem istnienia pojedynczej kontrolki.

Kiedy muszę tworzyć wywołanie klasy AtlAxWinTerm?

AtlAxWinTerm wyrejestrowuje klasę okna "AtlAxWin80". Należy wywołać tę funkcję (jeśli nie trzeba już tworzyć okien hosta) po zniszczeniu wszystkich istniejących okien hosta. Jeśli ta funkcja nie zostanie wywołana, klasa okna zostanie automatycznie wyrejestrowana po zakończeniu procesu.

Hostowanie kontrolek ActiveX przy użyciu biblioteki ATL AXHost

W przykładzie w tej sekcji pokazano, jak utworzyć axhost i jak hostować kontrolkę ActiveX przy użyciu różnych funkcji ATL. Pokazano również, jak uzyskać dostęp do zdarzeń kontroli i ujścia (przy użyciu protokołu IDispEventImpl) z hostowanej kontrolki. Przykład obsługuje kontrolkę Kalendarz w oknie głównym lub w oknie podrzędnym.

Zwróć uwagę na definicję symbolu USE_METHOD . Możesz zmienić wartość tego symbolu tak, aby różniła się w zakresie od 1 do 8. Wartość symbolu określa sposób tworzenia kontrolki:

  • W przypadku parzystym numerem wartości USE_METHODwywołania w celu utworzenia podklas hosta okno i konwertuje je na hosta sterującego. W przypadku wartości z nieparzystą liczbą kod tworzy okno podrzędne, które działa jako host.

  • W przypadku wartości z USE_METHOD zakresu od 1 do 4 dostęp do kontroli i ujścia zdarzeń odbywa się w wywołaniu, które tworzy również hosta. Wartości z zakresu od 5 do 8 wysyłają zapytanie do hosta dla interfejsów i podłączają ujście.

Oto podsumowanie:

USE_METHOD Gospodarz Kontrolowanie dostępu i ujścia zdarzeń Pokazano funkcję
1 Okno podrzędne Jeden krok CreateControlLicEx
2 Okno główne Jeden krok AtlAxCreateControlLicEx
3 Okno podrzędne Jeden krok CreateControlEx
100 Okno główne Jeden krok AtlAxCreateControlEx
5 Okno podrzędne Wiele kroków CreateControlLic
6 Okno główne Wiele kroków AtlAxCreateControlLic
7 Okno podrzędne Wiele kroków CreateControl
8 Okno główne Wiele kroków 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;   
   }
}