WTL source code analysis --- atlapp.h

xiaoxiao2021-03-06  64

Author: Jiang Jiang QQ: 457283E-mail: jznsmail@163.netATLAPP.H contains the message loop class, some basic class definition interface classes, and generate the necessary application.

The class is defined as follows:

CMessageFilter class --- for message filtering

CIDEHANDLER class --- for free message processing

CMessageloop class --- for message loop

CAPPModule Class --- Application Basic Class

CserveRAppModule class --- Application class for COM service architecture

There are also three full-class functions:

ATLGETDEFAULTGUIFONT () Get the default display font

ATLCREATEBOLDFONT () generates a bold font

AtlinitcommonControls () Initialize the common DLL you need to control some controls

WTL program structure

The creation of a window program to the destruction process is mainly due to the following stages.

1. Registration window class

2. Create a window

3. Enter the message loop

If a person written by Cezen Win32 window program will remember the following structure:

// Window process handler

LResult Callback WndProc (HWND HWND, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM);

Int WinApi WinMain (Hinstance Hinstance, Hinstance Hprevinstance, LPSTR SZCMDLINE, INT ICMDSHOW)

{

HWND HWND = NULL;

MSG msg;

...

WNDCLASS WNDCLASS;

WNDCLASS.Style = CS_HREDRAW | CS_VREDRAW;

WNDCLASS.LPFNWNDPROC = WNDPROC;

...

// Register window

IF (! registerclass (& wndclass))

{

MessageBox (Null, Text ("Porgram Requires Windows NT!"), SZAPPNAME, MB_ICONERROR);

Return 0;

}

// Create a window

HWND = CREATEWINDOW (Szappname, Text ("My Application"),

WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, HINSTANCE, NULL;

ShowWindow (hwnd, icmdshow);

UpdateWindow (HWND);

// Enter the message loop

While (GetMessage (& MSG, NULL, 0, 0))

{

TranslateMessage (& MSG);

DispatchMessage (& MSG);

}

Return msg.wparam;

}

Then where you may ask the WTL's Winmain function? If you guide an application via the WTL / ATL, you will find the following code in the .cpp file with the same name as the project name:

Int WinApi _twinmain (Hinstance Hinstance, Hinstance / * Hprevinstance * /, LPTSTR LPSTRCMDLINE, INT NCMDSHOW)

{

HRESULT HRES = :: Coinitialize (NULL);

// if you are running on nt 4.0 or higher you can use the following call instead to

// Make The Exe Free Threaded. This Means That Calls Come in A Random Rpc thread.// HRESULT HRES = :: CoinitializeEx (NULL, COINIT_MULTITHREADED);

Atlassert ("succeeded (hres));

// this Resolves ATL WINDOW THUNKING Problem When Microsoft Layer For Unicode (MSLU) IS Used

:: DefWindowProc (NULL, 0, 0, 0L);

AtlinitcommonControls (ICC_COOL_CLASS | ICC_BAR_CLASSES); // Add Flags to Support Other Controls

HRES = _Module.init (NULL, HINSTANCE); //, analyzes its implementation atlassert (succeeded (hres));

INT nret = run (lpstrcmdline, ncmdshow); // key points for programs

_Module.Term ();

:: Couninitialize ();

Return nret;

}

From this _twinmain function, you can find that the key part of the program is the Run () function that I am labeled in my purple. This function is a custom function, but if you automatically generate such a Run () function, let's first analyze this automatically generated RUN function.

INT Run (LPTSTR / * LPSTRCMDLINE * / = null, int ncmdshow = sw_showdefault)

{

CMessageloop theloop; // Define message loop

_Module.AddMessageLoop (& TheLoop); // Add messages to message loop

CMAINFRAME WNDMAIN; // Application Framework

// Generate a framework

IF (WNDMAIN.CREATEX () == NULL)

{

ATLTRACE (_T ("Main Window Creation Failed! / N")));

Return 0;

}

// Display framework

WNDMAIN.SHOWINDOW (NCMDSHOW);

// Run the message loop

INT nret = theloop.run ();

// Clear the message

_Module.RemoveMessageloop ();

Return nret;

}

Through this Run function we can see the following procedures in the function:

1. Generate a message loop object (theloop)

2. Add this message loop in the global _module

3. Generate an application framework object

4. Display application framework

5. Start message loop

6. End message loop

7. Return to WinMain functions, end the program

Implementation analysis

In this article I don't want too much to analyze the details of the application framework and window, which will be placed in detail in several articles, this paper mainly analyzes some of the processes implemented in atlapp.h header files.

First start from the global variable _module.

_Module maintains the main thread that generates the application, controls the message loop queue of the program, is an object of a CappModule. This cappmodule inherits from atl :: ccommodule.

In WTL :: CappModule, 8 public member functions are defined, respectively:

AddMessageloop () Add a message loop to enter the message loop queue. RemoveMessageLoop () Removes the message loop queue.

GetMessageloop () gets the message loop.

INITSETTINGENGENOTIFY () initialization environment

AddSettingChangeNotify () Add a window handle.

RemoveSettingChangeNotify () Clean up the environment

In addition to eight public member functions, this class also defines three public member variables.

m_dwmainthreadid is responsible for saving the main thread ID of the application

M_PMSGLOOPMAP is responsible for the storage message loop

M_PSettingChangeNotify is responsible for the storage window handle

The implementation of several major member functions is analyzed separately:

Bool AddMessageloop (CMessageloop * PMSGLOOP)

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

/ / Lock the key pieces, due to the relationship of the process synchronization! ! !

IF (filed (Lock.lock ())))

