Google

2011-09-12

Writing Binary Data to Registry

Uh, oh! I found yet another post in drafts from 2007. I do not recall the events but posting it for common good :)

**************************************************************

Yesterday, a friend from work showed me an interesting script he was working on. His script was reading a reg_binary type registry key, modifying its value and was 'attempting' to write it back to registry.

There was an issue with 'writing back to registry'. He was using SetBinaryValue method to write an array, which had modified values, back to registry but vbscript kept on complaining there was a "type mismatch" for this line:

Return = oReg.SetBinaryValue(HKEY_LOCAL_MACHINE, strKeyPath & "\" & subKey, strValueName, arrValues

if he set the arrValues to a static array like this

arrValues=Array(1,2,3,4,5,6)

script worked without any issues.

I took the code and tried to figure out what was wrong with it. I would like to write down a couple of key points for those people who are trying to do something similar.

* When we are talking about Binary data in Registry, we are actually referring to Hexadecimal values, because that's the Registry-speak (1984 anyone?). We can use GetBinaryValue Method of WMI's StdRegProv class. Output is "an array of binary bytes"

* However, binary bytes (hex values) are not meaningful to us, so if we are reading it to, let's say, modify a value, we will probably want to convert it to string using CHR function, which returns a character associated with the specified ANSI character code. I.e. a decimal value between 0..127 (see ascii table).

Also, although registry speaks in hex as far as binary data is concerned, "SetBinaryValue" method does not understand Hex

Consider the following Reg Key/Value (pasting from exported .reg):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\Adobe Acrobat\7.0\FeatureLockDown\cDefaultLaunchURLPerms]"

sSchemePerms2"=hex:76,65,72,73,69,6f,6e,3a,31,7c,73,68,65,6c,6c,3a,33,7c,68,\ 63,70,3a,33,7c,6d,73,2d,68,65,6c,70,3a,33,7c,6d,73,2d,69,74,73,3a,33,7c,6d,\ 73,2d,69,74,73,73,3a,33,7c,69,74,73,3a,33,7c,6d,6b,3a,33,7c,6d,68,74,6d,6c,\ 3a,33,7c,68,65,6c,70,3a,33,7c,64,69,73,6b,3a,33,7c,61,66,70,3a,33,7c,64,69,\ 73,6b,73,3a,33,7c,74,65,6c,6e,65,74,3a,33,7c,73,73,68,3a,33,7c,6a,61,76,61,\ 73,63,72,69,70,74,3a,31,7c,76,62,73,63,72,69,70,74,3a,31,7c,61,63,72,6f,62,\ 61,74,3a,32,7c,6d,61,69,6c,74,6f,3a,32,7c,66,69,6c,65,3a,32,00

If we convert it to string, we get something like

version:1shell:3hcp:3ms-help:3ms-its:3
ms-itss:3its:3mk:3mhtml:3help:3disk:3
afp:3disks:3telnet:3ssh:3javascript:1
vbscript:1acrobat:2mailto:2 file:2

Then, you will need to change
mailto:2
 to
mailto:3
 with vbscript's REPLACE funtion

sNewValue = replace(sOldValue,"mailto:2","mailto:3", 1, -1 , 1)


* SetBinaryValue method is used to write "an array of binary data values" to registry. What is misleading here, and this was the key to solving our issue, is that method actually needs a variant or you will get type mismatch.

So this code works :

'Assumes objRegistry is a valid StdRegProv object.On Error Resume Next
Const HKEY_LOCAL_MACHINE As Long = &H80000002
Dim lRC As Long
Dim sPath As String
Dim uBinary() As Variant
sPath = "SOFTWARE\MyKey"
uBinary = Array(1,2,3,4,5,6,7,8)

lRC = objRegistry.SetBinaryValue(HKEY_LOCAL_MACHINE, sPath, "MyBinaryNamedValue", uBinaryData)

If (lRC = 0) And (Err.Number = 0)  Then   

  'Do something

Else    

  'An error occurred

End If 
* Pay attention to Array function, which returns a Variant containing an array as mentioned in MS documentation:

"A variable that is not declared as an array can still contain an array. Although a Variant variable containing an array is conceptually different from an array variable containing Variant elements, the array elements are accessed in the same way."

No comments: