The new vbAccelerator Site - more VB and .NET Code and Controls
Source Code
3 Code Libraries  
 

malloc in VB?

 
 

A COM object you can use in VB providing equivalent functions to C runtime's malloc, free and delete

 


 NOTE: this code has been superceded by the version at the new site.



 

IMalloc Calls

Download the vbAccelerator IMalloc Demonstrator (9kb)

  Before you Begin  
  The source code project requires the IShellFolder Extended Type Library v1.2 (ISHF_Ex.TLB) when running in the IDE. Make sure you have downloaded and registered this before trying the project.  


Overview
Of course you're not supposed to allocate your own memory in Basic. Don't be so silly, what are you thinking of? And you should stop using that CopyMemory call and certainly those pointers should not be there at all.

Just in case you're not feeling like any sort of Basic purist, this article is here to show you how to create little chunks of memory completely independently of variables or classes, how to access their contents, reallocate them and free them.

Just don't tell your boss that this is what you're doing...


What's It Good For?
This code has got three main uses:

  1. For direct translation of C code samples using the C run-time calls alloc and free
  2. Building structures which will store large amounts of data and are otherwise very difficult to manage in Basic, for example Hash Tables, Skip Lists, Markov Chains and so on.
  3. Storing data when only a long variable (pointer) is available to refer to the data, such as in API controls.
Of course, it is also useful whenever you have to allocate memory which needs to be shared with the Shell, for example with Namespace extensions (surely someone has to rise to the challenge of doing this in VB sometime?)


Getting a Malloc Object
IMalloc is a COM interface which defines the methods and properties a COM Malloc object will support. Anyone is free to design their own implementation of this interface and share it between objects. One such implementation is provided by the Windows Shell, and you can get it using the ShGetMalloc call.

The first problem is how to use this call. The API declaration can be written like this:

   Private Declare Function SHGetMalloc Lib "shell32" (ppMalloc As Object) As Long

You could just pass a standard VB Object variable into the ppMalloc variable, but that means you end up with an untyped object which will refer to the Shell's Malloc object through the comparatively slow late-binding (Automation) method. In addition you don't get any design-time auto-complete nor do you get any compile-time syntax checking.

A much better way to use this object is through a Type Library. Within a Type Library you can define the IMalloc interface so you can then use IMalloc as if it were a predefined object in Visual Basic. You can then rewrite the API call to get early-binding and all the advantages that go with that:

   Private Declare Function SHGetMalloc Lib "shell32" (ppMalloc As IMalloc) As Long

Remember that Type Libraries are only required when working in the VB IDE. You don't have to ship them with any binaries you build from VB, because VB will already have compiled in the Type Library information.

This sample, and other samples at this site, use Brad Martinez's IShellFolder Extended Type Library (v1.2), however there are other type libraries available containing the IMalloc interface, notably Win.TLB and WinU.TLB shipped with Bruce McKinney's Hardcore VB. I chose this type library simply because it is smaller than the Hardcore VB versions size, making it a more reasonable download!

Now to get the IMalloc interface you use this code:

Private Declare Function SHGetMalloc Lib "shell32" (ppMalloc As IMalloc) As Long
' Defined as an HRESULT that corresponds to S_OK.
Private Const NOERROR = 0
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
      lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

' Returns a reference to the IMalloc interface.
Public Function isMalloc() As IMalloc
   Static im As IMalloc
   If (im Is Nothing) Then
      If Not (SHGetMalloc(im) = NOERROR) Then
         ' Fatal error
         Err.Raise 7
      End If
   End If
   Set isMalloc = im
End Function

The isMalloc is made public and put in a module to encourage all code in the same project to use the same instance of the object.


Allocating and Freeing Memory
Once you have a Malloc object you can then start creating and destroying memory at will! The following table summarises the available methods:

Method     Description  
Alloc     Allocates a block of memory of the specified number of bytes, returning a pointer to the memory.
   lPtr = isMalloc.Alloc(24) ' Allocates 24 bytes

 
DidAlloc     Returns true if the specified pointer was created using this instance of the Malloc object.
   b = isMalloc.DidAlloc(ByVal lPtr) ' True if allocated

 
DidAlloc     Returns true if the specified pointer was created using this instance of the Malloc object.
   b = isMalloc.DidAlloc(ByVal lPtr) ' True if allocated

 
Free     Frees a previously allocated block of memory
   isMalloc.Free ByVal lPtr ' Frees up the memory

 
HeapMinimze     Minimizes the heap as much as possible by releasing unused memory to the operating system.
   isMalloc.Free ByVal lPtr ' Frees up the memory

 
Realloc     Reallocates a memory block previously allocated using Alloc and returns the new pointer to it.
   lPtr = isMalloc.Realloc(ByVal lPtr, 36) ' Resizes the block to 36 bytes.

 



Examples Of Use
The following examples demonstrate how to move data from Visual Basic data types to a pointer allocated through the Malloc object:
  • To save and restore a Byte Array

    ' To Save the array b():
    Public Function SaveToMemory(ByRef b() as Byte) As Long
       Dim lSize As Long
       Dim lPtr As Long

       On Error Resume Next ' Error checking: UBound/LBound can fail.
       lSize = UBound(b) - LBound(b)
       If Err.Number=0 Then
          lSize = lSize + 1
       Else
          ' No Data:
          lSize = 0
       End If

       On Error Goto 0
       lPtr = isMalloc.Alloc(lSize + 4)
       If Not (lPtr=0) Then
          ' Store the size of the array:
          CopyMemory ByVal lPtr, lSize, 4
          If lSize > 0 Then
             ' Store the array:
             CopyMemory ByVal lPtr + 4, b(0), lSize
          End If
       End If

       ' Return the Value of lPtr
       SaveToMemory = lPtr
    End Function

    ' To Restore the array from the Pointer lPtr:
    Public Sub RestoreFromMemory(ByVal lPtr As Long, ByRef b() as Byte)
       Dim lSize As Long

       Erase b
       If Not (lPtr = 0) Then
          ' Get the size of the array:
          CopyMemory lSize, ByVal lPtr, 4
          If lSize > 0 Then
             ReDim b(0 To lSize-1) As Byte
             CopyMemory b(0), ByVal lPtr, lSize
          End If
       End If

    End Sub



  • To save and restore a User-Defined Type
    Provided there are no variable length strings in the type, then you can save and restore a type in exactly the same way as for a ByteArray. Just replace the last argument with Len(udtThis) where udtThis is your Type.

  • To save and restore a String

    ' To Save the String sThis
    Public Function SaveToMemory(ByRef sThis as String) As Long
       Dim lSize As Long
       Dim lPtr As Long

       ' Size of sThis in Bytes:
       lSize = LenB(sThis)

       lPtr = isMalloc.Alloc(lSize + 4)
       If Not (lPtr=0) Then
          ' Store the size of the string:
          CopyMemory ByVal lPtr, lSize, 4
          If lSize > 0 Then
             ' Store the Unicode String:
             CopyMemory ByVal lPtr + 4, ByVal StrPtr(sThis), lSize
          End If
       End If

       ' Return the Value of lPtr
       SaveToMemory = lPtr
    End Function

    ' To Restore the array from the Pointer lPtr:
    Public Function RestoreFromMemory(ByVal lPtr As Long) As String
       Dim lSize As Long
       Dim sThis As String

       If Not (lPtr = 0) Then
          ' Get the size of the array:
          CopyMemory lSize, ByVal lPtr, 4
          If lSize > 0 Then
             sThis = String$(lSize\2,0)
             CopyMemory ByVal StrPtr(sThis), ByVal lPtr + 4, lSize
          End If
       End If

    End Sub

Other VB types can be moved using similar techniques.


Sample Code
The sample code in the download illustrates four different ways to create a Stack object capable of storing strings. A Stack is a simple data structure in which there are only two operations - pushing an item onto the stack and poping it back off again. The last item to be added to the stack is the first to be retrieved.

Whilst such a simple data structure is most easily achieved using arrays (and in fact this method runs quickest for most amounts of data), allocating data using IMalloc always comes a close second and in fact beats the array method for 50,000 elements:

Here are the results for 50,000 strings in the stack (all times given in milliseconds):
Method     Time  
Collection     20,103   
Linked Objects     6,190  
Array     3,222  
IMalloc     2,872  



TopBack to top
Source Code - What We're About!Back to Source Code


 
 

About  Contribute  Send Feedback  Privacy

Copyright © 1998-1999, Steve McMahon ( steve@vbaccelerator.com). All Rights Reserved.
Last updated: 25 August 1999