1.继续完成进程间通信
1.1 完成接收端的内存文件映射接受
1.在 Recv 端添加一个按钮 接收映射文件内存 ;
2.在 CRecvDlg::OnBnClickedButton3 函数中,打开内存文件映射: HANDLE h_mapping_file = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"HH") ;
3.获取成功则获取内存空间: wchar_t* pwsz_content = (wchar_t*)::MapViewOfFile(h_mapping_file, FILE_MAP_ALL_ACCESS, 0, 0, 4096) ;
4.不为空则进行拷贝: m_str_recv = pwsz_content ;
5.从调用进程的地址空间取消映射文件的映射视图: UnmapViewOfFile(pwsz_content) ;
6.关闭内存映射: ::CloseHandle(h_mapping_file) ; h_mapping_file = 0 ;
void CRecvDlg::OnBnClickedButton3()
{
// 1. 打开内存文件映射
HANDLE h_mapping_file = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"HH");
if(h_mapping_file == 0)
{
MessageBox(L"文件映射打开失败");
return;
}
// 2. 获取成功则获取内存空间
wchar_t* pwsz_content = (wchar_t*)::MapViewOfFile(h_mapping_file, FILE_MAP_ALL_ACCESS, 0, 0, 4096);
if(pwsz_content != 0)
{
// 不为空则进行拷贝
m_str_recv = pwsz_content;
UpdateData(FALSE);
}
//
UnmapViewOfFile(pwsz_content);
// 关闭内存映射
::CloseHandle(h_mapping_file);
h_mapping_file = 0;
}
2.内存管理
2.1 对于一个32位操作系统来说,其前 64k 称为 空指针区域 ,不允许访问;从 64k 到 2GB ,称为 用户模式 ,即用户程序需要的内存空间在此分配;后 2GB 为 内核模式 ,即那些内核对象所在的位置。
2.2 连续空间分配
1.单一连续空间:内存在此方式下分为系统区和用户区;作业串行执行(一个作业包含若干个程序);
2.固定分配区域:最简单的一种多道程序存储管理方式;将用户内存空间划分为若干个固定大小的区域,每个分区只装入一道作业,当有空闲分区时,便可以再从外存的后备作业队列中,选择适当大小的作业装入该分区,程序可能太大而放不进任何一个分区中,这时使用覆盖技术;内部有空间浪费;
3.动态分区分配:不预先将内存划分,而是在进程装入内存时,根据进程的大小动态地建立分区;CPU出现空闲,操作系统就换出进程,装入新进程。由于新进程占用内存较小就会产生碎片;可以通过紧凑(Compaction)技术来解决,但碎片会越来越多;
2.3 非连续空间分配(现在常用)
1.页式管理:用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配;
2.段式管理:页面是主存物理空间中划分出来的等长的固定区域。分页方式的优点是页长固定,因而便于构造页表、易于管理,且不存在外碎片。但分页方式的缺点是页长与程序的逻辑大小不相关。例如,某个时刻一个子程序可能有一部分在主存中,另一部分则在辅存中。这不利于编程时的独立性,并给换入换出处理、存储保护和存储共享等操作造成麻烦。另一种划分可寻址的存储空间的方法称为分段。段是按照程序的自然分界划分的长度可以动态改变的区域。通常,程序员把子程序、操作数和常数等不同类型的数据划分到不同的段中,并且每个程序可以有多个相同类型的段。 段表本身也是一个段,可以存在辅存中,但一般是驻留在主存中。将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。
3.段页式管理:段页式存储组织是分段式和分页式结合的存储组织方法,这样可充分利用分段管理和分页管理的优点。
(1) 用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。
(2) 用分页方法来分配和管理实存。即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。程序对内存的调入或调出是按页进行的。但它又可按段实现共享和保护。
3.继续任务管理器
3.1 给主对话框上添加控件
1.将对话框横向拉长,从上到下依次添加:两个 Edit 控件,两个 Text Control 控件(名字分别为PNAME和PID),一个 Text Control 控件(要查找的值),一个 Edit 控件,三个按钮控件,一个 List Control 控件,两个 Text 控件(要修改的地址,要修改的值)和两个 Edit 控件,一个按钮控件(修改);
2.给所有的 Edit 控件添加 value 变量,给 List 控件添加变量: CString m_str_pname ; DWORD m_dw_process_id ; DWORD m_dw_findvalue ; DWORD m_dw_changeaddr ; DWORD m_dw_changevalue ; CListCtrl m_ls_showaddr ;
3.将 List 控件的属性 View 更改为 report ;
4.将最上面两个 Edit 控件的 Read Only 属性修改为 True ;
5.给 List 控件的第一行插入一行语句: m_ls_showaddr.InsertColumn(0, L"搜索的结果:", 0, 450) ;
6.为了能够双击左边 List 控件中的某一行,并且将双击选中行的进程名和进程ID放到右侧最上面两个 Edit 控件中,我们需要给左边的 List 控件添加一个事件处理函数,右键 List 控件,选择添加事件处理函数,选择消息类型为 NM_DBCLICK ,类列表为主对话框的类;
7.在 CTaskManagerDlg::OnNMDblclkList2 函数中,首先获取双击选中的项: int index = pNMItemActivate->iItem ;
8.若有双击选中的项,则获取进程名和进程ID: m_str_pname = m_lsProcessInfo.GetItemText(index, 0) ;CString str_process_id ; str_process_id = m_lsProcessInfo.GetItemText(index, 1) ; m_dw_process_id = _wtoi(str_process_id) ;
void CTaskManagerDlg::OnNMDblclkList2(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// 获取双击选中的项
int index = pNMItemActivate->iItem;
if(index != -1) // 有双击选中的项
{
// 获取进程名
m_str_pname = m_lsProcessInfo.GetItemText(index, 0);
// 获取进程ID
CString str_process_id;
str_process_id = m_lsProcessInfo.GetItemText(index, 1);
m_dw_process_id = _wtoi(str_process_id);
// 更新数据
UpdateData(FALSE);
}
*pResult = 0;
}
9.给项目添加一个C++类, CModifyMemory ,该类有一个成员变量: HANDLE m_hOpenPracess ,该变量在构造里置为零,在析构里进行关闭: ::CloseHandle(m_hOpenPracess) ; m_hOpenPracess = 0 ; 一个成员函数: bool OpenSelectProcess(DWORD processID) ;
10.在 CModifyMemory::OpenSelectProcess 函数中,我们首先判断 m_hOpenPracess 是否为 0 ,若是零,则可以打开进程,否则应该先关闭已打开的进程;
bool CModifyMemory::OpenSelectProcess 函数,并且在 主窗口的成员中(DWORD processID)
{
if(m_hOpenPracess == 0) // 若为空,则可以打开进程
{
// 打开进程
m_hOpenPracess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if(m_hOpenPracess != NULL)
return true;
}
else // 若当前有进程打开,则先关闭打开的进程再打开新的进程
{
// 关闭已经打开的进程
::CloseHandle(m_hOpenPracess);
m_hOpenPracess = 0;
m_hOpenPracess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if(m_hOpenPracess != NULL)
return true;
}
return false;
}
11.在双击 List 控件的函数 CTaskManagerDlg::OnNMDblclkList2 中进行调用上述 bool CModifyMemory::OpenSelectProcess 函数,并且在主窗口中定义一个 CModifyMemory mm ;
void CTaskManagerDlg::OnNMDblclkList2(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// 获取双击选中的项
int index = pNMItemActivate->iItem;
if(index != -1) // 有双击选中的项
{
// 获取进程名
m_str_pname = m_lsProcessInfo.GetItemText(index, 0);
// 获取进程ID
CString str_process_id;
str_process_id = m_lsProcessInfo.GetItemText(index, 1);
m_dw_process_id = _wtoi(str_process_id);
// 打开进程
if(mm.OpenSelectProcess(m_dw_process_id) == false)
{
m_str_pname = L"";
m_dw_process_id = 0;
MessageBox(L"进程打开失败");
}
// 更新数据
UpdateData(FALSE);
}
*pResult = 0;
}