OK; I think I understand what you're getting at and I hope this will clarify things.
Conceptually, VirtualAlloc works on individual pages.
For simplicity, let's consider a 32-bit x86 process. The virtual address space is a sequence of pages from page 0 through to page 1048575. Each of these pages may or may not be reserved; if reserved, it may or may not be committed. (If committed, it will also have zero or more memory-protection options, and there are various other states a page might be in, but we can pretty much ignore all that for now.)
There is no way for only part of a page to be reserved or committed, or for two parts of the same page to have different memory-protection options. Conversely, it doesn't matter whether the reserved and/or committed pages are consecutive.
If you call VirtualAlloc with a particular starting address and region size, then it acts on every page containing one or more bytes within the virtual address region specified. The address and size are used only to calculate which pages to act on. The only reason that the argument is an address rather than a page number is to simplify things for the programmer.
Conceptually, a single call to VirtualAlloc covering multiple pages is equivalent to calling VirtualAlloc once for each of those pages. The only difference (other than efficiency) is that acting on multiple pages at once is atomic, so will either fail or succeed for the entire range.
Note in particular that if you successfully make multiple calls to VirtualAlloc covering consecutive pages, there is no way to tell afterwords that the pages were allocated separately. The operating system only remembers what state a page is in, not how it got there. [Addendum: Oops; this is wrong. The documentation for VirtualQuery
says that it can tell whether consecutive pages were part of the same allocation or not. Perhaps they're tagged with a unique allocation ID or something. I don't believe this information is actually used by the memory manager at all, but apparently it is kept.]
Keep in mind that the HeapCreate function already allows you to create a heap whose memory blocks allow code execution. Unless your application has very unusual needs it is unlikely that you will gain anything by writing your own heap manager.