Передача данных в VB

Тема в разделе "WASM.BEGINNERS", создана пользователем OFFSIDE, 23 сен 2006.

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Выделить память под строку любым удобным способом. Правда все остальные способы типа VirtualAlloc, HeapAlloc будут очень неудобными с учётом того, что тут задействован VB со своей переменной типа As String. Этот тип просто заставляет использовать SysAllocStringByteLen. Хотя можно использовать и VirtualAlloc, но при этом кода будет написано значительно больше.
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    cresta
    Память, выделенная VirtualAlloc не будет освобождаться в VB, а вот Heap и Global вполне можно юзать и все "лишние телодвижения" при замене SysAllocStringByteLen например на GlobalAlloc сводятся всего к добавлению пары строчек
    В твоем примере:
    Код (Text):
    1.     ...
    2.     lea      edi,[ebx+eax+5]
    3.     invoke GlobalAlloc 0, edi
    4.     sub     edi,5
    5.     mov    [eax],edi
    6.     lea      edi,[eax+4]
    7.     ...
    А если эти строчки в процедурку оформить типа vbStrAlloc, то и вовсе будет тоже самое ;)
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    ага, только ты забыл ещё vb-часть дописать :)

    Dim retString As String
    Dim strAddr As Long

    'тут получаем из dll строку
    retString = bla-bla.
    'тут восстанавливаем адрес, полученый от GlobalAlloc
    strAddr = StrPtr(bla-bla-bla) - 4
    'тут освобождаем её:
    GlobalFree (strAddr)

    ну и плюс твои "пара строчек".
    Зачем все это, если vb позволяет обойтись без всего этого?
    Если хочется мазохизма, то можно к примеру драйвер написать, там выделить nonPaged память, соединить в ней строки, затем скопировать результат в shared section, взвести event, чтобы vb забрал эту секцию, и т.д. и т.п.
    Способов можно миллион придумать, вот только удобней и проще чем SysAlloc ничего не получится :)
     
  4. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    cresta
    Да с чего ты это взял ? За чистый VB ручаться не могу (не проверял), а вот к примеру VBA MS Word сам прекрасно освобождает память, выделенную Heap\GlobalAlloc. Можешь сам проверить, добавив в dll функцию контроля выделенного блока
    Код (Text):
    1. --------- dll ------------
    2. .data
    3.   saveptr dd 0
    4.   sfree db 0,0,0,0,"???",0
    5.   fmt db "Len = %d",13,10,"Str = %s",0
    6.   caption db "CheckStrPtr",0
    7.   msg db 256 dup (0)
    8.  
    9. SomeFunc proc ...
    10.   ...
    11.   invoke GlobalAlloc 0, edi  
    12.   mov saveptr, eax  ;сохраняем указатель для контроля
    13.   ...
    14. SomeFunc endp
    15.  
    16. CheckStrPtr proc uses ebx
    17.   mov eax,saveptr
    18.   lea ebx, [sfree+4]
    19.   test eax,eax
    20.   je @F
    21.   invoke GlobalFlags,eax
    22.   cmp eax,GMEM_INVALID_HANDLE
    23.   je @F
    24.   mov ebx,saveptr
    25.   add ebx,4
    26. @@:
    27.   invoke wsprinf, addr msg, addr fmt,[ebx-4],ebx
    28.   ;add esp,4*4
    29.   invoke MessageBox,0,addr msg,addr caption,0
    30.   ret
    31. CheckStrPtr endp
    32.  
    33. --------- VB ------------
    34. sub XXX ()
    35.   Dim S as string
    36.   S = SomeFunc(...)
    37.   CheckStrPtr  'блок занят строкой, возвращаемой SomeFunc
    38.   MsgBox S
    39.   'S = ""
    40.   CheckStrPtr  'блок свободен или перезаписан другими данными
    41. end sub
    42.  
    43. sub YYY ()     'для надеги можно проверить отдельно
    44.   CheckStrPtr
    45. end sub
    Ну это как посмотреть ;) Если бы SysAlloc сидела в kernel32, то конечно незачем, а вот ради экономии двух строчек цеплять oleout32 если тот же vb позволяет обойтись без этого - кому-то может показаться излишеством
    И потом использование Heap\Global позволяет например не только возвращать строку из функции, но и перезаписывать строку, переданную ByRef - простым Realloc (хотя сисами наверное тоже можно ;)
     
  5. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    А есть ли возможность передавать в ВБ массив (строк или чисел) приблизительно так?

    Код (Text):
    1. Declare Function Conversion(ByVal inputData as long,ByRef outputData() as long) as long
    2.  
    3. Private D() as long
    4.  
    5. Sub XXX()
    6. Dim i as long
    7. di=12.3E+12
    8. Conversion di,D
    9. For i=0 to Ubound(D)
    10. Me.Print ,i,CStr(D(i))
    11. Next
    12. End Sub
    То есть передать в длл-ку неинициализированный массив, а получить на выходе обработанные данные в массиве.
     
  6. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    OFFSIDE
    Ну если ты уже разобрался со структуами BSTR\ABSTR, то теперь можешь смело браться и за SafeArray ;))
     
  7. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    leo

    Не могу вернуть значение:


    Код (Text):
    1. StrProc proc stroka:dword,stroka1:dword
    2. mov eax,stroka
    3. mov stroka1,eax
    4. ret
    5. StrProc Endp
    Код (Text):
    1. Declare Function StrProc(ByVal inputData as String,ByRef outputData as String) as long
    2.  
    3. Private D as String
    4.  
    5. Sub XXX()
    6. Dim Di as String
    7. di="Бла-Бла"
    8. StrProc di,D
    9. Me.Print D
    10. End Sub
    Как сделать возврат в приложение?
     
  8. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    Нашел ответ ):

    Код (Text):
    1. StrProc proc stroka:dword,stroka1:dword
    2. mov esi,[stroka1]
    3. mov eax,stroka
    4. mov [esi],eax
    5. ret
    6. StrProc Endp
     
  9. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Видимо, ты и в асме не очень-то разобрался.
     
  10. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    Сами догадалися? :)
    Не зря яж в бегиннерс посты засылаю. Ваша помощь неоценима:

    Код (Text):
    1. StrTest proc Str1:dword,Str2:dword
    2. mov esi,[Str2]
    3. mov ebx,[esi]
    4. invoke szRemove,Str1,Str1,ebx
    5. invoke lstrlen,Str1
    6. invoke SysAllocStringByteLen,NULL,eax
    7. invoke lstrcpy,eax,Str1
    8. mov [esi],eax
    9. ret
    10. StrTest endp
     
  11. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Если по смыслу, то лучше назвать их pStr1, ppStr2.

    Проще invoke SysAllocStringByteLen,Str1,eax
    Система сама скопирует строку. Читай справку что ли.
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    OFFSIDE
    Молодец, часть ответа нашел ;) Но такая прямая перезапись указателя может приводить к утечке памяти. По хорошему нужно делать проверку [esi] - если не равно 0 (NULL) и не равно указателю на первую ByVal строку, то нужно освободить память, иначе после перезаписи указателя старый блок памяти так и останется висеть в куче.
    А указатель [esi]=0 будет только для неициализированной строки, если же ей что-нибудь присвоить, хоть S="", то под стоку выделяется память и ее нужно освобождать перед изменением указателя

    Как можно освобождать\выделять память под ByRef строку и изменять ее длину не используя SysXXX (ой, боюсь cresta будет ругаться ;)
    Если ты еще не понял, как устроена ABSTR, то вот подсказка: ByRef Str2 это указатель на указатель, т.е.
    mov esi, [Str2] ;esi - указатель на указатель
    mov ebx,[esi] ;ebx - указатель на ASCIIZ строку, он передается при ByVal
    lea edi,[ebx-4] ;edi - указатель на дворд длины строки = начало блока памяти для Heap\GlobalFree
    mov ecx,[edi] == mov ecx,[ebx-4] ;ecx - длина строки без учета замык.нуля

    Т.е. перед строкой находится дворд, в котором хранится длина строки, и указатель на этот дворд (edi = ebx-4) и является началом выделенного блока памяти. Если строка объявлена как ByVal, то структура остается той же самой, просто в функцию передается сразу значение ebx (но перед ним все равно сидит дворд длины)
    В твоих примерах #22,23 строка возвращалась с мусором в конце, т.к. ты укорачивал строку, но не уменьшал ее длину - если длина стала меньше, то нужно записать новое значение по смещению (-4) от указателя на строку. Если длина становится больше, то на старое место ее писать опасно - нужно освобождать старый блок по адресу edi=ebx-4, выделять новый блок и записывать в него сначала дворд длины, а затем символы строки с замык.нулем. При этом в [esi] или в eax, если возврат идет через функцию As String, нужно записывать ес-но указатель на первый символ строки, т.е. +4 от начала блока
     
  13. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    leo

    Хитро, весьма кстати. А можно вопрос - почему -4? Длина строки - дворд? И еще - почему если вызвать из вб LoadLibrary и FreeLibrary память не освобождается?
     
  14. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    IceStudent

    Спасибо за указание. По масму даже встроеный хелп весьма хилый, а MSDN весь перечитать - долго и нудно. Но необходимость есть, я это понимаю. И повторюсь - ВАШ опыт весьма ценен. Ваша помощь мне нужна, так как кодить на асме собираюсь вместо поднадоевшего вб, а си я не знаю, и знать не хочу... Может и зря, но учить еще один язык(Си) как-то впадло... Пусть уж будет Ассемблер.
     
  15. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Да.

    Какая память? LoadLibrary для загрузки библиотек.

    Не надо весь. Можно просто справку смотреть по конкретной функции.

    А придётся, т.к. в MSDN примеры на сях, много сорцов на нём и, наконец, заголовочные файлы со структурами и константами.
     
  16. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    Надо еще и знать, какой функции... ;)
    Сажусь за СИ

    Страдаю косноязычием. Не выгружается созданная мной библиотека из адресного пространства процесса. Смотрю процесс эксплорероом.
     
  17. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Если библиотека была загружена, LoadLibrary увеличивает счётчик ссылок и одним FreeLibrary не обойтись. Или проверь, что возвращает FreeLibrary и GetLastError.
     
  18. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    Код (Text):
    1. Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
    2. Const LANG_NEUTRAL = &H0
    3. Private Declare Function StrProc Lib "testdll.dll" (ByVal stroka As String, stroka1 As String) As Long
    4. Private Declare Function GetLastError Lib "kernel32" () As Long
    5. Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
    6. Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
    7. Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
    8.  
    9. Private Sub Cmd_Click()
    10. Dim c As Long, e As Long, buffer As String
    11. buffer = Space(200)
    12. c = LoadLibrary("testdll.dll")
    13. Dim k As String
    14. k = " "
    15. StrProc "ds gg hf g", k
    16. Me.Print k
    17. e = FreeLibrary(c)
    18. MsgBox e
    19. FormatMessage FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, GetLastError, LANG_NEUTRAL, buffer, 200, ByVal 0&
    20. MsgBox buffer
    21. End Sub
    Возвращает 1, GetLastError = 0... Но из процесса ссылка на ддл-ку не уходит...

    А что нужно еще?
     
  19. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    OFFSIDE
    Я не знаю VB, но вот эта строка, судя по остальным, не просто объявляет функцию, а и импортирует её.

    Кстати, попутный вопрос. Если библиотека загружена лоадером, её нельзя выгрузить через FreeLibrary(GetModuleHandle("lib.dll")) ? У меня не получилось, FreeLibrary возвращает true, но библиотека не выгружается.

    --
    Разобрался, лоадер кеширует загруженные библиотеки и помечает те, которые были загружены не явно, а для таблицы импорта. Поэтому и не даёт выгрузить последние.
     
  20. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    IceStudent

    Хотелось бы подгрузить длл-ку и освободить ее после выполнения кода(как к примеру, стелс - вирус), чтобы ушастый юзер не мог увидеть ее никоим образом...