WTL architecture (2)

zhaozj2021-02-16  41

WTL architecture

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.

(Endlessly)

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

New Post(0)