WTL architecture

xiaoxiao2021-03-06  68

introduction

WTL is finally coming, and it provides the function I want. I list the WTL main feature in WTL BYTESIZE (translated) article. In this article, I will describe the WTL architecture, and I will give some simple Example to demonstrate how to use it. I hope to help you.

WTL application type

WTL has several application types for you to choose from AppWizard.

The following table describes these applications. This elastic constitutes a part of the WTL architecture.

Application Type Description SDI Application Single text interface - only one window Multiple Threads SDI single process has one or more window MDI Application Multi-text interface - In the frame, you can have zero or more sub-window Dialog Based Based on dialog-based

You may still have a multi-threaded SDI application for the first time, but don't worry, its concept is easy to understand. It will have a window after the multi-thread SDI program starts, and the window shows a document. When you want the program to create another When a document, the problem will only display a document. In order to solve this problem, multi-threaded SDI creates another SDI window. It seems to be a new instance is running, actually it is just the original The process creates a new window and attached it to a new thread of the process. The new window of IE is doing this.

In addition to multi-threaded SDI, all of these applications can be used as a COM server, and the application wizard provides this option. In addition, the application wizard also allows you to specify whether the program hosts an ActiveX control. It is a puzzling Different program types, select "Host ActiveX Controls". Different. In addition to other types of dialog applications, the dialog type is placed in the second page.

Other options in the second page are available to the types other than the dialog program. They let you specify whether the program needs the toolbar, Status Bar and the View Window.

If you select the "Toolbar" option, you can choose whether to put the toolbar in the IE Rebar control via "Rebar". If you choose Rebar, you can pass the Frame Window member m_hwndtoolbar (detail later Description) to access it. You can add other toolbars in your own place. After "Rebar", you can decide whether to choose "Command Bar". Command bar is like CE's Command Bar control. Just WTL is implemented in a class, while in CE, Command Bar is a system window class. Command bar is very useful, it can join the window to the toolbar. If you choose this option, tool The strips and menus will be implemented as Toolbar. This allows menu items to have associated icons, and when you move your mouse to a menu item, the menu item will be set to high. From Office 97, Office The software's menus have the above features.

On the second page, there is an option for the specified program to use (mostly you want to use), and you can decide how these views are implemented. The following table lists all optional views.

