Проблема с вызовом функции из DLL

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Проблема с вызовом функции из DLL

Сообщение Pasha 111 » 10.07.2003 (Чт) 12:07

Есть массив элементов типа MY_TYPE. Мне нужно передать его в качестве параметра в функцию из DLL (написана на C++).

Когда пишу "Declare Function MyFunc ..... (... Array() As MY_TYPE ...)", в функцию передается всякая мура.

Когда пишу "Declare Function MyFunc ..... (..., Array As MY_TYPE, ...)", и вызываю её, написав Call MyFunc(... Array(0) ....), передается только нулевой элемент, а затем опять мура. Как быть :?:

GoGosha
Постоялец
Постоялец
 
Сообщения: 642
Зарегистрирован: 02.08.2002 (Пт) 9:14
Откуда: Russia

Re: Проблема с вызовом функции из DLL

Сообщение GoGosha » 10.07.2003 (Чт) 12:13

Pasha 111 писал(а):Есть массив элементов типа MY_TYPE. Мне нужно передать его в качестве параметра в функцию из DLL (написана на C++).

Когда пишу "Declare Function MyFunc ..... (... Array() As MY_TYPE ...)", в функцию передается всякая мура.

Когда пишу "Declare Function MyFunc ..... (..., Array As MY_TYPE, ...)", и вызываю её, написав Call MyFunc(... Array(0) ....), передается только нулевой элемент, а затем опять мура. Как быть :?:


В Си++ параметр объявляй так: MYTYPE* param тоесть как ссылку
А в VB как ByRef Param и передавай первый элемент массива

Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Сообщение Pasha 111 » 10.07.2003 (Чт) 13:12

В Си++ параметр объявляй так: MYTYPE* param тоесть как ссылку
А в VB как ByRef Param и передавай первый элемент массива


Пишу в VB:

Код: Выделить всё
Declare ..... MyFunc(ByRef Param As MY_TYPE)

Dim Array(2) As MY_YPE
.....
Call MyFunc (Array(0))


В C++:

Код: Выделить всё
extern "C" __declspec(dllexport) int MyFunc(MY_TYPE* Param)
{
      ....
}


Ставлю брек поинт на 1ую строку функции и в Watch1 слежу за Param[0], Param[1] и Param[2]. При вызове функции, Param[0] - все OK, а остальное - мусор.

А зачем ByRef писать? VB ведь и так указатель передает?

corgi
ToyMan
ToyMan
 
Сообщения: 1367
Зарегистрирован: 01.10.2002 (Вт) 9:59
Откуда: Россия, Москва

Сообщение corgi » 10.07.2003 (Чт) 13:41

Call MyFunc (Array(0))

ты же так передаешь только нулевой элемент
вот так попробуй Call MyFunc (Array)
Ничто так не ограничивает полёт мысли программиста, как компилятор

GoGosha
Постоялец
Постоялец
 
Сообщения: 642
Зарегистрирован: 02.08.2002 (Пт) 9:14
Откуда: Russia

Сообщение GoGosha » 10.07.2003 (Чт) 13:41

код на СИ

MyDll.cpp
Код: Выделить всё
#include <windows.h>
#include <stdio.h>

#define CCONV _stdcall

int CCONV funk(MYTYPE* param)
{
   
}


MyDll.def
Код: Выделить всё
LIBRARY MyDll

EXPORTS
   funk   @1


на VB
Код: Выделить всё
Private Declare Function funk Lib= "MyDll"(param As MyType)
Dim Arrays(2) As MyType

...
   funk arrays(0)
...



всё должно работать(я с этим когдато тоже гемороился)
Последний раз редактировалось GoGosha 10.07.2003 (Чт) 13:47, всего редактировалось 1 раз.

GoGosha
Постоялец
Постоялец
 
Сообщения: 642
Зарегистрирован: 02.08.2002 (Пт) 9:14
Откуда: Russia

Сообщение GoGosha » 10.07.2003 (Чт) 13:45

corgi писал(а):Call MyFunc (Array(0))

ты же так передаешь только нулевой элемент
вот так попробуй Call MyFunc (Array)


Я сказал ByRef чтоб ты не поставил ByVal

А я передаю не нулевой элемент, а ссылку на нулевой элемент
т.е массивы в памяти хранятся подряд значение за значением и передавая ссылку на нулевой элемент мы как бы передаём ссылку на начало массива

Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Сообщение Pasha 111 » 10.07.2003 (Чт) 17:17

GoGosha
Написал все как ты сказал (так, в принципе и до этого было) - не работает. Вот окно Watch1:

Код: Выделить всё
Array[0]                                             MY_TYPE
   Name      0x0013db44 "1st array element text 1"   char *
   Comment   0x0013d4bc "1st array element text 2"   char *
   Content   0x0013df8c "1st array element text 3"   char *

Array[1]                                             MY_TYPE
   Name      0x1002ac10 "ѓм ЎxМSVѓшяWЗD$"         char *
   Comment   0x00000003 <Bad Ptr>                     char *
   Content   0x00390484 <Bad Ptr>                     char *

Array[2]                                             MY_TYPE
   Name      0x00000080 <Bad Ptr>                     char *
   Comment   0x66022753 "‹Шf…Ы…№I"                  char *
   Content   0x00004008 <Bad Ptr>                     char *



В принципе на худой конец можно сделать в DLL'ке функцию типа CreateArray() и в цикле попередавать туда по одному элементы, указывая номер, но это слишком сложно и хотелось бы нормальным способом.

Слушай, а если у тебя все работало, может пришлеш исходник? Интересно, может это я где-то не то написал и даже не замечаю.

GoGosha
Постоялец
Постоялец
 
Сообщения: 642
Зарегистрирован: 02.08.2002 (Пт) 9:14
Откуда: Russia

Сообщение GoGosha » 10.07.2003 (Чт) 17:25

Pasha 111 писал(а):GoGosha
Написал все как ты сказал (так, в принципе и до этого было) - не работает. Вот окно Watch1:

Код: Выделить всё
Array[0]                                             MY_TYPE
   Name      0x0013db44 "1st array element text 1"   char *
   Comment   0x0013d4bc "1st array element text 2"   char *
   Content   0x0013df8c "1st array element text 3"   char *

Array[1]                                             MY_TYPE
   Name      0x1002ac10 "ѓм ЎxМSVѓшяWЗD$"         char *
   Comment   0x00000003 <Bad Ptr>                     char *
   Content   0x00390484 <Bad Ptr>                     char *

Array[2]                                             MY_TYPE
   Name      0x00000080 <Bad Ptr>                     char *
   Comment   0x66022753 "‹Шf…Ы…№I"                  char *
   Content   0x00004008 <Bad Ptr>                     char *



В принципе на худой конец можно сделать в DLL'ке функцию типа CreateArray() и в цикле попередавать туда по одному элементы, указывая номер, но это слишком сложно и хотелось бы нормальным способом.

Слушай, а если у тебя все работало, может пришлеш исходник? Интересно, может это я где-то не то написал и даже не замечаю.


Да, хорошо. Но примерчик на VB чисто тестовый ссылается на некоторые картинки на моём харде. Так значит там функе PSet передаётся массив цветов пикселей

Я думаю что это не работает из-за переменных нефиксированной длинны вместо name as string юзай name as string * 255 и т. п.

Мыло только дай

Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Сообщение Pasha 111 » 11.07.2003 (Пт) 12:00

GoGosha, я получил твой пример, спасибо. Тока у тебя там передается только массив байтов и структура, но одна, а не массив.

Вот прога, где у меня баг:
http://prs.narod.ru/test.rar

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Сообщение Vi » 11.07.2003 (Пт) 17:15

