ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MFC - 钩子、窗口、消息

2022-08-02 09:02:19  阅读:168  来源: 互联网

标签:MESSAGE MFC 窗口 钩子 WM CMyWinApp pFrame CMyFrameWnd public


 

钩子

win32 技术。钩子有优先钩取消息的权力,消息产生后会先被钩子钩走,钩子处理完后再把消息返回回来。

  1. 创建钩子
    WINUSERAPI
    HHOOK
    WINAPI
    SetWindowsHookExA(
        _In_ int idHook,         // 钩子类型,不同类型的钩子处理不同消息。 WH_CBT:专注窗口创建消息,MFC多用
        _In_ HOOKPROC lpfn,      // 钩子处理函数
        _In_opt_ HINSTANCE hmod, // 目标应用程序实例句柄,为空时钩取所有实例的消息
        _In_ DWORD dwThreadId);  // 目标线程ID,为0时钩取所有线程
  2. 钩子处理函数
    LRESULT CALLBACK HOOKPROC(
        int code,      // 钩子码,与钩子类型对应。 HCBT_CREATEWND 与 WH_CBT 对应
        WPARAM wParam, // 在WH_CBT类型钩子中,是刚刚创建成功窗口句柄
        LPARAM lParam  // ...
    );
  3. 更改窗口 处理函数/样式
    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;

 单文档程序:

  1. 框架类
  2. 应用程序类
  3. 文档类
  4. 视图类

 

使用到的类:

 MFC 窗口创建过程:

  1. 加载菜单
  2. 调用 CWmd::CreateEx 函数创建窗口
    调用 PreCreateWindow 函数设计和注册窗口类调用 AfxDeferRegisterClass函数,在这个函数中设计窗口类:
    WNDCLASS wndcls; // 设计窗口类
    ...
    wndcls.lpfnWndProc = DefWindowProc; // 定义窗口的处理函数为DefWindowProc
    调用 _AfxRegisterWithIcon 函数
        在函数内部,加载图标,并调用AfxRegisterClass 函数,
            在函数内部,调用 ::RegisterClass win32API函数注册窗口类

MFC 消息

 MFC 消息处理:

  1. 当收到消息时,进入 AfxWndProc 函数
  2. AfxWndProc 函数根据消息的窗口句柄,查询对应框架类对象的地址(pFrame)
  3. 利用框架类对象地址(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 虚函数的情况下仍能处理消息

必备条件:

  1. 类内添加声明宏
    DECLARE_MESSAGE_MAP()
  2. 类外添加实现宏
    BEGIN_MESSAGE_MAP(theClass, baseClass)
    END_MESSAGE_MAP()

 当一个类具备上述两个要件,这个类就可以按照消息映射机制处理消息。

消息映射机制的具体实施,以 WM_CREATE 为例:

  1. BEGIN_MESSAGE_MAP(theClass, baseClass)END_MESSAGE_MAP() 之间添加 ON_MESSAGE(WM_CREATE, OnCreate)
  2. 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;

 

消息分类

定义了特殊的宏用于处理消息

  1. 标准windows消息
    ON_WM_XXX 大多数消息
    处理每种消息的回调函数参数与返回值都不同,具体查询手册
  2. 通用消息
    ON_MESSAGE用于处理自定义消息
    回调参数类型:LRESULT fun(WPARAM, LPARAM);
  3. 命令消息
    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 菜单

 菜单对应类型:

  1. win32:HMENU
  2. MFC:CMenu 类对象,内部包含变量 m_hMenu

 

  1. 添加菜单资源
  2. 将菜单设置到窗口
    1. 利用 pFrame 调用Create函数时传参
      // 在MFC中消息没有被处理的菜单项会被置为灰色
      pFrame->Create(NULL, "MFCCreate", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, (char *)IDR_MENU1);
    2. 在处理框架窗口的WM_CREATE 消息时
      CMenu menu;
      menu.LoadMenu(...);
      
      int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
      {
      	this->menu.LoadMenuA((LPCTSTR)IDR_MENU1);
      	this->SetMenu(&menu);
      	return CFrameWnd::OnCreate(pcs);
      }
  3. 消息处理
    消息映射宏: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
    封装了关于工具栏的操作,以及和框架窗口的关系。代表工具栏容器

工具栏使用

  1. 添加工具栏资源
  2. 创建工具栏 CToolBar::CreateEx
  3. 加载工具栏 CToolBar::LoadToolBar
  4. 设置工具栏的停靠
    CToolBar::EnableDocking
    CFrameWnd::EnableDocking
    CFrameWnd::DockControlBar

 

标签:MESSAGE,MFC,窗口,钩子,WM,CMyWinApp,pFrame,CMyFrameWnd,public
来源: https://www.cnblogs.com/zhh567/p/16540818.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有