Depending on the Generic Window a simple window. This window allows programmers to write a process function for WM_Paint messages. Suitable for documents that need to be directly Paint. The form has a dialog template. Suitable for windows with ActiveX controls. Application The program is operated. LLIST Box This is a list box. Its simplest form means that you can add a string by calling the addstring () method. Edit Control. Estate, it provides a Notepad Program. List view This is a list view universal control. Use this control to display related items (for example, the control panel is a List view of an Explorer, all items are control panel applets .tree View This is a Tree View General Control. This applies to data with hierarchical relationships. For example, you can use it to display the Schema of the database. Top branch is a table and stored procedure, the secondary branch is a field in the table. Rich Edit This is a Rich Edit control. Like WordPad.html Page, this will host an IE Web Browser control. It regards a hosted a web page as a view. This article requires a dialog template, but also a menu, so Form View is an ideal choice.

Program thread

Like ATL, the WTL program also requires a _Module global variable to save global data, which is convenient for application level code access. In WTL, this variable is an instance of CAPPMODULE or CSERVERAPPModule, which is used as a COM server simultaneously. Each application has one or more UI threads. WTL uses two ways to manage these threads. If the application has only one UI thread (except for multi-threaded SDI, other program types only have only one UI thread), thread calls global functions Run ():

int Run (LPTSTR / * lpstrCmdLine * / = NULL, int nCmdShow = SW_SHOWDEFAULT) {CMessageLoop theLoop; _Module.AddMessageLoop (& theLoop); CMainFrame wndMain; if (wndMain.CreateEx () == NULL) {ATLTRACE (_T ( "Main window Creation failed! / n ")); return 0;} wndmain.showwindow (ncmdshow); int nret = theloop.Run (); _Module.removeMessageloop (); return nret;}

The message loop of the thread is included inside the CMessageLoop. The function creates a CMessageLoop instance to put it in the Message Loop map. With the thread ID, other code running in the thread can access this instance The message loop object contains Message Filter and IDLE Handler. The UI Element running in this UI thread can have its own idle handler, running when the message queue is empty [Demo: CMESSAGELOOP :: AddIdleHandler ) Add this UI component to the cMessageloop's IDLE Handler array]. CMessageloop :: run () contains Main Message Map of the UI thread. The lower side is its pseudo code: msg m_msg; int cMessageloop :: run () {For (;;) {while (! :: peekmessage (& m_msg, null, 0, 0, pm_noremove)) DoidleHandlers (); Bret = :: getMessage (& M_MSG, NULL, 0, 0); if (Bret = = -1) Continue; Else if (! Bret) Break; if (! DoadsageFilters) {:: TranslateMessage; :: DispatchMessage (& M_MSG);}}}} Return (int) m_msg.wparam;} can see When this function drives the message queue. When there is no message, run the IDLE Hander registered to the thread. If the message is detected in the queue, take it out, pass it to each message filter. If the message is not processed by these functions, it Will be sent to the target window according to the usual way. If the program has more than one UI thread, you can use the WTL thread manager, multi-threaded SDI is doing this. The main thread is used as a manager thread, which will make each new The window creates a new new thread. The main process is as follows: int nRet = m_dwCount; DWORD dwRet; while (m_dwCount> 0) {dwRet = :: MsgWaitForMultipleObjects (m_dwCount, m_arrThreadHandles, FALSE, INFINITE, QS_ALLINPUT); if (dwRet> = WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 m_dwCount - 1)) RemoveThread (DWRET - WAIT_Object_0); Else IF (wait_Object_0 m_dwcount)) {:: GetMessage (& MSG, NULL, 0, 0); if (msg.Message == WM_USER) AddThread (_t ("), sw_shownormal );

}} Those thread handles are placed in an array. Threads are added to an array via addthread (), and removeThread () removes from the array. Wait statement will be interrupted in both cases: thread death (thread thread Transfer from an array) or thread receives the WM_USER message (a thread has created a window in a new thread). Thread managers are a class in the program, so you can join your own Message Handler in the loop, such as when the program There is a window type. Creating a new window is very simple, just call in any window :: PostthreadMessage (_Module.m_dwmainthreadid, wm_user, 0, 0L); this loop will run until all The UI thread is closed. The UI thread has a Thread Procedure, which is the same as the RUN () method of the single UI thread. However, since the thread manager uses MsgWaitFormultipleObjects (), this will only have maximum_wait_objects-1 UI thread This also means that you can only create up to 63 windows. Frame WTL is actually two types of window: Frame window and view window. As in the name of the name, the frame window provides the title bar (Caption bar) and border, you The code uses it to handle the toolbar and menu item. The program window you see is actually a view window, and the view covers the client area of ​​the frame window. The client area means that the frame window is not subject to the status, The part of the modifier of the toolbar. The thread creates an instance of the main frame window. Creating a view is done by the WM_CREATE message processing function of the main frame window. For SDI programs, this process is simple. Put the view An example of a class as a member of the main framework class, calls the Create () method of the view class. MDI program is slightly different, and the MDI main frame window creates a window called MdiClient by cmdiframeWindowImpl <> :: CreateMdiclient (). This customer window will use the CMDICHILDWINDOWIMPL <> window as its sub-window, a sub-window has a view. This also reflects the fact that the MDI program can have zero or more sub-windows, each with a border and title bar. Frame Window Oncreate () is very interesting, let me see: Lresult Oncreate (Uint, WParam, Lparam, Bool &) {// Create Command bar window HWND hWndCmdBar = m_CmdBar.Create (m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE); // attach menu m_CmdBar.AttachMenu (GetMenu ()); // load command bar images m_CmdBar.LoadImages (IDR_MAINFRAME); // remove old menu SetMenu (NULL); HWND hWndToolBar = CreateSimpleToolBarCtrl (m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE); CreateSimpleReBar (ATL_SIMPLE_REBAR_NOBORDER_STYLE); AddSimpleReBarBand (hWndCmdBar); AddSimpleReBarBand (hWndToolBar, NULL, TRUE); CreateSimpleStatusBar (); m_hWndClient = m_view.Create (m_hWnd, rcDefault , NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE

UIAddToolBar (hWndToolBar); UISetCheck (ID_VIEW_TOOLBAR, 1); UISetCheck (ID_VIEW_STATUS_BAR, 1); CMessageLoop * pLoop = _Module.GetMessageLoop (); pLoop-> AddMessageFilter (this); pLoop-> AddIdleHandler (this); return 0;} This A code from an SDI program that has a COMMAND BAR-based toolbar and a status bar. The first line of the function creates a Command Bar instance, then initialize it, add the frame window. Menu and Tools Chart. This code first removes the menu, converts all the drop-down menu to the toolbar button, and save the menu in a variable to use it. Give people a menu is made by the toolbar Realize - then let's call it toolbar menu. The Command Bar then loads the icon of the program toolbar into the image list and saves their IDs in an array. When you click the button of the toolbar menu, CommandBar will find the corresponding submenu, create a pop-up menu. Compare the ID of the submenu item with the ID of the submenu, which is associated with the toolbar icon in Image List. If it is successful, Put the associated icon to the menu item. This means that the menu item and the toolbar button of the same ID have the same icon. Next, create a toolbar and associate it to CommandBar, then create status bars and views. You can see it. The HWnd of the view is stored in the m_hwndclient variable of the frame window. This window handle is used in the WM_SIZE HANDAL of the frame window. When the frame window changes the size, it tells the view to change itself, but also consider the status strip and Command Bar at the same time. The next three lines (starting from the call uiaddtoolbar () used to display the UI item (UI Item) that changes the status at runtime. The article will override this topic later. Finally, the Message Loop, You should still remember that the message loop is stored in an array. GetMessageLoop () gets the current thread message loop, join the Message filter and iDle handler of the frame window, the default is PretranslateMessage () and ON . Idle () frame window inherits the following classes: class CMainFrame: public CFrameWindowImpl , public CUpdateUI , public CMessageFilter, after two abstract classes declared public CIdleHandler the frame window class implements the PreTranslateMessage () and the OnIdle () From CUPDATEUI <> inheritance represents the framework class supports the UI Update Map.

