接下来VirtualAlloc处理来自fdwAllocationType参数的各种标志值。首先,它看看是否有未公开的0x80000000标志,那意味要分配2GB以上的内存。VirtualAlloc忽略MEM_TOP_DOWN标志。然后它再测试是否你只传入了MEM_COMMIT或MEM_RESERVED标志。任何其他的标志都会引发调试版的一个警告信息。最后,函数代码调用mmPAGEToPC,那是一个辅助函数(下一节描述),把fdwProtect参数标志转换为VMM的_PageReserve所使用的标志。
这时候,函数兵分两路。如果不在乎哪一段内存要保留,就执行其中一路。如果调用者指定了某特定范围的内存,那么就执行另一路。不管是哪一路,如果内存要被保留,VirtualAlloc就调用Win32 Service 00010000,那是VMM’s _PageReserve函数的一个外包函数。保留这段内存之后,如果调用者还有指定MEM_COMMIT标志的话,VirtualAlloc就调用Win32 Service 00010001,那是VMM’s _PageCommit函数的一个外包函数。如果调用者指定了一个特定地址范围,VirtualAlloc会检查它是不是在0xC0000000(VxD领域的起始处)之下。
整个函数代码中,VirtualAlloc不断周到的检查返回至_PageReserve和_PageCommit。如果任何事情失败,它就会产生一个调试诊断信息,然后从某个唯一出口退出。该出口处会释放先前保留的内存。
VirtualAlloc函数的虚拟代码
// Parameters
// LPVOID lpvAddress
// DWORD cbSize
// DWORD fdwAllocationType
// DWORD fdwProtect
// Locals:
// DWORD address, startPage
// DWORD sizeInPages
// DWORD pcFlags // Return from mmPAGEToPC
// BOOL fReserve
if ( cbSize > 0x7FC00000 ) // 2GB – 4MB
{
_DebugOut(“VirtualAlloc: dwSize too big/n/r”, SLE_WARNING
+ FstopOnRing3MemoryError);
InternalSetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
address = lpvAddress;
// Calculate how many pages will be spanned by this memory request
sizeInPage = lpvAddress & 0x00000FFF;
sizeInPage += cbSize;
sizeInPage += 0x00000FFF;
sizeInPage = sizeInPage >> 12;
startPage = PR_PRIVATE; // 0x80000400 from VMM.INC This value can be either
// an actual page number or a PR_equate.
if ( fdwAllocationType & 0x80000000 ) // Undocumented shared mem flag
{
startPage = PR_SHARED; // 0x80000000 in VMM.INC
fdwAllocationType &= ~0x80000000; // Don’t need this flag anymore
}
fdwAllocationType &= ~MEM_TOP_DOWN; // Ignore the MEM_TOP_DOWN flag
// You can specify MEM_COMMIT and/or MEM_RESERVE, but no other flags
// (the Undocumented one above not with standing).
if ( (fdwAllocationType != MEM_COMMIT)
&& (fdwAllocationType != MEM_RESERVE)
&& (fdwAllocationType != (MEM_RESERVE | MEM_COMMIT)) )
{
_DebugOut( “VirtualAlloc: bad flAllocationType/n/r”,
SLE_WARNING + FstopOnRing3MemoryError );
InternalSetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
// Convert the fdwProtect flags into the PC_flag values used by
// VMM.VXD Pseudocode follows this function
pcFlags = mmPAGEToPC(fdwProtect);
if ( pcFlags == -1 ) // Something Error
return 0;
if ( lpvAddress == 0 ) // Don’t care where the memory is allocated.
{
// Reserve the memory block. startPage should be either
// PR_PRIVATE or PR_SHARED
lpvAddress = VxDCall( _PageReserve, startPage, sizeInPages, pcFlags );
if ( lpvAddress == -1 )
{
_DebugOut( “VirtualAlloc: reserver failed/n”,
SLE_WARNING + FStopOnRing3MemoryError );
InternalSetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
// If caller is just reserving, we’re finished.
if ( !(fdwAllocationType & MEM_COMMIT) )
return lpvAddress;
// Caller has specified MEM_COMMIT