1 (изменено: rx3apf, 2019-01-04 03:07:14)

Тема: 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. Отсюда и неправильное заполнение буфера с исходными данными и распечатка результата...

2

Re: VBS: искажение бинарных данных в строковых переменных ?

Строки в VBS представлены в Unicode, т. е. под каждый символ в памяти отведено 2 байта. Коды диапазона 128..255 представляют различные символы в разных кодовых таблицах, в зависимости от заданной локали. 1033 локали соответствует кодировка Windows-1252, а 1049 - Windows-1251. Таким образом, вот в этой строке n = n & chr(i) происходит преобразование в Unicode символов c кодами 128..255 из кодировки Windows-1252. А после переключения на 1049 локаль, вот в этом выражени asc(mid(string,i + j,1)) происходит попытка преобразовать символы Unicode, полученные из кодировки Windows-1252, в соответствующие коды в кодировке Windows-1251. Но в таблице символов Windows-1251 нет таких символов, и соответствия найти не удается. В этом случае происходит преобразование в имеющиеся символы без диакритических знаков, либо, если и таких нет, в знаки вопроса. Отсюда и искажение.

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

3 (изменено: rx3apf, 2019-01-05 00:46:17)

Re: VBS: искажение бинарных данных в строковых переменных ?

Да, спасибо, я все ж "допер" до этого самостоятельно (получив "целеуказание" на другом форуме). Ларчик просто открывался...

upd:
На самом деле, одна неясность все ж осталась - да, при заполнении, если установлена локаль 1033 или, скажем, 1049, действительно буфер строки заполняется юникодом с ненулевым старшим байтом в "проблемных" позициях (для локалей 1099, 1100 этой проблемы нет, как выяснилось, все строго 0000...00FF). Но и такая, "искаженная" строка, будучи отправлена в порт по .writebytes, как выяснилось, и отправляется нормально, и принимается тоже нормально ! Так что последовательность всех этих преобразований до конца мне все равно непонятна. Ну да ладно, основная проблема вроде как решена...

upd:
Я тут был неправ - если заполняю при локали 1049, то, хоть строка и выглядит "неправильно" в распечатке, отправляется в COM-порт все равно правильно и принимается правильно же. А вот если использую 1033 - и выглядит "неправильно" перед отправкой, и передается с "искажениями" в зоне байтов $80...9F. Как я понимаю, в первом случае (1049) обратное преобразование из юникода идет корректно, а во втором, при 1033, уже нет. Картина прояснилась окончательно.

4

Re: VBS: искажение бинарных данных в строковых переменных ?

На всякий случай — кроме Chr() и Asc() есть функции ChrB()/ChrW() и AscB()/AscW(). Кроме функции Mid(), Left(), Right(), Len() имеют свои байтовые аналоги — функции MidB(), LeftB(), RightB(), LenB().

5

Re: VBS: искажение бинарных данных в строковых переменных ?

Ну да, через них и выкрутился...

6 (изменено: rx3apf, 2019-01-05 01:32:34)

Re: VBS: искажение бинарных данных в строковых переменных ?

Как я понял, в этом варианте у людей возникли проблемы (да и как предполагается получать строку, если <cr> не будет, например ?). Но уже не помню, попадался ли он мне, когда потребовалось читать из порта. Выбор был или axserial или mscomm32/scomm64. Или winapi через DWX, но моих мозгов на то не хватило...

Ой, а куда оно (сообщение) исчезло ?

7

Re: VBS: искажение бинарных данных в строковых переменных ?

rx3apf,

Ой, а куда оно (сообщение) исчезло ?

Я своё сообщение убрал. ) Решил потестить перед тем как рекомендовать.  Но "подопытных" под рукой нет. Потестил на виртуальных портах. Кидает и читает вроде нормально. А что за проблема с "<cr>" ? Думаю можно использовать метод Read вместо ReadLine и получать нужное количество данных.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

8

Re: VBS: искажение бинарных данных в строковых переменных ?

Я имел в виду, что если readline, то без <cr> ведь строка не отдастся ? Но подозреваю, что с бинарными данными и там что-нибудь вылезет нехорошее...

9

Re: VBS: искажение бинарных данных в строковых переменных ?

Я имел в виду, что если readline, то без <cr> ведь строка не отдастся ?

Да. Совершенно верно - метод будет ждать появления перевода строки. Поэтому, я уточнил, что можно использовать метод Read, чтобы брать нужное количество данных. И ожидать конца данных по AtEndOfStream

Но подозреваю, что с бинарными данными и там что-нибудь вылезет нехорошее...

Да что же Вы так непозитивно настроены ?

Я пока что провёл тест на текстовых данных. Создал виртуальную пару портов используя Virtual Serial Port Driver, которые читают и пишут друг в друга крест на крест COM1 и COM2.

Читаю порт COM2 по 100 символов. Для байт данных можно читать побайтно.


Option Explicit
Dim oFSO, oCOM
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oCOM = oFSO.OpenTextFile("COM2:9600,N,8,1",1)
Do
	While Not oCOM.atEndOfStream
		WSH.StdOut.Write oCOM.Read(100)
	Wend
	WSH.Sleep 100
Loop

