Equivalent of CopyMemory in .NET






3.16/5 (31 votes)
Oct 24, 2004
3 min read

172877
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.
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
'Convert string to byte and copy to byte array
ByteArray = StrConv(Str, vbFromUnicode)
'copy entire array to variable Longvalue
CopyMemory Longvalue, ByteArray (0), 4
'Print it in immediate window
Debug.print LongValue
Equivalent VB.NET code
Imports System.Runtime.InteropServices
Imports System.Text
Dim LongValue As Integer
Dim Str As String = "Adnan Samuel"
'A byte array
Dim ByteArray () As Byte
'Convert string to byte and copy to byte array
ByteArray = Encoding.Default.GetBytes(Str)
'Create Gchandle instance and pin variable required
Dim MyGC As GCHandle = GCHandle.Alloc(LongValue, GCHandleType.Pinned)
'get address of variable in pointer variable
Dim AddofLongValue As IntPtr = MyGC.AddrOfPinnedObject()
'Use copy method to copy array data to variable’s
'address with length specified(4)
Marshal.Copy(ByteArray, 0, AddofLongValue, 4)
'First read value of variable from its address
'in memory in order to use it
LongValue = Marshal.ReadInt32(AddofLongValue)
'Print to output window
Debug.WriteLine("Vlaue of LongValue is: " & LongValue)
'Free GChandle to avoid memory leaks
MyGC.Free()
Now reverse of it (integer to byte array) is very easy, just a small change in Marshal.Copy
method, that is:
'VB 6 code
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)
'Rest of code same
That’s all.
Strings
Let us consider a VB 6 code to copy string.
'Source string to copy from
Dim Source as String
''Destination string to copy
Dim Dest as String
Source=”Adnan”
'Leave 5 spaces for Source string to copy before
'Dest string to show output as AdnanSamuel
Dest=” Samuel”
'Copy source string in beginning of Dest string
CopyMemory StrPtr(Dest), StrPtr(Source),10
'Show output as AdnanSamuel
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:
'Source string to copy from
Dim Source As String = "Adnan"
'Destination string to copy
Dim Dest As String = "Samuel"
'Copy source string in beginning of Dest string
Dest = Dest.Insert(0, Source)
'Show output as AdnanSamuel
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)
'Copy entire byte array to integer array of specified length (8)
CopyMemory IntArr(0), ByteArray(0), 8
'Print to immediate window
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
'Convert string to byte and copy to byte array
MyBytesString = Encoding.Default.GetBytes(Str)
'Use BlockCopy method to copy block of bytes array
'to integer array of specified length (8)
Buffer.BlockCopy(MyBytesString, 0, int, 0, 8)
'Print to output window
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.
'Declare Type
Private Type Test
Var1 As Integer
Var2 As Integer
End Type
Dim Str As String, i As Integer
Dim ByteArray () As Byte
' Declare Type variable to store its value
Dim Tst As Test
Str = "Adnan Samuel"
'Convert to string to bytes
ByteArray = StrConv(Str, vbFromUnicode)
'Copy entire byte array to Type of specified length (4)
CopyMemory Tst, ByteArray (0), 4
' use them ready to use print them
Debug.Print Tst.Var1
Debug.Print Tst.Var2
Equivalent VB.NET code
Imports System.Runtime.InteropServices
Imports System.Text
'In .NET Types are changed to Structures
Private Structure Test
Dim Var1 As Short
Dim Var2 As Short
End Structure
' Function to Create structure must be called first
Private Function BulidStr(ByVal Buff() As Byte, _
ByVal MyType As System.Type) As Object
Dim MyGC As GCHandle = GCHandle.Alloc(Buff, GCHandleType.Pinned)
'Marshals data from an unmanaged block of memory to a newly
'allocated managed object of the specified type.
Dim Obj As Object = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyType)
Return Obj
'Free GChandle to avoid memory leaks
MyGC.Free()
End Function
'Start here
Dim Str As String = "Adnan Samuel"
Dim Tst As Test ‘ Stuctuer variable
Dim ByteArray () As Byte, i As Int16
'convert to bytes
ByteArray = Encoding.Default.GetBytes(Str)
'Call BulidStr method to create structure
'and copy byte array data to structure
Tst = BulidStr(ByteArray, Tst.GetType)
'Now use it and print it
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”.