October 1999
Figure 1   Implementing AWE
// First, reserve a 1MB region for the address window
ULONG_PTR ulRAMBytes = 1024 * 1024;
PVOID pvWindow = VirtualAlloc(NULL, ulRAMBytes,
   MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE); 

// Get the number of bytes in a page for this CPU platform
SYSTEM_INFO sinf;
GetSystemInfo(&sinf);

// Calculate the required number of RAM pages for the desired number of bytes
ULONG_PTR ulRAMPages = ulRAMBytes / sinf.dwPageSize

// Allocate array for RAM page's page frame numbers
ULONG_PTR aRAMPages[ulRAMPages];

// Allocate the pages of RAM
// (requires Lock Pages in Memory user right)
AllocateUserPhysicalPages(
   GetCurrentProcess(), // Allocate the storage for our process
   &ulRAMPages,         // Input: # of RAM pages, Output: # pages allocated
   aRAMPages);          // Output: Opaque array indicating pages allocated

// Assign the RAM pages to our window
MapUserPhysicalPages(pvWindow,   // The address of the address window
   ulRAMPages,                   // Number of entries in array 
   aRAMPages);                   // Array of RAM pages

// Access the RAM pages via the pvWindow virtual address
•
•
•
// Free the block of RAM pages
FreeUserPhysicalPages(
   GetCurrentProcess(), // Free the RAM allocated for our process
   &ulRAMPages,         // Input, # of RAM pages, Output: # pages freed
   aRAMPages);          // Input: Array indicating the RAM pages to free

// Destroy the address window
VirtualFree(pvWindow, 0, MEM_RELEASE);


Figure 2   AWETest

AddrWindow.h


/*******************************************************
Module:  AddrWindow.h
Notices: Written by Jeffrey Richter
*******************************************************/

#pragma once

#include <tchar.h>
//////////////////////
class CSystemInfo : public SYSTEM_INFO {
public:
   CSystemInfo() { GetSystemInfo(this); }
};

//////////////////////
class CAddrWindow {
public:
   CAddrWindow()  { m_pvWindow = NULL; }
   ~CAddrWindow() { Destroy(); }

   BOOL Create(SIZE_T dwBytes, 
      PVOID pvPreferredWindowBase = NULL) {
      // Reserve address window region to view physical 
      // storage
      m_pvWindow = VirtualAlloc(pvPreferredWindowBase, 
         dwBytes,MEM_RESERVE | MEM_PHYSICAL, 
         PAGE_READWRITE);
      return(m_pvWindow != NULL);
   }

   BOOL Destroy() {
      BOOL fOk = TRUE;
      if (m_pvWindow != NULL) {
         // Destroy address window region
         fOk = VirtualFree(m_pvWindow, 0, MEM_RELEASE);
         m_pvWindow = NULL;
      }
      return(fOk);
   }

   BOOL UnmapStorage() {
      // Unmap all storage from address window region
      MEMORY_BASIC_INFORMATION mbi;
      VirtualQuery(m_pvWindow, &mbi, sizeof(mbi));
      return(MapUserPhysicalPages(m_pvWindow, 
         mbi.RegionSize / sm_sinf.dwPageSize, NULL));
   }

   // Returns virtual address of address window
   operator PVOID() { return(m_pvWindow); }

private:
   PVOID m_pvWindow;    // Virtual address of address 
                        // window region
   static CSystemInfo sm_sinf;
};

//////////////////////
CSystemInfo CAddrWindow::sm_sinf;

//////////////////////
class CAddrWindowStorage {
public:
   CAddrWindowStorage()  { m_ulPages = 0; 
      m_pulUserPfnArray = NULL; }
   ~CAddrWindowStorage() { Free(); }