{

Atltrace2 (ATLTraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: addMESSAGELOOP./N"));

Atlassert (false);

Return False;

}

Atlassert (PMSGLOOP! = NULL);

Atlassert (m_pmsgloopmap-> lookup (:: getcurrentthreadid ()) == null); // not in map yet

Bool Bret = m_pmsgloopmap-> add (: getcurrentthreadid (), pmsgloop;

Lock.unlock ();

Return Bret;

}

The key part I use the red font to marke out, what is it? Sign up by the ID of the current thread to indicate a message loop, stored in m_pmsgloopmap.

Bool removemessageloop ()

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: removemedageloop./n"));

Atlassert (false);

Return False;

}

Bool Bret = m_pmsgloopmap-> remove (:: getCurrentThreadId ());

Lock.unlock ();

Return Bret;

}

The key part also marks the red font, um, if you are just like the addMessageloop function, the function is also looking for a message loop to remove the message through the thread ID.

CMessageloop * getMessageloop (DWORD DWTHREADID = :: getcurrentthreadid ()) Const

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: getMessageloop./n")));

Atlassert (false);

Return NULL;

}

CMessageloop * ploop = m_pmsgloopmap-> lookup (dwthreadid); lock.unlock (); LOCK.UNLOCK

Return plop;

}

This function looks for a corresponding message loop through the thread ID in the m_pmsgloopmap message queue, and then finds it back.

Bool INITSETTINGENGENGENTIFY (DLGPROC PFNDLGPROC = _SETTINGCHANGPROC)

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: initsettingchange./N"))

Atlassert (false);

Return False;

}

IF (m_psettingchangenotify == null)

{

Typedef atl :: CsimpleArray _notifyclass;

ATLTRY (m_psettingchangenotify = new _notifyclass);

Atlassert (m_psettingchangenotify! = Null);

}

BOOL BRET = (m_psettingchangenotify! = Null);

IF (Bret && M_PsettingChangeNotify-> getSize () == 0)

{

// init everything

_ATL_EMPTY_DLGTEMPLATE TEMPL;

// Add a modular dialog

HWND HNTFWND = :: Createdialogindirect (getModuleInstance (), & Templ, NULL, PFNDLGPROC;

Atlassert (:: iswindow (hnts);

IF (: iswindow (hntfwnd))

{

// NEED CONDITIONAL CODE BECAUSE TYPES DON '' Match in Winuser.h

#ifdef_win64

:: SetWindowlongPtr (Hntfwnd, GWLP_USERDATA, (long_ptr) this);

#ELSE

:: SetWindowlongptr (Hntfwnd, GWLP_USERDATA, PTRTOLONG (THIS));

#ENDIF

/ / Add to this window handle

Bret = m_psettingchangenotify-> add (hntfwnd);

}

Else

{

Bret = false;

}

}

Lock.unlock ();

Return Bret;

}

This function is used to initialize an object that stores the window handle.

Bool INITSETTINGENGENGENTIFY (DLGPROC PFNDLGPROC = _SETTINGCHANGPROC)

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: initsettingchange./N"))

Atlassert (false);

Return False;

}

IF (m_psettingchangenotify == null) {

Typedef atl :: CsimpleArray _notifyclass;

ATLTRY (m_psettingchangenotify = new _notifyclass);

Atlassert (m_psettingchangenotify! = Null);

}

BOOL BRET = (m_psettingchangenotify! = Null);

IF (Bret && M_PsettingChangeNotify-> getSize () == 0)

{

// init everything

//? ? Empty ATL DIALOG TEMPLATE?

_ATL_EMPTY_DLGTEMPLATE TEMPL;

// Add a modular dialog

HWND HNTFWND = :: Createdialogindirect (getModuleInstance (), & Templ, NULL, PFNDLGPROC;

Atlassert (:: iswindow (hnts);

IF (: iswindow (hntfwnd))

{

// NEED CONDITIONAL CODE BECAUSE TYPES DON '' Match in Winuser.h

#ifdef_win64

:: SetWindowlongPtr (Hntfwnd, GWLP_USERDATA, (long_ptr) this);

#ELSE

:: SetWindowlongptr (Hntfwnd, GWLP_USERDATA, PTRTOLONG (THIS));

#ENDIF

Bret = m_psettingchangenotify-> add (hntfwnd);

}

Else

{

Bret = false;

}

}

Lock.unlock ();

Return Bret;

}

// Clean the message

Void TermSettingChangeNotify ()

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: termsettingchangenotify./N"))

Atlassert (false);

Return;

}

