15.6 改变保护属性
(1)VritualProtect函数
参数 |
描述 |
PVOID pvAddress |
指向要修改属性的内存基地址 |
SIZE_T dwSize |
区域的大小,以字节为单位 |
DWORD flNewProtect |
PAGE_*(除PAGE_WRITECOPY、PAGE_EXCUTE_WRITECOPY外) |
PDWORD pflOldProtect |
返回原来的保护属性,有时虽然不需要返回这个信息,但必须传入一个有效的pflOldProtect参数 |
(2)注意点
①保护属性是与整个物理存储页相关联的,不能给一个字节指定保护属性。
②当若干连续的物理存储页跨越不同区域时,则VirtualProtect不能改变它们的保护属性。如果有相邻区域,又想改变跨区域的连续页面的保护属性,则必须多次调用该函数。
【VirtualProtect程序】
#include <windows.h> #include <tchar.h> #include <time.h> #include <locale.h> #define MEMSIZE (1024*1024) int _tmain(){ _tsetlocale(LC_ALL, _T("chs")); srand((unsigned)time(NULL)); //1.保留并提交内存(1MB) VOID* pRecv = VirtualAlloc(NULL, MEMSIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (pRecv !=NULL){ _tprintf(_T("分配%dKB内存成功!\n"), MEMSIZE / 1024); } else{ _tprintf(_T("申请%dKB内存失败!(错误代码:%d)\n"), MEMSIZE / 1024,GetLastError()); return 0; } //2.内存写入操作 float* pfArray = (float*)pRecv; for (int i = 0; i < MEMSIZE / sizeof(float); i++){ pfArray[i] = 1.0f*(rand() % 10); } _tprintf(_T("从[0x%X]处开始,成功写入%d个Float型的数据!\n"), pRecv,MEMSIZE / sizeof(float));
//3.更改保护属性为只读 DWORD dwOldProtect = 0; BOOL bOk = VirtualProtect(pRecv, MEMSIZE, PAGE_READONLY, &dwOldProtect); if (bOk){ _tprintf(_T("成功修改申请的内存空间为只读属性!\n")); } else{ _tprintf(_T("试图修改申请的内存空间为只读属性失败!(错误代码:%d)\n"),GetLastError()); return 0; }
//4.读取所有值进行求和 float fSum = 0.0f; for (int i = 0; i < MEMSIZE / sizeof(float);i++){ fSum += pfArray[i]; } _tprintf(_T("%d个随机数总和为%f\n"), MEMSIZE / sizeof(float),fSum); //5.试图写入第10个元素,这将引起异常 __try{ pfArray[9] = 0.0f; }__except (EXCEPTION_EXECUTE_HANDLER){ _tprintf(_T("非法访问内存,试图在只读内存中写入数据!\n")); } //6.直接释放 bOk = VirtualFree(pRecv, 0, MEM_RELEASE); _tprintf(_T("释放内存%s!\n"),bOk? _T("成功"):_T("失败")); return 0; }
15.7 重置物理存储器的内容
(1)进程页表中的项(页表项,PTE)结构
(2)MEM_RESET标志:当内存中某页面内容被修改时,该页面的“脏”位置1,表示“己修改”。以后如果要从exe、DLL或页交换文件中载入新的页面到内存里。系统会在内存中查找可用的页面,如果找到的是己被修改过的页面,那么系统将把它们换出到页交换文件。但可以通过修改该页面的这个标志(即复位,即把“脏”位置0,表示没有修改过),此时该页面的内容将被当作垃圾而废弃,所以也就不会被写入页交换文件。这对一部分并不重要的数据来说,是可行的,而且这样做也有利于提高系统的性能。
(3)调用VirtualAlloc并传入MEM_RESET时,可能发生的两种情况
①要重置的页面还没被映射到物理内存中,这时系统将抛弃这些页面,当下次被映射到物理内存时,会使用新的、全部清零的内存页。
②重置页面己被映射进内存中,系统会将他们这些页面标志为没被修改过(即重置),从而这些页面的内容被当作垃圾,也就不会被写入页交换文件中。这些页面会在下次
(4)重置内存页面的注意事项
①当调用VirtualAlloc预订或提交时基地址能常会被向下取整到页面大小整数倍(即向地址小的方向)。大小则会被向上取整到页面大小的整数倍(即大的方向)。但重置存储器时,VirtualAlloc会从相反的方向进行取整!其目的是确保基地址之前的同一页面还有其他重要数据的情况下,不会被抛弃。同理大小向下取整也是出于同样的目的。
②MEM_RESET只能单独使用,不能将其与其他标志按位或起来。
③传入MEM_RESET时,需要传一个有效的保护属性(如PAGE_READWITE),即使实际上并没有用到这个值。
【MemReset程序】重置存储器示例程序
//MemReset.cpp
/************************************************************************ Module: MemReset.cpp Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre ************************************************************************/ #include "../../CommonFiles/CmnHdr.h" #include <tchar.h> ////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE, HINSTANCE, PTSTR, int){ TCHAR szAppName[] = TEXT("MEM_RESET 测试"); TCHAR szTestData[] = TEXT("Some text data"); //提交一页并修改他的内容;1024会被向上取整到一个页面的大小(4KB) PTSTR pszData = (PTSTR)VirtualAlloc(NULL, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); _tcscpy_s(pszData, 1024, szTestData); //如果不访问数据,就把pszData里的当成垃圾看待 if (IDNO ==MessageBox(NULL,TEXT("是否要保存数据,以便稍后来访问呢?"),szAppName,MB_YESNO)){ //告诉系统将pszData所指空间当作垃圾,这样该内存中的数据就不会被写入页交换文件中 //注意:传入MEM_RESET给VVirtualAlloc函数,该函数会将基地址和大小设置到一个安全的 //范围,比如: // VirtualAlloc(pvData,5000,MEM_RESET,PAGE_READWRITE); //当CPU的分配粒度为4KB时,将被重置1个页面。如果大于4KB时,被重置0个页面。 MEMORY_BASIC_INFORMATION mbi; //以下调用总是会成功,先获取区域大小并将让重置的区域大小等于该值。(4KB的整数倍) VirtualQuery(pszData, &mbi, sizeof(mbi)); VirtualAlloc(pszData, mbi.RegionSize, MEM_RESET, PAGE_READWRITE); } //为了演示页面被重置过,这里可以给系统内存增加一些压力,如 //提交跟整个物理内存大小一样大的区域(注意,虽然是预订和提交这么大的 //地址空间,但系统并不会真正为其分配物理内存,只是提交到页交换文件中 MEMORYSTATUS mst; GlobalMemoryStatus(&mst); SIZE_T dwSize = mst.dwTotalPhys>mst.dwTotalVirtual ? mst.dwAvailPhys: mst.dwTotalPhys; PVOID pvDummy = VirtualAlloc(NULL, dwSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); //在刚申请的整个空间中写入数据,这会给系统的内存造成很大的压力, //并导致原来内存中的一些的页面被写入到页交换文件(被修改过的页面,如pszData //所指的页面,当然如果后来又有被重置的话,是不会被写入的) if (pvDummy == NULL){ MessageBox(NULL, TEXT("试图提交所有可用物理内存大小的空间失败!"), szAppName, MB_OK); VirtualFree(pszData, 0, MEM_RELEASE); return 0; } ZeroMemory(pvDummy, dwSize); //因写入整个物理内存,这些导致 //原来的pszData页面被换出。 //比较原始的数据,与当前pszData里数据是否相同 if (_tcscmp(pszData, szTestData) == 0) { //pszData的数据与原始数据一样,因为ZeroMemory会迫使页面被写入页交换文件 MessageBox(NULL, TEXT("修改的数据己被保存!"), szAppName, MB_OK); } else{ //pszData的数据与原始数据不同,ZeroMemory并没有引起我们的页面被写入页交换文件 MessageBox(NULL, TEXT("修改的数据未被保存!"), szAppName, MB_OK); } //释放地址空间 VirtualFree(pvDummy, 0, MEM_RELEASE); VirtualFree(pszData, 0, MEM_RELEASE); return 0; }
//resouce.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 15_MemReset.rc 使用 // #define IDI_MEMRESET 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//MemReset.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_MEMRESET ICON "MemReset.ico" #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
15.8 地址窗口扩展(Address Windowing Extension,AWE)
(1)AWE的作用
①允许应用程序以一种特殊的方式分配内存,操作系统保证不会将以这种方式分配的内存换出到磁盘上
②允许应用程序访问比进程地址空间还要多的内存
③使用AWE时,所有物理页面的交换控制(如映射)由应用程序自己控制,但要注意AWE操作需要“锁定内存页”权限。
(2)使用AWE的基本步骤
①在进址的地址空间中“开窗”(VirtualAlloc+MEM_PHYSICAL)
②申请分配物理内存(AllocateUserPhysicalPages):会拿出物理页的编号(放数组中)
③将物理内存映射到“窗口”中(MapUserPhysicalPages)
④通过“窗口”读写内存
⑤释放物理内存页面(FreeUserPhysicalPages)
⑥清理预订的地址空间:VirtualFree,并传入MEM_RELEASE标志。
(3)相关函数介绍
①“开窗”操作:VirtualAlloc(NULL,ulRAMBytes,MEM_RESERVE|MEM_PHYSICAL,PAGE_READWRITE);
【注意】MEM_PHYSICAL表示该区域最终会以物理内存作为后备,AWE要求所有映射到地址窗口的存储器必须是可读写的,即PAGE_READWRITE是传给VirtualAlloc的唯一有效保护属性,且不能用VirtualProtect函数来改变保护属性。
②AllocateUserPhysicalPages函数:申请物理内存
参数 |
描述 |
HANDLE hProcess |
进程句柄,注意只能是当前进程,不会跨进程使用! |
PULONG_PTR pulRAMPages |
传入时,表示请求分配的内存页数量,传出时表示实际分配到的页面数量。 |
PULONG_PTR aRAMPages |
每个内存页的页框号保存在该指针指向的数组中。这些页框号是供系统使用的,我们的应用程序不用关心这些数值本身。 |
③MapUserPhysicalPages函数:把内存块指定给地址窗口
参数 |
描述 |
PVOID pvAddressWindow |
要将内存块映射到哪个地址窗口 |
ULONG_PTR ulRAMPages |
通过该地址窗口能看到多少个页面的内存 |
PULONG_PTR aRAMPages |
通过该地址窗口能看到哪些页面的内存 |
注意:A.当给aRAMPages传入NULL时,用来撤消映射。一旦映射成功,就可以通过这个地址窗口来读写真正的物理内存了。 |
④FreeUserPhysicalPages:释放之前申请的物理内存.
FreeUserPhysicalPages(hProcess,pulRAMPages,aRAMPages);
【注意】:
A.第2个参数表示要释放多少个页面。第3个参数表示要释放哪些页面的页框号
B.如果内存块己经被映射到地址窗口,那么系统会取消映射并释放内存块
【AWE程序】演示“地址窗口扩展”的应用——该程序需要“锁定内存页”的权限
//AWE.cpp
/************************************************************************ Module: AWE.cpp Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre ************************************************************************/ #include "../../CommonFiles/CmnHdr.h" #include "AddrWindow.h" #include "resource.h" #include <tchar.h> #include <strsafe.h> ////////////////////////////////////////////////////////////////////////// CAddrWindow g_aw[2]; //2个内存地址窗口 CAddrWindowStorage g_aws[2]; //2个内存块 const ULONG_PTR g_nChars = 1024; //1024个字符缓冲区 const DWORD g_cbBufferSize = g_nChars*sizeof(TCHAR); ////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){ chSETDLGICONS(hwnd, IDI_AWE); //创建2个地址窗口 chVERIFY(g_aw[0].Create(g_cbBufferSize)); chVERIFY(g_aw[1].Create(g_cbBufferSize)); //创建2个内存块 if (!g_aws[0].Allocate(g_cbBufferSize)){ chFAIL("分配RAM失败!\n可能的原因:当前用户没有“锁定内存页”的权限"); } chVERIFY(g_aws[1].Allocate(g_cbBufferSize)); //在第1个内存块中放入一些默认的文本信息 g_aws[0].MapStorage(g_aw[0]); _tcscpy_s((PTSTR)(PVOID)g_aw[0], g_cbBufferSize, TEXT("内存块0中的文本!")); //在第2个内存块中放入一些默认的文本信息 g_aws[1].MapStorage(g_aw[0]); _tcscpy_s((PTSTR)(PVOID)g_aw[0], g_cbBufferSize, TEXT("内存块1中的文本!")); //填写列表框控件 for (int n = 0; n <= 1;n++){ int id = ((n == 0) ? IDC_WINDOW0STORAGE : IDC_WINDOW1STORAGE); HWND hWndCB = GetDlgItem(hwnd, id); ComboBox_AddString(hWndCB, TEXT("无内存块")); ComboBox_AddString(hWndCB, TEXT("内存块 0")); ComboBox_AddString(hWndCB, TEXT("内存块 1")); //地址窗口0显示内存块0,窗口1显示内存块1 ComboBox_SetCurSel(hWndCB, n + 1); FORWARD_WM_COMMAND(hwnd, id, hWndCB, CBN_SELCHANGE, SendMessage); Edit_LimitText(GetDlgItem(hwnd, (n==0)?IDC_WINDOW0TEXT:IDC_WINDOW1TEXT),g_nChars); } return TRUE; } ////////////////////////////////////////////////////////////////////////// void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotity){ switch (id) { case IDCANCEL: EndDialog(hwnd, id); break; case IDC_WINDOW0STORAGE: case IDC_WINDOW1STORAGE: if (codeNotity == CBN_SELCHANGE){ //显示地址窗口所指定的内存块内容 int nWindow = ((id == IDC_WINDOW0STORAGE) ? 0 : 1); int nStorage = ComboBox_GetCurSel(hwndCtrl) - 1; if (nStorage == -1){ //撤消地址窗口的映射 chVERIFY(g_aw[nWindow].UnmapStorage());// } else{ if (!g_aws[nStorage].MapStorage(g_aw[nWindow])){ //无法将指定的内存中映射到地址窗口 ComboBox_SetCurSel(hwndCtrl, 0);//强制为“无内存” chMB("该内存块只能被映射一次!"); } } //更新地址窗口的显示文本 HWND hwndText = GetDlgItem(hwnd, ((nWindow == 0)?IDC_WINDOW0TEXT:IDC_WINDOW1TEXT)); MEMORY_BASIC_INFORMATION mbi; VirtualQuery(g_aw[nWindow], &mbi, sizeof(mbi)); //注意:如果地址窗口没被映射,则mbi.State == MEM_RESERVE EnableWindow(hwndText, (mbi.State == MEM_COMMIT)); Edit_SetText(hwndText, IsWindowEnabled(hwndText) ?(PCTSTR)(PVOID)g_aw[nWindow]:TEXT("无内存块")); } break; case IDC_WINDOW0TEXT: case IDC_WINDOW1TEXT: if (codeNotity == EN_CHANGE){ //更新地址窗口指定的内存块的内容 int nWindow = ((id == IDC_WINDOW0TEXT) ? 0 : 1); //注意,是通过地址窗口来访问相应的内存块的 Edit_GetText(hwndCtrl, (PTSTR)(PVOID)g_aw[nWindow], g_nChars); } break; } } ////////////////////////////////////////////////////////////////////////// INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ switch (uMsg){ chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog); chHANDLE_DLGMSG(hWnd, WM_COMMAND, Dlg_OnCommand); } return FALSE; } ////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nShowCmd){ DialogBox(hInstance, MAKEINTRESOURCE(IDD_AWE), NULL, Dlg_Proc); return 0; }
//AddrWindow.h
/************************************************************************ Module: AddrWindow.h Notices: Copyright(c) 2008 Jeffrey Richter & Christophe Nasrre ************************************************************************/ #pragma once ////////////////////////////////////////////////////////////////////////// #include "../../CommonFiles/CmnHdr.h" #include <tchar.h> ////////////////////////////////////////////////////////////////////////// //CSystemInfo类:对GetSystemInfo函数的简单封装,要在后面两个类中用到 class CSystemInfo :public SYSTEM_INFO{ public: CSystemInfo(){ GetSystemInfo(this);} }; ////////////////////////////////////////////////////////////////////////// //CAddrWindow类:封装了地址窗口 class CAddrWindow{ public: CAddrWindow(); ~CAddrWindow(); //预订(保留)地址窗口 BOOL Create(SIZE_T dwBytes, PVOID pvPreferredWindowBase = NULL); //销毁地址窗口 BOOL Destroy(); //撤消映射 BOOL UnmapStorage(); //通过operator 重载隐式转换,返回地址窗口的虚拟地址 //类型转换操作符(type conversion operator)是一种特殊的类成员函数, //它定义将类类型值转变为其他类型值的转换。转换操作符在类定义体内声明, //在保留字 operator 之后跟着转换的目标类型(即PVOID) operator PVOID(); private: PVOID m_pvWindow; //地址窗口区域的虚拟地址 static CSystemInfo sm_sinf; }; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //CAddrWindowStorage:对内存块进行封装 class CAddrWindowStorage{ public: CAddrWindowStorage(); ~CAddrWindowStorage(); //Allocate:分配内存(须有锁定面用户权限) BOOL Allocate(ULONG_PTR ulBytes); //Free:释放内存块 BOOL Free(); //HowManyPagesAllocated:返回己成功分配的页面数量 ULONG_PTR HowManyPagesAllocated(); //MapStorage:把内存块映射到一个地址窗口对象(CAddrWindow) BOOL MapStorage(CAddrWindow& aw); //UnmapStorage:撤消映射 BOOL UnmapStorage(CAddrWindow& aw); private: static BOOL EnablePrivilege(PCTSTR pszPrivName, BOOL bEnable = TRUE); private: ULONG_PTR m_ulPages; //物理页面数 PULONG_PTR m_pulUserPfnArray; //数组,用来接收分配到的物理页的帧号 static CSystemInfo sm_sinf; }; //////////////////////////////// End of File //////////////////////////////////
//AddrWindow.cpp
/************************************************************************ Module: AddrWindow.cpp Notices: Copyright(c) 2008 Jeffrey Richter & Christophe Nasrre ************************************************************************/ #pragma once ////////////////////////////////////////////////////////////////////////// #include "AddrWindow.h" ////////////////////////////////////////////////////////////////////////// //CAddrWindow类:封装了地址窗口 CAddrWindow::CAddrWindow(){ m_pvWindow = NULL; } CAddrWindow::~CAddrWindow(){ Destroy(); } //预订(保留)地址窗口 BOOL CAddrWindow::Create(SIZE_T dwBytes, PVOID pvPreferredWindowBase){ //预订地址窗口区域 m_pvWindow = VirtualAlloc(pvPreferredWindowBase, dwBytes, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE); return (m_pvWindow != NULL); } //销毁地址窗口 BOOL CAddrWindow::Destroy(){ BOOL bOk = TRUE; if (m_pvWindow != NULL){ //销毁地址窗口区域 bOk = VirtualFree(m_pvWindow, 0, MEM_RELEASE); m_pvWindow = NULL; } return bOk; } //撤消映射 BOOL CAddrWindow::UnmapStorage(){ MEMORY_BASIC_INFORMATION mbi; VirtualQuery(m_pvWindow, &mbi, sizeof(mbi)); return (MapUserPhysicalPages(m_pvWindow, mbi.RegionSize / sm_sinf.dwPageSize, NULL)); } //通过operator 重载隐式转换,返回地址窗口的虚拟地址 //类型转换操作符(type conversion operator)是一种特殊的类成员函数, //它定义将类类型值转变为其他类型值的转换。转换操作符在类定义体内声明, //在保留字 operator 之后跟着转换的目标类型(即PVOID) CAddrWindow::operator PVOID(){ return (m_pvWindow); } ////////////////////////////////////////////////////////////////////////// CSystemInfo CAddrWindow::sm_sinf; //给静态变量初始化 ////////////////////////////////////////////////////////////////////////// CAddrWindowStorage::CAddrWindowStorage(){ m_ulPages = 0; m_pulUserPfnArray = NULL; } CAddrWindowStorage::~CAddrWindowStorage(){ Free(); } //Allocate:分配内存(须有锁定面用户权限) BOOL CAddrWindowStorage::Allocate(ULONG_PTR ulBytes){ Free(); //清除己经存在的地址窗口 //计算指定的空间大小需要多少个物理页面 m_ulPages = (ulBytes + sm_sinf.dwPageSize - 1) / sm_sinf.dwPageSize; //分配存放物理页编号的数组空间 m_pulUserPfnArray = (PULONG_PTR)HeapAlloc(GetProcessHeap(), 0, m_ulPages*sizeof(ULONG_PTR)); BOOL bOk = (m_pulUserPfnArray != NULL); if (bOk){ //“内存锁定页面”权限提升 EnablePrivilege(SE_LOCK_MEMORY_NAME, TRUE); bOk = AllocateUserPhysicalPages(GetCurrentProcess(), &m_ulPages, m_pulUserPfnArray); EnablePrivilege(SE_LOCK_MEMORY_NAME, FALSE); } return bOk; } //Free:释放内存块 BOOL CAddrWindowStorage::Free(){ BOOL bOk = TRUE; if (m_pulUserPfnArray != NULL){ bOk = FreeUserPhysicalPages(GetCurrentProcess(), &m_ulPages, m_pulUserPfnArray); if (bOk){ //释放存放物理页编号的数组 HeapFree(GetProcessHeap(), 0, m_pulUserPfnArray); m_ulPages = 0; m_pulUserPfnArray = NULL; } } return bOk; } //HowManyPagesAllocated:返回己成功分配的页面数量 ULONG_PTR CAddrWindowStorage::HowManyPagesAllocated(){ return m_ulPages; } //MapStorage:把内存块映射到一个地址窗口对象(CAddrWindow) BOOL CAddrWindowStorage::MapStorage(CAddrWindow& aw){ return (MapUserPhysicalPages(aw, HowManyPagesAllocated(), m_pulUserPfnArray)); } //UnmapStorage:撤消映射 BOOL CAddrWindowStorage::UnmapStorage(CAddrWindow& aw){ return (MapUserPhysicalPages(aw, HowManyPagesAllocated(), NULL)); } BOOL CAddrWindowStorage::EnablePrivilege(PCTSTR pszPrivName, BOOL bEnable) { BOOL bOk = FALSE; //假设函数调用失败 HANDLE hToken; //尝试打开进程令牌 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)){ //启用“内存锁定页面”权限 TOKEN_PRIVILEGES tp = { 1 }; LookupPrivilegeValue(NULL, pszPrivName, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); bOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } return bOk; } ////////////////////////////////////////////////////////////////////////// CSystemInfo CAddrWindowStorage::sm_sinf; ////////////////////////////////////////////////////////////////////////// //////////////////////////////// End of File //////////////////////////////////
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 15_AWE.rc 使用 // #define IDD_AWE 101 #define IDI_AWE 102 #define IDC_WINDOW0TEXT 1006 #define IDC_WINDOW0STORAGE 1007 #define IDC_WINDOW1STORAGE 1008 #define IDC_WINDOW1TEXT 1009 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//AWE.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_AWE DIALOGEX 0, 0, 279, 44 STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "地址窗口扩展(Address Windowing Extensions)" FONT 10, "宋体", 400, 0, 0x0 BEGIN LTEXT "窗口0:",IDC_STATIC,9,6,23,8 COMBOBOX IDC_WINDOW0STORAGE,35,4,80,58,CBS_DROPDOWNLIST | WS_TABSTOP EDITTEXT IDC_WINDOW0TEXT,123,4,152,14,ES_AUTOHSCROLL LTEXT "窗口1:",IDC_STATIC,9,28,23,8 COMBOBOX IDC_WINDOW1STORAGE,35,25,80,58,CBS_DROPDOWNLIST | WS_TABSTOP EDITTEXT IDC_WINDOW1TEXT,123,25,152,14,ES_AUTOHSCROLL END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_AWE, DIALOG BEGIN LEFTMARGIN, 7 TOPMARGIN, 7 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_AWE ICON "AWE.ico" #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED