MFC
Win32程序
消息队列
系统消息队列,窗口消息队列
主要函数
WinMain 函数
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPCSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if (!hPrevInstance )
{
if (!InitApplication(hInstance))
{
return false;
}
}
if (!InitInstance(hInstace,nCmdShow))
{
return false;
}
while (GetMessage(&msg, NULL, 0, 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
InitApplication - 注册窗口
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VERDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;
....
return (RegisterClass(&wc);
}
InitInstance - 产生窗口
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
_hInst = hInstance;
_hWnd = CreateWindow(appName, title, ...); // 发送 WM_CREATE
if (!_hWnd)
{
return FALSE;
}
ShowWindow(_hWnd, nCmdShow);
UpdateWindow(_hWnd); // 发送 WM_PAINT
return TRUE;
}
WndProc - 窗口函数
LRESULT CALLBACK WndProc(HWND hWnd, UNIT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch(message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
swich(wmId)
{
case IDM_ABOUT:
DialogBox(...);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
defualt:
return (DefWindowProc(hWnd,message,wParam,lParam));
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd,message,wParam,lParam));
}
return (0);
}
Windows程序生死
- CreateWindow 发送WM_CREATE给窗口函数,做初始化操作。
- 如果消息循环收到WM_QUIT, 结束消息循环
- DispatchMessage 分派消息给窗口
- 不断执行2,3
- 当系统发送WM_CLOSE,通常程序窗口不拦截此消息,于是DefWindProc处理它。
- DefWindProc 收到WM_CLOSE后,调用DestoryWindow清除窗口,并发送WM_DESTROY.
- WM_DESTROY的处理是调用PostQuitMessage
- PostQuitMessage 没做什么只是发送WM_QUIT消息,结束循环。
MessageMap
MSGMAP_ENTRY
struct MSGMAP_ENTRY {
UINT message;
LONG (*pfn) (HWND, UINT, WPARAM, LPARAM);
}
# define dim(x) (sizeof(x) / sizeof(x[0]))
- _messageEntries[] , _commandEntries[]
struct MESASGE_ENTRY _messageEntries [] =
{
WM_CREATE, OnCreate,
WM_PAINT, OnPaint,
WM_SIZE, OnSize,
WM_COMMAND, OnCommand,
WM_SETFOCUS, OnSetFocus,
WM_CLOSE, OnClose,
WM_DESTROY, OnDestroy
};
struct MESSAGE_ENTRY _commandEntries[] =
{
IDM_ABOUT, OnAbout,
IDM_FILEOPEN, OnFileOpen,
....
};
- 窗口函数处理
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesage, WPARAM wParam, LPARAM lParam)
{
int i;
for(i=0; i<dim(_messageEntries); ++i)
{
if (mesage == _messageEntries[i].nMessage)
return ((*_messageEntries[i].pfn)(hWnd,message,wParam,lParam));
}
return (DefWindowProc(hWnd,message,wParam,lParam);
}
LRESULT OnCommand(HWND hWnd, UINT mesage, WPARAM wParam, LPARAM lParam)
{
int i;
for(i=0; i<dim(_commandEntries); ++i)
{
if (mesage == _commandEntries [i].nMessage)
return ((*_commandEntries [i].pfn)(hWnd,message,wParam,lParam));
}
return (DefWindowProc(hWnd,message,wParam,lParam);
}
Idle 处理
GetMessage, PeekMessage都从消息队列取消息。 如果抓不到消息,GetMessage 什么不做,于是操作系统再去关照其他人。PeekMessage 取回控制权执行一段时间
while(1)
{
if (PeekMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
OnIdle();
}
}
MFC 6 仿真技术
MFC Class hierachy
MFC 初始化过程
MFC 的 CWinApp 包含两个虚函数 InitApplication, InitInstance
MAIN:
InitApplication();
InitInstance();
Run();
RRTI 运行时类别
MFC 以链表的形式记录型别信息
struct CRuntimeClass
{
LPCTSTR m_lpszClassName;
int m_nObjectSize;
UNIT m_wSchema;
CObject* (PASCAL* m_pfnCreateObject)();
CRuntimeClass* m_pBaseClass;
static CRuntimeClass * pFirstClass;
CRuntimeClass * pNextClass;
}
动态创建 Dynamic Creation
#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
#define _DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static CRuntimeClass class##class_name; \
static CRuntimeClass* PASCAL GetThisClass(); \
virtual CRuntimeClass* GetRuntimeClass() const; \
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
{ return RUNTIME_CLASS(base_class_name); } \
AFX_COMDAT CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
&class_name::_GetBaseClass, NULL, class_init }; \
CRuntimeClass* PASCAL class_name::GetThisClass() \
{ return _RUNTIME_CLASS(class_name); } \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return _RUNTIME_CLASS(class_name); }
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL, NULL)
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject, NULL)
永久保存
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name) \
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
extern AFX_CLASSINIT _init_##class_name; \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject, &_init_##class_name) \
AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; }
消息传递
消息流向
1, 一般的WINDOWS WM_XXX消息, 派生类流向基类
2, WM_COMMAND
l FRAME: VIEW -> FRAME本身->CWinApp
l View: View->Document
l Document->Document template
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」