CopyMemory и строки в vb6

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
neit95
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 14
Зарегистрирован: 10.03.2013 (Вс) 22:05
Откуда: Калининград

CopyMemory и строки в vb6

Сообщение neit95 » 08.11.2013 (Пт) 0:57

Здравствуйте. Мне нужно было скопировать строку содержащуюся в бинарном массиве собственно в строку. Решил делать это при помощи CopyMemory, но получаю белиберду и периодические падения, причём:
Код: Выделить всё
Type T
    S As String * 4
End Type
'...
Dim A(0 To 3) As Byte
    Dim Var2 As T
    Dim Var1 As String * 4
   
    A(0) = &H61&
    A(1) = &H62&
    A(2) = &H63&
    A(3) = &H64&
   
    CopyMemory Var2, A(0), Len(Var2)
    MsgBox Var2.S
   
    CopyMemory Var1, A(0), Len(Var2)
    MsgBox Var1


Первое исполнение CopyMemory пройдёт нормально и в строке окажется то, что нужно, а на 2-ом либо упадёт, либо белиберду выведет.
Где-то слышал, что к строке спереди "приклеена" информация о её размере в количестве 4-х байт. Думал дело в этом, поэтому пробовал вместо простой передачи Var1 передать указатель с учётом "приклеенной" информации: VarPtr(Var1)+4. Может чушь сделал, но, в любом случае, не помогло, да и просто передача VarPtr(Var1) тоже. В общем, использовал всё, что могло прийти в мою буйную фантазию.
Вопроса по этому поводу два:
1) Каковы причины такого поведения (собственно, отличие строки в структуре от просто переменной)?
2) Как эту проблему можно решить?

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: CopyMemory и строки в vb6

Сообщение Mikle » 08.11.2013 (Пт) 8:43

neit95 писал(а):пробовал вместо простой передачи Var1 передать указатель с учётом "приклеенной" информации: VarPtr(Var1)+4

Когда в функцию вместо ByRef параметра передаёшь указатель на него, указатель нужно передавать ByVal:
Код: Выделить всё
ByVal VarPtr(var)

Для получения указателя на строку в VB6 существует функция StrPtr()
Строки в VB6 юникодные, один символ - два байта. Но при передаче их во внешние (объявленные через Declare) процедуры они автоматически конвертируются в ASCII. Если строка завёрнута в структуру, этого не произойдёт. Конвертировать между форматами ASCII и Unicode можно с помощью StrConv().

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: CopyMemory и строки в vb6

Сообщение Хакер » 08.11.2013 (Пт) 10:14

Вообще-то строка конвертируется в массив байтов очень просто:
Код: Выделить всё
Dim s1 as string
Dim s2 as string
Dim b() as byte

s1 = "Привет, земляне"

b = s1 ' Туда

s2 = b ' Обратно

Dim b_as_hex_dump as string
for i = LBound(b) To UBound(b)
        b_as_hex_dump= b_as_hex_dump + " " + Right("00" + Hex(b(i)), 2)
next i
MsgBox b_as_hex_dump


Но прежде нужно вести джихад против собственной убеждённости, что 1 символ строки соответствует одному элементу байтового массива. Это будет иметь смысл, только если есть некая таблица соответствия значений в диапазоне 0—255 и человеческим символов. Любой массив байтов не имеет никакого смысла, пока он дополнительно не снабжён информацией о том, какой из десятков придуманных человечеством подобных таблиц нужно пользоваться при преобразовании.

Читать 20 раз до просветления:
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

neit95
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 14
Зарегистрирован: 10.03.2013 (Вс) 22:05
Откуда: Калининград

Re: CopyMemory и строки в vb6

Сообщение neit95 » 19.11.2013 (Вт) 19:30

В общем, только что, после одного эксперимента мне удалось скопировать строку (точнее выполнить преобразование строка-байтовый массив-строка). Я просто не правильно строку передал. Вместо:
Код: Выделить всё
CopyMemory Var2, b(0), Len(Var2)

нужно было:
Код: Выделить всё
CopyMemory b(0), ByVal Var1, ByVal Len(Var1)

Причём, если отобразить элементы массива, то они не в Unicode (по крайней мере не в 2-х байтовом Unicode). Строки в vb в utf-8 получается?
За статьи и за простой метод преобразования спасибо. И, кстати, с StrPtr ничего не получилось, точнее StrPtr копирует строки, как Unicode (именно 2-х байтовый).

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: CopyMemory и строки в vb6

Сообщение Хакер » 19.11.2013 (Вт) 19:49

Всё зависит от того, как объявлена RtlMoveMemory. ByVal ... As String, ByRef ... As String или ... As Any.
С помощью Declare или же с помощью TLB. С помощью TLB для юникодных строк — правильне, ибо с Declare остаётся только вариант As Any.

neit95 писал(а):Строки в vb в utf-8 получается?

Нет.

Когда трава была зелёной, а MS хотели сделать COM некой грандиозной платформой, они VB делали максимально COM-орентированным языком. Поэтому строки в VB — это всего лишь частный случай COM-строк и все правила для них действуют. Поэтому VB-шная строка имеет тот же тип и устройство что и BSTR в COM.

Устройство простое: переменные, хранящие строку, функции, возвращающие строку, аргументы, принимающие строку, на самом деле хранят/возвращают/принимают 4-байтное значение, являющееся указателем.

Указатель указывает на начало UCS-2 строки в памяти. В конце присутствует нулевой юникодный символ (2-байтовый), а непосредственно перед началом строки хранится 4-байтовая длина.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: CopyMemory и строки в vb6

Сообщение ger_kar » 19.11.2013 (Вт) 20:03

neit95 писал(а): И, кстати, с StrPtr ничего не получилось, точнее StrPtr копирует строки, как Unicode (именно 2-х байтовый).
StrPtr вообще ничего не копирует, а возвращает указатель на текстовый буфер.
Хакер писал(а):Устройство простое: переменные, хранящие строку, функции, возвращающие строку, аргументы, принимающие строку, на самом деле хранят/возвращают/принимают 4-байтное значение, являющееся указатель.Указатель указывает на начало UCS-2 строки в памяти.
Вот именно этот адрес и возвращает StrPtr.
neit95 писал(а):Причём, если отобразить элементы массива, то они не в Unicode
Ну естественно они не в юникоде. При таком вызове как у тебя происходит неявное преобразование в ANSI и именно эти данные и были скопированы поэтому в массиве никакого юникода нет и в помине.
Бороться и искать, найти и перепрятать

neit95
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 14
Зарегистрирован: 10.03.2013 (Вс) 22:05
Откуда: Калининград

Re: CopyMemory и строки в vb6

Сообщение neit95 » 30.11.2013 (Сб) 1:26

Всё, теперь разобрался. Всем огромное спасибо.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot, Google-бот и гости: 41

    TopList