学习MFC已经两天了,我们来写一个小项目:16进制文件浏览器,简单实现,因为我们MFC学的还不是很透彻,这里会给出详细的每一个步骤,并且详细解释每一个方法:
文章目录
- 提前了解步骤:
- 基本步骤:
- 实现细节:
提前了解步骤:
拖拽文件消息:
WM_DROPFILES
WCHAR szPath[MAX_PATH]={0};
int nRes = DragQueryFile(hDropInfo,-1,NULL,0);
CDialogEx::OnDropFIles(hDropInfo);
if(nRes<=0){
return;
}else{
第二个参数:如果为-1,则代表返回文件个数,如果是nRes-1,则代表第n个文件
int nRes = DragQueryFile(hDropInfo,nRes-1,szPath,MAX_PATH);:
CDialogEx::OnDropFIles(hDropInfo);
}
基本步骤:
-
画出基本窗口,列表,树,进度条,菜单
-
OnInitDialog:
初始化列表,树
-
实现菜单中打开文件功能能,实现拖拽打开文件功能
-
获取打开文件路径字符串,打开文件,获取文件句柄,将文件二进制码读取到内存中
-
填充列表,实现进度条
实现细节:
-
画出基本窗口:
主对话框需要设置属性:接受文件。
为列表添加变量:控件类型,m_HexVIewList
为树添加变量:控件类型,m_FilePathTree
-
画出菜单
将主对话框MENU设置为创建好的菜单资源名称。
-
初始化列表,树控件
类中添加public变量:
HTREEITEM hTreeRoot
在OnInitDialog函数中,初始化树控件,初始化列表由于比较繁琐,将其封装为函数后,添加在OnInitDialog函数中:
VOID CHexBrowserDlg::InitFileList() { m_HexViewList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_SNAPTOGRID); m_HexViewList.InsertColumn(0, L"Addr", 0, 80); m_HexViewList.InsertColumn(1, L"0", 0, 30); m_HexViewList.InsertColumn(2, L"1", 0, 30); m_HexViewList.InsertColumn(3, L"2", 0, 30); m_HexViewList.InsertColumn(4, L"3", 0, 30); m_HexViewList.InsertColumn(5, L"4", 0, 30); m_HexViewList.InsertColumn(6, L"5", 0, 30); m_HexViewList.InsertColumn(7, L"6", 0, 30); m_HexViewList.InsertColumn(8, L"7", 0, 30); m_HexViewList.InsertColumn(9, L"8", 0, 30); m_HexViewList.InsertColumn(10, L"9", 0, 30); m_HexViewList.InsertColumn(11, L"A", 0, 30); m_HexViewList.InsertColumn(12, L"B", 0, 30); m_HexViewList.InsertColumn(13, L"C", 0, 30); m_HexViewList.InsertColumn(14, L"D", 0, 30); m_HexViewList.InsertColumn(15, L"E", 0, 30); m_HexViewList.InsertColumn(16, L"F", 0, 30); m_HexViewList.InsertColumn(17, L" ", 0, 15); m_HexViewList.InsertColumn(18, L"0", 0, 22); m_HexViewList.InsertColumn(19, L"1", 0, 22); m_HexViewList.InsertColumn(20, L"2", 0, 22); m_HexViewList.InsertColumn(21, L"3", 0, 22); m_HexViewList.InsertColumn(22, L"4", 0, 22); m_HexViewList.InsertColumn(23, L"5", 0, 22); m_HexViewList.InsertColumn(24, L"6", 0, 22); m_HexViewList.InsertColumn(25, L"7", 0, 22); m_HexViewList.InsertColumn(26, L"8", 0, 22); m_HexViewList.InsertColumn(27, L"9", 0, 22); m_HexViewList.InsertColumn(28, L"A", 0, 22); m_HexViewList.InsertColumn(29, L"B", 0, 22); m_HexViewList.InsertColumn(30, L"C", 0, 22); m_HexViewList.InsertColumn(31, L"D", 0, 22); m_HexViewList.InsertColumn(32, L"E", 0, 22); m_HexViewList.InsertColumn(33, L"F", 0, 22); }
// TODO: 在此添加额外的初始化代码 hTreeRoot = m_FilePathTree.InsertItem(L"最近打开的文件", TVI_ROOT, TVI_LAST); InitFileList();
-
为菜单中,打开文件添加消息处理程序:
这里先给出加载十六进制文件的函数,打开文件后就要调用:
VOID CHexBrowserDlg::InitFileViewList(WCHAR * szPath) { if (szBuffer != nullptr) { //代表上次的还存在,如果需要显示的话,要释放掉 delete[] szBuffer; } //清空列表上显示的内容: m_HexViewList.DeleteAllItems(); //打开文件,获取文件句柄: HANDLE hFile = CreateFile(szPath, GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //获取文件大小: DWORD dwFileSize = GetFileSize(hFile, NULL); //申请内存: szBuffer = new char[dwFileSize]; memset(szBuffer, 0, dwFileSize); //读取文件: DWORD dwReadSize = 0; ReadFile(hFile, szBuffer, dwFileSize, &dwReadSize, NULL); DWORD dwLines = (dwReadSize / 0x16 + 1);//列表中一共要显示的行数 //初始化进度条: m_Progress.SetRange32(0, dwLines); DWORD nIndex = 0;//当前显示的行数,随着设置,会增加 DWORD dwAddr = 0;//每一行最开始的,地址 CString cValue; for (size_t i = 0; i + 16 <= dwLines; i+=16) { //设置每一行第一列:地址 cValue.Format(L"%08X", dwAddr); m_HexViewList.InsertItem(nIndex, cValue, NULL); //设置十六进制文件浏览: for (size_t j = 0; j < 0x10; j++) { UCHAR uCode = szBuffer[i + j]; cValue.Format(L"%02X", uCode); m_HexViewList.SetItemText(nIndex, j + 1, cValue); } m_HexViewList.SetItemText(nIndex, 17, L" "); //设置ASCII浏览: for (size_t j = 0; j < 0x10; j++) { UCHAR uCode = szBuffer[i + j]; if (uCode == 0) { cValue.Format(L"."); } else { cValue.Format(L"%c", uCode); } m_HexViewList.SetItemText(nIndex, 18 + j, cValue); } dwAddr += 0x10; m_Progress.SetPos(i+1); nIndex++; } CloseHandle(hFile); }
void CHexBrowserDlg::OnSeleteFile() { // TODO: 在此添加命令处理程序代码 CFileDialog cFileDlg(TRUE, NULL, NULL, NULL, L"EXE|*.exe|DLL|*.dll|SYS|*.sys|All File|*.*||", this); cFileDlg.DoModal(); CString szPath = cFileDlg.GetPathName(); m_FilePathTree.InsertItem(szPath, hTreeRoot, TVI_LAST); InitFileViewList(szPath.GetBuffer(0));//CString.GetBuffer方法可以将字符串自动转化为WCHAR类型的字符串 }
-
接下来,我们设置拖拽打开文件:
拖拽文件消息:
WM_DROPFILES
void CHexBrowserDlg::OnDropFiles(HDROP hDropInfo) { // TODO: 在此添加消息处理程序代码和/或调用默认值 TCHAR szPath[MAX_PATH] = { 0 }; int nRes = DragQueryFile(hDropInfo, -1, NULL, 0); if (nRes <= 0) { return; } nRes = DragQueryFile(hDropInfo, -1, szPath, _countof(szPath)); m_FilePathTree.InsertItem(szPath, hTreeRoot, TVI_LAST); InitFileViewList(szPath); CDialogEx::OnDropFiles(hDropInfo); }
-
接下来来设置当我们点击树中保存的文件路径时的操作:
-
首先我们添加右键菜单:
-
这里给出的函数分别是:打开文件,删除节点,清空节点的代码:
void CHexBrowserDlg::OnContinueOpenFile() { // TODO: 在此添加命令处理程序代码 HTREEITEM hTreeNode = m_FilePathTree.GetSelectedItem(); CString szPath = m_FilePathTree.GetItemText(hTreeNode); InitFileViewList(szPath.GetBuffer(0)); } void CHexBrowserDlg::OnDeleteTreeNode() { // TODO: 在此添加命令处理程序代码 HTREEITEM hTreeNode = m_FilePathTree.GetSelectedItem(); m_FilePathTree.DeleteItem(hTreeNode); } void CHexBrowserDlg::OnClear() { // TODO: 在此添加命令处理程序代码 m_FilePathTree.DeleteAllItems(); }
-