• Welcome to Valhalla Legends Archive.
 

Explanation of CopyMemory

Started by FrostWraith, August 22, 2006, 05:32 PM

Previous topic - Next topic

FrostWraith

Let's say we have this function
Function MakeDWORD(Value As Long) As String
    Dim Result As String * 4
    CopyMemory ByVal Result, Value, 4
    MakeDWORD = Result
End Function


Could someone help me with a clear step-by-step explanation of what CopyMemory does? I hate using code I dont completely understand.

topaz

That function converts the given value into a signed(not sure if it's signed) long and returns it.
RLY...?

FrostWraith

Yes, but if this function had to be recoded w/o using copymemory, what would it look like?

topaz

Quote from: FrostWraith on August 22, 2006, 09:03 PM
Yes, but if this function had to be recoded w/o using copymemory, what would it look like?

As far as I know, CopyMemory is the only way you can convert between VB6 values and C structs.
RLY...?

TehUser

Quote from: Topaz on August 22, 2006, 09:53 PM
As far as I know, CopyMemory is the only way you can convert between VB6 values and C structs.

Not at all.

Quote from: FrostWraith on August 22, 2006, 05:32 PM
Could someone help me with a clear step-by-step explanation of what CopyMemory does? I hate using code I dont completely understand.
CopyMemory does exactly what it looks like it's doing.  It copies memory from one location to another.  However, in this case, it's being used to create a string value from a long integer.  Because if you used Visual Basic's CStr function (Convert to String), you'd end up with this:

Dim myNum as Long
Dim myStr as String
myNum = 12345678
myStr = CStr(myNum) ' myStr = "12345678"


When you use CopyMemory on the other hand, the long value (4 bytes on most systems), is copied into the string.  So if we look at 12345678 in hex, it's equal to 0x00BC614E (or rather, in memory, it's going to be stored as 0x4E61BC00 because of the endian-ness of the PC.)  Thus, the string after CopyMemory holds the character 0x4E, 0x61, 0xBC, and 0x00.  This is significantly different from the original string.

Now, for the purpose: Visual Basic doesn't have pointers (generally speaking) and type-casting on a low level, so when we're sending binary data (technically, all data is binary, but the term seems to be used for data that contains non-printable characters) we have to convert it into a string format.  There's a huge difference between sending the string "2" (0x32) and the number 2 (0x02000000).  What CopyMemory allows us to do is load that binary data into a string in an easy fashion.  And you can see it in MakeDWORD where an input long integer is converted to a four byte string.

Lastly, if you wanted to write a replacement, it would look something like this:

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, _
    source As Any, ByVal bytes As Long)


Private Sub Form_Load()
    Debug.Print DebugOutput(MakeDWORDVB(12345678))
    Debug.Print DebugOutput(MakeDWORDCopyMemory(12345678))
End Sub

Public Function MakeDWORDVB(Value As Long) As String
    Dim tempStr As String
    ' Convert the value to its hexadecimal representation.
    ' In the case of 12345678, this is "BC614E"
    tempStr = CStr(Hex(Value))
    ' Pad the string with zeros.
    ' Use the Right$ function to remove all but the last 8
    '  characters.  This is because a 4-byte value needs 8
    '  representative bytes.  In the case of 12345678, these
    '  bytes are "00BC614E".
    tempStr = Right$("00000000" & tempStr, 8)
   
    ' Now, because of the endianness of the PC (has to do with
    '  byte order), we have to reverse the bytes for the DWORD
    '  to be read appropriately.  This little loop takes care
    '  of converting each set of two bytes ("00" "BC" "61" "4E")
    '  to their character format.  It also reverses the byte
    '  order so that the DWORD will be read appropriately by the
    '  receiving end.
    Dim i As Byte
    For i = 1 To 7 Step 2
        MakeDWORDVB = Chr$("&H" & Mid$(tempStr, i, 2)) & MakeDWORDVB
    Next i
End Function

Function MakeDWORDCopyMemory(Value As Long) As String
    Dim Result As String * 4
    CopyMemory ByVal Result, Value, 4
    MakeDWORDCopyMemory = Result
End Function


Output:0000:  4E 61 BC 00                                       Na¼.............
0000:  4E 61 BC 00                                       Na¼.............

Networks

