vb6 и dll, способы передачи строк

Предыдущая тема Следующая тема Перейти вниз

vb6 и dll, способы передачи строк

Сообщение  Eric-S в Ср Авг 13, 2008 2:02 am

Как известно, vb6 вызывает dll, руководствуясь некими особыми правилами, особа не интересуясь, что хочет программист.

Так например при декларации функции из внешней библиотеки

Код:

declare function test1 lib "mylib.dll" ( byVal s as string ) as long


А в своей dll на freebasic я пишу так:

Код:

function test1( byVal s as zstring ptr ) as integer export
messagebox 0, *s, "test", 1
end function

Причём в vb6 строка была в unicode, а получаю я её в ansi.

Как я понимаю, vb6 при декларации функции
Код:

declare function test1 lib "mylib.dll" ( s as string ) as long

Вместо указателя, будет уже передавать именно дескриптор строки.

вопрос 1: как мне в dll, принимать дескриптор (как объявлять функцию)?

Код:

function test1( byVal s as wstring ) as integer export

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Eric-S в Ср Авг 13, 2008 2:11 am

А если я хочу, чтобы моя функция возвращала тоже строку, как мне сиё прописать?

Вот объявление на vb6

Код:

declare function test2 lib "mylib.dll" () as string


msgbox test2()



В примере, используеться некий тип bstr, но что это такое, и как с ним работать я пока не очень понимаю.

вопрос 2:
как мне вернуть строчку для vb6?

вопрос 3:
что такое bstr, или где об этом можно узнать?
windows.bi видимо берёт этот тип из другого файла.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Eric-S в Ср Авг 13, 2008 2:16 am

Но по любому, как я понимаю нужна переконвертация строк в разные стороны.

вопрос 4:
Как добиться максимального быстродействия, при передаче и возврате строк из функции в dll.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Eric-S в Ср Авг 13, 2008 5:50 am

И так, вот что я узнал.

bstr это тип данных, который описывает дескриптор строки ole.

Самого объявления всё ещё не нашел в инклудах.

Да и синтаксис команд который работает с ним не очень понятен.
Нужно наверное рыть в сторону winApi.


Сам же дескриптор (опять же только предположение, ещё не тестировал).
dword - указатель на строку unicode в памяти.
dword - длина строки.
Поправте, если не прав.

А вот линк на схожую тему.
http://www.vbnet.ru/forum/show.aspx?id=62767

Хм, как бы теперь это перевести с ассемблера на freebasic.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Eric-S в Ср Авг 13, 2008 8:59 am

Получается такой странный диалог, я спрашиваю, а потом сам же отвечаю. Люди! Вы где? Именно для вас рассказываю, как проблема была решена. Всё было сверх просто.
Просто излишние действия в примере меня попутали.

Значит так, ставим тип bstr, as returned.
Код:

function myfunc() as bstr export
dim r as string = "Hello, world!"

function = SysAllocStringByteLen(strPtr(r), len(r) * 2 )
end function


Причём, chr$(0) в конце строчки не очень-то и нужен. Я его не ставил и всё нормально работало.

Что-то можно ещё делать с этими bstr, но я не знаю. Кто-нибудь киньте ссылочку на эти api с руским описанием.

А я пошел, тему можно считать закрытой.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  vbman в Вс Дек 07, 2008 4:15 pm

А чем Вам мешает передать из функции через один из параметров указатель на строку (как это делает та же GetWindowText), причем любую, а ВБ сам все сделает... А возврат строки именно как значения функции - тоже несложно: просто верните указатель на строку, а в ВБ объявите эту функцию как возвращающую строку. Не надо по пустому заморачиваться на БСТР и т. д. Работайте так, как Вам надо. На всякий случай можно воспользоваться АПИ-функциями типа MultiByteToWideString и т. д. если им нечего делать со строкой - они и не сделают. Просто вернут ее.
avatar
vbman

Сообщения : 52
Дата регистрации : 2008-11-19
Возраст : 35
Откуда : Украина, Кировоград

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Eric-S в Пн Дек 08, 2008 8:33 am

Да, конечно, это понятно. Так можно в принципе сделать.
Но тут две проблемки, во первых char freebasic и срфк vb6 не равны. Придёться всё равно конвертировать.
А во вторых, меня припёрли к стенке, требованием, чтобы vb6 код был стандартным.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  vbman в Сб Апр 25, 2009 2:23 pm

Вот нашел в МСДН формат строки в ВБ6. Описать ее можно такой структурой (на ФБ):

Type VBString
vbs_Len As UInteger
vbs_Buf As ZString*255
End Type

Хотя по документации буффер должен ,быть WString, но такая проблема возникла: MsgBox возвращает только первый символ. Выходит, что строка обрезается до первого нуля. А WString - это 2-байтовые символы, у них младший байт всегда код символа, а старший - всегда 0. Вот и выходит. Тогда возникла идея просто поместить вместо WString обычный АНСИ-набор сиволов, то есть однобайтовых. Тогда все нормально заработало. bounce rabbit

Теперь по формату строки:
1. Строка в VB состоит из 8 байт.
2. Первые 4 байта указывают на длину строки.
3. Вторые 4 байта указывают на буффер, в котором лежит сама строка.
4. Строковая переменная типа String в VB всегда указывает именно на этот буфер (не на сам буфер, а на его положение в памяти).
5. При обращении к строке VB всегда берет адрес, на который указывает переменная, вычетает из него 4 и читает длину строки (собственно, туда же указывает VarPtr по отношению к строкам).
6. Потом в память из буфера копируется столько байтов, сколько VB получил в шаге 5 и мы получаем строку.

На FreeBASIC код возврата строки будет такой:

Код:

#Pragma Once
#Include "windows.bi"

Type VBString
   vbs_Len As UInteger
   vbs_Buf As ZString*255
End Type

Extern "windows-ms"

   Function GetVBString()As Any Ptr Export
      'Выделяем память под строковую структуру
      Dim vbs As VBString Ptr = Allocate(SizeOf(VBString))
      
      'Заполняем ее
      With *vbs 'звезда нужна для того, что мы обращаемся в память
         .vbs_Len=11 'Реальная длина нашей строки (максимум 2 Гб)
         .vbs_Buf=Str("Привет, мир") 'Наша строка...
      End With
      Return(@vbs->vbs_Buf)'Возвращаем именно указатель на буфер
   End Function

End Extern

Теперь VB:

Код:

Private Declare Function GetVBString Lib "c:\strdll.dll" () As String

Sub ee()
    Dim s As String
    s = GetVBString()
    MsgBox s
End Sub

В итоге мы получаем наше сообщение:
bounce What a Face Exclamation
avatar
vbman

Сообщения : 52
Дата регистрации : 2008-11-19
Возраст : 35
Откуда : Украина, Кировоград

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Замабувараев в Вт Дек 09, 2014 4:19 am

Чтобы окончательно поставить точку в этом обсуждении и закрыть тему.

Строки внутри VB6 хранятся в виде юникода. Пока мы пользуемся голым VB6, мы можем хранить в строке любую гадость.

Всё меняется, когда применяются API. VB6 уверен, что все API принимают и возвращают исключительно ANSI-строки — это при том, что внутри VB строки хранятся исключительно в юникоде. У нас нет никакого шанса избежать двух конвертаций (одна по дороге туда, вторая — обратно) при передаче строки в качестве параметра, объявленного As String.

Однако, передача и получение юникодных строк при вызовах API хотя и сопряжены с определёнными сложностями, но осуществимы. Во всех случаях, где это возможно, передачи строк в API как As String следует избегать. Это единственный способ, позволяющий избежать копирования строк взад-вперёд – неизбежного при использовании функций WideChar—MultiByte и StrConv, и уж тем более при конвертировании руками, в цикле, по одному символу.

1. При передаче строки из VB6 внутрь API нужно использовать StrPtr, а в декларации заменить ByRef As String на ByVal As Long.
Соответственно, в самом коде на фрибейсике строку нужно принимать как WString Ptr.

2. Если мы принимает строку из API внутрь VB6, то в декларации нужно объявлять её также ByVal As Long. Так мы получаем указатель на строку, в терминологии фрибейсика это WString Ptr. Но как же в VB6 заполучить саму строку по её указателю?
Всё просто: выделяем строковый буфер размером lstrlenW и копируем в него строку по CopyMemory(StrPtr,,lstrlenW).

3. И самое главное: объявляем все работающие со строками API функции внутри VB6 с буковкой W на конце вместо A, а в коде на фрибейсике переключаемся на использование юникода объявлением #define unicode и используем нормальный WString или WString Ptr.
avatar
Замабувараев

Сообщения : 99
Дата регистрации : 2008-08-20
Возраст : 33
Откуда : Красноярск

Посмотреть профиль http://www.freebasic.su

Вернуться к началу Перейти вниз

Re: vb6 и dll, способы передачи строк

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения