Valhalla Legends Archive

Programming => General Programming => Visual Basic Programming => Topic started by: FrostWraith on August 22, 2006, 05:32 PM

Title: Explanation of CopyMemory
Post by: FrostWraith on August 22, 2006, 05:32 PM
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.
Title: Re: Explanation of CopyMemory
Post by: topaz on August 22, 2006, 06:57 PM
That function converts the given value into a signed(not sure if it's signed) long and returns it.
Title: Re: Explanation of CopyMemory
Post by: 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?
Title: Re: Explanation of CopyMemory
Post by: topaz on August 22, 2006, 09:53 PM
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.
Title: Re: Explanation of CopyMemory
Post by: TehUser on August 22, 2006, 10:24 PM
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¼.............
Title: Re: Explanation of CopyMemory
Post by: Networks on August 22, 2006, 10:26 PM
Why were you born? Show off! :P
Title: Re: Explanation of CopyMemory
Post by: TheMinistered on August 23, 2006, 12:39 AM
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)
Title: Re: Explanation of CopyMemory
Post by: Joe[x86] on August 24, 2006, 01:18 AM
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();
}
Title: Re: Explanation of CopyMemory
Post by: MyndFyre on August 24, 2006, 06:03 AM
Yeah, don't call that C#.
Title: Re: Explanation of CopyMemory
Post by: Joe[x86] on August 24, 2006, 11:37 PM
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.
Title: Re: Explanation of CopyMemory
Post by: Warrior on August 25, 2006, 12:13 AM
Yea thats was to hard looking to be C#, C# is all about doing it easy.
Title: Re: Explanation of CopyMemory
Post by: MyndFyre on August 25, 2006, 10:45 AM
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#.
Title: Re: Explanation of CopyMemory
Post by: A2 on February 12, 2007, 09:06 PM
[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!
Title: Re: Explanation of CopyMemory
Post by: TheMinistered on February 13, 2007, 09:15 PM
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++
Title: Re: Explanation of CopyMemory
Post by: shout on February 14, 2007, 06:37 AM
Quote from: MyndFyre[vL] on August 25, 2006, 10:45 AM

i.ToString("x8");


"X8" for uppercase! :D
Title: Re: Explanation of CopyMemory
Post by: Ante on February 14, 2007, 10:08 AM
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?

Function Makedword(Value as long) as string
if value >= 0 then
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr((value mod (256^4)) \ (256^3))
else
value=value + 2147483648#
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr(((value mod (256^4)) \ (256^3))+128)
end if
End Function


notice they are backward slashes (\), which mean integer division, not normal division

if its not the above, then add Makedword=strreverse(makedword) right below the "End if"
Title: Re: Explanation of CopyMemory
Post by: Joe[x86] on February 14, 2007, 09:42 PM
Quote from: Ante on February 14, 2007, 10:08 AM
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?

Function Makedword(Value as long) as string
if value >= 0 then
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr((value mod (256^4)) \ (256^3))
else
value=value + 2147483648#
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr(((value mod (256^4)) \ (256^3))+128)
end if
End Function


notice they are backward slashes (\), which mean integer division, not normal division

if its not the above, then add Makedword=strreverse(makedword) right below the "End if"

OH DEAR GOD THAT HURT, lol.

Function MakeDWORD(Value as Long) As String
    Dim RET as String * 4
    Mid(RET, 1, 1) = Value And &HFF000000
    Mid(RET, 2, 1) = Value And &HFF0000
    Mid(RET, 3, 1) = Value And &HFF00
    Mid(RET, 4, 1) = Value And &HFF
    MakeDWORD = RET
End Function


Note that you're doing three bad things:
1. Using return as a variable.
2. Concatenating to a string that has no contents.
3. Modifying a value passed to the function with out intention of making a ByRef return.

I don't even know what that whole if is about. :P
Title: Re: Explanation of CopyMemory
Post by: Ante on February 17, 2007, 09:08 AM
Function MakeDWORD(Value as Long) As String
    Dim RET as String * 4
    Mid(RET, 1, 1) = Value And &HFF000000
    Mid(RET, 2, 1) = Value And &HFF0000
    Mid(RET, 3, 1) = Value And &HFF00
    Mid(RET, 4, 1) = Value And &HFF
    MakeDWORD = RET
End Function


that's setting values of longs into chars. for example, if the value is &H11111111, the first line will read Mid(RET, 1, 1) = &H11000000. at least add chr to convert it to string. make sure to shift it over several places
Title: Re: Explanation of CopyMemory
Post by: l2k-Shadow on February 17, 2007, 09:17 AM
FYI, neither one of those functions work.
Title: Re: Explanation of CopyMemory
Post by: l)ragon on February 17, 2007, 09:25 AM
Frozen's will also overflow at random for no reason btw, can tell you this without even testing it.
You should never use a straight out value of 256 in that manor.
Title: Re: Explanation of CopyMemory
Post by: Ante on February 18, 2007, 11:24 AM
Quote from: l2k-Shadow on February 17, 2007, 09:17 AM
FYI, neither one of those functions work.
does mine work if u add Makedword=strreverse(makedword) at the end of the function?
Title: Re: Explanation of CopyMemory
Post by: l2k-Shadow on February 18, 2007, 01:36 PM
Quote from: Ante on February 18, 2007, 11:24 AM
Quote from: l2k-Shadow on February 17, 2007, 09:17 AM
FYI, neither one of those functions work.
does mine work if u add Makedword=strreverse(makedword) at the end of the function?

