学习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:
初始化列表,树
实现菜单中打开文件功能能,实现拖拽打开文件功能
获取打开文件路径字符串,打开文件,获取文件句柄,将文件二进制码读取到内存中
填充列表,实现进度条
将主对话框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();
}