![]() |
Languages »
VB.NET »
General
Intermediate
Using CopyMemory in .NETBy James MimeaultDemonstrates the use of CopyMemory in .NET to initialize classes |
C#, VB, Windows, .NET 1.0, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

This tutorial will show you how to use the WIndows API function CopyMemory to populate Class data using a string as input.
In my line of work, I have to deal with several file formats that contain fixed length records. This is probably the fastest, most straight-forward way to read those files because the data is a 'known size'. CopyMemory is ideal for this because parsing data is virtually eliminated.
I'm going to walk you through the entire process and explain as I go, starting with a new ConsoleApplication. You should follow the article using .NET on your own machine. I try to avoid straying from the topic at hand, so when you get to the bolded sections of code, just copy and paste them into your program.
CopyMemory is a function that will copy the contents of one 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, especially for objects like Structures, Classes and Strings.
CopyMemorySample in the Name box.Module Module1
Sub Main()
End Sub
End Module
NOTE: We put the declarations into a class because it makes our code much easier to understand. It is not necessarily required, but you will see that it works nicely.
WINAPI in the Name box.WINAPI will be added and you will see the class in the Code Viewer as follows:Public Class WINAPI
End Class
Public Class WINAPI
' Declare the Windows API function CopyMemory
' Note that all variables are ByVal. pDst is passed ByVal because we want
' CopyMemory to go to that location and modify the data that is pointed to
' by the IntPtr, and not the pointer itself.
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal pDst As IntPtr, _
ByVal pSrc As String, _
ByVal ByteLen As Long)
End Class
CopyMemorySample Project. (Just under the Solution in bold.)CClassTest in the Name box.CClassTest will be added and you will see the class in the Code Viewer as follows:Public Class CClassTest
End Class
Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Sequential)> _
Public Class CClassTest
' StructLayout(LayoutKind.Sequential) dictates that the below values will be
' stored sequentially in memory, in other words; ID first, Name second and
' Address third in one sequential block of memory.
' MarshalAs tells the Marshaler what the intended type (and size in this case)
' of data we are trying to work with.
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> Public ID As Char()
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=20)> Public Name As Char()
' Private storage for property values, still populated.
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=30)> Private m_chAddress As Char()
' no problem with standard properties either because the private members get
' the data.
Public Property Address() As Char()
Get
Return m_chAddress
End Get
Set(ByVal Value As Char())
m_chAddress = Value
End Set
End Property
End Class 'CClassTest
' copies a string into a class's properties using CopyMemory
Private Function CopyStringToClass(ByVal Source As String, ByVal Target As Object) As Object
' If the Target is nothing, immediate return of nothing.
If Target Is Nothing Then Return Nothing
' get an instance of the WINAPI class that
' holds the API functions.
Dim API As WINAPI = New WINAPI()
' Declare an IntPtr which will hold a memory address, don't
' panic here! Just keep going!
Dim p_objTarget As IntPtr
Try
' Call AllocHGlobal to allocate enough memory on the heap
' for a 'Target' object. AllocHGlobal returns a pointer
' to this memory, which is needed for the next call.
p_objTarget = Marshal.AllocHGlobal(Marshal.SizeOf(Target))
' To copy Target to the heap, use StructureToPtr
' as in the following line of code. This is useful
' for API calls that require prefilled structures.
'Marshal.StructureToPtr(Target, p_objTarget, True)
' Use CopyMemory to take the data from the source string
' (Source) and copy it to the block of memory on the
' heap (which, coincidentally is the same size as the
' source string, we defined sizes in our class definition).
API.CopyMemory(p_objTarget, Source, Marshal.SizeOf(Target))
' Now, tell the Marshaler to copy the data on the heap
' (the results of CopyMemory) into our instance of the
' Target object (clsTest).
Marshal.PtrToStructure(p_objTarget, Target)
' Free the memory that was allocated on the heap, otherwise
' you will create a memory leak.
Marshal.FreeHGlobal(p_objTarget)
Catch ex As System.OutOfMemoryException
' An exception could occur if the system is out of
' memory and the block of heap memory could not be
' set aside for you.
CoughUpCookies(ex)
Catch e As Exception
' General exception caught, show the message and move on...
CoughUpCookies(e)
End Try
' Free resources assigned to our instance of the WINAPI class
API = Nothing
' send the results back for printing
Return Target
End Function 'CopyStringToClass
CopyStringToClass takes a String and an Object instance as parameters.WINAPI' and initialize it using the New keyword.IntPtr' to hold a memory address.
Try..Catch block, trap any exceptions (specifically OutOfMemory exceptions).System.Runtime.InteropServices.Marshal class, allocate a 'Target' sized block of memory on the Global Heap
and assign the returned pointer to that memory to p_objTarget (which is an IntPtr object).CopyMemory of the WINAPI object to copy the string into the memory
that we set aside for clsTest (the 'Target' sized block of heap memory).System.Runtime.InteropServices.Marshal.PtrToStructure method to copy the data from the heap memory that is pointed to
by p_objTarget into the Target object.System.Runtime.InteropServices.Marshal.FreeHGlobal method to free the block of
memory that we allocated on the heap for the copy. If this is not done, it will result in a memory leak.WINAPI) to Nothing (null).Now add the following code listed between the 'ADD THIS CODE' comments to Module1. Module1 is complete (for now):
Imports System.Runtime.InteropServices
Module Module1
Sub Main()
'----------- ADD THIS CODE -----------
' 60 char string for sample data
Dim strSource As String = "10785236ABJohn F. Kennedy Jr. 1234 Pennsylvania Blvd. "
' parameter for function, also receives return value
Dim clsTemp As CClassTest = New CClassTest()
' String to Class Copy
clsTemp = CopyStringToClass(strSource, clsTemp)
PrintResultsOfCopy(strSource, clsTemp)
'----------- END OF CODE -----------
End Sub 'Main
' copies a string into a class's properties using CopyMemory
Private Function CopyStringToClass(ByVal Source As String, ByVal Target As Object) As Object
' If the Target is nothing, immediate return of nothing.
If Target Is Nothing Then Return Nothing
' get an instance of the WINAPI class that
' holds the API functions.
Dim API As WINAPI = New WINAPI()
' Declare an IntPtr which will hold a memory address, don't
' panic here! Just keep going!
Dim p_objTarget As IntPtr
Try
' Call AllocHGlobal to allocate enough memory on the heap
' for a 'Target' object. AllocHGlobal returns a pointer
' to this memory, which is needed for the next call.
p_objTarget = Marshal.AllocHGlobal(Marshal.SizeOf(Target))
' To copy Target to the heap, use StructureToPtr
' as in the following line of code. This is useful
' for API calls that require prefilled structures.
'Marshal.StructureToPtr(Target, p_objTarget, True)
' Use CopyMemory to take the data from the source string
' (Source) and copy it to the block of memory on the
' heap (which, coincidentally is the same size as the
' source string, we defined sizes in our class definition).
API.CopyMemory(p_objTarget, Source, Marshal.SizeOf(Target))
' Now, tell the Marshaler to copy the data on the heap
' (the results of CopyMemory) into our instance of the
' Target object (clsTest).
Marshal.PtrToStructure(p_objTarget, Target)
' Free the memory that was allocated on the heap, otherwise
' you will create a memory leak.
Marshal.FreeHGlobal(p_objTarget)
Catch ex As System.OutOfMemoryException
' An exception could occur if the system is out of
' memory and the block of heap memory could not be
' set aside for you.
CoughUpCookies(ex)
Catch e As Exception
' General exception caught, show the message and move on...
CoughUpCookies(e)
End Try
' Free resources assigned to our instance of the WINAPI class
API = Nothing
' send the results back for printing
Return Target
End Function 'CopyStringToClass
'------------ ADD THIS CODE ---------------
' ask the user to press <Enter> and return
Private Sub PromptForEnter()
Console.WriteLine()
Console.Write("Press <Enter> to continue...")
Console.ReadLine()
End Sub 'PromptForEnter
Private Sub PrintResultsOfCopy(ByVal Source As String, ByVal Value As CClassTest)
' let's see what we got from our Source
Console.WriteLine(ControlChars.CrLf & "Results of CopyMemory for CCLassTest:")
Console.WriteLine("Source String = " & Source)
Console.WriteLine("CClassTest.ID = " & CType(Value.ID, String))
Console.WriteLine("CClassTest.Name = " & CType(Value.Name, String))
Console.WriteLine("CClassTest.Address = " & CType(Value.Address, String))
' Prompt for user input
Call PromptForEnter()
End Sub 'PrintResultsOfCopy
'exception display, prompt and return
Private Sub CoughUpCookies(ByVal e As System.Exception)
Console.WriteLine()
Console.WriteLine("Exception Caught: " & e.Message)
Console.WriteLine()
' Prompt for user input
Call PromptForEnter()
End Sub 'CoughUpCookies
' exception display, prompt and return
Private Sub CoughUpCookies(ByVal e As System.OutOfMemoryException)
Console.WriteLine()
Console.WriteLine("Exception Caught: " & e.Message)
Console.WriteLine()
' Prompt for user input
Call PromptForEnter()
End Sub 'CoughUpCookies
'--------------- END OF CODE ---------------
End Module
ISSUE: You should note that, although the MSDN documentation for MarshalAs(UnManagedType.ByValTStr) shows that this can be used to marshal strings for Classes and Structures, it does not work for Classes and Structures. One character is lost for every string in your class or structure (Standard Strings work fine). This is why I use Char Arrays in my Class and Structure examples
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 8 Mar 2003 Editor: Barry Lapthorn |
Copyright 2003 by James Mimeault Everything else Copyright © CodeProject, 1999-2009 Web22 | Advertise on the Code Project |