Пишу в порт COM1


Option Explicit
Dim oFSO, oCOM
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oCOM = oFSO.OpenTextFile("COM1:9600,N,8,1",2)
oCOM.Write "data"

И данные получаю без искажений. В принципе можно попробовать сделать сэмпл пересылки файла через такую связку.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

10 (изменено: rx3apf, 2019-01-05 14:35:14)

Re: VBS: искажение бинарных данных в строковых переменных ?

Любопытно. Оно даже работает. Но:

1. Порт больше COM9 - не понимает
2. Что делать с таймаутом приема ? Интересно, что если я ожидаю 256, а посылаю меньше, то принятая строка будет содержать именно столько, сколько послано. Т.е. какой-то встроенный таймаут все ж есть (и очень небольшой, поскольку даже цельные блоки 128 байтов "рвутся" и принимаются как несколько фрагментов). А если вообще ничего ?
3. Как быть с дуплексом, когда передаем и принимаем через один порт ? Ну пусть не дуплекс, а полудуплекс, но ведь и открытие/закрытие происходят не мгновенно, так что ответ вполне может быть утерян ?
4. Но самое огорчительное, что с бинарными данными не работает. $00...7F - нормально. А вот если в потоке есть $80 или больше, то "недопустимый вызов или аргумент процедуры"


И попутно еще вопрос (хотя подозреваю, что ответ будет отрицательный) - а нет ли какого-то метода замены одного (ну или нескольких) символов в строке с явным указанием где и сколько и на что заменить, иначе как через склейку mid исходного и новых данных ? Уж больно коряво выходит. Если б mid умела работать и в "обратном" направлении...

11

Re: VBS: искажение бинарных данных в строковых переменных ?

1. Порт больше COM9 - не понимает

Да. Проверил у себя. Интересное наблюдение. Но возможно есть способ обхода.

2. Что делать с таймаутом приема ? Интересно, что если я ожидаю 256, а посылаю меньше, то принятая строка будет содержать именно столько, сколько послано. Т.е. какой-то встроенный таймаут все ж есть (и очень небольшой, поскольку даже цельные блоки 128 байтов "рвутся" и принимаются как несколько фрагментов). А если вообще ничего ?

Сразу не скажу. Тут только эксперименты и пробы. ) Честно говоря, я сам тоже первый раз в жизни пробую эту возможность FSO

3. Как быть с дуплексом, когда передаем и принимаем через один порт ? Ну пусть не дуплекс, а полудуплекс, но ведь и открытие/закрытие происходят не мгновенно, так что ответ вполне может быть утерян ?

Тоже ещё не проверял.

4. Но самое огорчительное, что с бинарными данными не работает. $00...7F - нормально. А вот если в потоке есть $80 или больше, то "недопустимый вызов или аргумент процедуры"

Думаю тут надо поэкспериментировать с параметром Mode - режим открытия файла. Попробовать переключить его на TristateTrue (работа в Unicode). Либо чтение делать по Read(1) и Write побайтно.

И попутно еще вопрос (хотя подозреваю, что ответ будет отрицательный) - а нет ли какого-то метода замены одного (ну или нескольких) символов в строке с явным указанием где и сколько и на что заменить, иначе как через склейку mid исходного и новых данных ? Уж больно коряво выходит. Если б mid умела работать и в "обратном" направлении...

А чем Replace не угодил ? В нём есть позиция начала в строке, количество замен и указание что на что заменять ? Ну а на крайний случай есть RegExp

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

12 (изменено: rx3apf, 2019-01-05 15:41:51)

Re: VBS: искажение бинарных данных в строковых переменных ?

Xameleon пишет:

А чем Replace не угодил ? В нём есть позиция начала в строке, количество замен и указание что на что заменять ?

А разве там можно опустить данные для поиска ? Мне-то нужно заменить несколько байтов в известных позициях, но с неизвестным содержимым. А с regexp выйдет примерно столь же коряво, как и с нарезкой-склейкой, и еще проверять надо, как он к бинарным данным отнесется...

Xameleon пишет:

Попробовать переключить его на TristateTrue (работа в Unicode). Либо чтение делать по Read(1) и Write побайтно.

в unicode не ругается на аргумент, но и в порт идет не бинарник, а юникод, причем вообще какой-то странный, chrw(128) выдается как $4F $4E $02 $00.

А побайтно .write - тот же самый эффект, для кодов больше $7F ругается...

13

Re: VBS: искажение бинарных данных в строковых переменных ?

rx3apf

А разве там можно опустить данные для поиска ? Мне-то нужно заменить несколько байтов в известных позициях, но с неизвестным содержимым. А с regexp выйдет примерно столь же коряво, как и с нарезкой-склейкой, и еще проверять надо, как он к бинарным данным отнесется...

Теперь понял Вас. Для этого подходят ADODB.Stream и SAPI.SpMemoryStream и SAPI.SpFileStream

в unicode не ругается на аргумент, но и в порт идет не бинарник, а юникод, причем вообще какой-то странный, chrw(128) выдается как $4F $4E $02 $00.

А побайтно .write - тот же самый эффект, для кодов больше $7F ругается...

Ну тогда надо изучать вопрос глубже. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !