Модераторы: mihanik
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> VBA и DLL, Как вернуть в VBA результат из DLL 
:(
    Опции темы
Dementor
Дата 11.2.2016, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



И снова всем привет!

Возникла проблема связывания макроса на VBA с DLL, которая пишется на C++.

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

Итак в чем суть: есть макрос на VBA, который пишется под Microstation, и DLL, которая фактически реализует возможности General Polygon Clipper.

В DLL пока есть одна функция, доступная для VBA, которая на входе получает два SAFEARRAY и один gpc_polygon, который в итоге, по моему мнению, она и должна заполнить.

Как выглядит сама функция в DLL (ее внутренности не привожу, т.к. особого смысла в этом нет):
Код

int __stdcall GPC::ClipPolygons(SAFEARRAY **Master, SAFEARRAY **Slave, gpc_polygon *Result)


Из VBA в качестве Master и Slave подаются массивы Point3d (это тип данных, состоящий из 3-х double), которые сама DLL переводит в gpc_polygon, для того чтобы уже их отдать General Polygon Clipper для обработки. В итоге работы General Polygon Clipper мы получаем еще один gpc_polygon, который и должны как-то вернуть в макрос VBA.

Вопрос именно в том как этот gpc_polygon вернуть. Я предполагал, что за это будет отвечать тот самый *Result, но к сожалению это не работает. Как я понимаю не работает по причине того, что сам gpc_polygon внутри себя содержит динамические массивы и соответственно VBA у меня на этом и падает, выдавая ошибку. При этом в том же gpc_polygon есть и обычная переменная num_contours, которая вполне нормально может быть возвращена через gpc_polygon  *Result.

Сам тип gpc_polygon я реализовал и на VBA конечно же, хотя если честно я не совсем уверен, что подобные вещи вообще нужно делать и что подобные типы данных могут передаваться.

Очень прошу помощи! Как подобное можно реализовать? Может быть есть какой-то вариант возвращения не самого gpc_polygon, а просто нескольких массивов?
PM MAIL   Вверх
Akina
Дата 11.2.2016, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 25
Всего: 453



Я мало что смыслю в С++, но назвал бы это процедурой, а не функцией.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Dementor
Дата 17.2.2016, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Akina, я тоже не большой специалист, но все же это функция - она же возвращает значение, а процедура была бы void и ничего бы не возвращала.

Но суть не в том как называть конечно.

В общем решил я проблему использованием в качестве Result того же SAFEARRAY, который содержал Point3d. Но так как вернуться может несколько контуров, то пришлось пойти дальше и опять нарваться на непонимание.

Я в DLL объявил вот такую структуру:
Код

typedef struct
{
    SAFEARRAY *Vertexes;
} Contour;

Итак на входе у функции имеются три SAFEARRAY, каждый из которых содержит внутри себя массив структур Contour. В общем если говорить по-простому, то на входе у нас есть куча контуров, каждый из которых состоит из кучи вершин.

И в общем-то если говорить о Master и Slave, то все отлично - никаких проблем: передали, получили, обработали.

А вот с заполнением Result есть проблема. Если, например, в первом варианте функции SAFEARRAY **Result у меня содержал просто массив Point3d, то все было отлично - функция его замечательно заполняла и далее VBA-макрос его замечательно обрабатывал. А вот теперь получается проблема: массив Result проходит изменение размера до нужного, далее в цикле по контурам, которые мне надо добавить в массив, я создаю еще один SAFEARRAY *NewContour, в который записываю вершины, и после того как вершины записаны я с помощью SafeArrayPutElement добавляю NewContour в Result. На мой взгляд все правильно и логично, но вот на деле оказывается иначе: после того как все отработает я получаю Result нужного размера, но содержащий в качестве всех элементов только последний добавленный NewContour.

В общем видимо надо писать в раздел по C++, ибо я уже совсем не понимаю что не так.
PM MAIL   Вверх
Romikgy
Дата 17.2.2016, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7325
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: нет
Всего: 146



насколько мне известно понятие ссылка у с++ и у вба отличаются... поэтому могут вести по разному


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Dementor
Дата 18.2.2016, 16:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



В общем что бы проблема получила решение я опишу мое решение и может быть это кому-нибудь да пригодится (решение не является 100% правильным!).

Итак, основная проблема у меня состояла в том, что я вынужден работать с SAFEARRAY, который содержит в качестве элементов другие SAFEARRAY, которые свою очередь содержат структуры Point3d (повторюсь, что Point3d - это просто три double).

Самое правильное и легальное решение подобной проблемы (как я это понимаю) - объявить структуру в IDL и далее уже беспрепятственно создавать массивы таких структур (под массивами надо понимать именно SAFEARRAY, а не обычный массив C/C++). Но к сожалению я не владею полными данными о том, как это делать, поэтому был вынужден придумывать обход.

 Суть обхода заключается в том, что я должен был как-то "обмануть" систему. И вот как я это сделал:
1. На входе в DLL-функцию подается 3 массива SAFEARRAY, два из которых заполнены данными, а третий нужен для возврата результата в VBA;
2. Используя SafeArrayCopy мы копируем один из заполненных массивов в результирующий массив. Вот тут и была моя первая ошибка - я не копировал массив, а делал просто *Result = *Master;
3. Теперь результирующий массив у нас имеет как минимум один элемент (а это по условиям моей задачи тоже SAFEARRAY), который отвечает всем правилам (т.е. как-будто мы его создали SAFEARRAY используя структуру IDL). Почему как минимум один элемент я думаю понятно;
4. Изменяем размер результирующего массива с помощью SafeArrayRedim до нужного (при этом понимаем, что если у нас после копирования в результирующем массиве был только 1 элемент, а теперь стало 5, то первый элемент никак не изменился!);
5. А теперь копируем первый элемент результирующего массива во все остальные используя все тот же SafeArrayCopy. Таким образом мы получаем результирующий массив, состоящий из нужного количества элементов SAFEARRAY, которые гарантированно способны хранить в себе структуры Point3d. Думаю понятно, что тут была моя вторая ошибка ибо я делал вот такую ересь: NewContour = MasterArray[0].Vertexes;.

Понятно, что такой подход нельзя назвать грамотным и правильным, но если нет желания копать про IDL, то вариант вполне рабочий.

PM MAIL   Вверх
kapbepucm
Дата 29.2.2016, 16:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 993
Регистрация: 14.6.2007
Где: Латвия

Репутация: 3
Всего: 12



насколько я правильно понял от пункта 2 до пункта 5 - это выполнение вне VBA, со есть в C++ DLL; а result получаете в VBA? корректный?
VBA не даёт такого гибкого доступа к памяти, как это можно делать в C++, однако можно через winapi попробовать

Это сообщение отредактировал(а) kapbepucm - 29.2.2016, 16:39


--------------------
(С) kapbepucm
PM MAIL Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Программирование, связанное с MS Office"
mihanik staruha

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами



  • Несанкционированная реклама на форуме запрещена
  • Пожалуйста, давайте своим темам осмысленный, информативный заголовок. Вопль "Помогите!" таковым не является.
  • Чем полнее и яснее Вы изложите проблему, тем быстрее мы её решим.
  • Оставляйте свои записи в "Книге отзывов о работе администрации"
  • А вот тут лежит FAQ нашего подраздела


Если Вам понравилась атмосфера форума, заходите к нам чаще!
С уважением mihanik и staruha.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Программирование, связанное с MS Office | Следующая тема »


 




[ Время генерации скрипта: 0.1394 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.