MFC 学习笔记

admin 7381 2026-07-22 05:48:13

MFC 学习笔记

MFC的概念和作用

什么是MFC?

全称是Microsoft Foundation Class Library,我们称作微软基础类库

它封装了windows应用程序的各种API以及相关机制的C++类库

总结:

MFC是一个大的类库

MFC是一个应用程序框架

为什么需要MFC?

基于应用程序框架之上,使用提供的类库快速开发,提高项目的开发效率,减少开发周期和成本

常用的头文件

MFC类库常用的头文件

afx.h:将各种MFC头文件包含在内

afxwin.h:包含了各种MFC窗口类,包含了afx.h和windows.h

afxext.h:提供了扩展窗口类的支持,例如工具栏、状态栏等

...

MFC程序的分类

MFC控制台程序

和win32的控制台程序的差别

main函数不同于普通的控制台程序

CWinApp theAPP; 多了一个全局对象

经验之谈

以Afx开头可以确定为MFC库中的全局函数

以::开头可以确定为win32的API函数

MFC的库程序

使用MFC制作自己的静态库程序

MFC的动态库

使用静态的NFC库制作自己的动态库

使用动态的MFC库制作自己的动态库

MFC扩展库

规则库可以被各种程序所调用,扩展库只能被MFC程序调用

相关函数

单文档视图架构程序

CWinApp:应用程序类,负责管理应用程序的流程

CFrameWnd:框架窗口类,负责管理框架窗口

CView:视图窗口类,负责显示数据

CDocument:文档类,负责管理数据

多文档视图架构程序

CWinApp:应用程序类

CMDIFrameWnd:多文档主框架窗口类

CMDIChildWnd:多文档子框架窗口类

CView:视图窗口类,显示数据

CDocument:文档类,管理数据

对话框应用程序

CWinApp:应用程序类

CDialog:对话框窗口类

MFC库中类的简介

Object类

MFC类库中绝大部分类的父类,提供了MFC类库中一些基本的机制

对运行时类信息的支持

对动态创建的支持

对序列化的支持

CWinApp类:应用程序类,封装了应用程序、线程等信息

CDocument类:文档类,管理数据

Frame Windows:框架窗口类,封装了窗口程序组成的各种框架窗口

CSplitterWnd:用来完成拆分窗口的类

Control Bars:控制条类

DIalog Boxes:对话框类,封装了各种对话框,通用的对话框

Views:视图类,封装了各种显示窗口

Controls:控件类,封装了各种常用的控件

Exceptions:异常处理类,封装了MFC中常用的各种异常

绘图类,包括CDC类和CGdiObject类

数据集合类,CArray/CList/CMap,封装了相应的数据结构管理

非CObject类的子类

提供了各种数据结构相关的管理,CPoint、CTime、CString等

第一个MFC程序

设置开发环境

头文件为

setting当中设置使用MFC库

总结:win32程序和MFC程序区别仅仅为能不能使用MFC而已

代码书写

定义自己的框架类CMyFrameWmd,派生自CFrameWnd类

class CMyFrameWnd : public CMyFrameWnd

{

};

定义自己的应用程序类CMyWinApp,派生自CWinApp类,并定义构造以及重写InitInstance虚函数,在函数中创建并显示窗口

class CMyWinApp : public CWinApp

{

public:

CMyWinApp()

{

}

virtual BOOL InitInstance()

{

CMyFrameWnd* pFrame = new CMyFrameWnd;

pFrame->Create(NULL, "MFCBase");

m_pMainWnd = pFrame;

pFrame->ShowWindow(SW_SHOW);

pFrame->UpdateWindow();

return TRUE;

}

};

定义CMyWinApp类的对象(程序的爆破点)

CMyWinApp theApp;

MFC程序启动

入口函数

与Win32窗口程序相同,都是从WinMain入口。但是MFC库已经实现了WinMain函数,所以在程序中不需要实现。

总结:在Win32程序中WinMain由程序员自己实现,那么流程是程序员安排,但到了MFC中,由于MFC库实现WinMain,也就意味着MFC负责安排程序的流程。

执行流程

程序的启动,构造theApp对象,调用父类CWinApp的构造函数

将theApp对象的地址保存到线程状态信息中

将theApp对象的地址保存到模块状态信息中

进入WinMain函数,调用AfxWinMain函数

进入入口函数WinMain

获取应用程序类对象theApp的地址

利用theApp地址调用InitApplication,初始化当前应用程序的数据

利用theApp地址调用InitInstance函数初始化程序,在函数中我们创建窗口并显示

利用theAPp地址调用CWinApp的Run函数进行消息循环

如果没有消息,利用theApp地址调用OnIdle虚函数实现空闲处理

程序退出利用theApp地址调用ExitInstance虚函数实现退出前的善后处理工作

CWinApp的成员

成员虚函数

InitInstance:程序的初始化函数,完成了窗口创建等初始化处理

ExitInstacne:程序退出时调用,清理资源等善后工作

Run:消息循环

OnIdle:空闲处理函数

成员变量

m_pWainWnd:当前应用程序的主窗口

MFC窗口和消息

钩子函数

创建钩子

HHOOK SetWindowHookEx(

int idHook, // 钩子类型(WH_CBT)

HOOKPROC lpfn, // 钩子处理函数

HINSTANCE hMod, // 应用程序实例句柄

DWORD dwThreadId // 线程ID

);

钩子处理函数

LRESULT CALLBACK CBTProc(

int nCode, // 钩子码(HCBT_CREATEWND)

WPARAM wParam, // 刚刚创建成功的窗口句柄

LPARAM lParam

);

更改窗口处理函数

LONG_PTR SetWindowLongPtr(

HWND hWnd, // 窗口句柄

int nIndex, // GWLP_WNDPROC

LONG_PTR dwNewLong // 新的窗口处理函数名(函数地址)

);

代码书写

定义自己的框架类(CMyFrameWnd),派生自CFrameWnd

定义自己的应用程序类(CMyWinApp),并重写父类成员虚函数InitInstance

定义全局对象CmyWinApp theApp;(爆破点)

MFC窗口创建过程

加载菜单

调用CWnd::CreateEx函数创建窗口

调用PreCreateWindow函数设计和注册窗口类调用AfxDeferRegisterClass函数,在这个函数中设计窗口类:

WNDCLASS wndcls; // 设计窗口类

...

// 定义窗口的处理函数为DefWindowProc

wndcls.lpfnWndProc = DefWindowProc;

调用_AfxRegisterWithIcon函数

在函数内部,加载图标,并调用AfxRegisterClass函数,在函数内部,调用::RegisterClass win32API函数注册窗口

消息映射机制的作用

在不重写WindowProc虚函数的大前提下,仍然可以处理消息

消息映射机制的使用

类必须具备的要件

类内必须添加声明宏:DECLARE_MESSAGE_MAP()

类外必须添加实现宏:BEGIN_MESSAGE_MAP(theClass, baseClass)、END_MESSAGE_MAP()

总结

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

消息映射机制的具体实施

以WM_CREATE消息为例:

BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间添加ON_MESSAGE(WM_CREATE, OnCreate)宏

在CMyFrameWnd类内添加OnCreate函数的声明和定义

数据结构

结构体

struct AFX_MSGMAP_ENTRY { // 静态数组每个元素的类型

UINT nMessage; // 消息ID

UINT nCode; // 通知码

UINT nID; // 命令ID

UINT nLastID; // 最后一个命令ID

UINT_PTR nSig; // 处理消息的函数类型

AFX_PMSG pfn; // 处理消息的函数名(地址)

};

宏展开各部分的作用

GetThisMessageMap() 讲台函数

作用:定义静态变量和静态数组,并返回本类静态变量地址(获取链表头)

_messageEntries[] 静态数组(进程及生命周期)

作用:数组每个元素,保存为消息ID和处理消息的函数名(地址)

messageMap 静态变量(进程及生命周期)

作用:第一个成员,保存父类宏展开的静态变量地址

第二个成员,保存本类的静态数组首地址

GetMessageMap() 虚函数

作用:返回本类静态变量首地址(获取链表头)

创建窗口的原理

消息产生进入窗口处理函数(AfxWndProc)

根据已知窗口句柄,找到和它绑定在一起的框架类对象地址(pFrame)

利用框架类对象地址(pFrame)调用框架类成员虚函数WindowProc

获取本类对应的静态变量,并到对应数组中匹配查找

如果没有找到,获取父类对应的静态变量,并到对应数组中匹配查找