Проще всего передавать массив из VB как есть: или через Variant (VARIANT), или через Type() (SAFEAARRAY(Type)). И уж в С++ разбираться с этим массивом - там, по-моему, всего-то один-два оператора. Однако проблем с передачей точно не будет.

SAFEARRAY * psa = ... получить ...;
MY_TYPE * psadata = NULL;
HRESULT hr = ::SafeArrayAccessData(psa, (void**)&psadata);
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Сообщение Pasha 111 » 11.07.2003 (Пт) 19:25

Vi
Проще всего передавать массив из VB как есть: или через Variant (VARIANT), или через Type() (SAFEAARRAY(Type)). И уж в С++ разбираться с этим массивом - там, по-моему, всего-то один-два оператора. Однако проблем с передачей точно не будет.

SAFEARRAY * psa = ... получить ...;
MY_TYPE * psadata = NULL;
HRESULT hr = ::SafeArrayAccessData(psa, (void**)&psadata);


А значение psa получать надо из SafeArrayCreate() ? А как ее юзать? И вообще, как это все работает?

Я тут подумал: VB ведь правильно передат массивы типа byte. Поэтому я переделал код формы так :D :

Код: Выделить всё
Private Type MY_TYPE
    Name As String
    Type As Long
    Comment As String
    Content As String
End Type

Private Declare Function TestFunc Lib "Test.dll" (ByRef Massiv As Byte) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Private Sub Form_Load()
Dim arr(2) As MY_TYPE

arr(0).Name = "1st array element text 1"
arr(0).Comment = "1st array element text 2"
arr(0).Type = 1
arr(0).Content = "1st array element text 3"

arr(1).Name = "2nd array element text 1"
arr(1).Comment = "2nd array element text 2"
arr(1).Type = 2
arr(1).Content = "2nd array element text 3"

arr(2).Name = "3rd array element text 1"
arr(2).Comment = "3rd array element text 2"
arr(2).Type = 3
arr(2).Content = "3rd array element text 3"

Dim i As Long
ReDim byte_arr(Len(arr(0)) * (UBound(arr) + 1)) As Byte
For i = 0 To UBound(arr)
    CopyMemory byte_arr(Len(arr(0)) * i), arr(i), Len(arr(0))
Next i

Call TestFunc(byte_arr(0))
End Sub


Т.е. передаю в функцию, которая ждет указатель типа MY_TYPE, указатель на BYTE. Запускаю и смотрю что получилось... А получилось так, что почему-то все ячейки саммива заняты ТРЕТЬИМ ЭЛЕМЕНТОМ!!!!! :cry: Т.е. в Watch1 все 3 элемента массива одинаковы и содержат:
"3rd array element text 1"
"3rd array element text 2"
3
"3rd array element text 3"

В чем дело? :cry:

Pasha 111
Начинающий
Начинающий
 
Сообщения: 15
Зарегистрирован: 31.12.2002 (Вт) 14:47
Откуда: Москва

Сообщение Pasha 111 » 11.07.2003 (Пт) 21:47

Вообщем, я так понял, проблема нерешабельна :evil:

Просто в моей проге есть функция WriteDoc(), в которую я передаю массив эелементов моего типа. Прога сначала пишет в указанный файл его заголовок (для идентификации), а потом все эти элементы. Раз не получилось передавать массив, то в таком случае просто сделаю 2 функции: CreateDoc() - будет создавать файл и писать в него заголовок, и WriteElement() - пишет по полученному дескриптору в CreateDoc() переданный элемент моего типа. Я предполагал, что файл из VB можно будет сохранить вызовом только 1й функции, т.е 1й строкой. Что ж, это нужно будет делать четырьмя строками кода :| Зато теперь моя DLL'ка будет более гибкой при программировании :wink:
Спасибо всем, кто пытался помочь!


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот, SemrushBot и гости: 25

    TopList