Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 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-сайт: hw.t-k.ru
 Профиль | | #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 вызовет наезд на чужой кусок памяти со всеми вытекающими...

В общем делал так:

    invoke lstrlen,addr ANSIString
    mov edi,eax
    invoke SysAllocStringByteLen,addr ANSIString,edi
    invoke SysReAllocStringLen,hVBString,eax,edi


Т.е. сначала выделил строку и скопировал в неё ANSI, получил BSTR, затем сделал SysReAllocStringLen, чтобы переопределить полученную строку по адресу, полученному из VB-проги. При этом, согласно msdn, должен был быть заменен указатель VB-строки на новый, полученный от SysReAllocStringLen:

Allocates a new string, copies cch characters from the passed string into it, and then appends a null character. Frees the BSTR referenced currently by pbstr, and resets pbstr to point to the new BSTR.


Но че-то программа падает :(

Вызывал так:
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:

invoke lstrlen,SADD("ANSI from 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-сайт: basicproduction.nm.ru
 Профиль | | #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-сайт: hw.t-k.ru
 Профиль | | #7
Добавлено: 26.01.05 10:56
String переменная это тот же указатель, это есть DWORD значение указывающее на кусок памяти с данными и у которого StrPtr - 2/4 есть указание длинны строки....

Сейчас тоже попробую поэкспериментировать...

Ответить

Номер ответа: 8
Автор ответа:
 sne



Разработчик Offline Client

ICQ: 233286456 

Вопросов: 34
Ответов: 5445
 Web-сайт: hw.t-k.ru
 Профиль | | #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]

Option Explicit

Private Declare Function TestProc Lib "c.dll" (sStr As String) As String

Private Sub main()
    Dim a As String
    MsgBox TestProc(a)
    MsgBox a
End Sub


[/vb6]

Ответить

Номер ответа: 9
Автор ответа:
 sne



Разработчик Offline Client

ICQ: 233286456 

Вопросов: 34
Ответов: 5445
 Web-сайт: hw.t-k.ru
 Профиль | | #9
Добавлено: 26.01.05 11:36
SADD() - макрос что позволяет вставлять строку посреди кода...

Ответить

Номер ответа: 10
Автор ответа:
 cresta



Вопросов: 117
Ответов: 1538
 Профиль | | #10 Добавлено: 26.01.05 12:06
LamerOnLine

Для того и искал, чтобы не делать лишних движений вроде StrConv, чтобы не готовить буфер Redim'ом (или например String(1234,Chr(0)). Именно от этих вещей и хотел избавиться :) До сих пор как раз и применял код, аналогичный приведенному тобой.

SADD MACRO quoted_text:VARARG
   EXITM <ADDR literal(quoted_text)>
ENDM

Ответить

Номер ответа: 11
Автор ответа:
 CyRax



Разработчик Offline Client

ICQ: 204447456 

Вопросов: 180
Ответов: 4229
 Web-сайт: basicproduction.nm.ru
 Профиль | | #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-сайт: basicproduction.nm.ru
 Профиль | | #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 со своими копированиями и перегрузками строк и затяжками времени не вмешивался. Надо будет попробовать потестировать, как быстрее.

Ответить

Страница: 1 | 2 | 3 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам