Discussion:
How to create a "Array of Bytes" in VBScript?
(too old to reply)
Arno Bosch
2005-05-23 14:42:11 UTC
Permalink
Hello everybody out there,

I need to create an "array of bytes" in VBScript. If I try something like:
===
dim Test5()
for j=0 to 10
redim preserve Test5(j)
Test5(j) = CByte(j)
next
===
Result:
Though: vartype(Test5(1)) = 17 = Byte
there is: vartype(Test5) = 8204 = array of variant

Has anybody an idea how to create the correct data type?

Thanks a lot
Arno
Richard Mueller [MVP]
2005-05-23 17:30:28 UTC
Permalink
Post by Arno Bosch
===
dim Test5()
for j=0 to 10
redim preserve Test5(j)
Test5(j) = CByte(j)
next
===
Though: vartype(Test5(1)) = 17 = Byte
there is: vartype(Test5) = 8204 = array of variant
Has anybody an idea how to create the correct data type?
Hi,

As you've found, you can create an array of byte values, but the datatype
for the array is variant. You cannot create a variable of datatype Byte()
(byte array) in VBScript (although you can read a byte array). You can only
create or modify a byte array in VB, where you can Dim it as Byte().
--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab web site - http://www.rlmueller.net
--
Michael Harris (MVP)
2005-05-24 00:09:40 UTC
Permalink
Post by Richard Mueller [MVP]
Post by Arno Bosch
Has anybody an idea how to create the correct data type?
Hi,
As you've found, you can create an array of byte values, but the
datatype for the array is variant. You cannot create a variable of
datatype Byte() (byte array) in VBScript (although you can read a
byte array). You can only create or modify a byte array in VB, where
you can Dim it as Byte().
It *is* possible to create a "Byte()" via an ADODB.Stream object...

'====
' How to create a true Byte Array in VBScript.
' A true Byte Array will have Typename() -> "Byte()"
'====

Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateOverWrite = 2

set fso = createobject("scripting.filesystemobject")
set stream = createobject("adodb.stream")
temp = fso.gettempname()

stream.type = adTypeText
stream.charset = "ASCII"
stream.open

'here you would loop over your binary source string
'with lenb(),midb(),ascb(),chrb() functions...
'
'this demo loop from 0 to 255 just proves that
'stream.writetext is OK with any binary character value...
'
for i = 0 to 255
wscript.echo i,chr(i)
stream.writetext chr(i)
next

stream.savetofile temp, adSaveCreateOverWrite
stream.close

stream.type = adTypeBinary

stream.open
stream.loadfromfile temp
trueByteArray = stream.read
stream.close
fso.deletefile temp
msgbox "typename(trueByteArray) -> " & typename(trueByteArray)
msgbox ByteArrayToHexString(trueByteArray)

wscript.quit

Function ByteArrayToHexString(bytearray)
Dim I
Redim B(lenb(bytearray)-1)

For I=1 to lenb(bytearray)
B(I-1) = right("0" & hex(AscB(MidB(bytearray,I,1))),2)
Next
ByteArrayToHexString = Join(B,",")

End Function
--
Michael Harris
Microsoft MVP Scripting
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Please ask follow-up questions via the original newsgroup thread.
Richard Mueller [MVP]
2005-05-24 01:44:01 UTC
Permalink
Post by Michael Harris (MVP)
Post by Richard Mueller [MVP]
Post by Arno Bosch
Has anybody an idea how to create the correct data type?
Hi,
As you've found, you can create an array of byte values, but the
datatype for the array is variant. You cannot create a variable of
datatype Byte() (byte array) in VBScript (although you can read a
byte array). You can only create or modify a byte array in VB, where
you can Dim it as Byte().
It *is* possible to create a "Byte()" via an ADODB.Stream object...
'====
' How to create a true Byte Array in VBScript.
' A true Byte Array will have Typename() -> "Byte()"
'====
Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateOverWrite = 2
set fso = createobject("scripting.filesystemobject")
set stream = createobject("adodb.stream")
temp = fso.gettempname()
stream.type = adTypeText
stream.charset = "ASCII"
stream.open
'here you would loop over your binary source string
'with lenb(),midb(),ascb(),chrb() functions...
'
'this demo loop from 0 to 255 just proves that
'stream.writetext is OK with any binary character value...
'
for i = 0 to 255
wscript.echo i,chr(i)
stream.writetext chr(i)
next
stream.savetofile temp, adSaveCreateOverWrite
stream.close
stream.type = adTypeBinary
stream.open
stream.loadfromfile temp
trueByteArray = stream.read
stream.close
fso.deletefile temp
msgbox "typename(trueByteArray) -> " & typename(trueByteArray)
msgbox ByteArrayToHexString(trueByteArray)
wscript.quit
Function ByteArrayToHexString(bytearray)
Dim I
Redim B(lenb(bytearray)-1)
For I=1 to lenb(bytearray)
B(I-1) = right("0" & hex(AscB(MidB(bytearray,I,1))),2)
Next
ByteArrayToHexString = Join(B,",")
End Function
Hi,

I just saw and replied to your similar post in the server.scripting
newsgroup. Since then I have confirmed that using the Stream object does
create a variable of type Byte(), I can assign any binary values I desire,
and I can assign this byte array to the logonHours attribute of a user
object, as exposed by the LDAP provider (and presumably, the loginHours
attribute exposed by WinNT). Up until now I have believed that this could
only be done in VB. I must have missed assigning stream.type in the past. I
assume adTypeBinary = 1.

However, it gets tricky, because the bytes seem to be written in "reverse"
order. For example, when I assign hex FC, which is binary "11111100", the
corresponding logon hours are "11001111", which is hex CF. Similar to
working in assembly language.
--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab web site - http://www.rlmueller.net
--
Arno Bosch
2005-05-24 09:26:04 UTC
Permalink
Hi Richard,

I tried Michaels example code and had good results for chr(i) where
0<=i<=127 but it did not work for 128<=i<=255 at all.

You have to change the line "Stream.Charset = "ASCII"" to "Stream.Charset =
"windows-1252"" for making it work for 0<=i<=255.

So this code should work for my problem even though it is a detour when I
first have to create a file and then can import it as a byte-array.

Anyway I get the correct data-type (8209=array of byte). Thats what I wanted!

Thanks a lot to both of you for your help!

Arno
Miyahn
2005-05-24 13:12:42 UTC
Permalink
Post by Arno Bosch
So this code should work for my problem even though it is a detour when I
first have to create a file and then can import it as a byte-array.
You can copy data from a text stream to a binary stream, so you can get
a array of bytes without creating a temporary file.

The following script demonstrate this method.

' FileName: BinHandle.vbs
Const Path = "%userprofile%\My Documents\TestData.xls"
Dim Buffer, FileName
FileName = CreateObject("WScript.Shell").ExpandEnvironmentStrings(Path)
' Read Excel file to an array of variants.
Buffer = ReadBinary(FileName)
' Convert the array of variants to an array of bytes & overwrite to file.
WriteBinary FileName, Buffer
MsgBox "A test was completed."
'
Function ReadBinary(FileName)
Dim Buf(), I
With CreateObject("ADODB.Stream")
.Mode = 3: .Type = 1: .Open: .LoadFromFile FileName
ReDim Buf(.Size - 1)
For I = 0 To .Size - 1: Buf(I) = AscB(.Read(1)): Next
.Close
End With
ReadBinary = Buf
End Function
'
Sub WriteBinary(FileName, Buf)
Dim aBuf, aStream
aBuf = BuildString(Buf)
Set aStream = CreateObject("ADODB.Stream")
aStream.Type = 1: aStream.Open
With CreateObject("ADODB.Stream")
.Type = 2: .Open: .WriteText aBuf
' Copy data from a text stream to a binary stream.
' (skip Unicode mark? :FFFE)
.Position = 2: .CopyTo aStream, UBound(Buf) + 1: .Close
End With
' At this point aStream.Read give an array of bytes.
aStream.SaveToFile FileName, 2: aStream.Close
Set aStream = Nothing
End Sub
'
Function BuildString(Buf)
Dim I, aBuf(), Size
Size = UBound(Buf): ReDim aBuf(Size \ 2)
For I = 0 To Size - 1 Step 2
aBuf(I \ 2) = ChrW(Buf(I + 1) * 256 + Buf(I))
Next
If I = Size Then aBuf(I \ 2) = ChrW(Buf(I))
BuildString = Join(aBuf, "")
End Function
--
Miyahn (Masataka Miyashita) JPN
Microsoft MVP for Microsoft Office - Excel(Jan 2005 - Dec 2005)
***@nifty.ne.jp
mayayana
2005-05-25 14:19:19 UTC
Permalink
You didn't mention what you need this for, but
you can do anything binary with Textstream. You
don't need ADODB and in many cases you
don't need conversion to bytes. A Textstream string
is binary until you look at it (quantum Textstream?).
Since VBS uses Chr(0) to demarcate string ends,
if you try to get the length of the string you'll get
the offset of the first Chr(0). If you try to use ReadAll
you'll only read up to the first Chr(0). Aside from those
limitations, you can read and write binary as Textstrream
strings.

