学习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(); }
-