vb6 и dll, способы передачи строк
Участников: 3
FreeBasic :: Программирование :: Общее
Страница 1 из 1
vb6 и dll, способы передачи строк
Как известно, vb6 вызывает dll, руководствуясь некими особыми правилами, особа не интересуясь, что хочет программист.
Так например при декларации функции из внешней библиотеки
А в своей dll на freebasic я пишу так:
Причём в vb6 строка была в unicode, а получаю я её в ansi.
Как я понимаю, vb6 при декларации функции
Вместо указателя, будет уже передавать именно дескриптор строки.
вопрос 1: как мне в 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
Re: vb6 и dll, способы передачи строк
А если я хочу, чтобы моя функция возвращала тоже строку, как мне сиё прописать?
Вот объявление на vb6
В примере, используеться некий тип bstr, но что это такое, и как с ним работать я пока не очень понимаю.
вопрос 2:
как мне вернуть строчку для vb6?
вопрос 3:
что такое bstr, или где об этом можно узнать?
windows.bi видимо берёт этот тип из другого файла.
Вот объявление на vb6
- Код:
declare function test2 lib "mylib.dll" () as string
msgbox test2()
В примере, используеться некий тип bstr, но что это такое, и как с ним работать я пока не очень понимаю.
вопрос 2:
как мне вернуть строчку для vb6?
вопрос 3:
что такое bstr, или где об этом можно узнать?
windows.bi видимо берёт этот тип из другого файла.
Re: vb6 и dll, способы передачи строк
Но по любому, как я понимаю нужна переконвертация строк в разные стороны.
вопрос 4:
Как добиться максимального быстродействия, при передаче и возврате строк из функции в dll.
вопрос 4:
Как добиться максимального быстродействия, при передаче и возврате строк из функции в dll.
Re: vb6 и dll, способы передачи строк
И так, вот что я узнал.
bstr это тип данных, который описывает дескриптор строки ole.
Самого объявления всё ещё не нашел в инклудах.
Да и синтаксис команд который работает с ним не очень понятен.
Нужно наверное рыть в сторону winApi.
Сам же дескриптор (опять же только предположение, ещё не тестировал).
dword - указатель на строку unicode в памяти.
dword - длина строки.
Поправте, если не прав.
А вот линк на схожую тему.
http://www.vbnet.ru/forum/show.aspx?id=62767
Хм, как бы теперь это перевести с ассемблера на freebasic.
bstr это тип данных, который описывает дескриптор строки ole.
Самого объявления всё ещё не нашел в инклудах.
Да и синтаксис команд который работает с ним не очень понятен.
Нужно наверное рыть в сторону winApi.
Сам же дескриптор (опять же только предположение, ещё не тестировал).
dword - указатель на строку unicode в памяти.
dword - длина строки.
Поправте, если не прав.
А вот линк на схожую тему.
http://www.vbnet.ru/forum/show.aspx?id=62767
Хм, как бы теперь это перевести с ассемблера на freebasic.
Re: vb6 и dll, способы передачи строк
Получается такой странный диалог, я спрашиваю, а потом сам же отвечаю. Люди! Вы где? Именно для вас рассказываю, как проблема была решена. Всё было сверх просто.
Просто излишние действия в примере меня попутали.
Значит так, ставим тип bstr, as returned.
Причём, chr$(0) в конце строчки не очень-то и нужен. Я его не ставил и всё нормально работало.
Что-то можно ещё делать с этими bstr, но я не знаю. Кто-нибудь киньте ссылочку на эти api с руским описанием.
А я пошел, тему можно считать закрытой.
Просто излишние действия в примере меня попутали.
Значит так, ставим тип 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 с руским описанием.
А я пошел, тему можно считать закрытой.
Re: vb6 и dll, способы передачи строк
А чем Вам мешает передать из функции через один из параметров указатель на строку (как это делает та же GetWindowText), причем любую, а ВБ сам все сделает... А возврат строки именно как значения функции - тоже несложно: просто верните указатель на строку, а в ВБ объявите эту функцию как возвращающую строку. Не надо по пустому заморачиваться на БСТР и т. д. Работайте так, как Вам надо. На всякий случай можно воспользоваться АПИ-функциями типа MultiByteToWideString и т. д. если им нечего делать со строкой - они и не сделают. Просто вернут ее.
vbman- Сообщения : 52
Дата регистрации : 2008-11-19
Возраст : 42
Откуда : Украина, Кировоград
Re: vb6 и dll, способы передачи строк
Да, конечно, это понятно. Так можно в принципе сделать.
Но тут две проблемки, во первых char freebasic и срфк vb6 не равны. Придёться всё равно конвертировать.
А во вторых, меня припёрли к стенке, требованием, чтобы vb6 код был стандартным.
Но тут две проблемки, во первых char freebasic и срфк vb6 не равны. Придёться всё равно конвертировать.
А во вторых, меня припёрли к стенке, требованием, чтобы vb6 код был стандартным.
Re: vb6 и dll, способы передачи строк
Вот нашел в МСДН формат строки в ВБ6. Описать ее можно такой структурой (на ФБ):
Type VBString
vbs_Len As UInteger
vbs_Buf As ZString*255
End Type
Хотя по документации буффер должен ,быть WString, но такая проблема возникла: MsgBox возвращает только первый символ. Выходит, что строка обрезается до первого нуля. А WString - это 2-байтовые символы, у них младший байт всегда код символа, а старший - всегда 0. Вот и выходит. Тогда возникла идея просто поместить вместо WString обычный АНСИ-набор сиволов, то есть однобайтовых. Тогда все нормально заработало.
Теперь по формату строки:
1. Строка в VB состоит из 8 байт.
2. Первые 4 байта указывают на длину строки.
3. Вторые 4 байта указывают на буффер, в котором лежит сама строка.
4. Строковая переменная типа String в VB всегда указывает именно на этот буфер (не на сам буфер, а на его положение в памяти).
5. При обращении к строке VB всегда берет адрес, на который указывает переменная, вычетает из него 4 и читает длину строки (собственно, туда же указывает VarPtr по отношению к строкам).
6. Потом в память из буфера копируется столько байтов, сколько VB получил в шаге 5 и мы получаем строку.
На FreeBASIC код возврата строки будет такой:
Теперь VB:
В итоге мы получаем наше сообщение:
Type VBString
vbs_Len As UInteger
vbs_Buf As ZString*255
End Type
Хотя по документации буффер должен ,быть WString, но такая проблема возникла: MsgBox возвращает только первый символ. Выходит, что строка обрезается до первого нуля. А WString - это 2-байтовые символы, у них младший байт всегда код символа, а старший - всегда 0. Вот и выходит. Тогда возникла идея просто поместить вместо WString обычный АНСИ-набор сиволов, то есть однобайтовых. Тогда все нормально заработало.
Теперь по формату строки:
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
В итоге мы получаем наше сообщение:
vbman- Сообщения : 52
Дата регистрации : 2008-11-19
Возраст : 42
Откуда : Украина, Кировоград
Re: vb6 и dll, способы передачи строк
Чтобы окончательно поставить точку в этом обсуждении и закрыть тему.
Строки внутри 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.
Строки внутри 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.
FreeBasic :: Программирование :: Общее
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения
|
|