如果找到了,利用找到的数组元素的最后一个成员,并调用之,完成消息处理

消息的分类

标注Windows消息

ON_WM_XXX,如ON_WM_CREATE等

自定义消息

ON_MESSAGE

命令消息

ON_COMMAND

MFC菜单

菜单相关问题

Win32:HMENU

MFC:CMenu类对象

CMenu类简介

封装了关于菜单的各种操作成员函数,另外还封装了一个非常重要的成员变量m_hMenu(菜单句柄)

菜单的使用

添加菜单资源

将菜单设置到窗口

利用pFrame调用Create函数时,传参

在处理框架窗口的WM_CREATE消息时

CMenu menu;

menu.LoadMenu(...);

消息的处理

ON_COMMAND(菜单项ID, 处理消息是函数名)

命令消息的处理顺序:框架类 -> 应用程序类

设置菜单项状态

Win32

WM_INITMENUPOPUP

::CheckMenuItem / ::EnableMenuItem

MFC

ON_WM_INITMENUPOPUP

CMenu::CheckMenuItem / CMenu::EnableMenuIten

右键菜单

Win32

WM_CONTEXTMENU

::TrackPopupMenu

MFC

ON_WN_CONTEXTMENU

CMenu::TrackPopupMenu

工具栏

相关类

CToolBarCtrl:父类CWnd,封装了关于工具栏控件的各种操作

CToolBar:父类CControlBar,封装了关于工具栏的操作,以及和框架窗口的关系

工具栏的使用

添加工具栏资源

创建工具栏:CToolBar::CreateEx

加载工具栏:CToolBar::LoadToolBar

设置工具栏的停靠

CToolBar::EnableDocking

CFrameWnd::EnableDocking

CFrameWnd::DockControlBar

运行时类信息机制

运行时类信息机制的作用

在程序运行过程中可以获知对象的类的相关信息(例如:对象是否属于某个类)

运行时类信息机制的使用

类必须派生自CObject

类内必须添加声明宏 DECLARE_DYNAMIC(theClass)

类外必须添加实现宏 IMPLEMENT_DYNAMIC(theClass, baseClass)

当一个类具备上述三个要件后,CObject::IsKingOf函数就可以正确判断对象是否属于某个类

动态创建机制

动态创建机制的作用

在不知道类名的情况下,将类的对象创建出来

动态创建机制的使用

类必须派生自CObject

类内必须添加声明宏:DECLARE_DYNCREATE(theClass)

类外必须添加实现宏:IMPLEMENT_DYNCREATE(theClass, baseClass)

当一个类具备上述三个要件后,CRuntimeClass::CreateObject(对象加工厂)函数就可以将类的对象创建出来

与运行时类信息的区别

多了一个静态函数

CObject* PASCAL CDog::CreateObject()

{

return new CDog; // new了一个CDog类对象,并返回对象地址

}

静态变量的第四个成员不再为NULL,而为新增加的这个静态函数的地址

执行过程

利用本类(CDog)的静态变量,调用CRuntimeClass的成员函数CreateObject(对象加工厂函数)

获取静态变量的第四个成员(新增加静态函数),并调用之

新增加的静态函数内部,完成类对象的创建,并返回对象地址

视图窗口

视图窗口的作用

提供一个用于显示数据的窗口

视图窗口的相关类

CView及其子类,父类为CWnd类,封装了关于视图窗口的各种操作,以及和文档类的数据交互

视图窗口的使用

定义一个自己的视图类(CMyView),派生自CView,并重写父类成员纯虚函数OnDraw(可以用于绘图)

其余框架类和应用程序类代码不变

在处理框架窗口的WM_CREATE消息时,定义CMyView类对象,并调用Create函数创建视图窗口

视图窗口的ID为AFX_IDW_PANE_FIRST

命令消息处理顺序

视图类 -> 框架类 -> 应用程序类

对象关系图

m_pMainWnd = pFrame;

m_pViewActive = pView;

theApp

m_pMainWnd(pFrame框架类对象地址)

m_pViewActive(pView视图类对象地址)

文档类

相关类

CDocument

提供了一个用于管理数据的类,封装了关于数据的管理(数据获取、数据转换、数据存储等),并和视图类进行数据交互

文档类的使用

定义一个自己的文档类(CMyDoc),派生自CDocument

对象关系图

theApp

m_pMainWnd(框架类对象地址pFrame)

m_pViewActive(视图类对象地址pView)

m_pDocument(文档类对象地址pDoc)

m_viewList(所有视图类对象地址)

文档类对象用一个链表成员变量,保存视图类对象地址

视图类用一个普通成员变量,保存文档类对象地址

经过分析可知:一个文档类对象可以对应多个视图类对象(视图窗口),而一个视图类对象(视图窗口)只能对应一个文档类对象

窗口切分

相关类

CSplitterWnd:不规则框架窗口类,封装了关于不规则框架窗口的操作

窗口切分的使用

重写CFrameWnd类的成员虚函数OnCreateClient

在虚函数中调用CSplitterWnd::CreateStatic创建不规则框架窗口

在虚函数中调用CSplitterWnd::CreateView创建视图窗口

文档类和视图类的关系

视图类成员函数

获取和视图类成员对象关联的文档类对象,调用GetDocument()

文档类成员对象

当文档类数据发生变化时,调用UpdateAllViews刷新和文档类对象相关联的视图类对象(视图窗口)

单文档视图架构

单文档视图架构特点

只能管理一个文档(只有一个文档类对象)

单文档视图架构使用

参与架构的类

CFrameWnd/CWinApp/CView/CDocument

需要用到的类

CDocTemplate(文档模板类)

CSingleDocTemplate(单模板文档类)

CDocManager(文档管理类)

参与架构的四个类除了应用程序类外,其余三个类均要支持动态创建机制

执行过程

theApp

m_pDocManager(文档管理类对象地址)

m_template(单文档模板对象地址)

CSingleDocTemplate *pTemplate

m_pOnlyDoc // 唯一的文档类对象地址

m_pDocClass // RUNTIME_CLASS(CMyDoc)

m_pFrameClass // RUNTIME_CLASS(CMyFrameWnd)

m_pViewClass // RUNTIME_CLASS(CMyView)

多文档视图架构

多文档视图架构特点

可以管理多个文档(可以有多个文档类对象)

多文档视图架构使用

参与架构的类

CMDIFrameWnd/CMDIChildWnd/CWinApp/CView/CDocument

需要用到的类

CDocTemplate(文档模板类)

CMultiDocTemplate(多文档模板类)

CDocManager(文档管理类)

MFC绘图

绘图相关类

CDC类(绘图设备类)

封装了各种绘图相关的函数,以及两个非常重要的成员变量m_hDC和m_hAttribDC

CPaintDC类,封装了在WM_PAINT消息中绘图的绘图设备

CCLientDC类,封装了在客户区绘图的绘图设备

CGdiObject类(绘图对象类)

封装了各种绘图对象相关的操作,以及一个非常重要的成员变量m_hObject(绘图对象句柄)

CPen类,封装了画笔的操作

CBrush类,封装了画刷的操作

CFont类,封装了字体的操作

CBItmap类,封装了位图的操作

序列化机制

文件操作相关类

CFIle:文件操作类,封装了关于文件读写等操作

CFile::Open

CFIle::Write/Read

CFile::Close

CFile::SeekToBegin/SeekToEnd/Seek

序列化机制的作用

以二进制流形式读写磁盘文件。但效率很高

序列化机制相关类

CFIle:文件操作类,完成磁盘文件的读写操作

CArchive:归档类,完成内存数据的读写操作

序列化机制的使用

创建或打开文件——CFile::Open

定义归档类对象——CArchive ar;

数据序列化(存储/写)——ar << 数据

关闭归档类对象——ar.Close();

关闭文件——CFile::Close();

反序列化机制的使用

打开文件——CFile::Open

定义归档类对象——CArchive ar;

数据反序列化(加载/读)——ar >> 变量

关闭归档类对象——ar.Close();

关闭文件——CFile::Close();

数据结构

class CArchive {

enum Mode { store = 0, load = 1 ...};

BOOL m_nMode; // 访问方式

int m_nBufSize; // buff的大小

CFile* m_pFile; // 操作的文件对象

BYTE* m_lpBufCur; // 当前指向

BYTE* m_lpBufMax; // 终止指向

BYTE* m_lpBufStart; // 开始指向

...

}

序列化执行过程

ar对象维护一个缓冲区

将各个数据依次序列化(存储)到ar对象维护的缓冲区中,并将m_lpBufCur的指针指向移动相应字节

如果ar维护的缓冲区不足,则将ar维护的缓冲区的数据写入硬盘文件,并重置m_lpBufCur为开始指向

当关闭ar对象时,将ar对象维护的缓冲区数据写入硬盘文件,并释放ar对象维护的缓冲区

反序列化执行过程

ar对象维护一个缓冲区

当反序列化第一个数据时,将文件数据全部读取到ar维护的缓冲区中,并将第一个数据反序列化到第一个变量,并将m_lpBufCur移动相应的字节数

依次反序列化每个数据到变量中

当关闭ar对象时,释放ar维护的缓冲区

序列化类对象

序列化类对象的使用

类必须派生自CObject

类内必须添加声明宏DECLARE_SERIAL(theClass)

类外必须添加实现宏IMPLEMENT_SERIAL(theClass, baseClass, 1)

类内必须重写虚函数Serialize

当类具备以上三个要件后,类对象就可以序列化到文件中保存了

对话框架构

对话框架构特点

对话框分类

模式对话框/无模式对话框

无模式对话框

对话框架构使用

参与架构的类

CDialog/CWinApp

代码书写

添加对话框资源

定义一个自己的对话框类(CMyDlg),管理对话框资源,派生自CDIalog或CDialogExt均可

执行过程

程序启动进入入口函数WinMain

获取应用程序类对象theApp的地址

利用theApp地址调用InitApplication,初始化当前应用程序的数据

利用theApp地址调用InitInstance函数,在函数中创建无模式对话框并显示

利用theApp地址调用CWinApp的Run()函数进行消息循环

如果没有消息,利用theApp地址调用OnIdle虚函数实现空闲处理

当对话框销毁(必须利用DestoryWindow),消息循环才可退出

退出前,利用theApp地址调用ExitInstance虚函数实现退出前的善后处理工作

模式对话框

模式对话框架构使用

参与架构的类

CDialog/CWinApp

代码书写

添加对话框资源

定义一个自己的对话框类(CMyDlg),管理对话框资源,派生自CDialog或CDialogExt均可

执行过程

DoModal内部执行过程

将父窗口设置为不可用

创建无模式对话框

进入消息循环(自带的)

退出消息循环(父类的OnOK/OnCancle导致循环退出)

将父窗口设置为可用状态

销毁无模式对话框

不再执行CWinApp的Run()函数进行的消息循环

程序结束

对象和控件绑定

绑定的作用

将控件窗口和类对象绑定具有两大作用

如果和数据类对象绑定,对象和控件可以进行数据交换

如果和控件类对象绑定,对象就可以代表整个控件

与数据类型对象绑定的使用

数据类型对象和控件可以实现数据交互

重写父类成员虚函数DoDataExchange

在函数内部通过一系列的DDX_xxx函数,实现控件和数据类型对象的数据交互

如果需要实现数据交互,调用UpdateData函数

UpdateDate(TRUE) :控件 -> 变量

UpdateData(FALSE) :变量 -> 控件

与控件类型对象绑定的使用

控件类型对象和控件可以实现对象代表整个控件

重写父类成员虚函数DoDataExchange

在函数内部通过一系列的DDX_xxx函数,实现控件句柄和控件类型对象的绑定

控件类型对象,就代表这个控件

控件消息的基本原理

控件消息的处理

WM_COMMAND消息

LOWORD(wParam)——菜单项ID,控件ID

HIWORD(wParam)——菜单项,为0

控件,通知码(控件发生的事情)

lParam——均无用

基本控件

下压式按钮

相关类

CButton类,父类为CWnd,封装了关于下压式按钮控件的各种操作

消息

当下压式按钮被单击

WM_COMMAND消息(通知码BN_CLICKED)

编辑框

相关类

CEdit类:父类为CWnd,封装了关于编辑框控件的各种操作

常见操作

获取编辑框文本内容

设置编辑框文本内容

消息

当编辑框文本内容发生变化

WM_COMMAND消息(通知码EN_CHANGE)

复选框按钮

相关类

CButton类,父类为CWnd,封装了关于复选框按钮控件的各种操作

常见操作

获取复选框状态

CButton::GetCheck

设置复选框状态

