|
Модераторы: mihanik |
|
Dementor |
|
|||
Шустрый Профиль Группа: Участник Сообщений: 60 Регистрация: 9.7.2007 Репутация: нет Всего: нет |
И снова всем привет!
Возникла проблема связывания макроса на VBA с DLL, которая пишется на C++. Сразу уточню - DLL пытаюсь писать так же я, поэтому нет никаких ограничений в решении проблемы - лишь бы решить. Итак в чем суть: есть макрос на VBA, который пишется под Microstation, и DLL, которая фактически реализует возможности General Polygon Clipper. В DLL пока есть одна функция, доступная для VBA, которая на входе получает два SAFEARRAY и один gpc_polygon, который в итоге, по моему мнению, она и должна заполнить. Как выглядит сама функция в DLL (ее внутренности не привожу, т.к. особого смысла в этом нет):
Из 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, а просто нескольких массивов? |
|||
|
||||
Akina |
|
|||
Советчик Профиль Группа: Модератор Сообщений: 20570 Регистрация: 8.4.2004 Где: Зеленоград Репутация: 25 Всего: 453 |
Я мало что смыслю в С++, но назвал бы это процедурой, а не функцией.
-------------------- О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума. |
|||
|
||||
Dementor |
|
|||
Шустрый Профиль Группа: Участник Сообщений: 60 Регистрация: 9.7.2007 Репутация: нет Всего: нет |
Akina, я тоже не большой специалист, но все же это функция - она же возвращает значение, а процедура была бы void и ничего бы не возвращала.
Но суть не в том как называть конечно. В общем решил я проблему использованием в качестве Result того же SAFEARRAY, который содержал Point3d. Но так как вернуться может несколько контуров, то пришлось пойти дальше и опять нарваться на непонимание. Я в DLL объявил вот такую структуру:
Итак на входе у функции имеются три SAFEARRAY, каждый из которых содержит внутри себя массив структур Contour. В общем если говорить по-простому, то на входе у нас есть куча контуров, каждый из которых состоит из кучи вершин. И в общем-то если говорить о Master и Slave, то все отлично - никаких проблем: передали, получили, обработали. А вот с заполнением Result есть проблема. Если, например, в первом варианте функции SAFEARRAY **Result у меня содержал просто массив Point3d, то все было отлично - функция его замечательно заполняла и далее VBA-макрос его замечательно обрабатывал. А вот теперь получается проблема: массив Result проходит изменение размера до нужного, далее в цикле по контурам, которые мне надо добавить в массив, я создаю еще один SAFEARRAY *NewContour, в который записываю вершины, и после того как вершины записаны я с помощью SafeArrayPutElement добавляю NewContour в Result. На мой взгляд все правильно и логично, но вот на деле оказывается иначе: после того как все отработает я получаю Result нужного размера, но содержащий в качестве всех элементов только последний добавленный NewContour. В общем видимо надо писать в раздел по C++, ибо я уже совсем не понимаю что не так. |
|||
|
||||
Romikgy |
|
|||
Любитель-программер Профиль Группа: Участник Клуба Сообщений: 7325 Регистрация: 11.5.2005 Где: Porto Franco Odes sa Репутация: нет Всего: 146 |
насколько мне известно понятие ссылка у с++ и у вба отличаются... поэтому могут вести по разному
-------------------- Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. |
|||
|
||||
Dementor |
|
|||
Шустрый Профиль Группа: Участник Сообщений: 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, то вариант вполне рабочий. |
|||
|
||||
kapbepucm |
|
|||
Опытный Профиль Группа: Участник Сообщений: 993 Регистрация: 14.6.2007 Где: Латвия Репутация: 3 Всего: 12 |
насколько я правильно понял от пункта 2 до пункта 5 - это выполнение вне VBA, со есть в C++ DLL; а result получаете в VBA? корректный?
VBA не даёт такого гибкого доступа к памяти, как это можно делать в C++, однако можно через winapi попробовать Это сообщение отредактировал(а) kapbepucm - 29.2.2016, 16:39 -------------------- (С) kapbepucm |
|||
|
||||
Правила форума "Программирование, связанное с MS Office" | |
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще!
|
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Программирование, связанное с MS Office | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |