uLib  User mode C/C++ extended API library for Win32 programmers.
MemFunc.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode utility library.
3 // Module: Shared memory and heap allocation routines.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib\MemFunc.h>
9 #include <uLib\UtilFunc.h> // MsgBox
10 #include <uLib\Debug.h>
11 
12 HANDLE app_Heap = GetProcessHeap();
13 
14 //==---------------------------------------------------------------------------
15 
16 static void __mem_FatalHeapError( CSTR Where )
17 {
18  MsgBox( hMainWnd, MB_ERROR, _T("FATAL ERROR"),
19  _T("[%s] Heap validation failed.\nTry to save your work, then terminate the program!"),
20  Where
21  );
22 }
23 
24 //==---------------------------------------------------------------------------
25 // mem_Alloc -- Allocate memory.
26 //==---------------------------------------------------------------------------
27 
28 #ifndef ERROR_INVALID_CRUNTIME_PARAMETER
29  #define ERROR_INVALID_CRUNTIME_PARAMETER 1288L
30  // "The parameter passed to a C runtime function is incorrect."
31 #endif
32 
33 void* mem_Alloc( size_t Bytes )
34 {
35  // Global objects might call mem_Alloc *before* C++ has initialized app_Heap.
36  if (!app_Heap) app_Heap = GetProcessHeap();
37  if (!Bytes)
38  {
39  SetLastError( ERROR_INVALID_CRUNTIME_PARAMETER );
40  return NULL; // Zero,null
41  }
42 
43  void* pBlk = HeapAlloc( app_Heap, HEAP_ZERO_MEMORY, Bytes );
44  if (!pBlk)
45  {
46  DPrint( DP_ERROR, _F("HeapAlloc(%u) failed.\n"), Bytes );
47  SetLastError( ERROR_OUTOFMEMORY );
48  if (mem_Compact()) // Coalesce heap and decommit free blocks.
49  {
50  pBlk = HeapAlloc( app_Heap, HEAP_ZERO_MEMORY, Bytes );
51  if (!pBlk)
52  {
53  DPrint( DP_ERROR, _F("HeapAlloc retry failed.\n") );
54  SetLastError( ERROR_OUTOFMEMORY );
55  if (!HeapValidate( app_Heap, 0, NULL )) // Validate the whole heap
56  {
57  DPrint( DP_ERROR, _F("FATAL - Heap validation failed!\n") );
58  SetLastError( ERROR_ARENA_TRASHED );
59  #if 1
60  if (IsDebuggerPresent()) _BREAK; // If debugged, hit breakpoint, else ...
61  else __mem_FatalHeapError( _T("mem_Alloc") );
62  #elif 0
63  RaiseException( STATUS_NO_MEMORY, 0,0,NULL );
64  #else
65  if (hMainWnd) PostMessage( hMainWnd, WM_DESTROY, 0,0 );
66  //else PostQuitMessage( ERROR_ARENA_TRASHED );
67  else ExitProcess( ERROR_ARENA_TRASHED );
68  #endif
69  }
70  }
71  }
72  }
73  return pBlk;
74 }
75 
76 //==---------------------------------------------------------------------------
77 // mem_Realloc -- Reallocate memory.
78 //==---------------------------------------------------------------------------
79 
80 void* mem_Realloc( void* pBlk, size_t Bytes )
81 {
82  if (!app_Heap) app_Heap = GetProcessHeap();
83  if (!pBlk) return mem_Alloc( Bytes );
84  if (!Bytes) return mem_Free( pBlk ); // Zero,null
85 
86  void* pRea = HeapReAlloc( app_Heap, HEAP_ZERO_MEMORY, pBlk, Bytes );
87  if (!pRea)
88  {
89  DPrint( DP_ERROR, _F("HeapReAlloc(:%p,%lu) failed.\n"), pBlk, Bytes );
90  SetLastError( ERROR_OUTOFMEMORY );
91  if (mem_Compact()) // Coalesce heap and decommit free blocks.
92  {
93  pRea = HeapReAlloc( app_Heap, HEAP_ZERO_MEMORY, pBlk, Bytes );
94  if (!pRea)
95  {
96  DPrint( DP_ERROR, _F("HeapReAlloc retry failed.\n") );
97  if (!HeapValidate( app_Heap, 0, pBlk ))
98  {
99  SetLastError( ERROR_ARENA_TRASHED );
100  if (IsDebuggerPresent()) _BREAK; // If debugged, hit breakpoint, else ...
101  else __mem_FatalHeapError( _T("mem_Realloc") );
102  }
103  else // pBlk is ok..
104  {
105  TRACE( DP_INFO, _F("Calling HeapAlloc instead..\n") );
106  pRea = mem_Alloc( Bytes );
107  if (pRea)
108  {
109  size_t oldSize = HeapSize( app_Heap, 0, pBlk );
110  memcpy( pRea, pBlk, min_<size_t>( Bytes, oldSize ));
111  mem_Free( pBlk ); // Delete the old block
112  }
113  }
114  }
115  }
116  }
117  return pRea;
118 }
119 
120 //==---------------------------------------------------------------------------
121 // mem_Free -- Deallocate memory.
122 //==---------------------------------------------------------------------------
123 
124 void* mem_Free( void* pBlk )
125 {
126  if (pBlk) // Sanity check..
127  {
128  // Access violation is raised if trying to free an already freed block.
129  #ifdef HAVE_STRUCTURED_EH
130  __try { if (HeapFree( app_Heap, 0, pBlk )) pBlk = NULL; }
132  {
133  DWORD xptCode = GetExceptionCode();
134  DPrint( DP_ERROR, _F("Exception %#x in mem_Free(%#x)\n"), xptCode, pBlk );
135  BREAK();
136  }
137  __end_except; //<< gcc kludge
138  #else // No SEH.. May crash...
139  if (HeapFree( app_Heap, 0, pBlk )) pBlk = 0;
140  #endif
141  }
142  if (pBlk) DPrint( DP_ERROR, _F("HeapFree(%#x) failed: %s\n"), pBlk, SysErrorMsg() );
143  return pBlk;
144 }
145 
146 //==---------------------------------------------------------------------------
147 // mem_Compact -- Coalesce free blocks and decommit unused pages
148 //==---------------------------------------------------------------------------
149 
151 {
152  size_t Largest = HeapCompact( app_Heap, 0 );
153  bool ok = (Largest > 0);
154 
155  // Note: HeapCompact *does* SetLastError (unlike HeapAlloc & co).
156  // However, in the unlikely case that there is absolutely no space available in the heap,
157  // the function return value is zero, and GetLastError returns the value NO_ERROR.
158 
159  if (Largest == 0 && GetLastError() == 0)
160  {
161  ok = false;
162  SetLastError( ERROR_OUTOFMEMORY ); // Absolutely no space available in the heap.
163  BREAK();
164  }
165 
166  if (!ok) DPrint( DP_ERROR, _F("HeapCompact failed: %s\n"), SysErrorMsg() );
167  #if _DEBUG
168  else DPrint( DP_INFO, _F("HeapCompact returned largest block = %lu\n"), Largest );
169  #endif
170  return ok;
171 }
172 
173 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174 // Page buffers
175 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176 
177 PVOID AllocMemoryPages( WORD nPages, DWORD Access )
178 {
179  DWORD pgSize = GetMemoryPageSize();
180  DWORD cbPages = pgSize * nPages;
181 
182  PVOID pBlk = VirtualAlloc( NULL, cbPages, MEM_COMMIT | MEM_RESERVE, Access );
183 
184  // Lock the pages into physical memory so we don't get page faults.
185  // (Handling page faults during e.g. time-critical audio processing cause ugly glitches.)
186 
187  if (pBlk) VirtualLock( pBlk, cbPages );
188  return pBlk;
189 }
190 
191 //==---------------------------------------------------------------------------
192 
193 PVOID FreeMemoryPages( PVOID pBlk )
194 {
195  DWORD err = ERROR_INVALID_PARAMETER; // Assume pBlk is invalid one way or another
196  // First, get the size of pBlk so it can be fully unlocked.
197  UINT cbRegion = GetPageRegionSize( pBlk );
198  if (cbRegion)
199  {
200  BOOL ok = VirtualUnlock( pBlk, cbRegion );
201  if (ok) ok = VirtualFree( pBlk, 0, MEM_RELEASE );
202  if (!ok) err = GetLastError();
203  else
204  {
205  pBlk = NULL;
206  err = 0;
207  }
208  }
209  if (err) SetLastError( err );
210  return pBlk;
211 }
212 
213 //==---------------------------------------------------------------------------
214 
216 {
217  SYSTEM_INFO si; IF_DEBUG( memset( &si, 0, sizeof(si) ));
218  GetWinSystemInfo( &si ); // Get correct info for x86, x64, and WoW64.
219  return si.dwPageSize;
220 }
221 
222 UINT GetPageRegionSize( PVOID pBlk )
223 {
224  UINT cbRegion = 0;
225  MEMORY_BASIC_INFORMATION mi; IF_DEBUG( memset( &mi, 0, sizeof(mi) ));
226  if (VirtualQuery( pBlk, &mi, sizeof(mi) ))
227  {
228  if (pBlk == mi.AllocationBase) cbRegion = (UINT) mi.RegionSize;
229  else SetLastError( ERROR_INVALID_PARAMETER ); //ERROR_INVALID_ADDRESS
230  }
231  return cbRegion;
232 }
233 
234 PVOID GetPageBaseAddress( PVOID pBlk )
235 {
236  PVOID pBase = NULL;
237  MEMORY_BASIC_INFORMATION mi; IF_DEBUG( memset( &mi, 0, sizeof(mi) ));
238  if (VirtualQuery( pBlk, &mi, sizeof(mi) )) pBase = mi.BaseAddress;
239  return pBase;
240 }
241 
242 PVOID GetPageAllocationBase( PVOID pBlk )
243 {
244  PVOID pBase = NULL;
245  MEMORY_BASIC_INFORMATION mi; IF_DEBUG( memset( &mi, 0, sizeof(mi) ));
246  if (VirtualQuery( pBlk, &mi, sizeof(mi) )) pBase = mi.AllocationBase;
247  return pBase;
248 }
249 
250 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251 // SharedMem - Shared memory
252 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
253 
254 SharedMem::SharedMem( size_t Size, CSTR Name ): pData(_pmem)
255 {
256  _hmem = CreateFileMapping(
257  INVALID_HANDLE_VALUE, &DefSec, PAGE_READWRITE, 0, (DWORD)Size, Name
258  );
259  _pmem = _hmem ? MapViewOfFile( _hmem, FILE_MAP_RW, 0,0,0 ) : NULL;
260 }
261 
262 SharedMem::SharedMem( CSTR Name ): pData(_pmem)
263 {
264  _hmem = OpenFileMapping( FILE_MAP_RW, TRUE, Name );
265  _pmem = _hmem ? MapViewOfFile( _hmem, FILE_MAP_RW, 0,0,0 ) : NULL;
266 }
267 
269 {
270  if (_pmem) UnmapViewOfFile( _pmem );
271  if (_hmem) CloseHandle( _hmem );
272 }
273 
275 {
276  size_t size = 0;
277  if (_pmem)
278  {
279  // This technique is undocumented, and may therefore be fragile.
280 
281  MEMORY_BASIC_INFORMATION mbi;
282 
283  size_t cb = VirtualQuery( _pmem, &mbi, sizeof(mbi) );
284  if (cb >= sizeof(mbi)) size = mbi.RegionSize;
285  }
286  return size;
287 }
288 
289 bool SharedMem::Flush( PVOID Addr, size_t Range )
290 {
291  return bool_cast( FlushViewOfFile( Addr, Range ));
292 }
293 
294 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
295 // Address Windowing Extensions (AWE) Physical memory.
296 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
297 
298 // AWE procs must have "Lock Pages in Memory" (SE_LOCK_MEMORY_NAME) privilege.
299 #include <uLib/_Internal.h> // __EnableProcPrivilege()
300 #ifdef _DEBUG
301 #include <uLib/StrFunc.h> // IsoDataSizeStr()
302 #endif
303 
304 namespace { // internal
305 
306  int _pageSize = 0;
307  typedef struct _physicalMem* _PPhys; // aka HPHYSICAL
308  struct _physicalMem
309  {
310  PVOID pMem;
311  UINT64 cbMem;
312  PULONG_PTR pageNrs; // Page index array, may get *large*..
313  ULONG_PTR nrPages;
314  };
315 
316  #ifdef _DEBUG // This kludge is to be removed once the code has matured..
317  #define _IF_ERR( cond, fmt, ... ) if (cond) { \
318  DPrint( DP_ERROR, fmt, __VA_ARGS__ ); \
319  if (IsDebuggerPresent()) __debugbreak(); \
320  else MessageBox( HWND_DESKTOP, \
321  _T("MemFunc Breakpoint:\nNo debugger present.. You may want to attach one now."), \
322  dbg_Name, MB_OK| MB_ICONSTOP ); \
323  }
324  #else
325  #define _IF_ERR( ... )
326  #endif
327 
328 } // end internal
329 
330 PVOID PhysicalPtr( HPHYSICAL hMem ) {
331  return _PPhys(hMem)->pMem;
332  }
333 
335  return _PPhys(hMem)->cbMem;
336  }
337 
338 ULONG_PTR PhysicalPageCount( HPHYSICAL hMem ) {
339  return _PPhys(hMem)->nrPages;
340  }
341 
342 // [PRELIMINARY]
343 
345 {
346  _PPhys pm = NULL; // Return value
347  if (!_pageSize) _pageSize = GetMemoryPageSize(); // If first call
348 
349  DWORD err = NO_ERROR;
350  UINT64 cbRequest = ROUND_UP2( nBytes, _pageSize );
351  SIZE_T cbSize = (SIZE_T) cbRequest; // x86 truncates this
352  #ifndef _WIN64
353  if (UINT64(cbSize) != cbRequest) // cbSize may overlow on x86 due to small (32bit)
354  // SIZE_T, and VirtualAlloc unfortunately takes a SIZE_T size argument.
355  // That not withstanding, VirtualAlloc x86 also impose a limit of max 2047 MB.
356  // Under x64, a SIZE_T is 64 bits, so the overflow test is superfluous.
357  err = ERROR_INVALID_PARAMETER; // or ERROR_NOT_ENOUGH_MEMORY
358  else
359  #endif
360  if (!cbRequest) err = ERROR_INVALID_PARAMETER;
361  else
362  {
363  HANDLE hProc = GetCurrentProcess(), hToken;
364  ULONG_PTR nPages = ULONG_PTR( cbRequest / _pageSize );
365  ULONG_PTR cPages = nPages;
366 
367  SIZE_T cbPageIndex = nPages * sizeof(ULONG_PTR);
368  PULONG_PTR memPageNrs = (PULONG_PTR) mem_Alloc( cbPageIndex );
369  // NOTE: The page index array becomes a whopper at GB size requests!
370  if (memPageNrs)
371  {
372  TRACE( DP_DEBUG, _F("Page index overhead: %s\n"), DataSizeStr( cbPageIndex ));
373 
374  TOKEN_PRIVILEGES tp = { 1, { 0,0,0 }};
375  bool prvOk = __ChkOkGetErr( // We must have "Lock Pages in Memory" privilege.
376  __EnableProcPrivilege( SE_LOCK_MEMORY_NAME, &tp.Privileges[0], &hToken ),
377  &err
378  );
379  _IF_ERR( !prvOk, _F("__EnableProcPrivilege( SE_LOCK_MEMORY_NAME ): %s\n"), SysErrorMsg( err ));
380  // If privilege request failed, continue anyway,and let system decide what to do..
381 
382  bool ok = __ChkOkGetErr( // Allocate the physical memory.
383  AllocateUserPhysicalPages( hProc, &cPages, memPageNrs ),
384  &err
385  );
386  _IF_ERR( !ok, _F("AllocateUserPhysicalPages: %s\n"), SysErrorMsg( err ));
387  if ( ok )
388  {
389  // If only partial alloc, set an error code but continue mapping what we got.
390  if (cPages != nPages) err = ERROR_NOT_ENOUGH_MEMORY;
391  cbSize = cPages * _pageSize; // Actual size we got..
392 
393  PVOID pMem = VirtualAlloc( // Reserve the 'virtual' physical memory.
394  NULL, cbSize, MEM_PHYSICAL | MEM_RESERVE, PAGE_READWRITE
395  );
396  bool memOk = __ChkOkGetErr( pMem != NULL, &err );
397  _IF_ERR( !memOk, _F("VirtualAlloc( %s ): %s\n"), DataSizeStr( cbSize ), SysErrorMsg( err ));
398  // If ok, then map the physical memory into the AWE window.
399  if ( memOk ) memOk = __ChkOkGetErr(
400  MapUserPhysicalPages( pMem, cPages, memPageNrs ),
401  &err
402  );
403  if ( memOk )
404  {
405  pm = (_PPhys) mem_Alloc( sizeof(_physicalMem) );
406  pm->pMem = pMem;
407  pm->cbMem = cbSize;
408  pm->pageNrs = memPageNrs;
409  pm->nrPages = cPages; // Note: May be smaller than memPageNrs (nPages).
410  }
411  else // Failure.. Clean up.
412  {
413  _IF_ERR( err, _F("MapUserPhysicalPages: %s\n"), SysErrorMsg( err ));
414  if (pMem) VirtualFree( pMem, 0, MEM_RELEASE ); // Rescind the reservation
415  FreeUserPhysicalPages( hProc, &cPages, memPageNrs ); // Revert the physical allocation
416  mem_Free( memPageNrs );
417  }
418  }
419  if (prvOk) RestorePrivilege( hToken, &tp );
420  }
421  }
422  if ( err ) SetLastError( err );
423  return (HPHYSICAL) pm;
424 }
425 
426 // [PRELIMINARY]
427 
429 {
430  _PPhys pm = (_PPhys) hMem;
431 
432  HANDLE hProc = GetCurrentProcess(), hToken;
433  TOKEN_PRIVILEGES tp = { 1, { 0,0,0 }};
434  BOOL prvOk = __EnableProcPrivilege( SE_LOCK_MEMORY_NAME, &tp.Privileges[0], &hToken );
435  _IF_ERR( !prvOk, _F("__EnableProcPrivilege( SE_LOCK_MEMORY_NAME ): %s\n"), SysErrorMsg() );
436 
437  BOOL ok = MapUserPhysicalPages( pm->pMem, pm->nrPages, NULL ); // Unmap
438  _IF_ERR( !ok, _F("(Un)MapUserPhysicalPages: %s\n"), SysErrorMsg() );
439  if ( ok )
440  {
441  ok = VirtualFree( pm->pMem, 0, MEM_RELEASE ); // Free virtual memory.
442  _IF_ERR( !ok, _F("VirtualFree: %s\n"), SysErrorMsg() );
443 
444  ok = FreeUserPhysicalPages( hProc, &pm->nrPages, pm->pageNrs ); // Free physical pages.
445  _IF_ERR( !ok, _F("FreeUserPhysicalPages: %s\n"), SysErrorMsg() );
446  if ( ok )
447  {
448  mem_Free( pm->pageNrs ); // Free page index array
449  pm = (_PPhys) mem_Free( pm ); // Free internal
450  }
451  }
452  if (prvOk) RestorePrivilege( hToken, &tp );
453  return (HPHYSICAL) pm;
454 }
455 
456 // EOF
unsigned long DWORD
Definition: Common.h:414
PVOID FreeMemoryPages(PVOID pBlk)
Definition: MemFunc.cpp:193
HPHYSICAL PhysicalFree(HPHYSICAL hMem)
Definition: MemFunc.cpp:428
#define CSTR
Definition: Common.h:329
unsigned short WORD
Definition: Common.h:413
#define IF_DEBUG(code)
Definition: Debug.h:236
DWORD GetMemoryPageSize()
Definition: MemFunc.cpp:215
void * mem_Realloc(void *pBlk, size_t Bytes)
Definition: MemFunc.cpp:80
#define DP_DEBUG
Definition: Debug.h:85
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
ULONG_PTR PhysicalPageCount(HPHYSICAL hMem)
Definition: MemFunc.cpp:338
~SharedMem()
Definition: MemFunc.cpp:268
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
UINT GetPageRegionSize(PVOID pBlk)
Definition: MemFunc.cpp:222
#define TRACE(_lvl,...)
Definition: Debug.h:216
PVOID GetPageBaseAddress(PVOID pBlk)
Definition: MemFunc.cpp:234
#define __except_execute
Definition: Common.h:647
bool Flush(PVOID Addr, size_t Range)
Definition: MemFunc.cpp:289
#define BREAK()
Definition: Debug.h:208
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
void GetWinSystemInfo(SYSTEM_INFO *si)
Definition: Common.cpp:135
#define ERROR_INVALID_CRUNTIME_PARAMETER
Definition: MemFunc.cpp:29
#define _BREAK
Definition: Debug.h:198
CSTR SysErrorMsg(DWORD Err=0, TSTR Buf=NULL, UINT Length=0)
Definition: Debug.cpp:39
unsigned __int64 UINT64
Definition: Common.h:400
bool mem_Compact()
Definition: MemFunc.cpp:150
SECURITY_ATTRIBUTES DefSec
Definition: Common.cpp:20
bool RestorePrivilege(HANDLE hToken, PTOKEN_PRIVILEGES pSaved)
See EnablePrivilege(()
Definition: SecUtil.cpp:162
bool __forceinline bool_cast(BOOL B52)
Definition: Common.h:767
#define DP_ERROR
Definition: Debug.h:82
HPHYSICAL PhysicalAlloc(UINT64 nBytes)
Definition: MemFunc.cpp:344
Debug and error handling support.
int __cdecl MsgBox(HWND Owner, UINT Type, CSTR Cap, CSTR Fmt,...)
Definition: UserUtil.cpp:271
__inline bool __ChkOkGetErr(BOOL Ok, PDWORD pErr)
Definition: _Internal.h:34
CSTR DataSizeStr(UINT64 Size)
Definition: StrFunc.cpp:1042
#define _F(s)
Definition: Debug.h:49
#define ROUND_UP2(x, chunk)
Definition: Common.h:984
#define DP_INFO
Definition: Debug.h:84
#define FILE_MAP_RW
Definition: Common.h:1133
bool __EnableProcPrivilege(IN CSTR Privilege, OUT LUID_AND_ATTRIBUTES *pPrv, OUT HANDLE *pToken)
Definition: _Internal.cpp:16
size_t Size()
Definition: MemFunc.cpp:274
HWND hMainWnd
Definition: Common.cpp:12
PVOID AllocMemoryPages(WORD nPages, DWORD Access)
Definition: MemFunc.cpp:177
#define _IF_ERR(cond, fmt,...)
Definition: MemFunc.cpp:317
SharedMem(size_t Size, CSTR Name)
Definition: MemFunc.cpp:254
PVOID GetPageAllocationBase(PVOID pBlk)
Definition: MemFunc.cpp:242
#define MB_ERROR
Definition: UtilFunc.h:1228
HANDLE app_Heap
Definition: MemFunc.cpp:12
PVOID PhysicalPtr(HPHYSICAL hMem)
Definition: MemFunc.cpp:330
HANDLE HPHYSICAL
Definition: MemFunc.h:156
UINT64 PhysicalSize(HPHYSICAL hMem)
Definition: MemFunc.cpp:334