CButton::SetCheck

消息

当复选框按钮被单击

WM_COMMAND消息(通知码BN_CLICKED)

单选框按钮

相关类

CButton类,父类为CWnd,封装了关于单选框按钮控件的各种操作

常见操作

获取单选框状态

CButton::GetCheck

设置单选框状态

CButton::SetCheck

消息

当单选框按钮被单击

WM_COMMAND消息(通知码BN_CLICKED)

分组框按钮

常见操作

用于控件的分组显示,提高界面友好性

文本静态框

常见操作

常用于显示字符串,提高界面友好性

CWnd::SetWindowText

图像静态框

常见操作

常用于显示图像

CStatic::SetIcon/CStatic::SetBitmap

组合框

分类

简单式组合框/下拉式组合框/下拉列表式组合框

相关类

CComboBox类:父类为CWnd,封装了关于组合框控件的各种操作

常见操作

添加选项

CComboBox::AddString

删除选项

CComboBox::DeleteString

获取选择项索引

CComboBox::GetCurSel

设置选择项

CComboBox::SetCurSel

获取选项文本内容

CComboBox::GetItemText

设置选项附加数据

CComboBox::SetItemData

获取选项附加数据

CComboBox::GetItemData

消息

当选择项发生变化时

WM_COMMAND消息(通知码CBN_SELCHANGE)

当文本内容发生变化时

WM_COMMAND消息(通知码CBN_EDITCHANGE)

列表框

相关类

CListBox类:父类为CWnd,封装了关于列表框控件的各种操作

常见操作

添加选项

CListBox::AddString

删除选项

CListBox::DeleteString

获取选择项

CListBox::GetCurSel

设置选择项

CListBox::SetCurSel

获取选项文本内容

CListBox::GetItemText

设置选项附加数据

CListBox::SetItemData

获取选项附加数据

CListBox::GetItemData

滑块控件

相关类

CSliderCtrl类:父类为CWnd,封装了关于滑块控件的各种操作

常见操作

设置范围

CSliderCtrl::SetRange

设置位置

CSliderCtrl::SetPos

获取位置

CSliderCtrl::GetPos

消息

当滑块的位置改变后

WM_COMMAND消息(通知码NM_CUSTOMDRAW)

进度条控件

相关类

CProgressCtrl类:父类为CWnd,封装了关于进度条控件的各种操作

常见操作

设置范围

CProgressCtrl::SetRange

设置位置

CProgressCtrl::SetPos

获取位置

CProgressCtrl::GetPos

文件搜索类

相关类

CFileFInd类:封装了关于文件遍历的各种操作

常见操作

开启查找,成功返回TRUE,失败返回FALSE

CFileFind::FindFile

找到当前文件,返回下一个文件是否存在

CFileFind::FindNextFile

调用一系列GetXXX函数获取文件信息

CFileFind::GetFileName/CFileFind::GetFilePath

调用一系列IsXXX函数判断文件属性

CFileFind::IsDirectory/CFileFind::IsDot

关闭查找

CFileFind::Close

列表控件

相关类

CListCtrl类:父类为CWnd,封装了关于列表控件的各种操作

风格

图标(LVS_ICON)

小图标(LVS_SMALLICON)

列表(LVS_LIST)

报表(LVS_REPORT)

修改风格

CWnd::ModifyStyle

常见操作

添加选项

CListCtrl::InsertItem

删除选项

CListCtrl::DeleteItem/DeleteAllItems

添加列

CListCtrl::InsertColumn

设置文本内容

CListCtrl::SetItemText

设置图像

CListCtrl::SetImageList

设置附加数据

CListCtrl::SetItemData

获取附加数据

CListCtrl::GetItemData

消息

当列表控件被双击

WM_COMMAND消息(通知码NM_DBCLK)

树控件

相关类

CTreeCtrl类:父类为CWnd,封装了关于树控件的各种操作

常见操作

添加选项

CTreeCtrl::InsertItem

删除选项

CTreeCtrl::DeleteItem/DeleteAllItems

获取选择项

CTreeCtrl::GetSelectedItem

获取选项文本内容

CTreeCtrl::GetItemText

设置选项高度

CTreeCtrl::SetItemHeight

设置图像

CTreeCtrl::SetImageList

上一篇
下一篇
相关文章