Тема: VBS: искажение бинарных данных в строковых переменных ?
1. Столкнулся с непонятным (для меня) искажением содержимого переменных, содержащих бинарные данные, при использовании setlocale:
Option Explicit
dim i,j,n,Reply
SetLocale(1033)
n = ""
for i = 0 to 255
n = n & chr(i)
next
hexdump n,""
newline
SetLocale(1049)
hexdump n,""
newline
'SetLocale(1049)
'hexdump n,""
'newline
wscript.quit 0
' Распечатка буфера (строковой переменной) в формате ASCII-hex
' В качестве параметров - распечатываемый буфер и строковая переменная,
' подменяющая адрес при распечатке (если задана)
sub HexDump(string,hdr)
dim b, i, j, k
dim DumpStr : DumpStr = ""
dim Header: Header = hdr ' заголовок
k = len(string) ' длина распечатываемого блока
for i = 1 to k step 16
' Формируем hex-строку
for j = 0 to 15
if i + j <= k then
DumpStr = DumpStr & " " & right("0" & hex(asc(mid(string,i + j,1))),2)
else
DumpStr = DumpStr & " "
end if
next
DumpStr = DumpStr & " "
' Формируем ASCII-строку
for j = 0 to 15
if i + j <= k then
b = asc(mid(string,i + j,1))
if b > 31 and b < 128 then
DumpStr = DumpStr & chr(b)
else
DumpStr = DumpStr & "."
end if
else
DumpStr = DumpStr & " "
end if
next
' Распечатка строки
if Header <> "" then
wscript.stdout.write right(" " & Header,4) & ":" & DumpStr & chr(13) & chr(10)
else
wscript.stdout.write right("000" & hex(i-1),4) & ":" & DumpStr & chr(13) & chr(10)
end if
DumpStr = ""
next
end sub
' Вывод пустой строки
sub NewLine
wscript.stdout.write vbCrLf
end sub
В результате имеем (исходно):
0000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
0010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
0020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
0040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
0050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[\]^_
0060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
0070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
0080: 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F ................
0090: 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F ................
00A0: A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF ................
00B0: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF ................
00C0: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF ................
00D0: D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF ................
00E0: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF ................
00F0: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................
Та же переменная, но после SetLocale(1049):
0000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
0010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
0020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
0040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
0050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[\]^_
0060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
0070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
0080: 88 3F 82 3F 84 85 86 87 3F 89 53 8B 3F 3F 5A 3F .?.?....?.S.??Z?
0090: 3F 91 92 93 94 95 96 97 3F 99 73 9B 3F 3F 7A 59 ?.......?.s.??zY
00A0: A0 3F 3F 3F A4 3F A6 A7 3F A9 3F AB AC AD AE 3F .???.?..?.?....?
00B0: B0 B1 3F 3F 3F B5 B6 B7 3F 3F 3F BB 3F 3F 3F 3F ..???...???.????
00C0: 41 41 41 41 41 41 3F 43 45 45 45 45 49 49 49 49 AAAAAA?CEEEEIIII
00D0: 3F 4E 4F 4F 4F 4F 4F 3F 4F 55 55 55 55 59 3F 3F ?NOOOOO?OUUUUY??
00E0: 61 61 61 61 61 61 3F 63 65 65 65 65 69 69 69 69 aaaaaa?ceeeeiiii
00F0: 3F 6E 6F 6F 6F 6F 6F 3F 6F 75 75 75 75 79 3F 79 ?nooooo?ouuuuy?y
Вопрос может показаться дурацким, но задаю не от нечего делать - проблема в том, что со схожим (но все же с отличиями, что делает ситуацию еще более загадочной) поведением я столкнулся при использовании компонента для работы с последовательным портом от ActiveXperts:
Option Explicit
dim i,j,TX,RX
Dim objComport
' Подготовка порта
Set objComport = CreateObject( "AxSerial.ComPort" )
objComport.Clear() ' рекомендовано разработчиком, но необходимости нет
' Вывод информации о компоненте
Wscript.Echo "ActiveXperts Serial Port Component " & objComport.Version
Wscript.Echo "Build: " & objComport.Build & vbCrLf & "Module: " & objComport.Module
Wscript.Echo "License Status: " & objComport.LicenseStatus & vbCrLf & "License Key: " & objComport.LicenseKey
' Настройка параметров порта
objComport.Device = "COM7"
objComport.BaudRate = 115200
objComport.HardwareFlowControl = objComport.asFLOWCONTROL_DISABLE
objComport.SoftwareFlowControl = objComport.asFLOWCONTROL_DISABLE
objComport.Parity = 1
' Открываю порт
objComport.Open
' Отладочная пропечатка результат открытия
Wscript.Echo "Open, result:" & objComport.LastError & " (" & objComport.GetErrorDescription( objComport.LastError ) & ")"
' Обработка ошибки открытия. Потом, наверное, сделаю чуть приличнее.
if objComport.LastError <> 0 then
wscript.Quit
end if
TX = ""
for i = 0 to 255
TX = TX & chr(i)
next
NewLine
wscript.echo "Transmitted data:"
HexDump TX,""
NewLine
objComport.WriteBytes TX
RX = objComport.ReadBytes()
NewLine
wscript.echo "Received data:"
HexDump RX,""
NewLine
wscript.quit 0
' Распечатка буфера (строковой переменной) в формате ASCII-hex
' В качестве параметров - распечатываемый буфер и строковая переменная,
' подменяющая адрес при распечатке (если задана)
sub HexDump(string,hdr)
dim b, i, j, k
dim DumpStr : DumpStr = ""
dim Header: Header = hdr ' заголовок
k = len(string) ' длина распечатываемого блока
for i = 1 to k step 16
' Формируем hex-строку
for j = 0 to 15
if i + j <= k then
DumpStr = DumpStr & " " & right("0" & hex(asc(mid(string,i + j,1))),2)
else
DumpStr = DumpStr & " "
end if
next
DumpStr = DumpStr & " "
' Формируем ASCII-строку
for j = 0 to 15
if i + j <= k then
b = asc(mid(string,i + j,1))
if b > 31 and b < 128 then
DumpStr = DumpStr & chr(b)
else
DumpStr = DumpStr & "."
end if
else
DumpStr = DumpStr & " "
end if
next
' Распечатка строки
if Header <> "" then
wscript.stdout.write right(" " & Header,4) & ":" & DumpStr & chr(13) & chr(10)
else
wscript.stdout.write right("000" & hex(i-1),4) & ":" & DumpStr & chr(13) & chr(10)
end if
DumpStr = ""
next
end sub
' Вывод пустой строки
sub NewLine
wscript.stdout.write vbCrLf
end sub
В результате имеем:
ActiveXperts Serial Port Component 3.2
Build: 3.2.1.50902 (64bit)
Module: AxSerial64.dll
License Status: Expires 02/02/2019
License Key:
Open, result:0 (Success)
Transmitted data:
0000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
0010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
0020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
0040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
0050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[\]^_
0060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
0070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
0080: 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F ................
0090: 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F ................
00A0: A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF ................
00B0: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF ................
00C0: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF ................
00D0: D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF ................
00E0: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF ................
00F0: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................
Received data:
0000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
0010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
0020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
0040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
0050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[\]^_
0060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
0070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
0080: 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F ????????????????
0090: 3F 3F 3F 3F 3F 3F 3F 3F 98 3F 3F 3F 3F 3F 3F 3F ????????.???????
00A0: A0 3F 3F 3F A4 3F A6 A7 3F A9 3F AB AC AD AE 3F .???.?..?.?....?
00B0: B0 B1 3F 3F 3F B5 B6 B7 3F 3F 3F BB 3F 3F 3F 3F ..???...???.????
00C0: 41 41 41 41 41 41 3F 43 45 45 45 45 49 49 49 49 AAAAAA?CEEEEIIII
00D0: 3F 4E 4F 4F 4F 4F 4F 3F 4F 55 55 55 55 59 3F 3F ?NOOOOO?OUUUUY??
00E0: 61 61 61 61 61 61 3F 63 65 65 65 65 69 69 69 69 aaaaaa?ceeeeiiii
00F0: 3F 6E 6F 6F 6F 6F 6F 3F 6F 75 75 75 75 79 3F 79 ?nooooo?ouuuuy?y
Данные заведомо ушли "правильно" (проконтролировано параллельным подключением через еще один USB-UART), однако принимаются с искажениями во второй части 256-байтовой таблицы. И картина похожа на первый пример (с setlocale), но все же отличается.
У используемого компонента есть еще метод readbyte, и вот он-то работает без искажений (выгребаю данные в цикле, пока не получу таймаут). И вроде бы проблема решена (хоть и коряво), но когда потребовался еще и сетевой компонент от того же производителя, столкнулся с той же самой проблемой "искажения" данных, а там "побайтовый" метод оказался практически неприменим.
Итак, "кто виноват ?" и "что делать ?".
-----
p.s. Вопрос, наверное, снимается - причина в моем недопонимании устройства строчных переменных в vbs. Отсюда и неправильное заполнение буфера с исходными данными и распечатка результата...