Implement a window in ATL

xiaoxiao2021-03-06  42

ATL provides some tool classes to implement windows so that you can create a window without relying on the MFC in an ATL component.

First, implement the dialog

Three template classes in ATL can be used to create a dialog:

(1) CSIMPLEDIALOG: Create a mode dialog, you can host Windows Controls

Template Class CsimpleDialog: Public CDialogIMPLBase

(2) CDIALOGIMPL: Create a mode or non-Mode dialog, you can host Windows Controls

Template Class ATL_NO_VTABLE CDIALOGIMPL: Public CDialogImplbaset

(3) CAXDIALOGIMPL: Create a mode or non-Mode dialog, you can host Windows Controls and ActiveX Controls

Template Class ATL_NO_VTABLE CAXDIALOGIMPL: PUBLIC CDIALOGIMPLBASET

With CSIMPLEDIALOG and CDIALOGIMPL, you cannot display dialogs containing the ActiveX control, only CAXDIALOGIMPL. If you want to handle the event in the dialog, ATLADVISINKMAP (this, true) is added to OnInitDialog (). Add AtladViseSinkMap (this, false) when exiting. The dialog box generated by Insert / New ATL Object / Miscellaneous / Dialog is inherited from CaxDialogIMPL.

The use of these three classes is very similar. They are all derived from a new class and make sure there is a member of the IDD to indicate the resource ID. Such as:

