zoukankan      html  css  js  c++  java
  • 第15章 在应用程序中使用虚拟内存(2)

    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内存成功!
    "), MEMSIZE / 1024);
        } else{
            _tprintf(_T("申请%dKB内存失败!(错误代码:%d)
    "), 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型的数据!
    "), pRecv,MEMSIZE / sizeof(float));
    //3.更改保护属性为只读 DWORD dwOldProtect = 0; BOOL bOk = VirtualProtect(pRecv, MEMSIZE, PAGE_READONLY, &dwOldProtect); if (bOk){ _tprintf(_T("成功修改申请的内存空间为只读属性! ")); } else{ _tprintf(_T("试图修改申请的内存空间为只读属性失败!(错误代码:%d) "),GetLastError()); return 0; }
    //4.读取所有值进行求和 float fSum = 0.0f; for (int i = 0; i < MEMSIZE / sizeof(float);i++){ fSum += pfArray[i]; } _tprintf(_T("%d个随机数总和为%f "), MEMSIZE / sizeof(float),fSum); //5.试图写入第10个元素,这将引起异常 __try{ pfArray[9] = 0.0f; }__except (EXCEPTION_EXECUTE_HANDLER){ _tprintf(_T("非法访问内存,试图在只读内存中写入数据! ")); } //6.直接释放 bOk = VirtualFree(pRecv, 0, MEM_RELEASE); _tprintf(_T("释放内存%s! "),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"
    END
    
    2 TEXTINCLUDE 
    BEGIN
        "#include ""winres.h""
    "
        ""
    END
    
    3 TEXTINCLUDE 
    BEGIN
        "
    "
        ""
    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失败!
    可能的原因:当前用户没有“锁定内存页”的权限");
        }
        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"
    END
    
    2 TEXTINCLUDE 
    BEGIN
        "#include ""winres.h""
    "
        ""
    END
    
    3 TEXTINCLUDE 
    BEGIN
        "
    "
        ""
    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
  • 相关阅读:
    upload.go
    heartbeat.go
    delete.go
    get.go
    handler.go
    uuid.go
    kingpin_parser.go
    disk.go
    logrus_hook.go
    反连接NOT EXISTS子查询中有or 谓词连接条件SQL优化一例
  • 原文地址:https://www.cnblogs.com/5iedu/p/4859637.html
Copyright © 2011-2022 走看看