#5
Why were you born? Show off! :P

TheMinistered

I don't much feel like reading TehUsers long overcomplicated explanation, so I'll explain it simply:

Function MakeDWORD(Value As Long) As String
    Dim Result As String * 4
    CopyMemory ByVal Result, Value, 4
    MakeDWORD = Result
End Function

This takes a 4byte DWORD and converts it to a 4 byte string.  There are no conversion operators for visual basic that work on this level.

Copymemory works by moving a section/block of memory from one location to another Src to Dest

In this case Src is Value, Dest is Result.
Src = Long, Dest = String

Thus offering effecient conversion from Long To String (CStr does literal conversion to an ascii string)

Joe[x86]

Note, CopyMemory doesn't convert anything. It's given three values, in, out, and length. It copys, byte for byte, length bytes worth of in to the pointer specified in out. We just happen to use that to write the contents of a Long to a String. If you ask me, that behavior shouldn't be used in good programming practice, because that doesn't sound like the intended use.

Excuse my Java/C#/whatever you call this, but this is what is, by my standards, a proper makeDword(int) function. Untested, of course, but you'll live (seriously, you will!):
public String makeDword(int i)
{
    byte b0 = (byte)(i && 0xff000000) >> 24;
    byte b1 = (byte)(i && 0x00ff0000) >> 16;
    byte b2 = (byte)(i && 0x0000ff00) >> 8;
    byte b3 = (byte)(i && 0x000000ff);

    return b0.toString() + b1.toString() + b2.toSring() + b3.toString();
}
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

MyndFyre

QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Joe[x86]

Ah, quit insulting my coding styles and teach me the proper! I took a Java class and have those coding standards fixed in my brain now, so eh.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

Warrior

Yea thats was to hard looking to be C#, C# is all about doing it easy.
Quote from: effect on March 09, 2006, 11:52 PM
Islam is a steaming pile of fucking dog shit. Everything about it is flawed, anybody who believes in it is a terrorist, if you disagree with me, then im sorry your wrong.

Quote from: Rule on May 07, 2006, 01:30 PM
Why don't you stop being American and start acting like a decent human?

MyndFyre

Quote from: Joex86] link=topic=15573.msg157187#msg157187 date=1156480629]
Ah, quit insulting my coding styles and teach me the proper! I took a Java class and have those coding standards fixed in my brain now, so eh.
If you wanted to make it hex, you'd just call:

i.ToString("x8");


The 8 is included to ensure that it's 8 characters wide (with 0s prepended).  To skip that, just "x" will do.

Plus your code would have failed because you attempted to do the logical AND (&&) when the numerical AND was desired.

Plus it would have failed because you typecasted the result of the AND to (byte), and then shifted it, when you should have shifted the AND result and then typecasted.  Proper:
(byte)((i & 0xff000000) >> 24);

Plus your example would have printed out the number big-endian.  Not necessarily wrong (it's how we write individual numbers in hex), I'm just saying.

Note that Strings are not adequate nor proper places to store binary data in either Java or C# because they are subject to encoding strategies related to their runtime environments.  The CopyMemory function is used to store data in Strings in Visual Basic because people don't use byte arrays for it.  Byte arrays are, however, available in Java and C#.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

A2

[code]copy memory is really usefull, especially for filling vb types which can be build alot like cstructs

double = 8bytes
long = 4bytes
integer = 2bytes
byte = 1byte

to answer your question, without copymem that function looks like

function long2str(byval n as long) as string

  long2str = _
    chr((n and &HFF000000&) mod 256) & _
    chr((n and &H00FF0000&) mod 256) & _
    chr((n and &H0000FF00&) mod 256) & _
    chr(n and &H000000FF&)

end function[/code]

or backwards... dont know offhand, too lazy for testing!

TheMinistered

#13
It seems kind of pointless to use a function like that to convert between each other when you could just use pointers and mov operations?  I mean I'm sure pointers would be far more effecient and easier to read than using a bunch of binary operators to do it.  but then again joe is a complete newbie++ the vb6 users used copymemory because vb6 doesn't support pointers... and joes code also sucks because it only applys to dword->string conversion... what happens if you need support for bigger types/arrays... seems like a lot more overhead than required but as I said before joe is a completely dumb newbie++