Introduction
This tutorial will show you how to use the corresponding managed classes in .NET framework to get the same result as unmanaged Windows API function CopyMemory
(RtlMoveMemory
) provides. The equivalent classes I am going to describe are System.Runtime.InteropServices.Marshal
and System.Buffer
.
I will first give a little introduction to both these classes (Marshal
and Buffer
), and then take examples of CopyMemory
from VB 6 code and explain corresponding classes and code in Visual Basic .NET 2003 to achieve the same effect on data types such as integers, bytes, strings, arrays and structures. For good performance, install Service Pack 1 for .NET framework 1.1. I also compile all mentioned code with SP1. You can obtain it from Microsoft.
Explanation
CopyMemory
copies block of memory to a different block of memory without regard to the data type that is stored there. This results in an ultra fast copy of data. VB 6 declaration is as follows:
Private Declare Sub CopyMemory Lib "kernel32" Alias _
"RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
But in .NET, most usage of CopyMemory
is inappropriate and will not work properly. You need to use the corresponding managed class to do the same job such as System.Runtime.InteropServices.Marshal
or System.Buffer
.
System.Runtime.InteropServices.Marshal
This class provides a collection of methods for allocating unmanaged memory, copying unmanaged memory blocks, and converting managed to unmanaged types, as well as other miscellaneous methods used when interacting with unmanaged code to bridge between the managed and unmanaged programming models. I will show you VB.NET's amazing new power over memory and pointers. That power is found in three new tools: IntPtr
, .NET's platform-dependent representation of a memory address; GCHandle
, which helps you pin and retrieve the address of data in the managed memory heap; the Marshal
class, the one-stop shop for all your memory allocation, cleanup, and manipulation needs. For more detail about its members, see MSDN latest release.
System.Buffer
Manipulates arrays of primitive types such as Boolean
, Char
, SByte
, Byte
, Int16
, UInt16
, Int32
, UInt32
, Int64
, UInt64
, IntPtr
, UIntPtr
, Single
, and Double
, and does not apply to objects. Each primitive type is treated as a series of bytes without regard to any behavior or limitation associated with the primitive type. It has very useful members to manipulate arrays. For more detail about its members, see MSDN latest release.
Array to other data types or vice versa
Let us consider VB 6 code to copy data from byte array to integer variable.
Dim Longvalue As Long, Str As String
Str = "Adnan Samuel"
Dim ByteArray () As Byte
ByteArray = StrConv(Str, vbFromUnicode)
CopyMemory Longvalue, ByteArray (0), 4
Debug.print LongValue
Equivalent VB.NET code
Imports System.Runtime.InteropServices
Imports System.Text
Dim LongValue As Integer
Dim Str As String = "Adnan Samuel"
Dim ByteArray () As Byte
ByteArray = Encoding.Default.GetBytes(Str)
Dim MyGC As GCHandle = GCHandle.Alloc(LongValue, GCHandleType.Pinned)
Dim AddofLongValue As IntPtr = MyGC.AddrOfPinnedObject()
Marshal.Copy(ByteArray, 0, AddofLongValue, 4)
LongValue = Marshal.ReadInt32(AddofLongValue)
Debug.WriteLine("Vlaue of LongValue is: " & LongValue)
MyGC.Free()
Now reverse of it (integer to byte array) is very easy, just a small change in Marshal.Copy
method, that is:
CopyMemory ByteArray(0), Longvalue, 4
Equivalent VB.NET code will be, change in Copy
method requires source as Intptr
, destination array, index of destination array to start copy, and number of bytes to copy.
Marshal.Copy (AddofLongValue, ByteArray, 0, 4)
That’s all.
Strings
Let us consider a VB 6 code to copy string.
Dim Source as String
Dim Dest as String
Source="Adnan"
Dest=" Samuel"
CopyMemory StrPtr(Dest), StrPtr(Source),10
Msgbox Dest
Equivalent VB.NET code
However, you have equivalent of StrPtr()
function in VB.NET (that is by creating instance of GCHANDLE
and pinning a variable and then obtain its address as we did earlier). After that, you can even use unmanaged CopyMemory
function in VB.NET to do the same job. But I recommend that you should not do that since it is not .NET way. Instead, you should use very fast and powerful classes like String
and StringBuilder
and other String
functions such as MID
and StrConv()
etc. to achieve the same effect.
Let us consider VB.NET code to achieve the same effect mentioned above:
Dim Source As String = "Adnan"
Dim Dest As String = "Samuel"
Dest = Dest.Insert(0, Source)
Console.WriteLine(Dest)
Array to another Array
Let us consider VB 6 code for copying byte array to integer array.
Dim ByteArray() As Byte, Str As String
Dim IntArr(0 To 3) As Integer, i As Integer
Str = "Adnan Samuel"
ByteArray = StrConv(Str, vbFromUnicode)
CopyMemory IntArr(0), ByteArray(0), 8
For i = 0 To 3
Debug.Print IntArr(i)
Next
Equivalent VB.NET code
Imports System.Buffer
Imports System.Text
Dim Str As String = "Adnan Samuel"
Dim MyBytesString() As Byte, i As Integer
Dim int(3) As short ‘inter array
MyBytesString = Encoding.Default.GetBytes(Str)
Buffer.BlockCopy(MyBytesString, 0, int, 0, 8)
For i = 0 To 3
Debug.WriteLine(int(i))
Next
Again reverse is as easy, just change source array with destination array and rest of the code remains same.
Structures (user-defined type)
Let us copy data from byte array to Type
s (structures) in VB 6.
Private Type Test
Var1 As Integer
Var2 As Integer
End Type
Dim Str As String, i As Integer
Dim ByteArray () As Byte
Dim Tst As Test
Str = "Adnan Samuel"
ByteArray = StrConv(Str, vbFromUnicode)
CopyMemory Tst, ByteArray (0), 4
Debug.Print Tst.Var1
Debug.Print Tst.Var2
Equivalent VB.NET code
Imports System.Runtime.InteropServices
Imports System.Text
Private Structure Test
Dim Var1 As Short
Dim Var2 As Short
End Structure
Private Function BulidStr(ByVal Buff() As Byte, _
ByVal MyType As System.Type) As Object
Dim MyGC As GCHandle = GCHandle.Alloc(Buff, GCHandleType.Pinned)
Dim Obj As Object = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyType)
Return Obj
MyGC.Free()
End Function
Dim Str As String = "Adnan Samuel"
Dim Tst As Test ‘ Stuctuer variable
Dim ByteArray () As Byte, i As Int16
ByteArray = Encoding.Default.GetBytes(Str)
Tst = BulidStr(ByteArray, Tst.GetType)
Debug.WriteLine(Tst.Var1.ToString)
Debug.WriteLine(Tst.Var2.ToString)
Conclusion
I am always willing to help, so if you have any questions, suggestions about my article, feel free to email me. You can also reach me on MSN Messenger with screen name “Maxima”.
I am software engineer and working from last four years in the information technology field. I love to do intresting tasks. I love to see diffrent places and listening muzik.