As I suggested in your other post about this it is possible and perfectly safe. Here's a small DBPro example showing how you can manually delete a memblock, swap two memblocks and resize a memblock.
It uses the WINAPI HeapAllocate and HeapFree functions because DBPro's built-in MAKE MEMORY and DELETE MEMORY functions are restricted to only work with each other, ie. you can't use DELETE MEMORY on a pointer that you haven't allocated using MAKE MEMORY. In another language you can just replace these calls with the standard allocation / releasing functions such as malloc() and free() in C.
rem We need a reference to DBPro's memblock dll in order to call its internal
rem ReturnMemblockPtr function. This dll will always exist and be loaded along
rem with the DBPro program as long as any of the memblock functions are called
rem from within the DBPro program.
#constant memlib 1
load dll "DBProMemblocksDebug.dll", memlib
rem We will also need a reference to kernel32.dll in order to call the
rem HeapAlloc and HeapFree functions. DBPro's MAKE MEMORY / DELETE MEMORY functions
rem impose certain memory allocation restrictions which cause them to not be usable
rem for allocating or freeing memblock data, which is usually handled internally by DBPro.
rem From C you could just use malloc and free, with C++ you could use new and delete
rem instead of using these WINAPI calls directly.
#constant kernel32 2
load dll "kernel32.dll", kernel32
rem Create a memblock containing 4 integer values
make memblock 1, 16
write memblock dword 1, 0, 1
write memblock dword 1, 4, 2
write memblock dword 1, 8, 3
write memblock dword 1, 12, 4
rem Create another memblock containing 5 integer values
make memblock 2, 20
write memblock dword 2, 0, 5
write memblock dword 2, 4, 6
write memblock dword 2, 8, 7
write memblock dword 2, 12, 8
write memblock dword 2, 16, 9
rem Set to manual screen refreshing and use the escape key as a means to
rem close the program
sync on
sync rate 60
disable escapekey
rem Main loop
while not escapekey()
lastSpaceState = spaceState
lastReturnState = returnState
lastCtrlState = ctrlState
spaceState = spacekey()
returnState = returnkey()
ctrlState = controlkey()
rem Swap memblocks when hitting the space key
if spaceState = 1 and lastSpaceState = 0 then SwapMemblocks(1, 2)
rem Delete memblock 1 when hitting the control key
if ctrlState = 1 and lastCtrlState = 0 then DeleteMemblock(1)
rem Grow memblock 2 by one new integer (4 bytes) when pressing the return key
if returnState = 1 and lastReturnState = 0
ResizeMemblock(2, get memblock size(2) + 4)
rem The new final integer of the memblock will be initialized to 0 by default,
rem comment out the next line to verify this.
rem We set it to the next integer value following the last one stored in
rem the memblock for now though.
rem The ResizeMemblock function will simply do nothing if the memblock doesn't
rem exist so we need to check that before writing to it here as well.
if memblock exist(2) then write memblock dword 2, get memblock size(2) - 4, memblock dword(2, get memblock size(2) - 8) + 1
endif
rem Print the contents of the two memblocks
for mem = 1 to 2
set cursor 400 * (mem - 1), 32
if memblock exist(mem)
print "Memblock "; mem; " is "; get memblock size(mem); " bytes large:"
intCount = get memblock size(mem) / 4
for i = 0 to intCount - 1
set cursor 400 * (mem - 1), 32 + (16 * (i + 1)) ` Apparently we need to set this for each print....
print space$(4 - len(str$(intCount))); i; ": "; memblock dword(mem, i * 4)
next i
else
print "Memblock "; mem; " does not exist!"
endif
next mem
box 0, 0, screen width(), 32, 0x80006699, 0x80006699, 0x80006699, 0x80006699
center text screen width() / 2, 0, "Press [SPACE] to swap the memblocks. Press [RETURN] to expand memblock 2."
center text screen width() / 2, 16, "Press [CTRL] to delete memblock 1."
sync
cls
endwhile
rem Release the memblocks - this will cause the DBPro runtime to free the memory.
rem If it is unable to do this we will get a crash here, but as can be seen we don't.
delete memblock 1
delete memblock 2
exit prompt "Memblocks were free'd without any issues!", "Terminating program"
end
rem This function swaps the two memblock indices
function SwapMemblocks(memA as dword, memB as dword)
rem Obtain core memblock pointers
ptrA = make memory(4)
ptrB = make memory(4)
call dll memlib, "?ReturnMemblockPtrs@@YAXPAPAX0@Z", ptrA, ptrB
rem ptrA will now contain the address of a 258-element array containing DWORD values that
rem correspond to the size in bytes of the individual memblocks.
rem In the same manner, ptrB contains the address of another 258-element array containing
rem 32-bit pointers to the actual memblock data.
rem Both arrays are indexed by the memblock id's used from DBPro. ID 0 and seems to
rem be reserved and may be used internally by DBPro or plugins. It should be set to null (0)
rem when not used and its size to 0 as well. Interestingly, 256 and 257 are considered
rem valid memblock id's and can be used freely. I've no idea why such a limitation of values
rem was chosen rather than the more obvious 255.
rem In order to swap two memblocks we then simply swap what the given indicies point to.
rem This would be a lot more readable using the M1U pointer functions but we'll make do with
rem the built-in memory access functionality of standard DBPro to prove a point.
rem Get the pointer to the size of memblock A and B and temporarily store them to local variables...
ptrSizeA = (*ptrA) + (4 * memA)
ptrSizeB = (*ptrA) + (4 * memB)
cbMemA = *ptrSizeA
cbMemB = *ptrSizeB
rem ... And swap them
*ptrSizeA = cbMemB
*ptrSizeB = cbMemA
rem Now we do the same for the actual data pointers
ppDataA = (*ptrB) + (4 * memA)
ppDataB = (*ptrB) + (4 * memB)
pDataA = *ppDataA
pDataB = *ppDataB
*ppDataA = pDataB
*ppDataB = pDataA
rem Since we need to use dynamically allocated memory to return the initial pointers
rem we also have to release them now that we're done with them or our program will
rem leak memory.
delete memory ptrA
delete memory ptrB
rem That's it!
endfunction
rem This function manually deletes a memblock by releasing its data pointer
rem and sets its byte size value to zero.
function DeleteMemblock(mem as dword)
rem Obtain core memblock pointers
ptrA = make memory(4)
ptrB = make memory(4)
call dll memlib, "?ReturnMemblockPtrs@@YAXPAPAX0@Z", ptrA, ptrB
rem Obtain memblock data pointer
ppMem = (*ptrB) + (4 * mem)
pMem = *ppMem
rem Ensure that the memblock exists, ie. that its pointer isn't null (zero)
if (*pMem) <> 0
rem Free the memory block....
HeapFree(GetProcessHeap(), 0, pMem)
rem .... And update the corresponding size value
pSize = (*ptrA) + (4 * mem)
*pSize = 0
endif
rem Free local dynamically allocated memory
delete memory ptrA
delete memory ptrB
endfunction
rem This function will recreate a memblock to be of a different size, retaining all
rem data that existed in the original memblock. If the new size is less than the previous
rem size the data will be cut off after that many bytes as can fit into the new size.
function ResizeMemblock(mem as dword, newSize as dword)
rem Obtain core memblock pointers
ptrA = make memory(4)
ptrB = make memory(4)
call dll memlib, "?ReturnMemblockPtrs@@YAXPAPAX0@Z", ptrA, ptrB
rem Obtain memblock data and size pointers
ppMem = (*ptrB) + (4 * mem)
pMem = *ppMem
pSize = (*ptrA) + (4 * mem)
rem Ensure that the memblock exists, ie. that its pointer isn't null (zero)
if (*pMem) <> 0
rem Allocate enough memory for storing our resized memblock on the heap.
rem To correspond to DBPro standards we'll set the HEAP_ZERO_MEMORY flag (8)
rem to initialize all the allocated memory to 0 bytes. In this way all the
rem new "unused" memory will be set to 0, while we copy the contents of the
rem previous memblock over these zeroes at the beginning in the next step.
pNewMem = HeapAlloc(GetProcessHeap(), 8, newSize)
rem Copy the contents of the previous memblock to the beginning of the new one
numBytes = min(*pSize, newSize)
copy memory pNewMem, pMem, numBytes
rem Delete the old memblock data
HeapFree(GetProcessHeap(), 0, pMem)
rem Update the memblock data array to point to our new memory area instead
*ppMem = pNewMem
rem And update the size as well
*pSize = newSize
rem That's it; the DBPro runtime will free our newly created memory
rem when deleting the memblock.
endif
rem Free local dynamically allocated memory
delete memory ptrA
delete memory ptrB
endfunction
rem #####################################################################
rem # Utility WINAPI functions #
rem #####################################################################
function HeapAlloc(hHeap as dword, dwFlags as dword, cbSize as dword)
ptr = call dll(kernel32, "HeapAlloc", hHeap, dwFlags, cbSize)
endfunction ptr
function HeapFree(hHeap as dword, dwFlags as dword, ptr as dword)
success = call dll(kernel32, "HeapFree", hHeap, dwFlags, ptr)
endfunction success
function GetProcessHeap()
hHeap = call dll(kernel32, "GetProcessHeap")
endfunction hHeap
