Страница: 1 | 2 | 3 |
Вопрос: Вопрос наоборот
Добавлено: 25.01.05 22:56
Автор вопроса: cresta
Вот все спрашивают: "Как передать какой-нибудь параметр в dll?"
У меня же появился вопрос: "Как из dll передать в VB-программу строку?"
Поясню: процедура в dll работает со строкой. Очень длинной. Более 65256 байт. Поэтому в бейсиковый As String*const не влезает, т.к. строка фиксированной длины в VB не может быть длиннее 65256. А мне надо передать из dll строку так, чтобы её VB опознавал As String (не фиксированной длины)
Dim S As String
Call SomeProcInDll (ByVal S)
и как мне её заполнить, эту строку, вернее как растянуть под имеющийся объем данных, которые необходимо вернуть в S? Так чтобы VB нормально понял эту строку?
Ответы
Всего ответов: 31
Номер ответа: 1
Автор ответа:
sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #1
Добавлено: 26.01.05 00:52
Думается что нужно копать в сторону:
SysAllocString
SysAllocStringByteLen
SysAllocStringLen
SysFreeString
SysReAllocString
SysReAllocStringLen
SysStringByteLen
SysStringLen
могу и ошибаться но работают с BSTR строками...
Номер ответа: 2
Автор ответа:
cresta
Вопросов: 117
Ответов: 1538
Профиль | | #2
Добавлено: 26.01.05 02:46
Ну допустим, SysAllocStringByteLen копирует ANSI строку в BSTR строку и возвращает указатель на неё. Это понятно. Допустим я перевел свою строку в BSTR формат и получил указатель на неё. Что с этим указателем делать? Как заставить VB-программу напечатать эту строку, имея только указатель на неё? Если сделать Dim S As String, то S будет пустая, и попытка скопиривать свою строку в S вызовет наезд на чужой кусок памяти со всеми вытекающими...
В общем делал так:
mov edi,eax
invoke SysAllocStringByteLen,addr ANSIString,edi
invoke SysReAllocStringLen,hVBString,eax,edi
Т.е. сначала выделил строку и скопировал в неё ANSI, получил BSTR, затем сделал SysReAllocStringLen, чтобы переопределить полученную строку по адресу, полученному из VB-проги. При этом, согласно msdn, должен был быть заменен указатель VB-строки на новый, полученный от SysReAllocStringLen:
Но че-то программа падает
Вызывал так:
Dim FindString As String
SomeProcInDll ByVal FindString
c декларациями порядок.
Номер ответа: 3
Автор ответа:
cresta
Вопросов: 117
Ответов: 1538
Профиль | | #3
Добавлено: 26.01.05 03:08
Гы, вылез каменный цветок
Может кому понадобится:
'Объявление:
Declare Function GetString Lib "MyLib" () As String
'Вызов:
MsgBox GetString()
В dll:
mov ebx,eax
invoke SysAllocStringByteLen,SADD("ANSI from dll",ebx
'в eax возвращаем адрес от SysAllocStringByteLen
'VB поймет это как функцию, объявленную As String
ret
Номер ответа: 4
Автор ответа:
CyRax
Разработчик Offline Client
ICQ: 204447456
Вопросов: 180
Ответов: 4229
Web-сайт:
Профиль | | #4
Добавлено: 26.01.05 05:37
А SADD() это что такое?
Номер ответа: 5
Автор ответа:
LamerOnLine
ICQ: 334781088
Вопросов: 108
Ответов: 2822
Профиль | | #5
Добавлено: 26.01.05 07:53
Так зачем передавать ссылку на строку? Передавай ссылку на массив байт, а затем делай этому массиву StrConv(Massive(),VBUnicode). Для задания размерности массива узнай длинну null-terminated строки через lstrlen или lstrlenW.
Номер ответа: 6
Автор ответа:
LamerOnLine
ICQ: 334781088
Вопросов: 108
Ответов: 2822
Профиль | | #6
Добавлено: 26.01.05 08:15
В принципе, пост N3 должен работать. Однако, ИМХО, лучше сделать вызов функции в стандарте C.
Option Explicit
Option Base 1
Declare Function GetString Lib "MyLib" (ByRef Buffer() As Byte, ByRef BuffLen As Long) As Long
Dim Buffer() As Byte
Private Sub Form_Load()
Dim Ret As Long
Dim BuffLen As Long
Dim MyStr As String
ReDim Buffer(0)
GetString Buffer, BuffLen 'При нехватке буфера возвращает требуемую длину в BuffLen
ReDim Buffer(BuffLen) 'Переопределяем размер буфера
Ret = GetString(Buffer, BuffLen) 'В Buffer копируется строка, в Ret - код ошибки.
MyStr = StrConv(Buffer, vbUnicode) 'Буфер конвертится в строку.
End Sub
Немного длиннее, но зато привычнее. Кроме того, не будет проблем с использованием этой dll с другими компиляторами.
Номер ответа: 7
Автор ответа:
sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #7
Добавлено: 26.01.05 10:56
String переменная это тот же указатель, это есть DWORD значение указывающее на кусок памяти с данными и у которого StrPtr - 2/4 есть указание длинны строки....
Сейчас тоже попробую поэкспериментировать...
Номер ответа: 8
Автор ответа:
sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #8
Добавлено: 26.01.05 11:33
[asm]
.486
.model flat, stdcall
option casemap: none
include windows.inc
include kernel32.inc
include oleaut32.inc
includelib kernel32.lib
includelib oleaut32.lib
.data
tst_str db "My test string", 0h
.code
DllMain proc hInst: DWORD, dwReserved: DWORD, fdReason: DWORD
mov al, 1h
ret
DllMain endp
TestProc proc lpOutString: DWORD
invoke lstrlen, offset tst_str
invoke SysAllocStringByteLen, offset tst_str, eax
mov edx, lpOutString
mov dword ptr [edx], eax
ret
TestProc endp
end DllMain
[/asm]
[vb6]
Private Declare Function TestProc Lib "c.dll" (sStr As String) As String
Private Sub main()
Dim a As String
MsgBox TestProc
MsgBox a
End Sub
[/vb6]
Номер ответа: 9
Автор ответа:
sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #9
Добавлено: 26.01.05 11:36
SADD() - макрос что позволяет вставлять строку посреди кода...
Номер ответа: 10
Автор ответа:
cresta
Вопросов: 117
Ответов: 1538
Профиль | | #10
Добавлено: 26.01.05 12:06
LamerOnLine
Для того и искал, чтобы не делать лишних движений вроде StrConv, чтобы не готовить буфер Redim'ом (или например String(1234,Chr(0)). Именно от этих вещей и хотел избавиться До сих пор как раз и применял код, аналогичный приведенному тобой.
EXITM <ADDR literal(quoted_text)>
ENDM
Номер ответа: 11
Автор ответа:
CyRax
Разработчик Offline Client
ICQ: 204447456
Вопросов: 180
Ответов: 4229
Web-сайт:
Профиль | | #11
Добавлено: 26.01.05 13:02
Что то типа:
MOV EAX, Offset MyString
MyString DB "ANSI from dll"
Номер ответа: 12
Автор ответа:
LamerOnLine
ICQ: 334781088
Вопросов: 108
Ответов: 2822
Профиль | | #12
Добавлено: 26.01.05 13:50
cresta, ну так не делай. Возвращай из функции указатель на строку, затем lstrlen - определяешь длину строки, далее через Space() создаешь строку такой же длины и через lstrcpy копируешь содержимое. Извратно, зато весело
Номер ответа: 13
Автор ответа:
LamerOnLine
ICQ: 334781088
Вопросов: 108
Ответов: 2822
Профиль | | #13
Добавлено: 26.01.05 13:52
Хотя, если уж так - просто делаешь строку типа MyStr=Space(75000) и передаешь её ByVal
Номер ответа: 14
Автор ответа:
CyRax
Разработчик Offline Client
ICQ: 204447456
Вопросов: 180
Ответов: 4229
Web-сайт:
Профиль | | #14
Добавлено: 26.01.05 13:53
[asm]
.486
Кстати директива .486 в этом коде совсем не обязательна. Можно её заменить на .386
Номер ответа: 15
Автор ответа:
cresta
Вопросов: 117
Ответов: 1538
Профиль | | #15
Добавлено: 26.01.05 15:50
>MOV EAX, Offset MyString
>MyString DB "ANSI from dll"
Это больше похоже на макрос CTXT, но принцип примерно такой.
LamerOnLine
Действительно извратно А делать MyStr=Space(75000) - двойная работа (соответственно двойная затрата времени). Первый раз забиваем пробелами, второй раз поверх пробелов забиваем полезную инфу. Плюс ещё существенный момент: а если неизвестно заранее, какова будет длина возвращаемой строки? Выделять 2 Гб пробелов? Чтобы наверняка хватило Опять же это время, время, время...
И заодно это попытка вместо VB самому подготовить строку, чтобы VB со своими копированиями и перегрузками строк и затяжками времени не вмешивался. Надо будет попробовать потестировать, как быстрее.