深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的

作者:工程材料    来源:未知    发布时间:2019-12-18 22:35    浏览量:

     //生成框架

1.怎么将分裂的窗口进度勾到一块儿
正史经历告诉我们,专制往往一时好工作。假诺每种窗口都有友好的窗口进度,那样管理起来就相比费心,最棒的做法是装有的窗口在同三个窗口进度中决定分发。
在BOOL CWnd::CreateEx(...卡塔尔(英语:State of Qatar)之中,实践AfxHookWindowCreate函数(使用SetWindowsHookEx API函数搜聚当前线程的具有音讯),采摘全体新闻放到_AfxCbtFilterHook函数里。
本条函数里实施:
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (DWORD_PTR)afxWndProc); // 注意afxWndProc函数

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.n"));

4.ATL封装窗口创制和消息分发

和MFC封装窗口类同样,这里形似必要思忖早前说的四个难点,首要的思想政治工作说三遍,笔者就再贴一回以前的话。

 

 

1.怎么将差异的窗口进程勾到一块

2.同样窗口进程中哪些将差异的hwnd消息分发给相应的CWnd类去管理响应

3.最后,倘诺CWnd得到了音讯,怎么样去大致有效的去管理和响应呢

 

这里和MFC一样,

1.具有的窗体窗口进度函数同样,保险统大器晚成管理

2.hwnd和对应窗口类是通过汇编免强粘附起来的

3.CWnd拿到新闻后贴近前边的C语言经过生龙活虎组宏简化switch case布局调用对应的音信响应函数

相符大家从源码起头出手:

具备的窗体类都持续于CWndImpl,大家关心那么些类就能够

     //消亡新闻

笔记:争取不要看上面的开始和结果,只看本身的笔记,就会记住这一个流程,固然知道了:

3. 生成贰个应用程序框架对象

2.改善窗口创建

能够观察,最原始的Win32 SDK编制程序完全都以面向进程编制程序成立,比较麻烦,为了简化编写,可在VS二〇一〇里面展开新建叁个Win32 程序能够见到代码如下:

 

[cpp] view plain copy

 

 print?图片 1图片 2

  1. // 1.设计和挂号音讯类  
  2. ...  
  3. MyRegisterClass(hInstance);  
  4.   
  5. // 2.施行应用程序开首化:  
  6. if (!InitInstance (hInstance, nCmdShow))  
  7. {  
  8.     return FALSE;  
  9. }  
  10.   
  11. hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN321));  
  12.   
  13. // 3.主音讯循环:  
  14. while (GetMessage(&msg, NULL, 0, 0))  
  15. {  
  16.     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  
  17.     {  
  18.         TranslateMessage(&msg);  
  19.         DispatchMessage(&msg);  
  20.     }  
  21. }  
  22.   
  23. return (int) msg.wParam;  

能够阅览依据在基本原理中讲的,这里微软的做法也相像,坚守三大学一年级部分包装到函数中,简化操作,InitApplication命名成了MyRegisterClass而已。

 

 

     ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL);   // not in map yet

a卡塔尔(英语:State of Qatar).窗口成立

相通我们拿源码来讲授,

 

在MFC中我们自定义的窗口类世袭关系如下:

CWnd->CFrameWnd->CMyFrameWnd

winfrm.cpp中CFrameWnd::LoadFrame

首先,调用GetIconWndClass->AfxRegisterWndClass完成窗口类设计和登记

然后,调用CFrameWnd::Create->CWnd::CreateEx实现窗口创建,如下:

 

[cpp] view plain copy

 

 print?图片 3图片 4

  1. BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)  
  2. {  
  3. ...  
  4.     LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);  
  5.     CString strTitle = m_strTitle;  
  6.     if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault, pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext))  
  7.     {  
  8.         return FALSE;   // will self destruct on failure normally  
  9.     }  
  10.   
  11. ...  
  12. }  

[cpp] view plain copy

 

 print?图片 5图片 6

  1. LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)  
  2. {  
  3. ...  
  4.     if (hIcon != NULL)  
  5.     {  
  6. ...  
  7.         {  
  8.             // register a very similar WNDCLASS  
  9.             return AfxRegisterWndClass(wndcls.style, wndcls.hCursor, wndcls.hbrBackground, hIcon);  
  10.         }  
  11.     }  
  12.     return NULL;        // just use the default  
  13. }  

在wincore.cpp的CWnd::CreateEx中,创造窗口

[cpp] view plain copy

 

 print?图片 7图片 8

  1. BOOL CWnd::CreateEx(...)  
  2. {  
  3. ...  
  4.     // allow modification of several common create parameters  
  5.     CREATESTRUCT cs;  
  6.     cs.dwExStyle = dwExStyle;  
  7.     cs.lpszClass = lpszClassName;  
  8.     cs.lpszName = lpszWindowName;  
  9.     cs.style = dwStyle;  
  10.     cs.x = x;  
  11.     cs.y = y;  
  12.     cs.cx = nWidth;  
  13.     cs.cy = nHeight;  
  14.     cs.hwndParent = hWndParent;  
  15.     cs.hMenu = nIDorHMenu;  
  16.     cs.hInstance = AfxGetInstanceHandle();  
  17.     cs.lpCreateParams = lpParam;  
  18.   
  19.     ...  
  20.   
  21.     AfxHookWindowCreate(this);  
  22.     HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,  
  23.             cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,  
  24.             cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);  
  25.   
  26.     ...  
  27. }  

其中,在AfxHookWindowCreate中设置钩子使全部窗口语资源信息息勾到一同处理如下:

 

 

[cpp] view plain copy

 

 print?图片 9图片 10

  1. void AFXAPI AfxHookWindowCreate(CWnd* pWnd)  
  2. {  
  3. ...  
  4.         pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());  
  5.     ...  
  6. }  

在_AfxCbtFilterHook中代码如下:

 

 

[cpp] view plain copy

 

 print?图片 11图片 12

  1. LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)  
  2. {  
  3. ...  
  4.         if (pWndInit != NULL)  
  5.         {  
  6.             AFX_MANAGE_STATE(pWndInit->m_pModuleState);  
  7.   
  8.             // the window should not be in the permanent map at this time  
  9.             ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL);  
  10.   
  11.             // connect the HWND to pWndInit...  
  12.             pWndInit->Attach(hWnd);  
  13.             // allow other subclassing to occur first  
  14.             pWndInit->PreSubclassWindow();  
  15.   
  16.             WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();  
  17.             ASSERT(pOldWndProc != NULL);  
  18.   
  19.             // subclass the window with standard AfxWndProc  
  20.             WNDPROC afxWndProc = AfxGetAfxWndProc();  
  21.             oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,  
  22.                 (DWORD_PTR)afxWndProc);  
  23.             ASSERT(oldWndProc != NULL);  
  24.             if (oldWndProc != afxWndProc)  
  25.                 *pOldWndProc = oldWndProc;  
  26.   
  27.         ...  
  28. }  

其中pWndInit->Attach完成句柄hwnd和窗口类CWnd*的绑定,创建一张hash表,对应的HashMap布局可参照他事他说加以考查CWnd::afxMapHWND对应的winhand_.h中的CHandleMap

SetWindowLongPtr使全数的窗口响应都走AfxWndProc中,在AfxWndProc中成就音信分发到相应的Cwnd中。

     hRes = _Module.Init(NULL, hInstance卡塔尔国; //等下解析它的贯彻      ATLASSERT(SUCCEEDED(hRes卡塔尔(英语:State of Qatar)卡塔尔;

1.MFC大框架

盗用侯捷先生一张图,MFC的宗旨档案的次序布局如下:

图片 13

MFC将张开新闻循环放到CWinThread中,将窗口挂号、成立、音信分发响应均放置CWnd中管理,那样有着和窗口管理相关的都以由同三个类来实现,切合C++的封装天性,也会有支持使用。

VS安装完目录VCatlmfcsrcmfc下有部分mfc源码,我们一贯看微软的完毕。

第生龙活虎,入口文件appmodul.cpp中定义入口如下:

 

[cpp] view plain copy

 

 print?图片 14图片 15

  1. extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow)  
  2. #pragma warning(suppress: 4985)  
  3. {  
  4.     // call shared/exported WinMain  
  5.     return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);  
  6. }  

下一场,在winmain.cpp查看定义AfxWinMain如下

 

 

[cpp] view plain copy

 

 print?图片 16图片 17

  1. int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow)  
  2. {  
  3.     ...  
  4.   
  5.     // AFX internal initialization  
  6.     if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))  
  7.         goto InitFailure;  
  8.   
  9.     // App global initializations (rare)  
  10.     if (pApp != NULL && !pApp->InitApplication())  
  11.         goto InitFailure;  
  12.   
  13.     // Perform specific initializations  
  14.     if (!pThread->InitInstance())  
  15.     {  
  16.         ...  
  17.     }  
  18.     nReturnCode = pThread->Run();  
  19.   
  20.     ...  
  21. }  

由此照旧InitApplication、InitInstance、Run三大块,AfxWinInit用于做一些框架的初叶化专门的学问。

CWinApp::InitApplication在appcore.cpp中,和C程序略有分歧,这里的行事任重先生而道远是Doc模板微处理机的发轫化职业。

CThread::InitInstance虚函数会被客户改写,在那中间调用CWnd达成窗口的挂号和开创,这几个在今后一起讲

CThread::Run在thrdcore.cpp中,Run-》PumpMessage-》AfxInternalPumpMessage完结音讯泵的敞开,如下:

 

[cpp] view plain copy

 

 print?图片 18图片 19

  1. BOOL AFXAPI AfxInternalPumpMessage()  
  2. {  
  3.     _AFX_THREAD_STATE *pState = AfxGetThreadState();  
  4.   
  5.     if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))  
  6.     {  
  7. ...  
  8.         return FALSE;  
  9.     }  
  10.   
  11. ...  
  12.   
  13.     if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))  
  14.     {  
  15.         ::TranslateMessage(&(pState->m_msgCur));  
  16.         ::DispatchMessage(&(pState->m_msgCur));  
  17.     }  
  18.   return TRUE;  
  19. }  

 

 

              ATLASSERT(m_pSettingChangeNotify != NULL);

 

     lock.Unlock();

#define ON_WM_CREATE()
{ WM_CREATE, 0, 0, 0, AfxSig_is,
(AFX_PMSG) (AFX_PMSGW)
(static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > ( &ThisClass :: OnCreate)) },
将WM_CREATE和OnCreate函数绑定

 

ATL就比非常多了,采取模板技巧简化了设计,也不曾那么多的等级次序布局,超轻量

          while(GetMessage(&msg,NULL,0,0))

Windows GUI选拔基于事件驱动的编制程序模型,事实上大约具有的界面库都是这样做的。在纯粹的Window32 SDK编制程序时期,大家还足以搞懂整个Windows窗体创造和音信的通商进度,不过在未来各个框架的包装下多数在Window32 SDK下很鲜明易懂的事物显得不是那么粗略了。本文力图去繁求简,教你看懂全体框架的主导协会,而事实上对于了然那整个的人的话,这个分界面框架的宏图都以如出风华正茂辙的,希望看完本文,再去看科学普及的MFC/WTL等框架时,不会再感觉有任何的不适。

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

b卡塔尔(قطر‎.新闻的散发和响应

 

[cpp] view plain copy

 

 print?图片 20图片 21

  1. LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3. ...  
  4.     // all other messages route through message map  
  5.     CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);  
  6.     ...  
  7.     return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);  
  8. }  

可以看出,依据hwnd获得相应的CWnd*,然后看AfxCallWndProc如下:

 

 

[cpp] view plain copy

 

 print?图片 22图片 23

  1. LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, WPARAM wParam = 0, LPARAM lParam = 0)  
  2. {  
  3. ...  
  4.   
  5.         // delegate to object's WindowProc  
  6.         lResult = pWnd->WindowProc(nMsg, wParam, lParam);  
  7. ...  
  8. }  

在这里地最早调用CWnd成员响应函数,终于又回来CWnd中了,接着往下看

 

 

[cpp] view plain copy

 

 print?图片 24图片 25

  1. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3. ...  
  4.     if (!OnWndMsg(message, wParam, lParam, &lResult))  
  5.         ...  
  6. }  

在OnWndMsg中做了什么样吧?看下边代码

 

 

[cpp] view plain copy

 

 print?图片 26图片 27

  1. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  2. {  
  3. ...  
  4.     //WM_COMMAND特殊管理  
  5.     if (message == WM_COMMAND)  
  6.     {  
  7.         if (OnCommand(wParam, lParam))  
  8.         {  
  9.             lResult = 1;  
  10.             goto LReturnTrue;  
  11.         }  
  12.         return FALSE;  
  13.     }  
  14. ...  
  15.   
  16.     //找到当前的CWnd类的MessageMap表,查表得到相应响应函数并管理  
  17.     const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();  
  18.     ...  
  19.   
  20.         for (/* pMessageMap already init'ed */; pMessageMap->pfnGetBaseMap != NULL;  
  21.             pMessageMap = (*pMessageMap->pfnGetBaseMap)())  
  22.         {  
  23.             ...  
  24.         }  
  25.   
  26. ...  
  27. }  

可以见到,到此成就了CWnd中的查表调用音讯对应的管理函数,至于实际的OnCommand音讯管理和现实响应函数调用进度,恕不详述。

 

可是等等,还可能有多个难题远非缓和,那就是CWnd中的消息-管理函数表怎么来的,那正是我们置身事外的如下构造

 

[cpp] view plain copy

 

 print?图片 28图片 29

  1. BEGIN_MESSAGE_MAP(CMainFrame, ...)  
  2.     ON_WM_CREATE()  
  3.     ON_WM_SETFOCUS()  
  4. ...  
  5. END_MESSAGE_MAP()  

头文件中的DECLARE_MESSAGE_MAP定义如下,能够观看回调函数中撤回息映射表的函数GetMessageMap在这里概念

 

 

[cpp] view plain copy

 

 print?图片 30图片 31

  1. #define DECLARE_MESSAGE_MAP()   
  2. protected:   
  3.     static const AFX_MSGMAP* PASCAL GetThisMessageMap();   
  4.     virtual const AFX_MSGMAP* GetMessageMap() const;   

 

BEGIN_MESSAGE_MAP布局举行如下

[cpp] view plain copy

 

 print?图片 32图片 33

  1. #define BEGIN_MESSAGE_MAP(theClass, baseClass)   
  2.     PTM_WARNING_DISABLE   
  3.     const AFX_MSGMAP* theClass::GetMessageMap() const   
  4.         { return GetThisMessageMap(); }   
  5.     const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap()   
  6.     {   
  7.         typedef theClass ThisClass;                          
  8.         typedef baseClass TheBaseClass;                      
  9.         static const AFX_MSGMAP_ENTRY _messageEntries[] =    
  10.         {  

可见确实的映射表构造_massgeEntries在那概念,ON_WM_CRATE完毕实际的表内容填充,举例:

[cpp] view plain copy

 

 print?图片 34图片 35

  1. #define ON_WM_CREATE()   
  2.     { WM_CREATE, 0, 0, 0, AfxSig_is,   
  3.         (AFX_PMSG) (AFX_PMSGW)   
  4.         (static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > ( &ThisClass :: OnCreate)) },  

WM_CREATE和OnCreate函数绑定

 

由来,窗口类的卷入进度尽在头里,大概您认为进程比较麻烦,那么本身把它总结如下:

1.Create窗口时做到两件事:(1卡塔尔窗口进度勾到联合处理(2)hwnd和相应的CWnd*绑定

2.CWnd中利用BEGIN_MESSAGE_MAP构造定义【音信-响应函数】的路由表

3.响应函数中依据传入的hwnd查表获得CWnd*,调用CWnd->GetMassageMap获取【音讯-响应函数】表,核对应新闻的响应函数,调用达成响应

当今再重临去看,是或不是鲜明明朗了?

          CStaticDataInitCriticalSectionLock lock;

1.基本原理

先说古老的Win32 SDK的做法,他们很猛烈,这里依然先贴上代码,为了裁减篇幅超级多地点笔者就归纳了

 

[cpp] view plain copy

 

 print?图片 36图片 37

  1. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)  
  2. {  
  3.     static TCHAR szAppName[] = TEXT ("TestClass");  
  4.     HWND         hwnd;  
  5.     MSG          msg;  
  6.     WNDCLASSEX   wndclassex = {0};  
  7.   
  8.     //1.设计窗口类  
  9.     wndclassex.cbSize        = sizeof(WNDCLASSEX);  
  10.     wndclassex.style         = CS_HREDRAW | CS_VREDRAW;  
  11.     wndclassex.lpfnWndProc   = WndProc ...  
  12.       
  13.     //2.注册窗口类  
  14.     if (!RegisterClassEx (&wndclassex))  
  15.     {  
  16.         MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);  
  17.         return 0;  
  18.     }  
  19.   
  20.     //3.成立窗口  
  21.     hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,   
  22.                           szAppName,   
  23.                           ...  
  24.       
  25.     //4.展现窗口  
  26.     ShowWindow (hwnd, iCmdShow);  
  27.     UpdateWindow (hwnd);  
  28.       
  29.     //5.开头音讯循环,又称音讯泵  
  30.     while (GetMessage (&msg, NULL, 0, 0))  
  31.     {  
  32.         TranslateMessage (&msg);  
  33.         DispatchMessage (&msg);  
  34.     }  
  35.     return msg.wParam;  
  36. }  
  37.   
  38. //回调函数中做音讯分发  
  39. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  40. {  
  41.     HDC hdc;  
  42.     PAINTSTRUCT ps;  
  43.   
  44.     //分发  
  45.     switch (message)  
  46.     {  
  47.     case WM_CREATE:  
  48.         return (0);  
  49.           
  50.     case WM_PAINT:  
  51.         ...  
  52.         return (0);  
  53.           
  54.     case WM_DESTROY:  
  55.         PostQuitMessage (0);  
  56.         return (0);  
  57.     }  
  58.   
  59.     //暗许管理函数  
  60.     return DefWindowProc (hwnd, message, wParam, lParam);  
  61. }  

设计窗口类和挂号窗口类可称为InitApplication,即发轫化Windows 应用所急需做的办事,那个窗口类能够是公用的。

 

创制一个窗口和出示可称为InitInstance,即起初化叁个Windows 应用实例所急需做的办事,对种种窗体来讲那都以唯生机勃勃的,可做定制化改进。

开启音讯泵可称为Run,后生可畏单音讯泵开启,意味着二个主次起头收受音讯和分发音信,整个应用程序算是开端运维了。

在WndProc中做的是剖断相应的信息,然后做相应的拍卖工作。

 

     BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc)

a卡塔尔国.窗口创制

atlwin.app中CWindowImpl::Create中如下,获得窗口音讯,注册窗口类

 

[cpp] view plain copy

 

 print?图片 38图片 39

  1. HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,  
  2.             DWORD dwStyle = 0, DWORD dwExStyle = 0,  
  3.             _U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)  
  4. {  
  5.     if (T::GetWndClassInfo().m_lpszOrigName == NULL)  
  6.         T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();  
  7.     ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);  
  8.   
  9.     dwStyle = T::GetWndStyle(dwStyle);  
  10.     dwExStyle = T::GetWndExStyle(dwExStyle);  
  11.   
  12.     ...  
  13.   
  14.     return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,  
  15.                                                          dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);  
  16. }  

能够见到调用GetWndClassInfo.Register注册窗口类,每种类中应用DECLARE_WND_CLASS等宏来填充对应音讯。

 

DECLARE_WND_CLASS张开如下:

 

[cpp] view plain copy

 

 print?图片 40图片 41

  1. #define DECLARE_WND_CLASS(WndClassName)   
  2. static ATL::CWndClassInfo& GetWndClassInfo()   
  3. {   
  4.     static ATL::CWndClassInfo wc =   
  5.     {   
  6.         { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc,   
  7.           0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL },   
  8.         NULL, NULL, IDC_ARROW, TRUE, 0, _T("")   
  9.     };   
  10.     return wc;   
  11. }  

可以见到暗中同意的怀有窗口的窗口过程函数是StartWindowProc,达成联合支配
实际的窗口创立函数如下:

 

 

[cpp] view plain copy

 

 print?图片 42图片 43

  1. template <class TBase, class TWinTraits>  
  2. HWND CWindowImplBaseT< TBase, TWinTraits >::Create(...)  
  3. {  
  4.     BOOL result;  
  5.     ATLASSUME(m_hWnd == NULL);  
  6.   
  7.     // 初始化Thunk结构体  
  8.     result = m_thunk.Init(NULL,NULL);  
  9. ...  
  10.   
  11.     //保存当前窗口类指针到全局  
  12.     _AtlWinModule.AddCreateWndData(&m_thunk.cd, this);  
  13.   
  14.     //成立窗口  
  15.     HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,  
  16.         dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,  
  17.         rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,  
  18.         _AtlBaseModule.GetModuleInstance(), lpCreateParam);  
  19. ...  
  20. }  

此处的Thunk和保存指针到全局之后再说。

 

于今创建进度完毕。

     if(!RegisterClass(&wndclass))

3.结尾,假如CWnd获得了新闻,怎么样去大致实用的去处理和响应呢
我们说过新闻的响应也是在Cwnd中处理,怎么着将获得的消息对应成现实的类成员函数呢?
BEGIN_MESSAGE_MAP(CMainFrame, ...)
ON_WM_CREATE()
ON_WM_SETFOCUS()
END_MESSAGE_MAP()

 

 

#endif


          ATLASSERT(SUCCEEDED(hRes));

C程序的管理格局

              _ATL_EMPTY_DLGTEMPLATE templ;

2.MFC封装窗口成立和音信分发

使用C++面向对象的风味,将窗口成立和信息分发、响应分装在四个类中,那样二个窗口类对应二个事实上窗口,特别轻巧直观。

率先大家动脑筋下,把窗口创造和音信分发封装在协作有怎么样难点?

1.怎么将区别的窗口进度勾到一块

正史经历告诉大家,专制往往一时好干活。若是每一种窗口都有投机的窗口进程,那样管理起来就相比较费心,最棒的做法是负有的窗口在同多个窗口进程中决定分发。

2.均等窗口进度中怎样将分歧的hwnd新闻分发给相应的CWnd类去管理响应

因为窗口回调函数的限量,回调函数不可能有所对应CWnd类的this指针,也正是说来了窗口语资源消息息,如何能力辨别对应的hwnd对应的CWnd,把音信分发给CWnd去管理呢?

3.谈起底,借使CWnd获得了新闻,怎么着去大致可行的去管理和响应呢

作者们说过音信的响应也是在Cwnd中管理,怎么样将获得的新闻对应成现实的类成员函数呢?

 

那么些难题串通后,MFC的做法,我们画一张音讯流通图如下:

图片 44

AddMessageLoop(卡塔尔(英语:State of Qatar)加多四个消息循环,步向新闻循环队列里。

2.雷同窗口进程中如何将不相同的hwnd消息分发给相应的CWnd类去管理响应
因为窗口回调函数的限量,回调函数无法有所对应CWnd类的this指针,也便是说来了窗口音讯,怎么着工夫辨别对应的hwnd对应的CWnd,把音信分发给CWnd去处理呢?
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// all other messages route through message map
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); // 转换成 pWnd->WindowProc(nMsg, wParam, lParam);
// 它正是CWnd::WindowProc,然后调用CWnd::OnWndMsg(message, wParam, lParam, &lResult卡塔尔国卡塔尔(英语:State of Qatar) 然后 AFX_MSGMAP* pMessageMap = GetMessageMap(卡塔尔; 向上查表获得音讯函数
}

 

b卡塔尔(英语:State of Qatar).消息分发和响应

日前说了,全体的窗口类的响应函数都以在StartWndProc中,如下:

 

[cpp] view plain copy

 

 print?图片 45图片 46

  1. template <class TBase, class TWinTraits>  
  2. LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)_AtlWinModule.ExtractCreateWndData();  
  5.     ...  
  6.     pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);  
  7.     WNDPROC pProc = pThis->m_thunk.GetWNDPROC();  
  8.     WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);  
  9.     ...  
  10.     return pProc(hWnd, uMsg, wParam, lParam);  
  11. }  

