MFC基本使用
1. VS2012创建一个MFC项目
新建->MFC应用程序->勾选“单文档”/勾选“MFC标准”->完成
2. MFC
Microsoft Foundation Class,微软基础类库,封装Windows API
句柄,API
句柄:窗口句柄,对应的用到的API:创建窗口,显示窗口,settime,getDC,------>CWndView
句柄:HDC,对应的API:CreateDC,SelectObject,bitblt,------->CDC
句柄:位图Hbitmap,对应的API:LoadBitmap,createbitmap,deletebitmap,--------->CBitmap
句柄:画刷Hbrush,对应的API:Create...,------->CBrush
句柄:画笔,-------->CPen
句柄:实例句柄,-------->CWinApp
3. 消息映射表
在Win32中,所有的消息都经由一个消息处理函数来响应,在消息处理函数中我们使用switch-case分支结构进行消息匹配,然后执行相应的消息处理动作,在链接: win32游戏框架中,CGameApp和CPlane类之间是通过继承的关系进行连接,CPlane去重写CGameApp中的接口函数,WinMain()中调用CGameApp中的接口函数实际上调用CPlane中的函数,这样做有一个缺点,在如果之后使用CGameApp框架的时候,用户想要使用的消息在CGameApp中没有相应的虚函数和case支持,那么还是要去修改CGameApp框架的代码,这有违我们写这个游戏框架的初衷。
所以我们需要另一种办法,摆脱对于虚函数和case的依赖,
我们知道虚函数底层是一个vtable,它里面装着一个个的函数指针,通过函数指针去调用实际要调用的函数,那么我们可以自己去定义函数指针,从而跳过从case调用CGameApp中的虚函数,再通过虚函数的vtable调用CPlane中的实际要调用的函数这一层,直接从case通过函数指针直接调用CPlane中相应的函数即可,至此我们摆脱了对于虚函数的依赖。
我们最初使用switch-case是为了实现消息匹配这一功能,所以说我们只需要找到另一种方法,不适用case的方法,去实现消息匹配即可,我们可以使用链表,将需要用到的消息装进链表当中,向消息处理函数提供链表头,消息处理函数就可以使用遍历链表进行匹配的方法实现消息匹配。至此,我们摆脱了case的依赖。
如何将这两者结合起来呢?当我们在链表中匹配到相应的消息的时候就使用相应的函数指针去调用相应的函数去处理。这里就引出了消息映射表(message map)的概念,它将消息与相应的函数指针形成映射的关系,再通过链表进行连接。在之后需要添加新的消息的时候,只需要往这个链表中去添加一个节点,写相应的处理函数即可,至此我们完成了不对游戏框架进行修改而实现动态添加消息。
4. MFC框架了解
以上是MFC的简单框架,我们要使用以上框架就添加一些类去继承他们,如下:
对于CMainFrame
CTestView
CTestDialog
(建立的项目名叫Test,所以是CTestView和CTestDialog)都有一个消息映射表,通过动态创建对象的方法添加消息,因此
如果要加一个消息需要两个步骤:
- 添加一条消息映射,
- 添加一个消息处理函数
5. 说说这个小窗口
CMainFrame
这个类代表的是整个窗口,包括状态栏,工具条,对话框……
2. CTestView
我们说的CTestView
这个类就是对应的是窗口中的中间最大的白色部分
所以,如果要添加这个区域内的消息的话,应该在这个类里面添加
工具条
菜单栏
标题栏
状态栏
对话框
非客户区(not client)
标题栏 + 菜单栏 = 非客户区域
非客户区的消息格式是:xxNCxx
客户区(client)
工具栏 + view + 状态栏 = 客户区
客户区的消息是:没有NC
6. MFC类层次
CObject类
CObject类是MFC提供的绝大多数类的基类,它本身并不提供什么功能,主要是通过6个宏完成实际工作。主要完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。动态类型创建和识别(判断两个类型是否是同一种类)都是在这里进行处理。
CCmdTarget类
由CObject类直接派生,它是MFC消息映射结构的基类,消息映射将系统事件(命令)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和调度工作,实现应用程序对象之间的协调运行。---这里,命令是指来自菜单项、命令按钮和加速键的消息。
也就是所有有关消息的操作都是由这个类来管理完成,查找消息映射表,遍历,调用函数指针的功能(OnCmdMsg函数),这个类就相当于之前的飞机大战中的炮弹盒子类充当一个管理者的功能。
CWinThread类
CWinThread类主要用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。
CWinApp类
CWinApp类是应用程序的管理者,MFC中一个全局的对象,WinMain执行之前会先构造该对象。管理程序的生死,操纵每个对象的产生。(关键的函数:InitApplication/InitInstance)(应用类)类封装了Windows应用的初始化、运行以及终止的全过程。
这个类就像原来写的CPlane类一样,代表一个程序,管理所有对象的产生、销毁,管理程序。
CWinApp本身就代表一个程序本体,程序本体是指与程序本身有关而不与窗口有关的数据或动作。比如,WinMain传递的四个参数,注册窗口类,分派消息等。比如,CWinApp类中就定义了WinMain函数的四个参数(m_hInstance,m_hPrevInstance,m_lpCmdLine,m_nCmdShow)。还定义了一些重要的如 InitApplication(),InitInstance(),Run()等函数。传统的WinMain函数就是由此三个函数完成。
另外,CWinApp中还应该有个主窗口的handle,是的,但它不在CWinApp类中,而是在CWinThread类中实现,在CWinThread类中,有一个指向窗口类的指针的成员变量。如下所示 CWnd* m_pMainWnd
对于每一个基于框架应用,它必须且只能有一个派生于CWinApp的类对象。这个对象的特别之处在于它是一个全局对象,因此它在创建任何窗口前首先被构造。
类CWinApp提供了几个关键的可重载的虚成员函数,它们是InitInstance、Run、ExitInstance以及OnIdle等。而且在程序中可以随时调用全局函数AfxGetApp,以便获得CWinApp类对象的指针。
CWnd类
CWnd类提供了微软基础类库中所有窗口类的基本功能。
CWnd对象与Windows的窗口不同,但是两者有紧密联系。CWnd对象是由CWnd的构造函数和析构函数创建或销毁的。另一方面,Windows的窗口是Windows的一种内部数据结构,它是由CWnd的Create成员函数创建的,而由CWnd的虚拟析构函数销毁。DestroyWindow函数销毁Windows的窗口,但是不销毁对象。
(有窗口对象,但是没窗口,要有窗口,就要调用这个类的对象的Create()函数去创建一个windows窗口,也就是说在构造函数当中,类当中的窗口句柄还是空的,如果要用到窗口句柄,需要在create()函数执行之后才能使用该类中的窗口句柄)
CWnd类和消息映射机制隐藏了WndProc函数。接收到的Windows通知消息通过消息映射被自动发送到适当的CWnd OnWndMsg成员函数。你可以在派生类中重载OnWndMsg成员函数以处理成员的特定消息。
CWnd类同时还使你能够为应用程序创建Windows的子窗口。先从CWnd继承一个类,然后在派生类中加入成员变量以保存与你的应用程序有关的数据。在派生类中实现消息处理成员函数和消息映射,以指定当消息被发送到窗口时应该如何动作。
CFrameWnd类
CFrameWnd类往往用于创建应用程序的主窗口,因为它能很好地支持系统菜单和控制条(工具条、状态条等),为此定义了大量的成员函数和变量。在编写文档/视图结构的应用程序时,CFrameWnd作为主窗口管理视图和文档对象。视图对象和控制条都成为CFrameWnd的子窗口,它们分享客户区,其位置被CFrameWnd有效地排列。
CFrameWnd直接支持单文档界面(SDI),对于多文档界面(MDI),使用其派生类CMDIFrameWnd和CMDIChildWnd。
被CWnd* m_pMainWnd
所指
CView类
CView视图类的主要功能是显示文档数据,并接受用户对数据的修改。它以图形化方式将数据显示出来,并提供了与用户交互的接口,将用户的输入操作解释为对文档对象的操作。
(以前使用控制台的时候,用户直接看到的是数据,这里在用户和数据之间加了一个view使得数据图形化,)
一个视图对象只能与一个文档对象连接,视图类是文档与用户间进行联系的纽带,当用户打开一个窗口或分割一个窗口时,程序框架就会构造一个视图类对象与文档相关联,一个文档对象可连接多个视图对象。
当文档对象发生变化时,与该文档连接的所有视图都应做出反应,这一过程通过调用CDocument::UpdateAllViews()函数来得到实现。
CView成员不太多,同CDocument类似,它也只提供了基础、必要的框架,用户通过对该类的派生来充实所需的功能。
CDocument类
这个类用来存储数据,当用户通过view提供的接口同计算机交互的时候,用户输入的操作会解释为数据保存在该类对象中。
CDialog类
CDialog类是在屏幕上显示的对话框基类。对话框有两类:模态对话框和非模态对话框。模态对话框在应用继续进行之前必须关闭。非模态对话框允许用户执行另外的操作而不必取消或删除该对话框。
7. 添加标准消息
标准消息
- 格式:WM_XXX
- 由系统发送
添加标准消息有以下步骤:
- 明确在那个区域添加消息(在哪个类里面添加?)
- 明确消息是客户区消息还是非客户区消息(对应的函数名不同)
- 添加消息:
类视图-->找到要添加消息的那个类-->右键属性-->消息-->选中对应消息-->Add消息 - 在消息处理函数中规定消息响应
8. 添加命令消息
命令消息
- 格式:WM_COMMAND
- 由菜单栏,工具条,快捷键发送
工具条属于客户区,在响应工具栏命令消息的时候也会响应客户区消息
添加一个菜单栏
资源视图-->Menu-->添加名和菜单选项
菜单栏命令消息添加步骤
- 命令按钮(菜单栏/工具条/快捷键)右键添加事件处理程序
- 选择消息类型:COMMAND
- 选择给哪个类添加:CAboutDlg、CMainFrame、CTestApp、CTestDoc、CTestView...
这个时候消息映射表中会添加一个ON_COMMAND(命令ID,处理函数的函数指针) - 添加状态栏提示信息(非必须,不添加控制台可能会有警告):选中命令按钮-->右键属性-->编辑Prompt的值
注意
菜单栏属于非客户区域,在响应菜单栏命令消息的时候,也会响应非客户区消息
添加一个快捷键:
资源视图-->Accelerator-->IDR_MAINFRAME-->添加快捷键
快捷键命令消息添加步骤
- 选中快捷键,右键添加事件处理程序
- 步骤同上添加菜单栏消息的步骤
添加一个工具条按钮
资源视图-->Toolbar-->IDR_MAINFRAME-->添加工具条按钮
选中工具条按钮往右拖拽一点可以在该按钮与前面按钮之间添加一个分隔符
添加一个工具条按钮命令消息
这个与添加菜单栏消息,添加快捷键消息会有所不同,这个工具条按钮是一个图片,无法通过右键添加事件处理程序的方式去添加,所以需要手动添加
步骤:
- 明确代码往哪儿添(哪个类对应的头文件,源文件)
- 在头文件里添加一个消息处理函数的声明:afx_msg ...
- 源文件中写消息处理函数的定义
- 源文件的消息映射表中添加映射关系:ON_COMMAND(工具条按钮ID,消息处理函数指针)
- 添加状态栏提示信息(非必须,不添加控制台可能会有警告):选中命令按钮-->右键属性-->编辑Prompt的值
9. 添加自定义消息
自定义消息由用户发送:
- SendMessage():直接调用回调函数。
- PostMessage():现将消息放入消息队列,依次被GetMessage()函数取用执行,回调函数执行。
SendMessage():
函数原型:
LRESULT WINAPI SendMessage( _In_ HWND hWnd, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam );
参数:
hWnd:窗口句柄,哪个窗口接收处理该消息,就放哪个窗口的句柄
Msg:要发送的自定义消息
wParam:消息携带的其他信息
lParam:消息携带的其他数据
PostMessage():
函数原型:
BOOL WINAPI PostMessage( _In_opt_ HWND hWnd, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam );
参数:
hWnd:窗口句柄,哪个窗口接收处理该消息,就放哪个窗口的句柄
Msg:要发送的自定义消息
wParam:消息携带的其他信息
lParam:消息携带的其他数据
如何在视图类或者其他类中拿到主窗口的句柄:之前有说过在CWinApp中有一个m_pMainWnd指针是指向主窗口的,并且CWinApp是一个全局的类,所以可以通过theApp拿到m_pMainWnd指针,然后找到定义在CMainFrame类中的窗口句柄:theApp.m_pMainWnd->m_hWnd;
如何在主窗口类或者其他类中拿到视图类的窗口句柄:在CWnd中有一个m_pViewActive
指针和一个CView* GetActiveView() const
函数可以获得视图类对象,然后拿到其句柄:m_pViewActive->m_hWnd(在主窗口类中),GetActiveView()->m_hWnd(在其他类中)
添加自定义消息步骤
- 自定义一个消息:在stdafx.h头文件中添加宏定义,自定义消息一般以UM_开头,用户自定义消息的值为了防止与系统消息冲突,从WM_USER(0x0400)往后排,所以一般格式是:#define UM_XXXX (WM_USER + x)
- 在发送的窗口类中调用SendMessage()或者PostMessage()函数发送自定义消息
- 在需要接收消息的窗口类中声明和定义接收函数:
afx_msg LRESULT 函数名(WPARAM wParam,LPARAM lParam);
- 在接收窗口的源文件中添加消息映射:ON_MESSAGE(自定义消息宏,接收消息函数);
10. 类中资源一观
在TestApp类中:
- 用于生成消息映射函数的宏DECLARE_MESSAGE_MAP()
- 初始化实例函数InitInstance()InitInstance()函数中完成了窗口的设计,注册和创建,创建成功之后就将Frame的对象赋值给m_pMainWnd指针,之后m_pManWnd调用主窗口的显示和更新
- 退出实例函数ExitInstance()、
- about对话框消息处理函数OnAppAbout()、
CMainFrame类中:
- 动态创建对象宏DECLARE_DYNCREATE(CMainFrame)、
- 用于生成消息映射函数的宏DECLARE_MESSAGE_MAP()
- 预创建PreCreateWindow(CREATESTRUCT& cs)窗口创建之前的一个接口函数,可以通过修改cs结构体(用来存放CreateWindow()的一些参数)的值去改变窗口样式,这个函数将在窗口创建之前调用
- 工具条对象m_wndToolBar
- 菜单栏对象m_wndStatusBar
- 窗口创建消息(WM_CREATE)处理函数OnCreate(),调用创建主窗口函数创建主窗口,创建菜单栏和工具条。
在CTestView类中:
- 动态创建对象宏DECLARE_DYNCREATE(CTestView)
- 获取文档数据函数GetDocument() const
- 绘图函数OnDraw()
- 预创建函数PreCreateWindow()用于预创建视图窗口
- 打印函数(打印机)
在CTestDoc类中:
- 动态创建对象宏DECLARE_DYNCREATE(CTestView)
- 用于生成消息映射函数的宏DECLARE_MESSAGE_MAP()
11. MFC外观
修改窗口初始化的位置按照屏幕分辨率居中显示
由上我们知道要修改窗口的外观,只需要修改PreCreateWindow()函数中的cs结构体即可,实现方式如下:
int CX = ::GetSystemMetrics(SM_CXSCREEN); //获取屏幕的宽度 int CY = ::GetSystemMetrics(SM_CYSCREEN); //获取屏幕的高度 cs.x = (CX - cs.cx) / 2; cs.y = (CY - cs.cy) / 2;
去掉样式
在Win32编程中的创建窗口函数中,有一个参数是_In_ DWORD dwStyle
该参数规定了要创建窗口的样式,对应的就是PreCreateWindow()
函数中的cs.style
参数所以修改该参数就可以添加或者去掉一些样式,如:
//去除窗口大小调整 cs.style = cs.style^WS_MINIMIZEBOX; cs.style = cs.style^WS_MAXIMIZEBOX; cs.style = cs.style^WS_THICKFRAME; //窗口设置为一个弹出窗口 cs.style = WS_POPUP;
修改标题
查阅帮助文档中的CFrameWnd类的说明可知,如果窗口的样式中定义了FWS_ADDTOTITLE
属性,窗口无法修改标题,所以在修改cs.lpszName之前需要将该属性移除。
cs.style = cs.style^FWS_ADDTOTITLE; cs.lpszName = L"你好啊龙哥";
移除菜单栏
在OnCreate()函数中使用SetMenu()函数修改
this->SetMenu(0);
设置工具栏
操作以下代码段,移除工具栏的话删除即可:
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("未能创建工具栏\n"); return -1; // 未能创建 } // TODO: 如果不需要可停靠工具栏,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar);
设置状态栏
操作以下代码段,移除状态栏的话删除即可:
if (!m_wndStatusBar.Create(this)) { TRACE0("未能创建状态栏\n"); return -1; // 未能创建 } m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
修改光标、图标、背景
光标、图标、背景这些内容的初始化在Win32中是在窗口注册的结构体(WNDCLASSEX)中被设计,所以在要修改这些东西最终都还是要修改用于窗口注册的结构体的值。在MFC中我们可以通过函数AfxRegisterWndClass()来实现这一点(当然也是在预创建函数中使用):
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,0);
加载图标资源:
- 首先确定要在哪个类中该,图标是主窗口中中的内容,所以在MainFrame类中的预创建函数中去修改
- 在资源视图-->Icon中添加要加载的光标资源
- Win32:HICON hIcon = ::LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(图标ID));
- MFC:HICON hIcon = theApp.LoadIcon(光标ID);
加载光标资源:
- 光标需要在CTestView类中的预创建函数中去修改
- 在资源视图-->右键添加资源-->Cursor-->添加自己要加载的光标资源
- Win32:HICON hCursor = ::LoadCursor(theApp.m_hInstance,MAKEINTRESOURCE(光标ID));
- MFC:HICON hCursor = theApp.LoadCursor(光标ID);
加载背景资源:
- 背景需要在CTestView类中的预创建函数中去修改
- Win32:HBRUSH hBrush = ::CreateSolidBrush(RGB(0,176,176));
- MFC:
10. MFC绘图
在哪里写?
CTestView类的OnDraw()中去写
绘制一个矩形
//Win32 HDC hdc = ::GetDC(this->m_hWnd); Rectangle(hdc,0,0,100,100); ::ReleaseDC(this->m_hWnd,hdc); //MFC CDC* pDC = this->GetDC(); pDC->Rectangle(0,0,100,100); this->ReleaseDC(pDC); //MFC,使用OnDraw()函数的形参pDC pDC->Rectangle(0,0,100,100);
注意:在MFC中调用一个函数一定是某个对象去调用,我们需要考虑清楚该函数放在那个类中,应该由哪个对象去调用。
用鼠标画直线
- 添加鼠标按下的消息,去标记直线起点,将画图标记置为true
- 添加鼠标移动消息,如果标记为true,移动时开始画图
- 添加鼠标抬起消息,记录直线的终点,将画图标记置为false
bool CTestView::b_drawFlag = false; CPoint CTestView::point = 0; // CTestView 消息处理程序 void CTestView::OnLButtonDown(UINT nFlags, CPoint point) { b_drawFlag = true; this->point = point; CView::OnLButtonDown(nFlags, point); } void CTestView::OnLButtonUp(UINT nFlags, CPoint point) { b_drawFlag = false; CView::OnLButtonUp(nFlags, point); } void CTestView::OnMouseMove(UINT nFlags, CPoint point) { if(this->b_drawFlag == true) { CDC* pdc = this->GetDC(); CBrush* pBrush = new CBrush(RGB(0,176,176)); pdc->SelectObject(pBrush); pdc->Rectangle(0,0,500,500); //覆盖移动痕迹 pdc->MoveTo(this->point); pdc->LineTo(point); this->ReleaseDC(pdc); } CView::OnMouseMove(nFlags, point); }
用鼠标画曲线
原理和画直线的原理相同,只是在每次移动并画线之后更新起点坐标为当前鼠标所在位置
void CTestView::OnMouseMove(UINT nFlags, CPoint point) { if(this->b_drawFlag == true) { CDC* pdc = this->GetDC(); pdc->MoveTo(this->point); pdc->LineTo(point); this->point = point; this->ReleaseDC(pdc); } CView::OnMouseMove(nFlags, point); }
CDC的派生类
为了特定用途,Microsoft基本类库提供了几个CDC派生类。
CPaintDC
包括BeginPaint和EndPaint调用。CClientDC
管理窗口用户区对应的显示上下文。CWindowDC
管理与整个窗口对应的显示上下文,包括它的结构和控件。CMetaFileDC
与带元文件的设备上下文对应。
CClientDC dc(this); //获取视图的客户区DC CClientDC dc(AfxGetMainWnd()); //获取主窗口CMainFrame的客户区DC CWindowDC dc(AfxGetMainWnd()); //获取主窗口CMainFrame的窗口DC(包括客户区和非客户区) CWindowDC dc(GetDesktopWindow()); //获取桌面的窗口DC(包括客户区和非客户区)
13. MFC图片
Win32
HDC hDC = ::GetDC(this->m_hWnd); HDC hmemDC = ::CreateCompatibleDC(hDC); HBITMAP hBitmap = ::LoadBitmap(theApp.m_hInstance,MAKEINTRESOURCE(IDB_BITMAP1)); ::SelectObject(hmemDC,hBitmap); ::BitBlt(hDC,0,0,48,48,hmemDC,0,0,MERGECOPY); ::DeleteObject(hBitmap); ::DeleteDC(hmemDC); ::ReleaseDC(this->m_hWnd,hDC);
MFC
CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CClientDC dc(this); CDC mdc; mdc.CreateCompatibleDC(&dc); mdc.SelectObject(bitmap); dc.BitBlt(0,0,48,48,&mdc,0,0,MERGECOPY);
14. 对话框
创建一个基于对话框的MFC项目(VS2012)
新建MFC应用程序-->勾选基于对话框-->完成
类层次
关于对话框
MFC基于对话框的项目结构比较简单,基于对话框的方便支持在于可以通过工具箱使用鼠标点击拖动快速编辑界面,对于每个空间可以添加相应的消息进行完成相应的功能。
类中资源一观
在CTestApp类中:
- 初始化实例句柄的函数InitInstance(),在该函数中:定义一个对话框,即主对话框,将该对话框赋值给m_pMainWnd指针,用主窗口调用DoModal(),即主窗口是一个模态对话框
在CTestDlg类中:
- 绑定了对话框的资源:enum...
- 绑定空间函数DoDataExchange()
- 对话框初始化函数OnInitDialog():对话框创建完之后执行的一些额外的初始化内容,开发者可以再次添加主窗口创建之后额外的初始化内容
添加一个对话框
资源视图-->右键添加资源-->Dialog-->新建一个对话框
添加对话框对应的类:
选中对话框-->右键添加类。
说明:
这个类是CDialogEx类的一个派生类,该类与该对话框绑定,创建一个这个类的对象就创建了一个该类对应的对话框,对于该对象的操作就是对对话框的操作。
非模态对话框
不关闭当前对话框,也可以操作其他对话框
添加一个非模态对话框:
CNMmyDlg nmmydlg; //定义一个对话框对象,这一条应该放在主窗口类的成员中,否则作为局部变量会在程序跳出当前函数之后销毁 nmmydlg.Create(IDD_DIALOG1,this); //这一条应该放在主窗口类的初始化函数中 nmmydlg.ShowWindow(SW_SHOW); //这一条放在用于控制非模态对话框显示的函数中
模态对话框
不关闭当前对话框,无法操作其他对话框(阻塞态的)。
添加一个模态对话框:
CMmyDlg m_mydlg; //定义一个对话框对象 mydlg.DoModal();
15. 一些简单语法收集:
控制台输出:
TRACE()
和printf的用法是一样的
加作用域和不加作用域的区别
不加作用域的函数默认是当前类的函数,加作用域是使用指定类的函数,::
表示Windows API的函数
MFC和Win32的区别
Win32需要传入句柄
MFC的句柄都放到自己类当中了,不用传入句柄,但是需要对象去调用
带Afx的函数
这种函数通常是MFC的全局函数
获取主窗口句柄
AfxGetMainWnd()
获取桌面窗口句柄
GetDesktopWindow
本文作者:Free152
本文链接:https://www.cnblogs.com/free152/p/17218234.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步