class CMyDialog: public CDialogImpl, ... {public: enum {IDD = IDD_MYDIALOG}; // this member must have IDD, generally enum type BEGIN_MSG_MAP (CMyDialog) MESSAGE_HANDLER (WM_INITDIALOG, OnInitDialog) END_MSG_MAP () LRESULT OnInitDialog (UINT UMSG, WPARAM WPARAM, LPARAM LPARAM, BOOL & BHANDERED) {Return 1;}}; cmydialog dlg; dlg.domodal ();

CSIMpleDialog can be more simple, as follows:

CSIMPLEDIALOG DLG; DLG.DOMODAL ();

In addition, CSIMpleDialog has intrinsic support to IDOK and IDCANCEL, which will automatically call EndDialog, which contains the following code in its definition:

BEGIN_MSG_MAP (thisClass) MESSAGE_HANDLER (WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER (IDOK, IDNO, OnCloseCmd) END_MSG_MAP () ...... LRESULT OnCloseCmd (WORD / * wNotifyCode * /, WORD wID, HWND / * hWndCtl * /, BOOL & / * BHANDED * /) {:: enddialog (m_hwnd, wid); return 0;} However, CDialogIMPL and CAXDialogIMPL do not have intrinsic support, so you must add your message handler to call EndDialog, such as:

COMMAND_ID_HANDLER (IDOK, OnOK) COMMAND_ID_HANDLER (IDCANCEL, OnCancel) LRESULT OnOK (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & bHandled) {EndDialog (wID); return 0;} LRESULT OnCancel (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL & Bhandled) {enddialog (wid); return 0;}

Second, SUBCLASS and SUPERCLASS

Subclass's role is to intercept messages and point to its own container process function. There are two kinds of subclass.

(1) Instance Subclass: Subclassization An instance of existing container objects. Each window object instance is allocated by the system (HWND is this memory block), saving various information with a window, including the address of WndProc. So you can override this address for your own WndProc address, so that the processing of the message can be intercepted. (Of course, I have to retain the original WndProc address, with pass message)

(2) Global Subclass: Subclass a Window Class. The address of WndProc is kept in WNDCLASS, so you can change it for your own WndProc address, so all object instances created based on this new Wndclass will point to the address of the new WndProc. as the picture shows:

Instance Subclass

Global Subclass

Superclass is the same as Subclass, there are two distinction: (1) No instance superclass, only superclass window classes. (2) SUBCLASS cannot intercept the creation of WM_CREATE, WM_NCCREATE, etc., and SuperClass can be intercepted, but it must be PASS to give the original WndProc to complete the initialization work.

Third, use CWINDOWIMPL to implement one window

CWindowIMPL is a template class that is defined as follows:

template class ATL_NO_VTABLE CWindowImpl: public CWindowImplBaseT template class ATL_NO_VTABLE CWindowImplBaseT: public CWindowImplRoot template CLASS ATL_NO_VTABLE CWINDOWIMPLROOT: PUBLIC TBASE, PUBLIC CMESEMAP is visible, for CWINDOWIMPL , the final base class is still CWindow (default). Template parameters Twintraits are primarily used to indicate the style of the window to create. ATL has built some types: CControlwintraits, CFraMewintraits, CMDichildwintraits, etc., the default is CControlwintraits, which contains whom with WM_Child | WM_Visible | WS_CLIPCHILDREN | WS_CLIPSIBLINGS. Of course, you can also define the style and extended styles of the window.

template class CWinTraits {public: static DWORD GetWndStyle (DWORD dwStyle) {return dwStyle == 0 t_dwStyle:? dwStyle;} static DWORD GetWndExStyle (DWORD dwExStyle) {return dwExStyle == 0? t_dwExStyle: dwExStyle;}}; typedef CWinTraits CControlWinTraits; typedef CWinTraits CFrameWinTraits; typedef CWinTraits cmdichildwintraits;

(1) Using SuperClass

Class CMYWINDOW: PUBLIC CWINDOWIMPL , ... {public: declare_wnd_superclass (null, "edit") // message mapping macro // message processing function}; cmywindow wnd; wnd.create (...); (2) Using Instance Subclass Class CMyWindow: Public CWindowImpl , ... {public: // message mapping macro // message processing function}; cmyWindow wnd; wnd.subclasswindow (hsomewnd); // Existing window handle (3) Create a new window

Class CMYWINDOW: PUBLIC CWINDOWIMPL , ... {public: declare_wnd_class ("myWindow") // only defines a class name, or NULL, the system will automatically generate a class name // message mapping macro // message processing CMYWINDOW WND; WND.CREATE (...);

Fourth, message mapping macro

A set of messages are defined in the ATL, and a typical example is as follows:

BEGIN_MSG_MAP (CMyClass) MESSAGE_HANDLER (WM_PAINT, OnPaint) CHAIN_MSG_MAP (CMyBaseClass) // CMyBaseClass base class that represents ALT_MSG_MAP (1) // ATL_MSG_MAP mainly for "contained window" CHAIN_MSG_MAP (CMyBaseClass) ALT_MSG_MAP (2) MESSAGE_HANDLER (WM_CHAR, OnChar) CHAIN_MSG_MAP_ALT ( CMYBASECLASS, 1) End_msg_map ()

The results of the macro show are roughly as follows:

Bool CMYCLASS :: ProcessWindowMessage (HWND, UINT, WPARAM, LPARAM, LRESULT & LRESULT, DWORD DWMSGMAPID) {BOOL BHAND = true; // This variable is used to determine if the message has been processed ... Switch (dwmsgmapid) // default 0 {case 0: if (UMSG == WM_Paint) {bhandled = true; LRESULT = OnPaint (UMSG, WPARAM, LPARAM, BHAND); // bhandled is a reference parameter if (bhandled) return true;} if (CMYBaseClass :: ProcessWindowMessage (hWnd, uMsg, wParam, lParam, lResult)) return TRUE; break; case 1: // ALT_MSG_MAP (1), the branch action if CMyBaseClass :: ProcessWindowMessage (hWnd, uMsg, wParam, lParam, lResult)) return TRUE; break; case 2: // ALT_MSG_MAP (1) if (uMsg == WM_CHAR) {bHandled = TRUE; lResult = OnChar (uMsg, wParam, lParam, bHandled); if (bHandled) return TRUE;} if CMyBaseClass :: ProcessWindowMessage ( HWND, UMSG, WPARAM, LPARAM, LRESULT, 1)) // Select branch 1 Return TR UE; break; default: ...} return false;} processWindowMessage () is a virtual function that is defined in CMessageMap in CMessageMap (the other is CWindow). ProcessWindowMessage is usually called in WindowProc, if the invoking failed, then returns false, then DEFWINDOWPROC, and DEFWINDOWPROC calls the member variable M_PFNSUPERWINDOWPROC pointing to the window process, which is used to retain the original window process pointer when Subclass and Superclass.

Chain_msg_map gave an opportunity to execute the ProcessWindowMessage function of ThechainClass (Generally, the parent class), which is generally used in the implementation of ActiveX Control, such as: chain_msg_map (ccomcontrol ). This macro is necessary because the parent class may handle some messages. If there is a few statements in the class definition of CCOMControl: Message_Handler (wm_paint, ccomcontrolbase :: onpaint) message_handler (wm_setfocus, ccomcontrolbase :: Onsetfocus ) Message_Handler (WM_KILLFOCUS, CCOMCONTROLBASE :: ONKILLFOCUS) Message_Handler (wm_mouseactivate, ccomcontrolbase :: onmouseactivate)

It can be seen that CCOMControl contains processing of four messages for WM_Paint, WM_SETFORCE, WM_KILLFOCUS, WM_MOUSEACTIVE. DEFWINDOWPROC should only be called only if the parent class can't handle this message.

V. Use Contained Window

Contained WINDOW is included in other objects, typical usage is as follows:

Class CMYCONTAINER: PUBLIC CCOMCONTROL , ... // a full control {public: ccontainedwindow m_wndit, m_wndlist; cmycontainer (): m_wndedit ("Edit", this, 1) // 1 Representation branch, m_wndlist ("List" , this, 2) // 2 Represents branch {...} begin_msg_map (cmycontainer) // handles yourself ALT_MSG_MAP (1) // case 1: // Processing the EDIT container message ALT_MSG_MAP (2) // Case 2: // Handling the message of the List container END_MSG_MAP () LRESULT OnCREATE (...); m_wndlist.create (...);} ...

Compare the message processing of CWindowImpl and CContainedWindWind: (1) CWindowImpl:

(2) ccontainedwindow:

It can be seen that Contained WINDOW first processes the message that contains its Container, if it cannot be processed to go to its own DefWindowProc. 6. Realizing Hosting ActiveX Control ATL also provides some classes to implement windows that you can Hosting ActiveX Control. The CAXDialogimpl in front of the previously ever is such a class, and the CaxWindow can be applied to a more versatile window. Its use method is also very simple, the following is a simple example, implements a window, including a calendar control. (1) a statement of the form class definition: class CAtlAxWindow: public CWindowImpl , public IDispEventImpl <1, CAtlAxWindow, & DIID_DCalendarEvents, & LIBID_MSACAL, 7, 0> {public: // Window Message BEGIN_MSG_MAP (CAtlAxWindow). .. END_MSG_MAP () // event processing BEGIN_SINK_MAP (CAtlAxWindow) SINK_ENTRY_EX (1, ​​DIID_DCalendarEvents, 0x1, OnAfterUpdateCalendar) ... END_SINK_MAP () STDMETHOD (OnAfterUpdateCalendar) (); private: CAxWindow m_axwnd; // host activex control};

Inheriting from CWindowIMPL, in order to create a parent window that contains ActiveX controls, here CFramewIntraits, indicates that the window creates a Frame style. Inheriting from IdispeventImpl, in order to accept events included in the control.

(2) There are two ways to create a Hosting window, as follows:

@ A method RECT rect = {0, 0, 400, 300}; m_axwnd.Create (m_hWnd, rect, _T ( "MSCAL.Calendar.7"), WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); m_axwnd.CenterWindow (); M_axwnd.SetWindowText ("ActiveX Host Window"); SubclassWindow (M_AXWnd.m_hWnd); // Method, you can also use m_axwnd, set Windowname to "Atlaxwin" directly in Create directly to create Rect Rect = { 0, 0, 400, 300}; Create (NULL, rect, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); CenterWindow (); SetWindowText (_T ( "ActiveX Host Window")); m_axwnd.Attach (m_hWnd); m_axwnd .CreateControl (Olestr ("Mscal.Calendar.7))); these words are very simple, the meaning of specific functions can be investigated MSDN.

(3) After the Hosting window is created, it is necessary to establish an event connection, as follows:

// Establish an event connection ccomptrol (m_axwnd.QueryControl (IID_IUNKNOWN, (Void **) & spiunknown; dispeventadvise (spiunknown, & diid_dcalendarevent);

The effect is as shown in the figure:

转载请注明原文地址:https://www.9cbs.com/read-56722.html

New Post(0)