If you use:

A1 = Array(1, 0, 100, 200, 255, 10)

you'll get a variant array. But those values can
be written to a string:

For i = 0 to UBound(A1)
s = s & Chr(A1(i))
Next

....and the string can be written to disk as binary.

For an example that reads and writes binary, also
using arrays to set up binary data, see here:

http://www.jsware.net/jsware/jsware/scripts.html#iconextr

It's a script that uses only Textstream to read from
any PE file that contains icons. It parses the resource
table, extracts the icon bytes, writes binary file headers
for each icon by using the array method above, then writes the
icons to disk. It may seem a bit sloppy to use Textstream for
that but it works, and on my Win98 1660 Athlon it extracts
and writes 350-odd icons from Shell32.dll almost instantly.
(It also avoids the version limitation associated with using
ADODB if the target computer doesn't have the version
with the Stream object - 2.6+, I think.)

--
--
Post by Arno Bosch
Hi Richard,
I tried Michaels example code and had good results for chr(i) where
0<=i<=127 but it did not work for 128<=i<=255 at all.
You have to change the line "Stream.Charset = "ASCII"" to "Stream.Charset =
"windows-1252"" for making it work for 0<=i<=255.
So this code should work for my problem even though it is a detour when I
first have to create a file and then can import it as a byte-array.
Anyway I get the correct data-type (8209=array of byte). Thats what I wanted!
Thanks a lot to both of you for your help!
Arno
Richard Mueller [MVP]
2005-05-26 16:14:00 UTC
Permalink
Hi,

The problem is that some Active Directory attributes, like logonHours, are
byte arrays. AD will not allow you to assign a variant array or binary
string to logonHours. Byte arrays can be read and handled in VBScript (with
effort), but you cannot declare or create a variable of datatype byte().
Fortunately, VBScript can read byte arrays from AD or the ADODB.Stream
object. ADO allows you to write bytes to the stream and ADO does the
conversion.
--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab web site - http://www.rlmueller.net
--
Post by mayayana
You didn't mention what you need this for, but
you can do anything binary with Textstream. You
don't need ADODB and in many cases you
don't need conversion to bytes. A Textstream string
is binary until you look at it (quantum Textstream?).
Since VBS uses Chr(0) to demarcate string ends,
if you try to get the length of the string you'll get
the offset of the first Chr(0). If you try to use ReadAll
you'll only read up to the first Chr(0). Aside from those
limitations, you can read and write binary as Textstrream
strings.
A1 = Array(1, 0, 100, 200, 255, 10)
you'll get a variant array. But those values can
For i = 0 to UBound(A1)
s = s & Chr(A1(i))
Next
....and the string can be written to disk as binary.
For an example that reads and writes binary, also
http://www.jsware.net/jsware/jsware/scripts.html#iconextr
It's a script that uses only Textstream to read from
any PE file that contains icons. It parses the resource
table, extracts the icon bytes, writes binary file headers
for each icon by using the array method above, then writes the
icons to disk. It may seem a bit sloppy to use Textstream for
that but it works, and on my Win98 1660 Athlon it extracts
and writes 350-odd icons from Shell32.dll almost instantly.
(It also avoids the version limitation associated with using
ADODB if the target computer doesn't have the version
with the Stream object - 2.6+, I think.)
--
--
Post by Arno Bosch
Hi Richard,
I tried Michaels example code and had good results for chr(i) where
0<=i<=127 but it did not work for 128<=i<=255 at all.
You have to change the line "Stream.Charset = "ASCII"" to
"Stream.Charset
Post by mayayana
=
Post by Arno Bosch
"windows-1252"" for making it work for 0<=i<=255.
So this code should work for my problem even though it is a detour when I
first have to create a file and then can import it as a byte-array.
Anyway I get the correct data-type (8209=array of byte). Thats what I
wanted!
Post by Arno Bosch
Thanks a lot to both of you for your help!
Arno
mr_unreliable
2005-05-24 15:27:47 UTC
Permalink
hi Richard (MVP),