lol... no it overflows on the first statement you can see it from the code.
Title: Re: Explanation of CopyMemory
Post by: Joe[x86] on February 18, 2007, 02:23 PM
Oh yeah.. add Chr() to mine.

I'm so used to byte[] now. :P
Title: Re: Explanation of CopyMemory
Post by: l2k-Shadow on February 18, 2007, 04:24 PM
Quote from: Joex86] link=topic=15573.msg165117#msg165117 date=1171830197]
Oh yeah.. add Chr() to mine.

I'm so used to byte[] now. :P

No that won't work either, you are forgetting that all variables in VB except char are signed. You'd have to do something like this to overcome that barrier (this won't work in all cases such as VB will think that &HFFFF = &HFFFFFFFF because both produce same result, -1.. therefore you'd have to have multiple functions recognizing each one, so if you must not use RtlMoveMemory, you'd best go with the Chr$(eachbyte of the DWORD) function as postead earlier):

Function MakeDWORD(Value As Long) As String
Dim Outbuf As String, nLng As Long

    Outbuf = Chr$((Value And &HFF))
   
    nLng = (((Value And &HFF00) \ (2 ^ 8)) Mod 256)
    If nLng < 0 Then nLng = (nLng + 256)
    Outbuf = Outbuf & Chr$(nLng)
   
    nLng = (((Value And &HFF0000) \ (2 ^ 16)) Mod 256)
    If nLng < 0 Then nLng = (nLng + 256)
    Outbuf = Outbuf & Chr$(nLng)
   
    nLng = (((Value And &HFF000000) \ (2 ^ 24)) Mod 256)
    If nLng < 0 Then nLng = (nLng + 256)
    Outbuf = Outbuf & Chr$(nLng)
   
    MakeDWORD = Outbuf
End Function
Title: Re: Explanation of CopyMemory
Post by: Ante on February 18, 2007, 08:24 PM
Quote from: l2k-Shadow on February 18, 2007, 01:36 PM
Quote from: Ante on February 18, 2007, 11:24 AM
Quote from: l2k-Shadow on February 17, 2007, 09:17 AM
FYI, neither one of those functions work.
does mine work if u add Makedword=strreverse(makedword) at the end of the function?

lol... no it overflows on the first statement you can see it from the code.
did u mean the if value >= 0 then line? cuz theres no place for that to overflow
i can't imagine which other line it could overflow from...every chr() has a value within it that is positive and less than 256
and the negative values are bumped into positive with that line, and put back into "negative" with the last char
Title: Re: Explanation of CopyMemory
Post by: l2k-Shadow on February 18, 2007, 08:49 PM
Quote from: Ante on February 18, 2007, 08:24 PM
Quote from: l2k-Shadow on February 18, 2007, 01:36 PM
Quote from: Ante on February 18, 2007, 11:24 AM
Quote from: l2k-Shadow on February 17, 2007, 09:17 AM
FYI, neither one of those functions work.
does mine work if u add Makedword=strreverse(makedword) at the end of the function?

lol... no it overflows on the first statement you can see it from the code.
did u mean the if value >= 0 then line? cuz theres no place for that to overflow
i can't imagine which other line it could overflow from...every chr() has a value within it that is positive and less than 256
and the negative values are bumped into positive with that line, and put back into "negative" with the last char

no i mean the statement after value >=0 line. it's because VB does math operations using long variables.. and (256 ^ 4) is &HFFFFFFFF which is an unsigned long, however since longs in VB are signed, overflow occurs.
Title: Re: Explanation of CopyMemory
Post by: Ante on February 19, 2007, 09:40 AM
hm...
u coulda jus doen this then

Function Makedword(Value as long) as string
if value >= 0 then
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr(value \ (256^3)
else
value=value + 2147483648#
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr((value  \ (256^3))+128)
end if
End Function
Title: Re: Explanation of CopyMemory
Post by: Imperceptus on February 19, 2007, 03:35 PM
Quote from: A2 on February 12, 2007, 09:06 PM
[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!

omg this post was more then 3 months old when you replied to it. jeez.
Title: Re: Explanation of CopyMemory
Post by: l2k-Shadow on February 19, 2007, 11:53 PM
Quote from: Ante on February 19, 2007, 09:40 AM
hm...
u coulda jus doen this then

Function Makedword(Value as long) as string
if value >= 0 then
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr(value \ (256^3)
else
value=value + 2147483648#
makedword = makedword & chr(value mod 256) & chr((value mod (256^2)) \ (256^1)) & chr((value mod (256^3)) \ (256^2)) & chr((value  \ (256^3))+128)
end if
End Function


Then your function produces the same result as any MakeDWORD VB function.. you get the -1 problem where &HFFFF = &HFFFFFFFF and produces ÿÿÿÿ if you input &HFFFF or &HFFFFFFFF... :'(