Edit

Bagikan melalui


FAQ Kontainer Kontrol ATL

Kelas ATL mana yang memfasilitasi ActiveX Control Containment?

Kode hosting kontrol ATL tidak mengharuskan Anda untuk menggunakan kelas ATL apa pun; Anda cukup membuat jendela "AtlAxWin80" dan menggunakan API hosting kontrol jika perlu (untuk informasi selengkapnya, lihat Apa ITU ATL Control-Hosting API. Namun, kelas berikut membuat fitur penahanan lebih mudah digunakan.

Kelas Deskripsi
CAxWindow Membungkus jendela "AtlAxWin80" , menyediakan metode untuk membuat jendela, membuat kontrol dan/atau melampirkan kontrol ke jendela, dan mengambil penunjuk antarmuka pada objek host.
CAxWindow2T Membungkus jendela "AtlAxWinLic80" , menyediakan metode untuk membuat jendela, membuat kontrol dan/atau melampirkan kontrol berlisensi ke jendela, dan mengambil penunjuk antarmuka pada objek host.
CComCompositeControl Bertindak sebagai kelas dasar untuk kelas kontrol ActiveX berdasarkan sumber daya dialog. Kontrol tersebut dapat berisi kontrol ActiveX lainnya.
CAxDialogImpl Bertindak sebagai kelas dasar untuk kelas dialog berdasarkan sumber daya dialog. Dialog tersebut dapat berisi kontrol ActiveX.
CWindow Menyediakan metode, GetDlgControl, yang akan mengembalikan penunjuk antarmuka pada kontrol, mengingat ID jendela host-nya. Selain itu, pembungkus Windows API yang diekspos oleh CWindow umumnya membuat manajemen jendela lebih mudah.

Apa ITU ATL Control-Hosting API?

API hosting kontrol ATL adalah sekumpulan fungsi yang memungkinkan jendela apa pun bertindak sebagai kontainer kontrol ActiveX. Fungsi-fungsi ini dapat ditautkan secara statis atau dinamis ke dalam proyek Anda karena tersedia sebagai kode sumber dan diekspos oleh ATL90.dll. Fungsi hosting kontrol tercantum dalam tabel di bawah ini.

Fungsi Deskripsi
AtlAxAttachControl Membuat objek host, menghubungkannya ke jendela yang disediakan, lalu melampirkan kontrol yang ada.
AtlAxCreateControl Membuat objek host, menghubungkannya ke jendela yang disediakan, lalu memuat kontrol.
AtlAxCreateControlLic Membuat kontrol ActiveX berlisensi, menginisialisasinya, dan menghostingnya di jendela yang ditentukan, mirip dengan AtlAxCreateControl.
AtlAxCreateControlEx Membuat objek host, menghubungkannya ke jendela yang disediakan, lalu memuat kontrol (juga memungkinkan sink peristiwa disiapkan).
AtlAxCreateControlLicEx Membuat kontrol ActiveX berlisensi, menginisialisasinya, dan menghostingnya di jendela yang ditentukan, mirip dengan AtlAxCreateControlLic.
AtlAxCreateDialog Membuat kotak dialog tanpa mode dari sumber daya dialog dan mengembalikan gagang jendela.
AtlAxDialogBox Membuat kotak dialog modal dari sumber daya dialog.
AtlAxGetControl Mengembalikan penunjuk antarmuka IUnknown dari kontrol yang dihosting di jendela.
AtlAxGetHost Mengembalikan penunjuk antarmuka IUnknown objek host yang tersambung ke jendela.
AtlAxWinInit Menginisialisasi kode hosting kontrol.
AtlAxWinTerm Batalkan menginisialisasi kode hosting kontrol.

Parameter HWND dalam tiga fungsi pertama harus merupakan jendela (hampir) jenis apa pun yang ada. Jika Anda memanggil salah satu dari tiga fungsi ini secara eksplisit (biasanya, Anda tidak perlu), jangan meneruskan handel ke jendela yang sudah bertindak sebagai host (jika Anda melakukannya, objek host yang ada tidak akan dibebaskan).

Tujuh fungsi pertama memanggil AtlAxWinInit secara implisit.

Catatan

API hosting kontrol membentuk fondasi dukungan ATL untuk penahanan kontrol ActiveX. Namun, biasanya ada sedikit kebutuhan untuk memanggil fungsi-fungsi ini secara langsung jika Anda memanfaatkan atau memanfaatkan sepenuhnya kelas pembungkus ATL. Untuk informasi selengkapnya, lihat Kelas ATL Mana yang Memfasilitasi Kontainer Kontrol ActiveX.

Apa itu AtlAxWin100?

AtlAxWin100 adalah nama kelas jendela yang membantu menyediakan fungsionalitas hosting kontrol ATL. Saat Anda membuat instans kelas ini, prosedur jendela akan secara otomatis menggunakan API hosting kontrol untuk membuat objek host yang terkait dengan jendela dan memuatnya dengan kontrol yang Anda tentukan sebagai judul jendela.

Kapan Saya Perlu Memanggil AtlAxWinInit?

AtlAxWinInit mendaftarkan kelas jendela "AtlAxWin80" (ditambah beberapa pesan jendela kustom) sehingga fungsi ini harus dipanggil sebelum Anda mencoba membuat jendela host. Namun, Anda tidak selalu perlu memanggil fungsi ini secara eksplisit, karena API hosting (dan kelas yang menggunakannya) sering memanggil fungsi ini untuk Anda. Tidak ada salahnya memanggil fungsi ini lebih dari sekali.

Apa itu Objek Host?

Objek host adalah objek COM yang mewakili kontainer kontrol ActiveX yang disediakan oleh ATL untuk jendela tertentu. Objek host mensubkelas jendela kontainer sehingga dapat mencerminkan pesan ke kontrol, ini menyediakan antarmuka kontainer yang diperlukan untuk digunakan oleh kontrol, dan mengekspos antarmuka IAxWinHostWindow dan IAxWinAmbientDispatch untuk memungkinkan Anda mengonfigurasi lingkungan kontrol.

Anda dapat menggunakan objek host untuk mengatur properti sekitar kontainer.

Dapatkah saya Menghosting Lebih dari Satu Kontrol dalam Satu Jendela?

Tidak dimungkinkan untuk menghosting lebih dari satu kontrol dalam satu jendela host ATL. Setiap jendela host dirancang untuk memegang tepat satu kontrol pada satu waktu (ini memungkinkan mekanisme sederhana untuk menangani pantulan pesan dan properti sekitar per kontrol). Namun, jika Anda memerlukan pengguna untuk melihat beberapa kontrol dalam satu jendela, itu adalah masalah sederhana untuk membuat beberapa jendela host sebagai anak-anak jendela itu.

Dapatkah saya Menggunakan Kembali Jendela Host?

Tidak disarankan agar Anda menggunakan kembali jendela host. Untuk memastikan ketahanan kode Anda, Anda harus mengikat masa pakai jendela host Anda ke masa pakai satu kontrol.

Kapan Saya Perlu Memanggil AtlAxWinTerm?

AtlAxWinTerm membatalkan pendaftaran kelas jendela "AtlAxWin80 ". Anda harus memanggil fungsi ini (jika Anda tidak perlu lagi membuat jendela host) setelah semua jendela host yang ada telah dihancurkan. Jika Anda tidak memanggil fungsi ini, kelas jendela akan dibatalkan pendaftarannya secara otomatis saat proses berakhir.

Hosting Kontrol ActiveX Menggunakan ATL AXHost

Sampel di bagian ini menunjukkan cara membuat AXHost dan cara menghosting kontrol ActiveX menggunakan berbagai fungsi ATL. Ini juga menunjukkan cara mengakses peristiwa kontrol dan sink (menggunakan IDispEventImpl) dari kontrol yang dihosting. Sampel menghosting kontrol Kalender di jendela utama atau di jendela anak.

Perhatikan definisi USE_METHOD simbol. Anda dapat mengubah nilai simbol ini menjadi bervariasi antara 1 dan 8. Nilai simbol menentukan bagaimana kontrol akan dibuat:

  • Untuk nilai USE_METHODbernomor genap , panggilan untuk membuat subkelas host jendela dan mengonversinya menjadi host kontrol. Untuk nilai bernomor ganjil, kode membuat jendela anak yang bertindak sebagai host.

  • Untuk nilai USE_METHOD antara 1 dan 4, akses ke kontrol dan tenggelamnya peristiwa dilakukan dalam panggilan yang juga membuat host. Nilai antara 5 dan 8 mengkueri host untuk antarmuka dan menghubungkan sink.

Berikut ringkasannya:

USE_METHOD Host Mengontrol akses dan peristiwa yang tenggelam Fungsi yang ditunjukkan
1 Jendela anak Satu langkah CreateControlLicEx
2 Jendela utama Satu langkah AtlAxCreateControlLicEx
3 Jendela anak Satu langkah CreateControlEx
4 Jendela utama Satu langkah AtlAxCreateControlEx
5 Jendela anak Beberapa langkah CreateControlLic
6 Jendela utama Beberapa langkah AtlAxCreateControlLic
7 Jendela anak Beberapa langkah CreateControl
8 Jendela utama Beberapa langkah 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;   
   }
}