Link to home
Start Free TrialLog in
Avatar of mdougan
mdouganFlag for United States of America

asked on

Formatting the values returned from RegEnumValue

I've been putting together a nice little class for reading and writing to the registry, copying or deleteing registry keys and all of their sub keys and/or values.  


My problem is that after running RegEnumValue, I'm displaying the contents of the values in a grid. This works fine for values of type string, but I'm not formatting the DWORD or BINARY return values correctly for display.  

What I'd like to do, is translate DWORD values so that they display exactly as they do in RegEdit.  So, a DWORD with a hex value of 20000, decimal value of 131072 will display as:

0x00020000 (131072)

and a BINARY value will display as:
9A 01 00 00 34 00 00 00
84 00 00 00 FC 02 00 00

and so on ....

(extra points if you can display it as:)
9A 01 00 00 34 00 00 00  ....4...
84 00 00 00 FC 02 00 00  .....u..

with the character representation on the right.

These are the two main types I need help displaying, but extra points for a more complete answer that formats all of the possible Registry value types.

Here is the kind of function I was trying to write:
(but it's not working properly)

Public Function FormatValue(vValue As Variant, nType As Long) As String
Dim Temp As String
Dim J As Long

 Select Case nType
     Case REG_DWORD
         For J = 1 To Len(vValue)
             Temp = Temp & CStr(CDec(Asc(Mid(vValue, J, 1))))
         Next J
         Temp = "0x0" & Temp & IIf(7 - Len(Temp) > 0, String(7 - Len(Temp), "0"), "")
         FormatValue = Temp
     Case REG_BINARY
         For J = 1 To Len(vValue)
             Temp = Temp & IIf(Len(CStr(Hex(Asc(Mid(vValue, J, 1))))) > 1, "", "0") & CStr(CDec(Asc(Mid(vValue, J, 1)))) & IIf(J Mod 8 = 0, vbCrLf, Space(1))
         Next J
         FormatValue = Temp
     Case Else
         FormatValue = vValue
End Select

End Function
ASKER CERTIFIED SOLUTION
Avatar of Gordonp
Gordonp
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
       Case REG_BINARY
            Dim sLine As String
            Dim sLine2 As String
       
            Dim I As Integer
            For I = 0 To UBound(byData)
                sLine = sLine & Format(byData(I), "00") & " "
                sLine2 = sLine2 & Chr(byData(I))
                               
                If (I Mod 8) = 0 Then
                    FormatValue = FormatValue & vbCrLf & sLine & vbTab & sLine2
                    sLine = ""
                    sLine2 = ""
                End If
            Next

Here the bit for the Binary formatting

Hope this helps

Gordon
Avatar of mdougan

ASKER

So far, this looks great, but I hadn't been copying the data to a byte array.  When I tried to do it in your routine I got a type missmatch, so, I'm not sure how to load the byte array.  

Here is the code I use in the enum function, which puts the value into a variant/string.  This type of variable works fine for the routine that copies one tree to another, but if you can suggest how to put the value into a byte array instead of a string/variant then the points are yours:

            nRet = RegEnumValue(hKey, nIndex, ValueName, nValueNameLen, ByVal 0&, nType, ByVal Value, nValueLen)
            If nRet = ERROR_SUCCESS Then
                ReDim Preserve Values(0 To 2, 0 To nStrings) As Variant
                Values(0, nStrings) = Left$(ValueName, nValueNameLen)
                Values(1, nStrings) = Left$(Value, nValueLen - 1)
                Values(2, nStrings) = nType


Or, if you can modify your routine to use a variant/string is the input parm, and then copy to a byte array in the routine, even better.
Avatar of mdougan

ASKER

GordonP's answer looks good, but it only takes me half way.  I'm currently getting the value out of RegEnumValue as a variant/string.  To use GordonP's function, I'd need it to be in a byte array.  

So, I'd either need a way to put the value in a Byte Array from RegEnumValue or, better for me, to have GordonP's function accept a variant/string and then do whatever it has to do to format it for display.

I'm opening this back up since GordonP hasn't replied in a couple of days.
Ok, I'm back.

I was on holiday.

Have you tried passing a byte array to RegEnumValue instead of a string

Other option is to convert your string

Dim byData() as byte
byData = strconv(Value,vbFromUnicode)

Hope these help

Gordon
Avatar of mdougan

ASKER

Adjusted points from 150 to 200
Avatar of mdougan

ASKER

Thanks!  I was finally able to get it to display as I wanted it to.  I did have to make a few adjustments to your original routine, so I'll post the final version below for the benefit of others that might buy this question.  

Putting the values returned from RegEnumValue into a variant/string type variable worked for me, as I created a two dimensional variant array that would hold the name of the key, the value, and the type of the key.  In all of the code for copying the values or otherwise manipulating the registry, I didn't have to do anything to the value, it was only in displaying it that I had to muck around with it.  So, I was happy to convert it to the byte array in the display routine.  Thanks for the strconv using vbFromUnicode, I don't think I ever would have figured that out on my own.

Some of the things that I had to change to get it to display the binary like RegEdit, I had to pad a line that was less than 8 characters, so that the last line's char rep would line up with the others.  I also changed certain ascii codes to "." in the char rep to match what RegEdit displays.  Also, I added the HEX function to get the hex rep of the decimal values.  This was necessary for both the DWORD and BINARY displays.  I also put in code to keep the very first line of the binary display from being prefaced by a tab.

Thanks again!

Public Function FormatValues(vValue As Variant, nType As Integer) As String
Dim sLine As String
Dim sLine2 As String
Dim i As Integer
Dim byData() As Byte
Dim sTemp As String
   
    byData = StrConv(vValue, vbFromUnicode)
                       
    Select Case nType
        Case REG_DWORD
            Dim dwValue As Long
            CopyMemory dwValue, byData(0), LenB(dwValue)
            sTemp = Hex(dwValue)
            FormatValues = "0x" & IIf(Len(sTemp) < 8, String(8 - Len(sTemp), "0"), "") & sTemp & " (" & dwValue & ")"
                         
        Case REG_SZ
            FormatValues = vValue

        Case REG_BINARY
        For i = 0 To UBound(byData)
            sTemp = Trim(Format(Hex(byData(i)), "@@"))
            sLine = sLine & IIf(Len(sTemp) < 2, "0", "") & sTemp & " "
            sLine2 = sLine2 & IIf((byData(i) < 32 Or _
                                  byData(i) = 127 Or _
                                 (byData(i) >= 129 And byData(i) <= 144) Or _
                                 (byData(i) >= 147 And byData(i) <= 159)), _
                                 ".", Chr(byData(i)))
            If ((i + 1) Mod 8) = 0 Then
                FormatValues = FormatValues & IIf(Len(FormatValues) > 0, vbCrLf, "") & sLine & vbTab & sLine2
                sLine = ""
                sLine2 = ""
            End If
        Next
        FormatValues = FormatValues & IIf(Len(FormatValues) > 0, vbCrLf, "") & sLine & IIf(Len(sLine) < 24, Space(24 - Len(sLine)), "") & vbTab & sLine2
    End Select
         
End Function
Avatar of mdougan

ASKER

Thanks again.