Hi there,
Can anybody show a practical real-world use for the CopyMemory API in VB apart from simply copying memory bits to an array ?
I still don't really understand all the fuss about this function .
Thanks in advance.
Printable View
Hi there,
Can anybody show a practical real-world use for the CopyMemory API in VB apart from simply copying memory bits to an array ?
I still don't really understand all the fuss about this function .
Thanks in advance.
where is the fuss besides here?
You use CopyMemory to convert a pointer into a UDT for many APIs.
CopyMemory is used to create basic structures such as stacks, queues, and linked lists.
VB, generally, does not allow direct access to memory. This can be prohibitively slow - in some cases - so some programmers prefer to get dirty and get down to the details to provide a (sometimes) huge increase in performance.
In many cases CopyMemory is used to dereference a pointer (as described above) but this is mostly unecessary.
For instance you can use IDL (to create a typelibrary) and squeeze implied semantic functionality from a few other 'unknown' functions:
VB Code:
[dllname("msvbvm60.dll")] module VirtualMachine { [entry("GetMem4"),propget] HRESULT MemLong ([in] long Address,[out,retval]long* Value); [entry("PutMem4"),propput] HRESULT MemLong ([in] long Address,[in] long Value); }
This allows the following:
VB Code:
Dim lp As Long Dim l As Long l = MemLong(lp) MemLong(lp) = l
. . . which allows for more natural dereferencing code (and it's much MUCH) faster.
I think that CopyMemory is so popular is because it's simply that it's so well known.
For instance, consider the following VB code (it won't run - if you want to play I can provide a link to the project)
VB Code:
Option Explicit 'Public Type MATRIX_HEADER ' i As Long 'Offset:0 ' j As Long 'Offset:4 ' Size As Long 'Offset:8 ' hHeap As Long 'Offset:12 'End Type Public Function MCreate(i As Long, j As Long) As Long On Error GoTo ERR_MCreate Dim HeaderSize As Long Dim pHeap As Long Dim hHeap As Long Dim Size As Long '****************************** '* Get the required sizes . . . '****************************** Size = i * j * 4 '********************** '* Get the memory . . . '********************** hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 16 + Size, 0) pHeap = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, Size) '******************************** '* Write the header records . . . '******************************** MemLong(pHeap) = i MemLong(pHeap + 4) = j MemLong(pHeap + 8) = Size MemLong(pHeap + 12) = hHeap '******************************************** '* Return pointer to start of structure . . . '******************************************** MCreate = pHeap Exit Function ERR_MCreate: Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End Function Public Sub MDestroy(pMatrix As Long) On Error GoTo ERR_MDestroy Dim hHeap As Long '************************************************************************* '* Derference the matrix header's heap record, and release the heap . . . '************************************************************************* hHeap = MemLong(pMatrix + 12) HeapDestroy hHeap Exit Sub ERR_MDestroy: Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End Sub Public Function MSMultiply(Scalar As Single, pMatrix As Long) As Long On Error GoTo ERR_MSMultiply Dim pMem1 As Long Dim pMem2 As Long Dim pMatrix2 As Long Dim i As Long Dim j As Long Dim s As Long '****************************************** '* Get start of memory block and size . . . '****************************************** pMem1 = pMatrix + 16 s = MemLong(pMatrix + 8) '************************************************************* '* Copy dimensions of source matrix, and use 'em for the return '* one . . . '************************************************************* i = MemLong(pMatrix) j = MemLong(pMatrix + 4) pMatrix2 = MCreate(i, j) pMem2 = pMatrix + 16 '**************************** '* Perform the multiply . . . '**************************** For i = 0 To s Step 4 MemSingle(pMem2 + i) = (MemSingle(pMem1 + i) * Scalar) Next '************************************ '* Return pointer to new matrix . . . '************************************ MSMultiply = pMatrix2 Exit Function ERR_MSMultiply: Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End Function
This avoids many VB things that could be considered slow. To be fair, you'd probably want to write this lot in C and implement it in a DLL that VB can access: I only wrote this to play with the MemLong function (and to test it's speed)
This fragment avoids SAFEARRAY overheads, and other VB safety features by directly allocating some memory, and then manipulating it according to various matrix rules. SAFEARRAYS are not great for dealing across different threads in a process with such wonderful features such as cbLocks in it's descriptor, and the automatic teardown code that goes with SAFEARRAYS (which, btw, makes VB marvellously simple and safe for beginners and experts alike)
Also, ideally, the memory needs to be allocated on the stack, rather than the heap, but - hey: one step at a time.
It also creates a completly arbitrary descriptor (I invented it, if you like) to describe the matrix structure. Which means the thread only needs to have a copy of the descriptor, and not the body of data. You can effectively pass around the descriptor instead of the data.
You can replace the vast majority of MemLong, and MemSingle calls in this fragment with CopyMemory calls - so hopefully you can see the advantage in using it. Normally, though, you'd be using CopyMemory to directly access parts of VB's internal system as in this example:
VB Code:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, source As Any, ByVal Length As Long) Public Type SafeArray1d cDims As Integer fFeatures As Integer cbElements As Long cLocks As Long pvData As Long cElements As Long lLbound As Long End Type Public Const ARRAY_NOT_INITIALISED As Long = -1 Public Function MaxOrdinal(ppSA As Long) As Long ' Eg: n = MaxOridinal(VarPtrArray(MyArray)) Dim SA As SafeArray1d Dim pSA As Long '*********************************************** '* Deref ppSA. C equivalent: = pSa=*ppSA . . . '*********************************************** CopyMemory pSA, ByVal ppSA, 4 '***************************************************** '* If we have a pointer then check to see how '* many elements we are allowed. If the array '* is not dimensioned then pSA will not be valid . . . '***************************************************** If pSA Then CopyMemory SA, ByVal pSA, LenB(SA) MaxOrdinal = (SA.cElements - 1) Else MaxOrdinal = ARRAY_NOT_INITIALISED End If End Function
which returns the highest ordinal allocated in an a single dimensional array, and ARRAY_NOT_INITIALISED if the array is not allocated yet; this is incredibly useful in production code, as well as being extremely fast.