   BOOL Allocate(ULONG_PTR ulBytes) {
      // Allocate storage intended for an address window

      Free();  // Clean up this object's existing address 
               // window

      // Calculate number of pages from number of bytes
      m_ulPages = (ulBytes + sm_sinf.dwPageSize) / 
         sm_sinf.dwPageSize;

      // Allocate array of page frame numbers
      m_pulUserPfnArray = (PULONG_PTR) 
         HeapAlloc(GetProcessHeap(), 0, m_ulPages * 
            sizeof(ULONG_PTR));

      BOOL fOk = (m_pulUserPfnArray != NULL);
      if (fOk) {
         // The "Lock Pages in Memory" privilege must be 
         // enabled
         EnablePrivilege(SE_LOCK_MEMORY_NAME, TRUE);
         fOk = AllocateUserPhysicalPages(
            GetCurrentProcess(), &m_ulPages, 
            m_pulUserPfnArray);
         EnablePrivilege(SE_LOCK_MEMORY_NAME, FALSE);
      }
      return(fOk);
   }

   BOOL Free() {
      BOOL fOk = TRUE;
      if (m_pulUserPfnArray != NULL) {
         fOk = FreeUserPhysicalPages(GetCurrentProcess(), 
            &m_ulPages, m_pulUserPfnArray);
         if (fOk) {
            // Free the array of page frame numbers
            HeapFree(GetProcessHeap(), 0, 
               m_pulUserPfnArray);
            m_ulPages = 0; 
            m_pulUserPfnArray = NULL; 
         }
      }
      return(fOk);
   }

   ULONG_PTR HowManyPagesAllocated() { return(m_ulPages); }

   BOOL MapStorage(CAddrWindow& aw) {
      return(MapUserPhysicalPages(aw, 
         HowManyPagesAllocated(), m_pulUserPfnArray));
   }

   BOOL UnmapStorage(CAddrWindow& aw) {
      return(MapUserPhysicalPages(aw, 
         HowManyPagesAllocated(), NULL));
   }

private:
   static BOOL EnablePrivilege(PCTSTR pszPrivName, 
      BOOL fEnable = TRUE) {

      BOOL fOk = FALSE;    // Assume function fails
      HANDLE hToken;

      // Try to open this process's access token
      if (OpenProcessToken(GetCurrentProcess(), 
         TOKEN_ADJUST_PRIVILEGES, &hToken)) {

         // Attempt to modify the "Lock pages in Memory" 
         // privilege
         TOKEN_PRIVILEGES tp = { 1 };
         LookupPrivilegeValue(NULL, pszPrivName, 
            &tp.Privileges[0].Luid);
         tp.Privileges[0].Attributes = fEnable ? 
            SE_PRIVILEGE_ENABLED : 0;
         AdjustTokenPrivileges(hToken, FALSE, &tp, 
            sizeof(tp), NULL, NULL);
         fOk = (GetLastError() == ERROR_SUCCESS);
         CloseHandle(hToken);
      }
      return(fOk);
   }

private:
   ULONG_PTR  m_ulPages;         // Number of storage pages
   PULONG_PTR m_pulUserPfnArray; // Page frame number 
                                 // array

private:
   static CSystemInfo sm_sinf;
};

//////////////////////
CSystemInfo CAddrWindowStorage::sm_sinf;

//// End of File ////
AWETest.cpp
/*******************************************************
Module:  AWETest.cpp
Notices: Written by Jeffrey Richter
*******************************************************/

#define _WIN32_WINNT 0x0500
#include <Windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "AddrWindow.h"
#include "Resource.h"

//////////////////////
CAddrWindow g_aw[2];             // 2 memory address windows
CAddrWindowStorage g_aws[2];     // 2 storage blocks
const ULONG_PTR g_nChars = 1024; // 1024 character 
                                 // buffers

//////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, 
   LPARAM lParam) {

   // Create the 2 memory address windows
   g_aw[0].Create(g_nChars * sizeof(TCHAR));
   g_aw[1].Create(g_nChars * sizeof(TCHAR));

   // Create the 2 storage blocks
   if (!g_aws[0].Allocate(g_nChars * sizeof(TCHAR))) {
      MessageBoxA(NULL, 
         "Failed to allocate RAM.\nMost likely reason: "
         "you are not granted the Lock Pages in Memory 
          user right.", 
         NULL, MB_OK);
      ExitProcess(0);
   }
   g_aws[1].Allocate(g_nChars * sizeof(TCHAR));

   // Put some default text in the 1st storage block
   g_aws[0].MapStorage(g_aw[0]);
   lstrcpy((PSTR) (PVOID) g_aw[0],
      TEXT("Text in Storage 0"));

   // Put some default text in the 2nd storage block
   g_aws[1].MapStorage(g_aw[0]);
   lstrcpy((PSTR) (PVOID) g_aw[0],
      TEXT("Text in Storage 1"));

   // Populate the dialog box controls
   for (int n = 0; n <= 1; n++) {
      // Set the combobox for each address window
      int id = ((n == 0) ? IDC_WINDOW0STORAGE : 
         IDC_WINDOW1STORAGE);
      HWND hwndCB = GetDlgItem(hwnd, id);
      ComboBox_AddString(hwndCB, TEXT("No storage"));
      ComboBox_AddString(hwndCB, TEXT("Storage 0"));
      ComboBox_AddString(hwndCB, TEXT("Storage 1"));

      // Window 0 shows Storage 0,
      // Window 1 shows Storage 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 hwndCtl, 
   UINT codeNotify) {

   switch (id) {

   case IDCANCEL:
      EndDialog(hwnd, id);
      break;

   case IDC_WINDOW0STORAGE:
   case IDC_WINDOW1STORAGE:
      if (codeNotify == CBN_SELCHANGE) {

         // Show different storage in address window
         int nWindow  = ((id == IDC_WINDOW0STORAGE) ? 
            0 : 1);
         int nStorage = ComboBox_GetCurSel(hwndCtl) - 1;
         // Show no storage in this window
         if (nStorage == -1) {   
            g_aw[nWindow].UnmapStorage();
         } else {
            if 
               (!g_aws[nStorage].MapStorage(
                  g_aw[nWindow])) {
                  // Couldn't map storage in window
                  g_aw[nWindow].UnmapStorage();
                  // Force "No storage"
                  ComboBox_SetCurSel(hwndCtl, 0);  
                  MessageBoxA(NULL, 
                     "This storage can be mapped only 
                     once.", 
                     NULL, MB_OK);
            }
         }
         
         // Update the address window's text display
         HWND hwndText = GetDlgItem(hwnd, 
            ((nWindow == 0) ? IDC_WINDOW0TEXT : 
            IDC_WINDOW1TEXT));
         MEMORY_BASIC_INFORMATION mbi;
         VirtualQuery(g_aw[nWindow], &mbi, sizeof(mbi));
         // Note: mbi.State == MEM_RESERVE if no storage 
         // is in address window
         EnableWindow(hwndText,
            (mbi.State == MEM_COMMIT));
         Edit_SetText(hwndText, IsWindowEnabled(hwndText) 
            ? (PCSTR) (PVOID) g_aw[nWindow] : 
            TEXT("(No storage)"));
      }
      break;

   case IDC_WINDOW0TEXT:
   case IDC_WINDOW1TEXT:
      if (codeNotify == EN_CHANGE) {
         // Update the storage in the address window
         int nWindow = ((id == IDC_WINDOW0TEXT) ? 0 : 1);
         Edit_GetText(hwndCtl, 
            (PSTR) (PVOID) g_aw[nWindow], g_nChars);
      }
      break;
   }
}

//// chHANDLE_DLGMSG Macro ////

// The normal HANDLE_MSG macro in WindowsX.h does not
// work properly for dialog boxes because DlgProc return 
// a BOOL instead of an LRESULT (like WndProcs).
// This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn) \
   case (message): return (SetDlgMsgResult(hwnd, uMsg, \
      HANDLE_##message((hwnd), (wParam), (lParam), 
         (fn))))

//////////////////////
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 hinstExe, HINSTANCE,
   PTSTR pszCmdLine, int) {

   DialogBox(hinstExe, MAKEINTRESOURCE(IDD_AWETEST), 
      NULL, Dlg_Proc);
   return(0);
}

//// End of File ////