钩子
win32 技术。钩子有优先钩取消息的权力,消息产生后会先被钩子钩走,钩子处理完后再把消息返回回来。
- 创建钩子
WINUSERAPI HHOOK WINAPI SetWindowsHookExA( _In_ int idHook, // 钩子类型,不同类型的钩子处理不同消息。 WH_CBT:专注窗口创建消息,MFC多用 _In_ HOOKPROC lpfn, // 钩子处理函数 _In_opt_ HINSTANCE hmod, // 目标应用程序实例句柄,为空时钩取所有实例的消息 _In_ DWORD dwThreadId); // 目标线程ID,为0时钩取所有线程
- 钩子处理函数
LRESULT CALLBACK HOOKPROC( int code, // 钩子码,与钩子类型对应。 HCBT_CREATEWND 与 WH_CBT 对应 WPARAM wParam, // 在WH_CBT类型钩子中,是刚刚创建成功窗口句柄 LPARAM lParam // ... );
- 更改窗口 处理函数/样式
WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA( _In_ HWND hWnd, // 窗口句柄 _In_ int nIndex, // 更改窗口的哪一部分 GWLP_WNDPROC:更改处理函数 _In_ LONG_PTR dwNewLong); // 新的窗口处理函数地址
简单MFC程序:
#include <afxwin.h>
// 框架类
class CMyFrameWnd : public CFrameWnd
{
public:
};
// 应用程序类
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
单文档程序:
- 框架类
- 应用程序类
- 文档类
- 视图类
使用到的类:
MFC 窗口创建过程:
- 加载菜单
- 调用 CWmd::CreateEx 函数创建窗口
调用 PreCreateWindow 函数设计和注册窗口类调用 AfxDeferRegisterClass函数,在这个函数中设计窗口类:WNDCLASS wndcls; // 设计窗口类 ... wndcls.lpfnWndProc = DefWindowProc; // 定义窗口的处理函数为DefWindowProc 调用 _AfxRegisterWithIcon 函数 在函数内部,加载图标,并调用AfxRegisterClass 函数, 在函数内部,调用 ::RegisterClass win32API函数注册窗口类
MFC 消息
MFC 消息处理:
- 当收到消息时,进入 AfxWndProc 函数
- AfxWndProc 函数根据消息的窗口句柄,查询对应框架类对象的地址(pFrame)
- 利用框架类对象地址(pFrame)调用框架类成员虚函数 WindowProc,完成消息的处理
重写消息处理虚函数
使用重写虚函数的方式处理消息并不是使用消息映射机制
#include <afxwin.h>
class CMyFrameWnd : public CFrameWnd
{
public:
virtual LRESULT WindowProc(UINT msg, WPARAM wParam, LPARAM lParam);
};
LRESULT CMyFrameWnd::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
AfxMessageBox("create");
break;
}
default:
break;
}
return CFrameWnd::WindowProc(msg, wParam, lParam);
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
MFC 消息映射机制
在不重写WindowProc 虚函数的情况下仍能处理消息
必备条件:
- 类内添加声明宏
DECLARE_MESSAGE_MAP()
- 类外添加实现宏
BEGIN_MESSAGE_MAP(theClass, baseClass) END_MESSAGE_MAP()
当一个类具备上述两个要件,这个类就可以按照消息映射机制处理消息。
消息映射机制的具体实施,以 WM_CREATE 为例:
BEGIN_MESSAGE_MAP(theClass, baseClass)
和END_MESSAGE_MAP()
之间添加ON_MESSAGE(WM_CREATE, OnCreate)
宏- 在
CMyFrameWnd
类内添加OnCreate
函数的声明和定义
#include <afxwin.h>
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
LRESULT OnCreate(WPARAM, LPARAM);
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_MESSAGE(WM_CREATE, OnCreate)
END_MESSAGE_MAP()
LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox("消息映射机制 WM_CREATE");
return 0;
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
消息分类
定义了特殊的宏用于处理消息
- 标准windows消息
ON_WM_XXX
大多数消息
处理每种消息的回调函数参数与返回值都不同,具体查询手册 - 通用消息
ON_MESSAGE
用于处理自定义消息
回调参数类型:LRESULT fun(WPARAM, LPARAM);
- 命令消息
ON_COMMAND
处理 WM_CREATE
的例子
#include <afxwin.h>
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
int OnCreate(LPCREATESTRUCT);
LRESULT OnCreate(WPARAM, LPARAM); // ON_MESSAGE 对应的回调函数签名,没有对参数进行封装
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
//ON_MESSAGE(WM_CREATE, OnCreate)
ON_WM_CREATE() // 与上一行类似,但是回调函数名称固定且处理每个消息的函数的参数与返回值不同
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
AfxMessageBox("消息映射机制 WM_CREATE");
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
MFC 菜单
菜单对应类型:
- win32:HMENU
- MFC:CMenu 类对象,内部包含变量 m_hMenu
- 添加菜单资源
- 将菜单设置到窗口
- 利用 pFrame 调用Create函数时传参
// 在MFC中消息没有被处理的菜单项会被置为灰色 pFrame->Create(NULL, "MFCCreate", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, (char *)IDR_MENU1);
- 在处理框架窗口的WM_CREATE 消息时
CMenu menu; menu.LoadMenu(...); int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) { this->menu.LoadMenuA((LPCTSTR)IDR_MENU1); this->SetMenu(&menu); return CFrameWnd::OnCreate(pcs); }
- 利用 pFrame 调用Create函数时传参
- 消息处理
消息映射宏:ON_COMMAND(菜单项ID,处理消息的函数名)
#include <afxwin.h> #include "resource.h" class CMyFrameWnd : public CFrameWnd { DECLARE_MESSAGE_MAP() public: afx_msg int OnCreate(LPCREATESTRUCT); afx_msg void OnFileNew(); private: CMenu menu; }; BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() ON_COMMAND(ID_FILE_NEW, OnFileNew) END_MESSAGE_MAP() int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) { this->menu.LoadMenuA((LPCTSTR)IDR_MENU1); this->SetMenu(&menu); return CFrameWnd::OnCreate(pcs); } void CMyFrameWnd::OnFileNew() { AfxMessageBox("新建"); } class CMyWinApp : public CWinApp { public: virtual BOOL InitInstance(); }; BOOL CMyWinApp::InitInstance() { CMyFrameWnd* pFrame = new CMyFrameWnd; this->m_pMainWnd = pFrame; pFrame->Create(NULL, "MFCCreate"); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; } CMyWinApp theApp;
命令消息处理顺序
实现消息映射的宏展开后发现,声明了一个由消息和处理函数地址组成的数组,还有一个结构体,结构体内两个指针,指向父结构体和数组。
但是 WM_COMMAND
消息的处理路径不一样,在一系列的框架类处理映射中没找到后,还会到应用程序类中查找消息处理映射。顺序:文档类 -> 视图类 -> 框架类 -> 应用程序类;这四种类都可以处理 WM_COMMAND
消息,但其他消息不是。
设置菜单项状态
win32
- WM_INITMENUPOPUP (菜单激活但是还没有显示)
- ::CheckMenuItem / ::EnableMenuItem
MFC
- ON_WM_INITMENUPOPUP (专用宏)
- CMenu::CheckMenuItem / CMenu::EnableMenuItem
菜单项打勾
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT);
afx_msg void OnInitMenuPopup(CMenu *pPopup, UINT nPos, BOOL i);
private:
CMenu menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_INITMENUPOPUP()
END_MESSAGE_MAP()
// 在指定菜单项上打勾
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{
pPopup->CheckMenuItem(ID_FILE_NEW, MF_CHECKED);
}
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
this->menu.LoadMenuA((LPCTSTR)IDR_MENU1);
this->SetMenu(&menu);
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
右键菜单(上下文菜单)
- win32
- WM_CONTEXTMENU
- ::TrackPopupMenu
- MFC
- ON_WM_CONTEXTMENU
- CMENU::TrackPopupMenu
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint pt);
private:
CMenu menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()
void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint pt)
{
// 获取顶层菜单中第一个弹出式菜单
//HMENU hPopup = ::GetSubMenu(menu.m_hMenu, 0);
CMenu* pPopup = menu.GetSubMenu(0);
// 右键弹出指定弹出菜单
//::TrackPopupMenu(hPopup, TPM_LEFTALIGN | TPM_TOPALIGN,
// pt.x, pt.y, 0, this->m_hWnd, NULL);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, this);
}
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
this->menu.LoadMenuA((LPCTSTR)IDR_MENU1);
this->SetMenu(&menu);
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
this->m_pMainWnd = pFrame;
pFrame->Create(NULL, "MFCCreate");
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
顶层菜单: 鼠标右键菜单:
MFC 工具栏
工具栏中按钮在菜单项一般都绑定着用。
相关类
- CToolBarCtrl – 父类 CWnd
封装了关于工具栏控件的各种操作,不代表工具栏,代表的时工具栏中按钮 - CToolBar – 父类 CControlBar
封装了关于工具栏的操作,以及和框架窗口的关系。代表工具栏容器
工具栏使用
- 添加工具栏资源
- 创建工具栏
CToolBar::CreateEx
- 加载工具栏
CToolBar::LoadToolBar
- 设置工具栏的停靠
CToolBar::EnableDocking
CFrameWnd::EnableDocking
CFrameWnd::DockControlBar
原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/278394.html