wtl architecture

Application typedescribe
sdiSingle text
Multithreaded sdiOne process, multiple windows
mdiFrame, multi window
dialogueDialog based

Multithreaded sdi new sdi windows and applications can be used as com servers Rebar bars are containers for toolbars, etc The command bar adds a window to the toolbar With rebar, press the toolbar to realize the toolbar and menu In this way, the menu also has associated icons
Optional visual:

Simple windowProcess WM_PAINT, when drawing directly
form With dialog template, application operation
list boxString can be added
Edit boxHere's your editor
List viewSuch as control panel
Tree visionFor hierarchical relationships,
Rich textRich text

Program thread

Same as atl, there is one_ Module, which is the instance of cappmodule / csserverappmodule (COM) The application has 1 / multiple ui threads Single ui calls global Run

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
    CMessageLoop theLoop;
    CMainFrame wndMain;
    if (wndMain.CreateEx() == NULL)
        ATLTRACE(_T("Failed to create main window"));
        return 0;
    int nRet = theLoop.Run();
    return nRet;

Loop messages within CMessageLoop Put into the global message mapping group Index by thread There are filter messages / idle processing, and interface elements can have their own idle processing Add yourself to the processor array of the message loop Run contains the main message mapping:

MSG m_msg;
int CMessageLoop::Run()
    for (;;)
        while (!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
        bRet = ::GetMessage(&m_msg, NULL, 0, 0);
        if(bRet == -1)continue;
        else if(!bRet)break;
        if (!DoMessageFilters(&m_msg))
    return (int)m_msg.wParam;

For multi interface threads, use wtl's thread manager

int nRet = m_dwCount;
DWORD dwRet;
while(m_dwCount > 0)
    dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles,
    if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1))
        RemoveThread(dwRet - WAIT_OBJECT_0);//Delete thread
    else if(dwRet == (WAIT_OBJECT_0 + m_dwCount))
        ::GetMessage(&msg, NULL, 0, 0);
        if(msg.message == WM_USER)
            AddThread(_T(""), SW_SHOWNORMAL);//Add a thread and start it

WM received / thread removed_ When the user message, disconnect the wait You can also add your own message processor to the pipeline When there are multiple window types, to create a window, you only need any window to execute

::PostThreadMessage(_Module.m_dwMainThreadID, WM_USER, 0, 0L);

Interface thread, there is a thread process The conduit uses MsgWaitForMultipleObjects, so the maximum is used_ WAIT_ Objects (64) thread, up to 63 windows


wtl, two types of windows: frame / view window The frame provides title bar / border, code processing toolbar / menu The view is the customer area
Thread creates the main frame in WM_CREATE view in create sdi has a view class. Just call to create it
mdi, create a window called MDICLIENT in cmdiframewindowimpl < >: createmdiclient() Take cmdichildwindowimpl < > as a sub window (with view), that is, mdi has 1 / multiple windows (with border / title bar, etc.)

    //Create toolbar (command bar)
    HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,
    //Framed menu (toolbar menu)
    //Add Icon
    //Delete the old menu,
    HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME,
    CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);//Toolbar, associating to the command bar
//Reinforcing bar It's a container, a command bar, a toolbar
    AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
    m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);//Handle
    UIAddToolBar(hWndToolBar);//Runtime change
    UISetCheck(ID_VIEW_TOOLBAR, 1);
    UISetCheck(ID_VIEW_STATUS_BAR, 1);
    CMessageLoop* pLoop = _Module.GetMessageLoop();
    pLoop->AddIdleHandler(this);//Two filters
    return 0;
class CMainFrame :
    public CFrameWindowImpl<CMainFrame>,
    public CUpdateUI<CMainFrame>,
    public CMessageFilter,
    public CIdleHandler
//Main frame

Cupdateui < > supports updating interface mapping


class CMyView : public CWindowImpl<CMyView>
    BOOL PreTranslateMessage(MSG* pMsg)
        pMsg;return FALSE;
        CPaintDC dc(m_hWnd);//To do: add painting code
        return 0;

Multithreaded sdi is similar to MDI, but there is no PreTranslateMessage method sdi uses it to distribute processing messages before framework processing, generally forwarding messages to view classes
To support mouse and keyboard, add corresponding message processing function to message mapping If you want to control based, add atlctrls h.
To add a scroll bar:

class CMyView : public CScrollWindowImpl<CMyView>
    typedef CScrollWindowImpl<CMyView> parent;
        CHAIN_MSG_MAP(parent)//On the chain
    void DoPaint(CDCHandle dc)//The function is changed
    {//Draw the entire view, not ` WM_PAINT`

To specify the scrolling range, size, or start point, you need to specify the scrolling range in WM_ Initialization in create
The frame window changes the size of the view window You can also use the splitter window to view trees and columns at the same time
You want to change the frame window to make the splitter window the view If there are:

CSplitterWindow m_view;
CTreeViewCtrl m_tree;
CListViewCtrl m_list;

When creating:

RECT rect;
GetClientRect(&rect);//Take the customer area
m_hWndClient = m_view.Create(m_hWnd, rect,
    NULL, WS_CHILD | WS_VISIBLE);//View create customer
m_list.Create(m_view, rcDefault,NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT, WS_EX_CLIENTEDGE);//Column view
m_view.SetSplitterPanes(m_tree, m_list);
m_view.SetSplitterPos();//When there is no parameter, the center line is 0, which appears on the far left and hides the left window

Like the view, the splitter takes the frame as the parent window, and rcDefault can also be used In WM_ Adjust at size
After creating a splitter window, to create a sub window, use SetSplitterPanes to determine the position of the splitter bar

Update interface

Enable menu, tick mark, or single / multiple choice Menus can have icons and text It can be changed during operation The toolbar is just an externalization of the menu Therefore, it can be grouped effectively Specify which interfaces you want to update at runtime It is realized by updating the interface macro


wtl creates an array to hold this information
Change status:

Menu, toolbar buttonUIEnable
Menu textUISetText
Select in selectUISetRadio/UISetCheck

For example:

BOOL bSelected = GetSelected();//condition
//Whether text is selected
UIEnable(ID_EDIT_CUT, bSelected);//Allow or not

It can be put into the corresponding processing function / OnIdle to check the class variables to determine the element state
Also determine whether they are all updated. Call a method of cupdateui < > to add the interface components to the list and have been automatically added to the main menu
Others add menus / toolbars through UIAddMenuBar() and UIAddToolBar()
After setting the toolbar status, use UIUpdateToolBar to update the status The menu does not have to be like this, because it generates sub menus dynamically Uiupdatemeubar is to restore the initial state
Uisetradio (multiple only single choice) is rarely used. You should code it yourself

dialog box

wtl adds input validation and callback functions For example, if you want to change the action when the user opens the folder in the dialog box, inherit from cfiledialogimpl < > and implement the OnFolderChange function

class CMyFileDialog : public CFileDialogImpl<CMyFileDialog>
    CMyFileDialog(BOOL b)
        : CFileDialogImpl<CMyFileDialog>(b) { }
    void OnFolderChange(LPOFNOTIFY lpon)
        char strFolder[MAX_PATH];
        if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)//Base class Take the path

In this way, it is executed when changing the folder


WTL provides encapsulation classes for all Win32 and general controls
Two usage methods: if there is a control in the dialog box, attach the HWND of the control to the encapsulated object, use its method to access the control, simplify reading and writing control data and processing notification messages
2, Add class to the inheritance of view class

class CMyView : public CWindowImpl<CMyView, CListBox>
//This window, inherited from CListBox,

Get the window class name with GetWndClassName The message will be sent to you. If it is not processed, it will be handled by the parent window
When an event occurs, most window controls send a notification to the parent window It is handled by the window If you want to process the button click, you only need to process BN_ The clicked notification is sent to the window class by the button Or inherit the button window from ccontainedwindow < > to handle click events Faster processing of notification messages and cumbersome inheritance
wtl also provides a command bar Other useful classes:

CBitmapButtonInstead of the title, bitmap can provide a list, which can be switched in normal state, failure, push and mouse falling on the button
CHyperLinkHyperlink, click to open the web page
CWaitCursorWait during construction and restore during destruction
CCheckListViewCtrlCheck the list box
CMultiPaneStatusBarCtrlMulti panel status bar

Added by fj1200 on Tue, 08 Feb 2022 06:56:35 +0200