IF (m_psettingchangenotify! = null && m_psettingchangenotify-> getSize ()> 0)

// Destroy the window

:: DestroyWindow ((* m_psettingchangenotify) [0]);

Delete m_psettingchangenotify;

M_PSettingChangenotify = NULL;

Lock.unlock ();

}

Bool AddsettingChangeNotify (HWND HWND)

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: addsettingchangenotify./n"));

Atlassert (false);

Return False;

}

Atlassert (:: iswindow (hwnd); bool bret = false;

IF (INITSETTINGENGENGENOTIFY ()! = false)

Bret = m_psettingchangenotify-> add (hwnd);

Lock.unlock ();

Return Bret;

}

Bool RemoveSettingChangeNotify (HWND HWND)

{

CStaticDataInitCriticalSECTIONLOCK LOCK;

IF (filed (Lock.lock ())))

{

ATLTRACE2 (Atltraceui, 0, _T ("Error: Unable to lock critical section in capmodule :: removesettingchangenotify./n"));

Atlassert (false);

Return False;

}

BOOL BRET = FALSE;

IF (m_psettingchangenotify! = null)

Bret = m_psettingchangenotify-> remove (hwnd);

Lock.unlock ();

Return Bret;

}

Now returns to the Run () function that just mentioned, the first place defines a CMessageLoop loop object, then join the _Module object Add to the loop queue until _Module calls the REMOVEMESSAGELOOP removal cycle queue, program End the loop and return to the WinMain function.

There is also a more important class here, that is, cMessageloop, is the message he maintaining the system, maintaining the life cycle of the program. Then let's take a look at the definitions and specific implementation methods of this class.

CMessageLoop contains some member functions and member variables

Member variables

// Processing a message

Atl :: csimpleArray m_amsgfilter;

// Process the free handle

Atl :: CSIMPLEARRAY M_AIDEHANDLER;

// Win32API message structure

MSG M_MSG;

Member function (functions with red tags is virtual function)

AddMessageFilter Add a message filtering

RemoveMessageFilter removes a message filtering

AddIdleHandler joins an free handle

RemoveidleHandler removes an free handle

Addupdateui designs for compatible ATL

RemoveUpdateui designs for compatible ATL

IsidleMessage filtering some messages such as WM_MOUSEMOVE

RUN message loop. Important section! ! !

PretranslateMessage Message Filter

OnIDLE idle processing

Then I don't prepare a detailed analysis of each function, mainly analyze the core functions run, CMessageLoop by it to maintain the system's message loop.

The function is as follows:

Int run ()

{

//idle?

Bool bdoidle = true;

// idle counter

INT NIDECOUNT = 0;

// Return to the logo

BOOL BRET;

// Start the message loop! ! !

For (;;)

{

// When bdoidle is True, and cannot take the message from the message queue, then start free operation! // pm_noremove: Remove the message from the queue after the PEEKMESSAGE function is processed

While (BDOIDLE &&! :: PeekMessage (& M_MSG, NULL, 0, 0, PM_NOREMOVE))

{

IF (! OnIdle (NidleCount ))

BDOIDLE = FALSE;

}

// Get a message from the current thread

// Return -1 indicates an error

// Returns 0 indicates that a WM_QUIT is submitted, and the program will exit.

// Successfully get a message, return a value equal to 0

Bret = :: getMessage (& M_MSG, NULL, 0, 0);

IF (BRET == -1)

{

Atltrace2 (Atltraceui, 0, _t (":: getMessage returned -1 (error) / n"));

Continue; // Error, Don't Process

}

Else if (! BRET)

{

ATLTRACE2 (Atltraceui, 0, _T ("cMessageloop :: run - exiting / n"));

Break; // wm_quit, EXIT Message Loop

}

// If you are familiar with the use of C language to write Win32 programmer, it is found that the statement that processes the message loop in WinMain is here! ! !

IF (! PretranslateMessage)

{

// Translates Virtual-Key Messages Into Character Messages.

:: TranslateMessage (& M_MSG);

// dispatches a message to a window procedure

:: DispatchMessage (& M_MSG);

}

/ / Judgment whether it is an idle message?

/ / Exclusions WM_MOUSEMOVE WM_NCMOUSEMOVE WM_SYSTIMER message

IF (ISIDEMESSAGE (& M_MSG))

{

BDOIDLE = True;

Nidlecount = 0;

}

}

Return (int) m_msg.wparam;

}

The above is the analysis of several important classes in Atlapp.h, and there are several other classes. I will put in future articles.

(to be continued...)

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

New Post(0)