Results 1 to 11 of 11

Thread: [RESOLVED] Understanding the CopyMemory method

  1. #1

    Thread Starter
    New Member
    Join Date
    Nov 2007
    Posts
    8

    Resolved [RESOLVED] Understanding the CopyMemory method

    This may sound like a silly question, but I've been having trouble reading an 8-byte REG_BINARY value from the registry and converting it to a Double. After extensive trial and error, I've discovered that the CopyMemory API is capable of doing that coversion. I've implemented it in the following way:
    Code:
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    ' Irrelevant code...
    Dim KeyHandle&, DataType&, BufferSize&, st$, lng&, bn() As Byte, dbl#
    ' Irrelevant code...
            Case REG_BINARY
                ReDim bn(0 To BufferSize - 1) As Byte
                Call RegQueryValueEx(KeyHandle, Name, 0&, 0&, bn(0), BufferSize)
                CopyMemory dbl, bn(0), CLng(UBound(bn) + 1)
                RegistryRead = dbl
    That way, a REG_BINARY value of hex:1c,0e,9a,bf,fe,3f,73,40 reads as 307.999694444444.

    What I wanted to know is how exactly it is done. If I wanted, for instance, to manually convert (calc.exe?) the hexadecimal values above to the decimal result, how would I do that?

  2. #2
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: Understanding the CopyMemory method

    I understood everything until I got to this:
    Quote Originally Posted by DonKeyDoo
    What I wanted to know is how exactly it is done. If I wanted, for instance, to manually convert (calc.exe?) the hexadecimal values above to the decimal result, how would I do that?
    I don't know what you are asking there....

    You don't have to use CopyMemory, you can also use the LSet, for example, here I wrote code to test your result:
    Code:
    Option Explicit
    
    Private Type t_Double
        D As Double
    End Type
    
    Private Type t_B8
        B(0 To 7) As Byte
    End Type
    
    Private Sub Form_Load()
        Dim Dbl As t_Double
        Dim DblB As t_B8
        Dim K As Long
        
        Dbl.D = 307.999694444444
        
        LSet DblB = Dbl
        
        For K = 0 To 7
            Debug.Print Right("0" & Hex(DblB.B(K)), 2) & ",";
        Next K
        
        Debug.Print
    End Sub
    Using LSet is safer because it does some checks before it copies the memory, so it won't crash you application in case you copy more memory than the buffer can hold (in that case CopyMemory will crash your application, but LSet won't)

    The only negative thing I don't like about LSet is that you have to define the Type structures and use those instead of variables... and it's kinda anoying... but it beats CopyMemory on safety...

    By the way, I got this result when testing with the code: "14,0E,9A,BF,FE,3F,73,40"

  3. #3
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: Understanding the CopyMemory method

    I like that LSet method
    Quote Originally Posted by CVMichael
    By the way, I got this result when testing with the code: "14,0E,9A,BF,FE,3F,73,40"
    The number will still display as 307.999694444444 if the first byte is within the range &h0C to &h1C.... In other words it would appear ~ 4 bits of a double cannot be displayed or entered.

  4. #4
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: Understanding the CopyMemory method

    Quote Originally Posted by DonKeyDoo
    <snip>...value of hex:1c,0e,9a,bf,fe,3f,73,40 reads as 307.999694444444.

    What I wanted to know is how exactly it is done. If I wanted, for instance, to manually convert the hexadecimal values above to the decimal result, how would I do that?
    Not so easily as the structure in memory does not align to bytes, you would have to extract and combine the appropriate bits from the bytes to get the Exponent and Mantissa.

  5. #5

    Thread Starter
    New Member
    Join Date
    Nov 2007
    Posts
    8

    Re: Understanding the CopyMemory method

    Thanks for your replies and assistance. I will definitely use the LSet method instead of CopyMemory. However, I'm still having difficulties understanding the logic behind the conversion. Viewing the structure of double in the memory helped, but mathematics is my soft spot, so there's still a gap. I've been trying to find a code that uses mathematical function for the conversion, rather than using the memory calls... but to no avail. Anyway, thanks again!

  6. #6

    Thread Starter
    New Member
    Join Date
    Nov 2007
    Posts
    8

    Re: Understanding the CopyMemory method

    Quote Originally Posted by CVMichael
    You don't have to use CopyMemory, you can also use the LSet, for example, here I wrote code to test your result:
    Can I use the LSet method the other way around? In your example you've shown how to convert double to to an 8-byte array, but how can I use LSet to convert the array to a double? I seem to be getting a type-mismatch error when I try to run it the other way around...

  7. #7
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: Understanding the CopyMemory method

    Quote Originally Posted by DonKeyDoo
    I'm still having difficulties understanding the logic behind the conversion. [...] I've been trying to find a code that uses mathematical function for the conversion, rather than using the memory calls...
    There is no mathematical way to do the conversion you ask for. The reason for that is that it depends on how you interpret the numbers. If you look at a binary number like 101, you might know that this equals 5 in the decimal system. However that is only true if 101 should be interpreted as an integer number. A stream of bits can be interpreted in many different ways depending on the data type you're using. A single or a double doesn't interpret a stream of bits as an integer number. A string wouldn't intepret it as that either, it would convert the bits into characters.

    The binary value you read from the registry happens to be 8 byte long, or 64 bits long. Depending on how you want to interpret the information it could represent a 8-byte floating point value (a Double) or maybe as a 8 or 4 character string (depending on the format used). Or maybe it represent two 32-bit integer values (Long) or four 16 bit integer values (Integer).

    When you use CopyMemory you simply copy the bit-stream from one memory location to another and depending on the data type used as the target you would get different interpretations of the data.

    In fact, the binary number 101, could just as well mean "bread and milk", in a shopping list application that interprets the numbers that way.

  8. #8
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: Understanding the CopyMemory method

    Quote Originally Posted by DonKeyDoo
    Can I use the LSet method the other way around? In your example you've shown how to convert double to to an 8-byte array, but how can I use LSet to convert the array to a double? I seem to be getting a type-mismatch error when I try to run it the other way around...
    The opposite is like this:
    Code:
    Option Explicit
    
    Private Type t_Double
        D As Double
    End Type
    
    Private Type t_B8
        B(0 To 7) As Byte
    End Type
    
    Private Sub Form_Load()
        Dim Dbl As t_Double
        Dim DblB As t_B8
        
        ' Set the binary data
        DblB.B(0) = &H1C
        DblB.B(1) = &HE
        DblB.B(2) = &H9A
        DblB.B(3) = &HBF
        DblB.B(4) = &HFE
        DblB.B(5) = &H3F
        DblB.B(6) = &H73
        DblB.B(7) = &H40
        
        ' Copy from byte array to a double
        LSet Dbl = DblB
        
        Debug.Print Dbl.D
    End Sub

  9. #9

    Thread Starter
    New Member
    Join Date
    Nov 2007
    Posts
    8

    Resolved Re: Understanding the CopyMemory method

    Hey everybody. Thanks again for your replies. You've been a great help.

    After reading about the double precision structure in memory, I've decided to write a covnersion function in spite of the LSet and CopyMemory methods... Here's a test example:
    vb Code:
    1. Public Sub Test()
    2.     Dim str$, x&, exponent&, mantissa As Double
    3.     mantissa = 1
    4.     divider = 1
    5.     str = "0100000001110011001111111111111010111111100110100000111000011100"
    6.     sign = CLng(Mid(str, 1, 1))
    7.     ' assuming 64-bit
    8.     For x = 12 To 2 Step -1
    9.         If CLng(Mid(str, x, 1)) = 1 Then exponent = exponent + (2 ^ (Abs(x - 12)))
    10.     Next x
    11.     For x = 13 To 64
    12.         If CLng(Mid(str, x, 1)) = 1 Then mantissa = mantissa + (1 / (2 ^ (x - 12)))
    13.     Next x
    14.     Debug.Print ((-1) ^ sign) * (2 ^ (exponent - 1023)) * mantissa 'exponent bias is 0x3ff = 1023
    15. End Sub

    It works!

    Thanks again!

  10. #10

    Thread Starter
    New Member
    Join Date
    Nov 2007
    Posts
    8

    Re: [RESOLVED] Understanding the CopyMemory method

    hmm.. disregard "divider = 1" I don't know how it got there :P

  11. #11
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: [RESOLVED] Understanding the CopyMemory method

    Just FYI... you can edit your post and make the changes, instead of making a new post stating the mistake....

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width