generalize
Substance: Bind code and control through ID, realize data exchange through DoDataExchange
Movement: Rewrite the message control to achieve interaction, pay attention to rewriting virtual functions
pch.h
Pre-Compiled Header
When compiling a program, if pch.h is used, the compiler will give priority to this file and compile it into an intermediate file. When compiling other source files, the compiler will use this intermediate file directly without recompiling pch.h. This reduces compilation time because these commonly used header files do not need to be recompiled every time
MFC Microsoft Foundation Classes
Driver, Win32 is used in the background, and MFC is used to design the interface.
MVC model view controller model (doc, data storage), view, control
Controls (icons) are identified by ID, and each page is managed by a class.
Implementation Mechanism
Encapsulated Win32
Execution phase
构造类
create 将窗口与类绑定
vie 选择ShowWindow/DoModal 文本/对话框 (可否切换)
销毁窗口
析构类
Message and control events
Establish a mapping mechanism for keyboard and mouse messages, etc., which is more convenient
Class view->Properties->Message, you can add the program corresponding to the message
IMPLEMENT_DYNCREATE(CPaintView, CView)
BEGIN_MESSAGE_MAP(CPaintView, CView)
//标准消息
ON_WM_MOUSEMOVE()
ON_WM_CHAR()
//命令消息,控件->响应事件
//通告消息,通知事件的发生,即按键的先后顺序,按下一个后另一个接受通知激活
ON_COMMAND(ID_LINE, &CPaintView::OnLine)
//用户自定义消息
END_MESSAGE_MAP()
kind
MFC class hierarchy diagram | Microsoft Learn
Data serialization : flatten data into json (JavaScript Object Notation, lightweight data transmission format)
1️⃣Linearly arranged array, 2️⃣Data such as {x:100, y:200}, converted into text according to actual needs 3️⃣Copy memory directly
CObject
-
Support serialized CArchive
-
Provide runtime class information
_GetBaseClass(),GetThieClass()
Because classes generally do not contain class information after they are compiled.
- Supports dynamic creation and object diagnostic output such as child windows
AssertVaild() Dump()
key class
process
C means Class
CWinapp main function->thread (initialize the thread after creating the app)
CDocManager is used to maintain a series of document templates
CDocTemplate has the following three member variables of type CRUNTIMECLASS
InitInstance->our code
CDocument: Single document/multiple documents/dialog document template, responsible for storing data
SDI SingleDocumentInterface MDI multiple Dlg dialog
CFrameWnd: The window frame divides the area menu bar, toolbar, file directory, etc.
CView: Responsible for displaying data and embodying the framework
Some functions of InitInstance
Note that Init is only for drawing and binding, and running is the last step in WinMain.
nReturnCode = pThread->Run();
// 唯一的 CPaintApp 对象
CPaintApp theApp;
// CPaintApp 初始化
BOOL CPaintApp::InitInstance()
{
//初始化自己
CWinAppEx::InitInstance();
//初始化socket
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
// 初始化 OLE 库 activeX
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
//各种manager,afx是一个工作室的名字
AfxEnableControlContainer();
//解决win7的任务栏bug
EnableTaskbarInteraction(FALSE);
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));//注册表
LoadStdProfileSettings(16); // 加载标准 INI 文件选项(包括 MRU)
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
// 注册应用程序的文档模板。 文档模板
// 将用作文档、框架窗口和视图之间的连接
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CPaintDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CPaintView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 启用“DDE 执行”
EnableShellOpen();
RegisterShellFileTypes(TRUE);
// 调度在命令行中指定的命令。 如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
// 仅当具有后缀时才调用 DragAcceptFiles
// 在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
// 启用拖/放
m_pMainWnd->DragAcceptFiles();
return TRUE;
}
ID binding
CView layer
When adding response functions and variables, it is also a class operation
Define in .h, bind in .cpp, use the initialization list for the variables, and the function will be defined by double-clicking the control.
In xxxdlg.cpp
Bind to response function
void CRunBTNDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BTN1, BTN1);
DDX_Control(pDX, IDC_BTN2, BTN2);
}
Bind to variable
BEGIN_MESSAGE_MAP(CRunBTNDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN1, &CRunBTNDlg::OnBnClickedBtn1)
ON_BN_CLICKED(IDC_BTN2, &CRunBTNDlg::OnBnClickedBtn2)
END_MESSAGE_MAP()
Variable data update
UpdateData();//将编辑框的数据获取到变量
UpdateData(FALSE);//将变量的数据更新到编辑框
Document based
Line and brush
Using the DC device context device environment, a series of things about drawing are defined.
.h
protected:
//用于绘制线条起点,当前,终点,以及按下后的状态
CPoint m_start;
CPoint m_cur;
CPoint m_stop;
BOOL m_status;
.cpp
void CPaintView::OnDraw(CDC* pDC)//重绘时调用
{
CPaintDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
//更换后记得还原,否则在类析构后越界访问
CPen pen(PS_DOT,1,RGB(0,255,0));//只有1的时候能看出来
CPen* pOldPen = pDC->SelectObject(&pen);
CBrush brush(RGB(255, 0, 0));
CBrush* pOldBrush = pDC->SelectObject(&brush);
if (m_status) {
pDC->FillRect(CRect(m_start, m_cur), pOldBrush);
//pDC->MoveTo(m_start);
//pDC->LineTo(m_cur);
}
else {
pDC->FillRect(CRect(m_start, m_stop), &brush);
//pDC->MoveTo(m_start);
//pDC->LineTo(m_stop);
}
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}
//下面三个是捕获消息的
void CPaintView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_start = point;
m_status = TRUE;
CView::OnLButtonDown(nFlags, point); //消息传递
}
void CPaintView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_stop = point;
InvalidateRect(NULL);
m_status = FALSE;
CView::OnLButtonUp(nFlags, point);
}
void CPaintView::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_status) {
InvalidateRect(NULL);
m_cur = point;
}
CView::OnMouseMove(nFlags, point);
}
Text and cursor
OnDraw section
//解决TextOut只能显示单行文本
CString sub = _T("");
int y=0;
for (int i = 0; i < m_strText.GetLength(); i++)
{
if (m_strText.GetAt(i) == '\r'|| m_strText.GetAt(i) == '\n')//'\n'来处理复制粘贴
{
pDC->TextOut(0, y, sub);
CSize sz = pDC->GetTextExtent(sub);
sub.Empty();
y += sz.cy+3;//获取字符宽度,并加上行间距
continue;
}
sub += m_strText.GetAt(i);
}
if (sub.IsEmpty() == false)
pDC->TextOut(0, y, sub);
CSize sz = pDC->GetTextExtent(sub);//获取扩展信息
//CPoint pt;
//pt.y = y;
//pt.x = sz.cx;
SetCaretPos(CPoint(sz.cx+2,y));
//::SetCaretPos(sz.cx+2,y);//系统api
Message capture part
int CPaintView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
CClientDC dc(this);
TEXTMETRIC tm;//text metric度量
dc.GetTextMetrics(&tm);
CreateSolidCaret(3, tm.tmHeight);
ShowCaret();
return 0;
}
void CPaintView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CClientDC dc(this);
m_strText += (TCHAR)nChar;
InvalidateRect(NULL);
CView::OnChar(nChar, nRepCnt, nFlags);
}
Menu Bar
Resource view->Menu->IDR_MAINFRAME
Description text + shortcut keys combined 画图(&P) Alt+P
separately 新建(&N)\tCtrl+N ctrl+N
Right click to add the corresponding selection C*View class list
Response priority of overloaded functions by class View>Doc>Frame>App
Debugging Tips Output Log TRACE("%s(%d):%s\r\n", __FILE__, __LINE__, __FUNCTION__);
toolbar
Resource view->Toolbar->IDR_MAINFRAME(_256) two
Delete: Hold down and drag outside
The ID can be the same as the menu bar, and the same function will be triggered.
Dialog based
display window
ChtdMFCdllApp theApp;
ChtdMFCdllApp* pTheApp;
CWndMain* m_WndMain;
m_WndMain = new CWndMain();
m_WndMain->Create(IDD_MAIN);
m_WndMain->ShowWindow(true);
Drag the control and write the response event
Hold down ctrl to perform batch operations. When aligning, the last one shall prevail (bold border)
AfxMessageBox
AfxMessageBox(L"afx", MB_OK | MB_ICONINFORMATION, 0);
MessageBox
MessageBox(_T("Ok/Cancel"), _T("标题"),MB_CANCELTRYCONTINUE);
MessageBoxA(0,"hello world","hello",0);
//MB_CANCELTRYCONTINUE
//MB_ICONERROR弹出错误
TRACE
Wide byte is not supported, convert
CString temp = m_list.GetItemText(i, j);
char text[256];
memset(text, 0, sizeof(text));
size_t total;
wcstombs_s(&total, text, sizeof(text), temp, temp.GetLength());
TRACE("%s\n", text);
New window
Windows are managed by creating a class, and various functions are managed by rewriting (initialization, mapping)
Create a child window: add a class (inherited from Dialog)
Resource view->Dialog->Add resource
Creation of modal and non-modal windows
Advantages of dynamic creation: create it when used, without occupying resources in advance
When the creation time is too long, you can open a thread at the beginning to create it silently.
#include "CSonWnd.h"
CSonWnd dlg;
void CDlgDlg::OnBnClickedSonWnd()
{
//CSonWnd dlg;
//dlg.DoModal();
//模态对话框,子窗口关闭后才能继续操作父窗口,代码会卡在这里
if(dlg.m_hWnd==NULL)
dlg.Create(IDD_DIG_EDY, this);
dlg.ShowWindow(SW_SHOW);//SW_HIDE
//非模态,因为不阻塞,要保证创建后不消失,就需要在全局进行声明
}
window size
button
protected:
CButton m_button;
void CSonWnd::OnBnClickedOk()
{
if (m_button.m_hWnd == NULL)
m_button.Create(_T("dynamic"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, CRect(100, 100, 200, 150), this, 9999);
}
Edit box
Multi-line display: Behavior->multiline, want return, appearance->vertical scroll Set these three to true
Format input: Appearance->Lowercase/Uppercase/Number
Events: Input change checking (basic syntax of code), blocking keywords (expletives)
- read
CWnd* pEdit01 = GetDlgItem(IDC_EDIT_ONE);
pEdit01->SetWindowText(_T("100"));
SetDlgItemText(IDC_EDIT_ONE, _T("200"));
CString strText;
pEdit01->GetWindowText(strText);
GetDlgItemText(IDC_EDIT_ONE, strText);
Override controls, escape button
Cbutton’s Zorder is higher
Ideas to adjust after mousemove and button position,
The failure is because the button Zorder is larger than the main window and mousemove will be captured but will not be processed, so the class needs to be overloaded to respond.
CRect curRect;
GetWindowRect(curRect);
curRect.bottom; curRect.top;curRect.Width()
Class Wizard->Add Class (upper right corner)->MFC Class->The parent class is CButton (used to replace the original CButton class)
Then add the member function mousemove to respond
void BTN::OnMouseMove(UINT nFlags, CPoint point)
{
ShowWindow(SW_HIDE);
Other->ShowWindow(SW_SHOW);
CButton::OnMouseMove(nFlags, point);
}
property page
Dlg->button->sheet->page
Related controls
- radio button
ctrl+D viewing order (the default is creation order, Tab order), which can be changed by clicking
The first radio button needs to be set to the group attribute
- checkbox(checked)
When adding variables, you can add an array instead of adding them one by one.
memset(m_skill, 0, sizeof(m_skill));
- List box (list) class view->override OnInitDialog
You can turn off the sorting in the properties, because the Chinese sorting rules are a bit strange.
BOOL PROP_01::OnInitDialog()
{
CPropertyPage::OnInitDialog();
// TODO: 在此添加额外的初始化
//两种添加方式
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1);
if (pListBox) {
pListBox->AddString(_T("ALI"));
pListBox->AddString(_T("HUAWEI"));
pListBox->AddString(_T("JD"));
m_com.AddString(_T("APPLE"));
}
return TRUE;
}
- Drop-down box (Combo) Properties->Behavior->Data->Separate with semicolons
Multiple page switching
Create page
Resource view, New dialog box
Add MFC class to manage pages, inherited from CPropertyPage
The class name should be the same as the page name IDD_PAGE_01 should be PAGE_01
Switch page
Implement switching by creating an inherited class of CPropertySheet
.h
#include "PROP_01.h"
#include "PROP_02.h"
public:
PROP_01 m_prop1;
PROP_02 m_prop2;
.cpp
There are two constructors, both of which need to be added
AddPage(&m_prop1);
AddPage(&m_prop2);
- Jump to multiple page switching
In fact, it can be made into an array, and the code will be more concise.
void CRunBTNDlg::OnBnClickedQueryBtn()
{
CPropSheet dlg(_T("调查"), this);
dlg.SetWizardMode();//wizard 向导 下一步上一步
if (ID_WIZFINISH == dlg.DoModal())
{
//创建成功后,将数据返回到父窗口
CString strMsg = _T("your lang: ");
//单选
switch (dlg.m_prop1.m_lang)
{
case 0:strMsg += "C++";break;
case 1:strMsg += "Java";break;
case 2:strMsg += "Python";break;
}
//多选
CString strSkill[4]={
_T("数据结构"),_T("计算机组成原理"),_T("操作系统"),_T("计算机网络")}
for(int i=0;i<4;i++)
if(dlg.m_prop1.m_skill[i])
strMsg += strSkill[i] + _T(",");
MessageBox(strMsg);
}
}
- Sheet related button customization
Override OnSetActive() of each page class
BOOL PROP_01::OnSetActive()
{
//第一页只需要next //PSWIZB_BACK | PSWIZB_FINISH 用于中间页和最后一页
((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
//去掉帮助按钮
((CPropertySheet*)GetParent())->GetDlgItem(IDHELP)->ShowWindow(SW_HIDE);
return CPropertyPage::OnSetActive();
}
- Check if selected
LRESULT PROP_01::OnWizardNext()//wizard向导,巫师
{
UpdateData(TRUE);
//TRUE表示将控件的值传到变量 FALSE相反
//检查单选框
if (m_lang == -1){
MessageBox(_T("请选择开发语言"));
return -1;
}
//检查复选框
bool skillchoose = false;
for(auto x : skill)
skillchoose |= x;
if(!skillchoose){
MessageBox(_T("请选择技能"));
return -1;
}
//检查列表框
if (m_company == ""){
MessageBox(_T("请选择公司"));
return -1;
}
return CPropertyPage::OnWizardNext();
}
Other commonly used controls
list box
When set to multi-select, add controls and response functions
void PROP_01::OnBnClickedOk()
{
CString strText;
int total = m_com.GetSelCount();
if (total == 0) {
MessageBox(_T("没有选择公司"));return;}
else {
int* index = new int[total];
m_com.GetSelItems(total, index);
CString strTemp;
for (int i = 0; i < total; i++)
{
m_com.GetText(index[i], strTemp);
strText += strTemp + _T(" ");
}
delete[] index;
MessageBox(strText);
}
}
drop down box
Added items: Properties->Behavior->Data->separated by semicolon
Is a partial collection of edit boxes and list boxes
m_simple.GetCurSel();
GetLBText();//LB ListBox
progress bar
Add a control and use a timer to regularly obtain background data. The i and j of the loop are mapped to (0,100)
int m_pro_pos;//全局的进度,用来存放i,j的映射
//初始化
{
//m_progress为控件名,设置范围和定时器
m_progress.SetRange(0, 100);//默认范围为int,可设置为SetRange32
SetTimer(99, 500, NULL);//(ID,触发间隔,NULL),可以设多个定时器,触发间隔不低于30帧,误差小
}
void PROP_01::OnTimer(UINT_PTR nIDEvent)
{
//添加消息中的timer
if (nIDEvent == 99)
m_progress.SetPos(m_pro_pos);
CPropertyPage::OnTimer(nIDEvent);
if(m_pro_pos==100)KillTimer(99);
/*if (nIDEvent == 99)//进度条自增
{
m_progress.SetPos(m_pro_pos);
if (m_pro_pos < 100)m_pro_pos++;
}*/
//int lower,upper
//m_progress.SetRange(lower, upper);
}
marquee The progress of the marquee loop, indicating that it is loading. After setting it to True, fill in the following code during initialization
m_progress.SetMarquee(TRUE, 50);
Report control
For window size and report style, CRECT or DWORD is obtained first, and then assigned back after setting.
mTab.GetClientRect(&rect);
Pages[i]->MoveWindow(&rect);
DWORD extStyle = ExeList.GetExtendedStyle();
ExeList.SetExtendedStyle(extStyle);
list control is similar to task manager
Appearance->always show selection/->true View->report single selection/multiple selection
Behavior->Sort/none
After adding the control CListCtrl m_list;
, during initialization
//背景色和文字背景
m_list.SetBkColor(RGB(0,0,255));
m_list.SetTextBkColor(RGB(0,0,255));
//整体风格
DWORD extStyle = m_list.GetExtendedStyle();
//LVS -- List View Style
extStyle |= LVS_EX_FULLROWSELECT;//选择一行
extStyle |= LVS_EX_GRIDLINES;//网格背景
extStyle |= LVS_EX_CHECKBOXES;//勾选
m_list.SetExtendedStyle(extStyle);
//设置列
//list view coloumn format
m_list.InsertColumn(0, _T("序号"), LVCFMT_LEFT, 50);
m_list.InsertColumn(1, _T("IP"), LVCFMT_LEFT, 150);
m_list.InsertColumn(2, _T("ID"), LVCFMT_LEFT, 100);
//添加行
m_list.InsertItem(0, _T("0"));//(新建一行
m_list.SetItemText(0, 1, _T("192.168.0.1"));//(插入某行的第几个
m_list.SetItemText(0, 2, _T("2e4a4f"));
retrieve data
int LineCount = m_list.GetItemCount();
CHeaderCtrl* pHeader = m_list.GetHeaderCtrl();
int ColumnCount = pHeader->GetItemCount();
for (int i = 0; i < LineCount; i++)
{
//获取选中状态
if (m_list.GetCheck(i)) {
TRACE("选中");}
else TRACE("未选中");
for (int j = 0; j < ColumnCount; j++)
{
CString temp = m_list.GetItemText(i, j);
MessageBox(temp);
}
}
Get double click status
void CWndINJ::OnNMDblclkList1(NMHDR* pNMHDR, LRESULT* pResult)
{
//获取选中状态 NM : notification message HDR : handler
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
*pResult = 0;
//只有下面一句,前面是自动生成的
int index = pNMItemActivate->iItem;
}
tree control
As shown in the file tree on the left
public:
CTreeCtrl m_tree;
CImageList m_icons;
//创建图像列表来管理图像
m_icons.Create(IDB_TREE, 32, 2, 0);
m_tree.SetImageList(&m_icons, TVSIL_NORMAL);
//文件的内容,句柄用以关联子结点
HTREEITEM hRoot = m_tree.InsertItem(_T("root"),0,1);
HTREEITEM hLeaf1 = m_tree.InsertItem(_T("leaf"),1,1,hRoot);
Tab control
Properties->Dynamic Layout->Resize Type->Both
Then add each tab dialog box, pay attention to set the border to None, Appearance->Style->child
Create a sub-window, because there are many sub-windows, encapsulate the process into a function
bool CGameHackerDlg::InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _PageName)
{
if (CurPage >= MAX_PAGE)return false;
else
{
//用数组的方式显示窗口
Pages[CurPage] = wnd;
Pages[CurPage]->Create(IDD_WND);
Pages[CurPage]->SetParent(this);
//PageINJ.Create(IDD_PAGE_1, this);//有问题
Pages[CurPage]->ShowWindow(false);
//更改窗口的位置,防止切换页面时子窗口覆盖,(⊙﹏⊙)
CRect rect;
mTab.GetClientRect(&rect);
rect.top += 48;
rect.left += 6;
Pages[CurPage]->MoveWindow(&rect);
mTab.InsertItem(CurPage, _PageName);
CurPage++;
return true;
}
}
Get newsmTab.GetCurSel()
void CGameHackerDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
int n = mTab.GetCurSel();
for (int i = 0; i < CurPage; i++)
Pages[i]->ShowWindow(i == n);
}