可知,率先次窗口响应会进去到此函数,这里的代码从大局布局中得到当前窗口类的指针,初步化Thunk,设置Thunk为代理窗口响应函数,通过pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);将窗口的this指针和窗口语资源音讯息管理函数WindowProc初步化到thunk静态布局里。设置富有的窗体进度函数为WindowProc。

 

 

这里运用了Thunk转变本事,所谓Thunk就是更改的意趣,这里的核心思维是轮番掉守旧的WndProc的率先个句柄参数hwnd,让这里的hwnd实际上是应和的CWndImpl的指针,那样形成了hwnd到窗体类的照耀。现实的落实在atlstdthunk.h中,如下:

 

[cpp] view plain copy

 

 print?图片 47图片 48

  1. #pragma pack(push,1)  
  2. struct _stdcallthunk  
  3. {  
  4.     DWORD   m_mov;          // 替换hwnd参数为对应CWndImpl指针 mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd)  
  5.     DWORD   m_this;         //  
  6.     BYTE    m_jmp;          // 跳转到WndProc  
  7.     DWORD   m_relproc;      // relative jmp  
  8.     BOOL Init(DWORD_PTR proc, void* pThis)  
  9.     {  
  10.         m_mov = 0x042444C7;  //C7 44 24 0C  
  11.         m_this = PtrToUlong(pThis);  
  12.         m_jmp = 0xe9;  
  13.         m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk)));   // write block from data cache and  
  14.         FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));    //  flush from instruction cache  
  15.         return TRUE;  
  16.     }  
  17. ...  
  18. };  
  19. #pragma pack(pop)  

 

WindowProc管理如下:

 

[cpp] view plain copy

 

 print?图片 49图片 50

  1. template <class TBase, class TWinTraits>  
  2. LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;//hwnd转换成CWindowImplBaseT指针  
  5.     ...  
  6.     BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0卡塔尔;//调用对应的窗体类的ProcessWindowMessage管理函数  
  7.     ...  
  8. }  

能够在现实的窗口进程函数中,将hWnd调换到对应的窗口类,接着调用窗口类的ProcessWindowMessage调用对应的窗体类管理函数。
每一种窗体类都有ProcessWindowMessage函数,它接纳生机勃勃组宏定义如下:

 

 

[cpp] view plain copy

 

 print?图片 51图片 52

  1. BEGIN_MSG_MAP(CMainFrame)  
  2.     MESSAGE_HANDLER(WM_CREATE, OnCreate)  
  3.     ...  
  4. END_MSG_MAP()  

举行显示如下:

 

 

[cpp] view plain copy

 

 print?图片 53图片 54

  1. #define BEGIN_MSG_MAP(theClass)   
  2. public:   
  3.     BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)   
  4.     {   
  5.         BOOL bHandled = TRUE;   
  6.         (hWnd);   
  7.         (uMsg);   
  8.         (wParam);   
  9.         (lParam);   
  10.         (lResult);   
  11.         (bHandled);   
  12.         switch(dwMsgMapID)   
  13.         {   
  14.         case 0:  
  15.           
  16. #define MESSAGE_HANDLER(msg, func)   
  17.     if(uMsg == msg)   
  18.     {   
  19.         bHandled = TRUE;   
  20.         lResult = func(uMsg, wParam, lParam, bHandled);   
  21.         if(bHandled)   
  22.             return TRUE;   
  23.     }  

实际上正是宏定义的switch case布局

 

至今整个经过如下:

1.Create中钦点统生机勃勃的窗口进度StartWindowProc

2.StartWindowProc第一遍响适那个时候候造成hwnd和CWndImpl的投射绑定,设置响应函数为WindowProc

3.WindowProc中转hwnd为CWndImpl*,调用对应类的ProcessWindowMessage分发处理音信

4.BEGIN_MSG_MAP简化switch case结构,在每一种窗口类中散发管理

简单的说封装窗口类供给思考此前说的三点,搞懂了那三点此外的标题也就缓和了。最终不要嫌自个儿烦,再贴一次小编一贯重申的首要,深深记住这三点,六柱预测应的框架封装进程如出生龙活虎辙:

 

1.怎么将差别的窗口进度勾到一齐

2.毫发不爽窗口进度中怎样将分裂的hwnd新闻分发给相应的CWnd类去管理响应

3.尾声,假若CWnd获得了新闻,如何去大概可行的去管理和响应呢

 

原创,转发请注脚来源

              CappModule 类---应用程序底蕴类

3.ATL大框架

MFC出未来C++尚未完备时,未有选用c++的高档级特性,基本上都以继续和虚函数、查表,类的层系过多,显得相比较痴肥。相比较来说,ATL就相当多了,选取模板才能简化了设计,也从未那么多的档次布局,超级轻量,在那底蕴上上包裹的WTL分界面库被进一层多的人利用。WTL尽管是在ATL上包裹的,然则窗口的创设和音信分发原理并不曾变,所以大家依然以ATL来说课整个进度。

ATL的框架基本上是温馨搭建起来的,本人编排_tWinMain函数,期间可凭仗CMessageLoop完结音讯泵的敞开,如下:

 

[cpp] view plain copy

 

 print?图片 55图片 56

  1. int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)  
  2. {  
  3. ...  
  4.     int nRet = Run(lpstrCmdLine, nCmdShow);  
  5. ...  
  6. }  
  7.   
  8.   
  9. int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)  
  10. {  
  11.     CMessageLoop theLoop;  
  12.     _Module.AddMessageLoop(&theLoop);  
  13.   
  14.     CMainFrame wndMain;  
  15.   
  16.     if(wndMain.CreateEx() == NULL)  
  17.     {  
  18.         ATLTRACE(_T("Main window creation failed!n"));  
  19.         return 0;  
  20.     }  
  21.   
  22.     wndMain.ShowWindow(nCmdShow);  
  23.   
  24.     int nRet = theLoop.Run();  
  25.   
  26.     _Module.RemoveMessageLoop();  
  27.     return nRet;  
  28. }  

可以看到CMainFrame::CreateEx完成窗口创设,atlapp.h中CMessageLoop实现音讯泵开启,代码如下:

 

 

[cpp] view plain copy

 

 print?图片 57图片 58

  1. // message loop  
  2.     int Run()  
  3.     {  
  4. ...  
  5.   
  6.         for(;;)  
  7.         {  
  8. ...  
  9.   
  10.             bRet = ::GetMessage(&m_msg, NULL, 0, 0);  
  11. ...  
  12.             if(!PreTranslateMessage(&m_msg))  
  13.             {  
  14.                 ::TranslateMessage(&m_msg);  
  15.                 ::DispatchMessage(&m_msg);  
  16.             }  
  17. ...  
  18.         }  
  19.         return (int)m_msg.wParam;  
  20.     }  

所有的事大框架和Win32 SDK很像,没什么封装,独一差别的是具备的窗口创制和音讯分发都卷入到窗口类中了,这一个接下去器重说说。

 

 

     关键部分本人用革命的字体标识出来了,意思是何等?通过当前线程的Id来标示三个新闻循环,存款和储蓄在m_pMsgLoopMap中。

3.修改音讯分发

前方讲了更改窗口创设,然而音讯分发仍为语无伦次,全部的音信响应都塞在switch case中,这里我们本来想到和窗口创立相像,对应的管理分发到函数中。而实质上微软也实乃如此做的,微软提供了头文件WindowsX.h来提携大家分发新闻,具体如下:

 

[cpp] view plain copy

 

 print?图片 59图片 60

  1. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     switch (message)  
  4.     {  
  5.         HANDLE_MSG(hWnd, WM_PAINT, Cls_OnPaint);  
  6.         HANDLE_MSG(hWnd, WM_DESTROY, Cls_OnDestroy);  
  7.     }  
  8.   
  9.     return DefWindowProc(hWnd, message, wParam, lParam);  
  10. }  
  11.   
  12. void Cls_OnPaint(HWND hwnd)  
  13. {  
  14.     HDC hdc;  
  15.     PAINTSTRUCT ps;  
  16.   
  17.     hdc = BeginPaint(hwnd, &ps);  
  18.     //...  
  19.     EndPaint(hwnd, &ps);  
  20. }  
  21.   
  22. void Cls_OnDestroy(HWND hwnd)  
  23. {  
  24.     PostQuitMessage(0);  
  25. }  

能够看出,这里依赖于HANDLE_MSG宏让新闻对应到具体的处理函数上,HANDLE_MSG进行如下:

 

 

[cpp] view plain copy

 

 print?图片 61图片 62

  1. #define HANDLE_MSG(hwnd, message, fn)      
  2.     case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))  

HANDLE##message为管理函数
可见到这里注重宏来裁减switch case代码的编写量,但实则代码内容是风姿浪漫致的。

 

实际对话框的拍卖略有不一致,如下:

 

[cpp] view plain copy

 

 print?图片 63图片 64

  1. #define chHANDLE_DLGMSG(hwnd, message, fn) case (message):   
  2.     return (SetDlgMsgResult(hwnd, uMsg, HANDLE_##message((hwnd), (wParam), (lParam), (fn))))  
  3.   
  4. INT_PTR CALLBACK Dlg_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  5. {  
  6.     UNREFERENCED_PARAMETER(lParam);  
  7.     switch (message)  
  8.     {  
  9.         chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);  
  10.         chHANDLE_DLGMSG(hwnd, WM_COMMAND,    Dlg_OnCommand);  
  11.     }  
  12.   
  13.     return (INT_PTR)FALSE;  
  14. }  

这里的chHANDLE_DLGMSG是仿照HANDLE_MSG自定义的。

 

 

          WNDCLASS wndclass;

_tWinMain-->AfxWinMain,它调用几个函数:
-->AfxWinInit用于做一些框架的开端化职业。
-->CWinApp::InitApplication在appcore.cpp中,和C程序略有不一致,这里的行事重大是Doc模板管理器的开端化工作。
-->CThread::InitInstance虚函数会被用户改写,在这里中间调用CWnd完毕窗口的注册和创办,这些在今后协同讲
-->CThread::Run在thrdcore.cpp中,Run->PumpMessage->AfxInternalPumpMessage实现消息泵的开启,如下:
BOOL AFXAPI AfxInternalPumpMessage()
{
_AFX_THREAD_STATE *pState = AfxGetThreadState();
if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
{
return FALSE;
}
if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}

     BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc)

C++程序的拍卖措施

在C++时期,大家提倡面向对象编制程序,对此窗口的创立和音讯的散发响应都以窗口的一举一动,所以差非常的少全部的框架都以想艺术把那二者封装在联合,那也是大家讲课的严重性。对于C++程序大家先讲大框架,再讲窗口类封装。

              return FALSE;

              }

          lock.Unlock();

     //运维音讯循环

          lock.Unlock();

       三个窗口程序的创始到销毁进度主要透过如下几个等第

     //注册窗口

                   ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));

              return FALSE;

              return NULL;

CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const

         {

              ATLTRY(m_pSettingChangeNotify = new _notifyClass);

              ATLASSERT(FALSE);

 

              typedef ATL::CSimpleArray<HWND>   _notifyClass;

AddSettingChangeNotify(卡塔尔国增加二个窗口句柄。

              AtlCreateBoldFont(卡塔尔(قطر‎   爆发叁个粗体字体

         return bRet;

     int nRet = theLoop.Run();

              _ATL_EMPTY_DLGTEMPLATE templ;

                   ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));

          lock.Unlock();

 

除此之外8个国有成员函数外,该类还定义了3个国有成员变量

 

                   bRet = FALSE;

GetMessageLoop(卡塔尔拿到音信循环。

              HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);

1. 挂号窗口类

              ATLASSERT(FALSE);

#ifdef _WIN64

     wndMain.ShowWindow(nCmdShow);

                   bRet = m_pSettingChangeNotify->Add(hNtfWnd);

     HRESULT hRes = ::CoInitialize(NULL);

              ATLASSERT(::IsWindow(hNtfWnd));

                   ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);

              if(::IsWindow(hNtfWnd))

              // init everything

_Module维持着转换应用程序的主线程,调整着程序的音信循环队列,是一个CAppModule的对象。该CAppModule从ATL::CcomModule世襲。

         {

     return FALSE;

     {

        AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // add flags to support other controls

          MessageBox(NULL,TEXT("Porgram requires Windows NT!"),szAppName,MB_ICONERROR);

// need conditional code because types don't match in winuser.h

2. 创办窗口

     _Module.AddMessageLoop(&theLoop卡塔尔(英语:State of Qatar);   //将音信增加到消息循环

在此篇小说笔者不想过多的分析应用程序框架和窗口的内幕,那几个内容将身处以往的几篇文章中详细解析,本文首要对ATL应用程式.H头文件中实现的局地进程进行详细剖判。

          CStaticDataInitCriticalSectionLock lock;

}   

BOOL RemoveMessageLoop()

      WTL程序的结构

         }

         BOOL bRet = (m_pSettingChangeNotify != NULL);

          ATLTRACE(_T("Main window creation failed!n"));

              }

                   ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);

 

 

         return 0;

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

 

     CW_USEDEFAULT,CW_USEDEFAULT,

          HWND hwnd = NULL;

        CidleHandler 类---用于空闲音讯管理的

 

     }

     {

{

// make the EXE free threaded. This means that calls come in on a random RPC thread.

     return bRet;

              ATLASSERT(FALSE);

 

#else

RemoveMessageLoop(卡塔尔移除音信循环队列。

ATL应用程式.H富含了新闻循环类、接口类、和发生应用程序所必备的部分底子类定义。

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.n"));

     //清理音讯

          …

          wndclass.lpfnWndProc = WndProc;

     if(wndMain.CreateEx() == NULL)

          MSG msg;

              AtlInitCommonControls(卡塔尔(英语:State of Qatar)最初化一些控件所需合营的DLL

              ATLASSERT(m_pSettingChangeNotify != NULL);

         }

              ATLASSERT(FALSE);

 

       其它还会有3个全局函数:

     {

          CStaticDataInitCriticalSectionLock lock;

         {

     ::CoUninitialize();

5. 始于音信循环

4. 呈现应用程序框架

// need conditional code because types don't match in winuser.h

          if(InitSettingChangeNotify() != FALSE)

     }

          CStaticDataInitCriticalSectionLock lock;

                   bRet = FALSE;

 

m_dwMainThreadID负担保存该应用程序的主线程ID

              {

 

          CStaticDataInitCriticalSectionLock lock;

 

#endif

     CMessageLoop theLoop;                  //定义音信循环

         }

LRESULT CALLBACK WndProc(HWND hwnd,UINT Message,WPARAM wParam,LPARAM lParam);

         BOOL bRet = (m_pSettingChangeNotify != NULL);

 

              return FALSE;

 

          if(FAILED(lock.Lock()))

              AtlGetDefaultGuiFont(卡塔尔国拿到默许的来得字体

                   //插足该窗口句柄

              }

     {

              else

         {

//     HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);

比如用C写过Win32窗口程序的人自然会记得如下的布局:

 

          if(m_pSettingChangeNotify == NULL)

上面分别来深入分析多少个关键成员函数的兑现:

     {

              ATLTRY(m_pSettingChangeNotify = new _notifyClass);

 

              CmessageFilter类---用于新闻过滤的

          if(m_pSettingChangeNotify == NULL)

 

        

          }

RemoveSettingChangeNotify(卡塔尔(قطر‎清理景况

          if(bRet && m_pSettingChangeNotify->GetSize() == 0)

// If you are running on NT 4.0 or higher you can use the following call instead to

              // init everything

2. 在全局的_Module中走入这几个音信循环

         {

#else

               DispatchMessage(&msg);

}

BOOL AddSettingChangeNotify(HWND hWnd)

 

该函数用来起始化三个贮存窗口句柄的靶子

          {

         BOOL bRet = FALSE;

     if(FAILED(lock.Lock()))

         BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId());

 

              return FALSE;

 

         {

          if(bRet && m_pSettingChangeNotify->GetSize() == 0)

         }

 

7. 回去WinMain函数,截止程序

     }

     return nRet;

         delete m_pSettingChangeNotify;

          if(FAILED(lock.Lock()))

              {

第大器晚成从全局变量_Module开始。

     {

          ATLASSERT(::IsWindow(hWnd));

              bRet

m_pSettingChangeNotify->Add(hWnd);

 

          lock.Unlock();

 

         return bRet;

     }

 

BOOL RemoveSettingChangeNotify(HWND hWnd)

     {

          CStaticDataInitCriticalSectionLock lock;

          if(FAILED(lock.Lock()))

         {

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.n"));

              ATLASSERT(FALSE);

              return FALSE;

         }

 

         BOOL bRet = FALSE;

          if(m_pSettingChangeNotify != NULL)

              bRet = m_pSettingChangeNotify->Remove(hWnd);

 

          lock.Unlock();

 

         return bRet;

     }

 

     现在回来刚才提到的Run(卡塔尔函数,里面最先河就定义了一个CmessageLoop循环对象,然后经过_Module对象的AddMessageLoop 成员函数参与到循环队列里面,直到_Module调用了RemoveMessageLoop移除循环队列,程序才甘休循环,重回到WinMain函数。

     在此还也许有三个极度主要的类,那便是CMessageLoop,是他保持了系统的信息,维持了程序的生命周期。那么上边大家来拜访那一个类的定义和切实的得以完成格局。

CmessageLoop包括了如下一些成员函数和分子变量

分子变量

//管理音信

     ATL::CSimpleArray<CMessageFilter*> m_aMsgFilter;

     //管理空闲句柄

     ATL::CSimpleArray<CIdleHandler*> m_aIdleHandler;

     //Win32API音讯布局

     MSG m_msg;

 

     成员函数(用鲜青标识的函数是虚函数)

AddMessageFilter         参与一条消息过滤

RemoveMessageFilter      移除一条音讯过滤

AddIdleHandler       参与一个空暇句柄

RemoveIdleHandler         移出多少个空余句柄

AddUpdateUI              为了同盟老的ATL而设计的

RemoveUpdateUI           为了同盟老的ATL而设计的

IsIdleMessage            过滤一些诸如WM_MOUSEMOVE之类的音讯

Run                      音信循环。关键部分!!!

PreTranslateMessage      音信过滤

OnIdle                   空闲处理

 

再这里笔者不考虑对各种函数都进展详细的分析,主要分析中央的函数Run,CmessageLoop由它来维系着系统的新闻循环。

函数如下:

int Run()

     {

         //空闲?

         BOOL bDoIdle = TRUE;

         //空闲计数器

         int nIdleCount = 0;

         //重临标记

         BOOL bRet;

 

         //先河新闻循环了啊!!!

          for(;;)

         {

 

              //当bDoIdle为TRUE,何况不可能从音讯队列之中抽取音信了,那么开首空闲操作了!

              //PM_NOREMOVE:再PeekMessage函数处理后不将音讯从队列里移除

              while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))

              {

                   if(!OnIdle(nIdleCount++))

                        bDoIdle = FALSE;

              }

             

              //从当下线程获取一个音信

              //重返-1意味出现多少个错误

              //再次来到0表示提交了三个WM_QUIT,程序将在退出

              //成功获得多少个音信,再次来到不等于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 - exitingn"));

                   break;   // WM_QUIT, exit message loop

              }

 

              //倘若熟知使用c语言来写Win32的程序猿会开采,原本WinMain中的哪个管理音讯循环的话语放到这里来了!!!

              if(!PreTranslateMessage(&m_msg))

              {

                   //translates virtual-key messages into character messages.

                   ::TranslateMessage(&m_msg);

                   //dispatches a message to a window procedure

                   ::DispatchMessage(&m_msg);

              }

             

              //判定是还是不是为空闲新闻?

              //排除WM_MOUSEMOVE WM_NCMOUSEMOVE WM_SYSTIMER消息

              if(IsIdleMessage(&m_msg))

              {

                   bDoIdle = TRUE;

                   nIdleCount = 0;

              }

         }

 

         return (int)m_msg.wParam;

     }

以上正是对ATLAPP.H中的多少个比较重大的类的解析,还会有其余多少个类的剖释笔者将坐落于现在的作品中

(待续。。。)

     }

     void TermSettingChangeNotify()

1. 生成一个音信循环对象(theLoop卡塔尔

 

              //销毁窗口

 

{

在WTL::CappModule中定义了8个国有成员函数,分别为:

     //突显框架

6. 甘休音信循环

 

     {

 

     {

     return msg.wParam;

     …

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.n"));

 

 

     ATLASSERT(pMsgLoop != NULL);

              return;

         }

     BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop);

{

          if(FAILED(lock.Lock()))

          ATLASSERT(FALSE);

         {

         }

     CStaticDataInitCriticalSectionLock lock;

          UpdateWindow(hwnd);

#ifdef _WIN64

 

          lock.Unlock();

{

         return bRet;

 

         }

}

          CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID);

//窗口进程管理函数

 

通过这么些Run函数大家得以看看在函数中完毕了之类多少个进程:

              //??空的ATL Dialog Template吗?

     }

 

          if(FAILED(lock.Lock()))

         }

              if(::IsWindow(hNtfWnd))

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.n"));

     //成立窗口

               TranslateMessage(&msg);

 

// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used

     int nRet = Run(lpstrCmdLine, nCmdShow卡塔尔;//程序的重大分

              //扩展一个无格局对话框

              else

     {

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.n"));

              ATLASSERT(FALSE);

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)

那么你只怕会问WTL的WinMain函数再哪里?假如您通过WTL/ATL导向生成一个应用程序,那么你会在跟工程名字同名的.cpp文件中窥见如下的代码:

              ATLASSERT(::IsWindow(hNtfWnd));

 

BOOL AddMessageLoop(CMessageLoop* pMsgLoop)

              typedef ATL::CSimpleArray<HWND>   _notifyClass;

     _Module.RemoveMessageLoop();

              }

该函数通过线程Id在m_pMsgLoopMap新闻队列中搜寻对应的音讯循环,找到后再次回到。

 

从这个_tWinMain函数的定义,你能够窥见前后相继的非常重要部分是本人藕荷色标志出来的Run(卡塔尔函数。那些函数是一个自定义的函数,可是如若经过ATL/WTL导向程序,那么会自动生成这么叁个Run(卡塔尔(英语:State of Qatar)函数的,上边大家先分析一下那一个自动生成的Run函数。

          ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.n"));

          return 0;

m_pMsgLoopMap负担存款和储蓄音讯循环

     WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)

InitSettingChangeNotify(卡塔尔先河化情状

              HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);

              ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.n"));

              CserverAppModule类---用于Com服务构架的应用程序类

     }

                   bRet = m_pSettingChangeNotify->Add(hNtfWnd);

         return bRet;

     }

     CMainFrame wndMain;                //应用程序框架类

     CW_USEDEFAULT,CW_USEDEFAULT,

m_pSettingChangeNotify担当存放窗口句柄

     hwnd = CreateWindow(szAppName,TEXT("My Application"),

          if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0)

     NULL,NULL,hInstance,NULL);

       关键部分近似通过铅色字体标志出来,嗯,没有错正如AddMessageLoop函数相似,该函数也是通过线程Id来查找消息循环移除对象的。

兑现深入分析

}

              ATLASSERT(FALSE);

          lock.Unlock();

          m_pSettingChangeNotify = NULL;

              {

          ShowWindow(hwnd,iCmdShow);

 

         {

              {

     return nRet;

         }

          if(FAILED(lock.Lock()))

          wndclass.style       = CS_HREDRAW | CS_VREDRAW;

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)

       类定义如下:

          if(FAILED(lock.Lock()))

         return pLoop;

 

        CmessageLoop类---用于消息循环的

     }

     _Module.Term();

        

          CStaticDataInitCriticalSectionLock lock;

         //走入音信循环

     //锁住关键片断,由于进度同步的关联!!!

3. 跻身信息循环

         {

              //增添叁个无形式对话框

         {

         }

下一篇:Thrift-java实例

相关新闻推荐

友情链接: 网站地图
Copyright © 2015-2019 http://www.kai-wang.com. AG亚游国际有限公司 版权所有