As an MVP, I'm sure that you know that Intel x86 machines are
"Little Endian". There are plenty of explanations of this to
be found on the web, but in plain English: the bytes in memory
do not appear in the same order as they do when fetched into
a register (as an integer, or a as long) -- or, vice-versa.

If that little detail has passed out of your consciousness,
then that may explain the "reverse order" effect you are
experiencing.

cheers, jw
Post by Richard Mueller [MVP]
However, it gets tricky, because the bytes seem to be written in "reverse"
order.
Bob Barrows [MVP]
2005-05-24 15:31:46 UTC
Permalink
Post by mr_unreliable
hi Richard (MVP),
As an MVP, I'm sure that you know
"MVP" is not equivalent to "expert in all computer-related issues". An MVP
is awarded because of the amount of help a person provides to the community,
as well as the appropriateness of the help provided.

Bob Barrows
--
Microsoft MVP -- ASP/ASP.NET
Please reply to the newsgroup. The email account listed in my From
header is my spam trap, so I don't check it very often. You will get a
quicker response by posting to the newsgroup.
McKirahan
2005-05-25 10:12:13 UTC
Permalink
Post by Bob Barrows [MVP]
Post by mr_unreliable
hi Richard (MVP),
As an MVP, I'm sure that you know
"MVP" is not equivalent to "expert in all computer-related issues". An MVP
is awarded because of the amount of help a person provides to the community,
as well as the appropriateness of the help provided.
Bob Barrows
--
Microsoft MVP -- ASP/ASP.NET
I didn't know that. I thought MVP was the new MCP title.
Bob Barrows [MVP]
2005-05-26 17:26:02 UTC
Permalink
Post by McKirahan
Post by Bob Barrows [MVP]
Post by mr_unreliable
hi Richard (MVP),
As an MVP, I'm sure that you know
"MVP" is not equivalent to "expert in all computer-related issues".
An MVP is awarded because of the amount of help a person provides to
the community, as well as the appropriateness of the help provided.
I didn't know that. I thought MVP was the new MCP title.
http://mvp.support.microsoft.com/
--
Microsoft MVP -- ASP/ASP.NET
Please reply to the newsgroup. The email account listed in my From
header is my spam trap, so I don't check it very often. You will get a
quicker response by posting to the newsgroup.
Fred Xiong (疯狂小瑞瑞)
2023-07-24 22:25:50 UTC
Permalink
在 2005年5月27日星期五 UTC+8 01:26:02,<Bob Barrows [MVP]> 写道:
Post by Bob Barrows [MVP]
Post by Bob Barrows [MVP]
Post by mr_unreliable
hi Richard (MVP),
As an MVP, I'm sure that you know
"MVP" is not equivalent to "expert in all computer-related issues".
An MVP is awarded because of the amount of help a person provides to
the community, as well as the appropriateness of the help provided.
I didn't know that. I thought MVP was the new MCP title.
http://mvp.support.microsoft.com/
--
Microsoft MVP -- ASP/ASP.NET
Please reply to the newsgroup. The email account listed in my From
header is my spam trap, so I don't check it very often. You will get a
quicker response by posting to the newsgroup.
If you just right want to fetch data with createObject("Microsoft.XMLHTTP"), the responseBody property returns a byte() and that is what you want.
Dim h As New MSXML2.XMLHTTP
h.open "GET", "https://127.0.0.1:81/file.zip", False
h.send
Dim a As New ADODB.Stream
a.Type = adTypeBinary ' Const adTypeBinary = 1
a.open
a.Position = 0 ' for if some one want to setHttpHeader range:
a.Write h.responseBody
a.saveToFile "D:\file2.zip", adSaveCreateOverWrite ' Const adSaveCreateOverWrite = 2
a.Close

Loading...