view

The view window looks very simple:

class CMyView: public CWindowImpl {public: DECLARE_WND_CLASS (NULL) BOOL PreTranslateMessage (MSG * pMsg) {pMsg; return FALSE;} BEGIN_MSG_MAP (CMyView) MESSAGE_HANDLER (WM_PAINT, OnPaint) END_MSG_MAP () LRESULT OnPaint (UINT, WPARAM, LPARAM , Bool &) {CPAINTDC DC (M_HWND); // Todo: Add Your Drawing Code Here Return 0;}}; The above is a view class of an SDI program. The view class of multi-threaded SDI and MDI is essentially like this. But they don't have a PretranslateMessage () method. The SDI program uses this function to catch the message before the framework class processing message. PretranslateMessage () The implementation in the SDI's frame class is to forward the message to the view class. Here display The view doesn't actually do something. You should add code that draws the document content in the onpaint () function. If you need to support your input, such as click on the mouse, you should join the corresponding message processing function to the class and In the mapping. You can see that this window is inherited from cwindowimpl <>, if you want it to be based on a Win32 control, you should inherit a WTL class defined in an atlctrls.h file. If you want to CWindowIMPL > The class is plus the scroll bar, then you should change the base class to cscrollwindowimpl <>, while putting the message chain to it:

class CMyView: public CScrollWindowImpl {public: typedef CScrollWindowImpl parent; BEGIN_MSG_MAP (CMyView) CHAIN_MSG_MAP (parent) END_MSG_MAP () void DoPaint (CDCHandle dc) {}}; base class guarantees window includes a scroll bar, and provides a rolling The default processing of the message. The view class no longer has a WM_Paint process function because it has been processed by CScrollWindowImpl <>. According to the position of the scroll bar, the CSCROLLWINDOWIMPL <> draws the corresponding part of the view. Reveared, in your class To implement DopAint (), here you need to draw a whole view. If you want to specify the range, size, or starting point of the scrolling, you need to add the function that processes the WM_CREATE message, put these initialization code inside. As I first mentioned When it comes, the frame window changes the size of the view window to make the portion of the client area not covered by the status bar and the toolbar. In most cases, it is enough. But when you want one What should I do when Windows Explorer? Windows Explorer's window contains a Tree View and a List view, there is a split bar between the two. WTL's solution is simple: use the splitter window! For this purpose You need to change the frame window, let it create an instance of the splitter window as its view. For example, there is a data member in your frame class: ctreeWindow m_view; ctreeviewctrl m_tree; clistviewctrl m_list; you can create one in oncreate () splitter window: // get the frame client rect, so that we set the splitter initial size // and we can get the splitter bar in the centreRECT rect; GetClientRect (& rect); m_hWndClient = m_view.Create (m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE); M_TREE.CRE ate (m_view, rcDefault, NULL, WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT, WS_EX_CLIENTEDGE); m_list.Create (m_view, rcDefault, NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT, WS_EX_CLIENTEDGE); m_view.SetSplitterPanes (m_tree, m_list); m_view .Setsplitterpos ();

The splitter window is like a view, the frame window as its parent window. In this code, I passed the actual size of the frame window client area to the splitter window. I can use RCDefault here, because once the frame window creates completion The frame window will forward the WM_SIZE message to splitter. Such splitter can change its own size to fill the frame. However, when I am ready to use a parameter-free setSplitterpos (), the split bar is set to the window midline, there is a problem. The splitter window uses its size to determine the center of the center, because rcdefault tells the window its size is 0 (therefore the center line is also 0), which means that the split strip will appear in Z left edge, hide the left window. Create Once the splitter window, you need to create the window you want to split. They will be created as the sub-window for the Splitter window. Finally, you will be added to the SPLitter window via setsplitterpanes () and determine the splice strip. The location. TheUI Update menu item can be set to be valid or invalid, you can take the check mark or like a Radio button, in a set of menu items, only one can be CHECK. In addition, the menu item can also with icon and Text. All of these states can be changed according to a value in the program at runtime. The toolbar can see some degree of easy-to-see menu because their buttons can be individually, or as a group Part of the part is set effective or invalid, pushing. UI Update mechanism allows you to specify which UI Element can change at runtime. WTL uses the following Update mapping to implement this feature: Begin_UPDATE_UI_MAP (CMAINFRAME ) UPDATE_ELEMENT (ID_FILE_SAVERESULTS, UPDUI_MENUPOPUP | UPDUI_TOOLBAR) UPDATE_ELEMENT (ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP) UPDATE_ELEMENT (ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP) END_UPDATE_UI_MAP () this example points out three menu items have a state needs to display at runtime, one, ID_FILE_SAVERESULTS, as well as a tool The strip button is associated with it. WTL saves this information by establishing an array. To this end, you need to complete two works:

The first is the status of the UI component. If it is a menu item, you can use uieNable () enable the menu item, uisetcheck () set the check mark, uiSettext () change the text of the menu. If it is the toolbar button, then you use uienable. Enable the button, uisetcheck () or uiSetradio () decision button is put into or launched. The following code is selected according to whether there is text, to enable the CUT menu item and the toolbar button: BOOL bselected = getSelected (); uieNable (Id_edit_cut, bselected); You can put this code into the corresponding processing function (such as a menu item depending on the action of another menu item, put it into the latter's processing function), or put onIdle () Method, by checking a certain type variable to determine the status of the component. Second, it is to determine if each UI component is updated, and for this, you need to call a certain method of CupdateUi <> to add the UI component to the list. Main menu Has been automatically added, but other menus and all the toolbars must be joined manually by calling uiaddmenubar () and uiaddtoolbar (). At other, there is also a bunch of things to pay attention. First, use UiupDateToolbar after setting the toolbar. ) So that the tool strip status is updated. For menus, you don't need this, because the submenu is dynamically generated .uiupdateMenubar () method also exists, but its role is to restore the menu to the initial state, if you change some The text of the item, the result of calling UiupdateMenubar () may not be what you expect (because the text of the menu item will become old). Although there is still a method uiTradio (), but there is no one menu item or toolbar The button is called a Radio button (that is, there is one and only one selected) mechanism. If you want to get this effect, you must encode yourself, but it is not difficult.

The dialog ATL's dialog supports the universal dialog, which has added a universal dialog package. Even joining the input verification and callback functions for the dialog. For example, you want to change the Year Open dialog in the user. some action folder, then you should <> CFileDialogImpl inherit from a class that implements OnFolderChange (): class CMyFileDialog: public CFileDialogImpl {public: CMyFileDialog (BOOL b): CFileDialogImpl (b) {} void OnfolderChange (LPOFNOTIFY LPON) {char strfolder [max_path]; if (getFolderPath (Strfolder, Sizeof (Strfolder))> 0) {MessageBox (Strfolder);}}};

When the path of the folder changes, CFiledialogIMPL <> calls onfolderchange (). This function uses the base class getFolderPath () to get a new path. Control WTL provides package classes for all Win32 and General Controls, including Windows 2000 new join Although only simple packaging, they make these controls easier access. For example, can you remember to read the message of the current selected item from the list view and the parameters that need to pass? (In fact, you need to send two messages, one is the index of the selected item, the other is to read its text.) The author of the WTL has completed these annoying work for you, providing a simple package function for You use it. There are two ways to use these controls. If you have a control in your dialog, you can attach the HWnd of the control to a package object, access the control using the package class. This method simplifies you read Write the control data and handle the code for the Notification message. Additional usage is to add these classes to your view class in the inheritance hierarchy: Class CMYVIEW: PUBLIC CWINDOWIMPL This means that CWindowImpl "is from CListBox inheritance Therefore, the created window will be a list box (because the name of the window class is obtained by calling clistbox :: getWndclassName (). In addition, the ATL window mechanism will type this window, will send it to the message route Your message map. It retains the old window function, so that the message you have not processed will be processed by the old window function. When your view class is inherited from the control class, WTL will use this technology. NOTIFICATION message and subclass of this topic, one thing is worth pointing, that is, when the event occurs, most of the window controls send the Notification message to their parent windows. Let you have a window to handle these Notification messages Category An existing control window (or subcatencies an existing class, then establish an instance), so that the message is much better before the control. For example, you want to handle the Click event you need to do. Just Handle BN_Clicked Notification. It will send you a window class by the button. Another way is to process Click messages from the CContainedWindow <> subclass button. I said this is because a well-known ATL advocacy gives me one This is done in the code. His code acquired a simple button Click event is 3 to 4 times that of others, because he is a button control, rather than a simple handling BN_Clicked Notification.WTL is also available. Some new controls, there is no peer in Win32. You have seen a - Command Bar, in fact, there are other very useful classes:

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

New Post(0)