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

Поиск:

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


Шустрый
*


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

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



Доброго всем дня!

Вопрос переехал из темы: VBA и DLL, Как вернуть в VBA результат из DLL

Что имеем:
1. Имеется структура:
Код

typedef struct
{
    SAFEARRAY *Vertexes;
} Contour;

2. Имеется функция:
Код

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


Массивы Master и Slave заполняются на стороне VBA и содержат внутри себя те же структуры Contour. С ними проблем нет - они адекватно получаются в DLL и адекватно обрабатываются.

Проблема возникает в заполнении массива Result.

Вот код, который используется для его заполнения:
Код

        if (ResultPolygon.num_contours > 0)
        {
            *Result = *Master;
            
            // Изменяем размер массива Result до нужного            
            SAFEARRAYBOUND ResultBound;
            ResultBound.cElements = ResultPolygon.num_contours;
            ResultBound.lLbound = 0;
            hr = SafeArrayRedim(*Result, &ResultBound);
        
            if (Result != NULL)
            {
                for (LONG i = 0; i != ResultPolygon.num_contours; i++)
                {                    
                    SAFEARRAY *NewContour;
                    SAFEARRAYBOUND ContourBound;
                    
                    ContourBound.cElements = ResultPolygon.contour[i].num_vertices;
                    ContourBound.lLbound = 0;
                                                                                
                    NewContour = MasterArray[0].Vertexes;
                    hr = SafeArrayRedim(NewContour, &ContourBound);

                    for (LONG j = 0; j != ResultPolygon.contour[i].num_vertices; j++)
                    {
                        Point3d ResultPoint;
                        ResultPoint.x = ResultPolygon.contour[i].vertex[j].x;
                        ResultPoint.y = ResultPolygon.contour[i].vertex[j].y;
                        ResultPoint.z = 0;

                        hr = SafeArrayPutElement(NewContour, &j, &ResultPoint);
                    }

                    hr = SafeArrayPutElement(*Result, &i, &NewContour);
                }
                return ResultPolygon.num_contours;
            }
        }


Поясню для чего я делаю *Result = *Master и NewContour = MasterArray[0].Vertexes: если я все правильно понял из гугления, то для того, что бы легально создать SAFEARRAY, который содержит внутри себя структуру, надо эту самую структуру создавать через IDL, но если честно, то как именно это сделать я не очень понял и поэтому методом проб и ошибок пришел к выводу, что вот подобное работает (в предыдущей версии функции все три массива содержали просто структуры Point3d и Result формировался без каких-либо проблем).

А теперь в чем же проблема: после всех операций массив Result содержит нужное количество элементов, однако все элементы одинаковые и равны последнему, который в него передавался.

Я пытался вместо SAFEARRAY *NewContour задавать массив Contour с количеством элементов как в Result, заполнять вершинами каждый i-ый элемент и в Result записывать именно i-ый элемент. Но ничего не изменилось.

Я конечно понимаю, что я чего-то недопонимаю в самом C++ и SAFEARRAY в частности, но очень прошу помощи в том, что бы разобраться в возникшей проблеме.

Заранее всем откликнувшимся огромное спасибо!
PM MAIL   Вверх
xvr
Дата 17.2.2016, 15:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(Dementor @  17.2.2016,  13:15 Найти цитируемый пост)
Поясню для чего я делаю *Result = *Master

Этого делать нельзя. ActiveX подсистема имеет полное право убить Master при возврате из вашего метода и ваш Result повиснет в воздухе.

Затем вы пытаетесь записать в SAFEARRAY *Vertexes структуру Point3d. Vertexes на это точно расчитан?

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


Шустрый
*


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

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



xvr, хорошо, тогда можем предположить, что никакого Result нет, а результат работы функции я буду записывать в Master, меняя его размер с помощью SafeArrayRedim под нужный мне и далее уже заново заполняя его элементы. Такой подход будет правильным?

Что касается SAFEARRAY *Vertexes и Point3d. Т.к. все три массива заведомо создаются на стороне VBA, то там это выглядит так:

Код

Type Contour
    Vertexes() As Point3d
End Type

Function GPC_IntersectionPolygon(MasterElement As Element, SlaveElement As Element) As Collection
Dim t As Long
Dim MasterArray() As Contour, SlaveArray() As Contour, ResultArray() As Contour
' Тут есть промежуточная функция, которая заполняет Master и Slave, преобразовывая MasterElement и SlaveElement в массивы
t = ClipPolygons(MasterArray, SlaveArray, ResultArray, 1)
End Function


Т.е. с моей точки зрения все достаточно правильно. По крайней мере я вижу подтверждение правильности на примере массивов Master и Slave, элементы которых и представляют из себя массивы Point3d.

Что касается самой структуры Point3d, то она и в C++ и в VBA состоит из 3-х Double.
PM MAIL   Вверх
Dementor
Дата 17.2.2016, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Просто ради интереса переделал. Убрал Result, вместо него теперь Master (хотя может это тоже не верно). Ну и перешел с SafeArrayPutElement на работу через SafeArrayAccessData. Но в общем-то ничего и не изменилось в плане результата: теперь уже в Master образуется нужное количество элементов, но каждый элемент равен последнему записанному.

Код

        if (ResultPolygon.num_contours > 0)
        {                
            SAFEARRAYBOUND ResultBound;
            ResultBound.cElements = ResultPolygon.num_contours;
            ResultBound.lLbound = 0;

            hr = SafeArrayRedim(*Master, &ResultBound);
            if (FAILED(hr)) return -1;

            Contour HUGEP *pcnt;
            hr = SafeArrayAccessData(*Master, (void HUGEP**)&pcnt);
            if (FAILED(hr)) return -2;

            for (LONG i = 0; i != ResultPolygon.num_contours; i++)
            {                    
                SAFEARRAYBOUND ContourBound;                    
                ContourBound.cElements = ResultPolygon.contour[i].num_vertices;
                ContourBound.lLbound = 0;
                                                                                
                pcnt[i].Vertexes = pcnt[0].Vertexes; //Если этого не сделать, то SafeArrayRedim не выполняется и возвращается -3
                hr = SafeArrayRedim(pcnt[i].Vertexes, &ContourBound);
                if (FAILED(hr)) return -3;

                Point3d HUGEP *pvrt;
                hr = SafeArrayAccessData(pcnt[i].Vertexes, (void HUGEP**)&pvrt);
                if (FAILED(hr)) return -4;

                for (LONG j = 0; j != ResultPolygon.contour[i].num_vertices; j++)
                {
                    pvrt[j].x = ResultPolygon.contour[i].vertex[j].x;
                    pvrt[j].y = ResultPolygon.contour[i].vertex[j].y;
                    pvrt[j].z = 0;
                }

                SafeArrayUnaccessData(pcnt[i].Vertexes);
            }

            SafeArrayUnaccessData(*Master);
            return ResultPolygon.num_contours;

        }

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


Шустрый
*


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

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



xvr, в общем все заработало.

Просто после SafeArrayRedim для главного SAFEARRAY я провел копирование нулевого элемента (который гарантированно всегда есть и который не уничтожается при SafeArrayRedim) во все остальные. Соответственно после этого адекватно проходит SafeArrayRedim для вложенного массива! Может это и костыль и так делать не очень правильно, но по крайней мере работает.

У меня остался один вопрос, который я не могу понять. Вот вы пишете, что "ActiveX подсистема имеет полное право убить Master при возврате из вашего метода и ваш Result повиснет в воздухе.", но почему ActiveX убьет массив, который после выполнения неких операций в DLL может еще использоваться в самом VBA?
PM MAIL   Вверх
xvr
Дата 17.2.2016, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(Dementor @  17.2.2016,  17:42 Найти цитируемый пост)
Просто после SafeArrayRedim для главного SAFEARRAY я провел копирование нулевого элемента (который гарантированно всегда есть и который не уничтожается при SafeArrayRedim) во все остальные. 

Это неправильно. Вы отдублировали ВСЕ массивы в один. Т.е. у вас реально один массив, по всем индексам.

Цитата(Dementor @  17.2.2016,  17:42 Найти цитируемый пост)
но почему ActiveX убьет массив, который после выполнения неких операций в DLL может еще использоваться в самом VBA? 

А может и нет. Поэтому может и убить.

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


Шустрый
*


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

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



xvr, простите, что достаю вопросами, но сам понять это я не в состоянии и поэтому прошу пояснить.

Предположим, что вот это делать нельзя:
Код

Contour HUGEP *pcnt;
hr = SafeArrayAccessData(*Master, (void HUGEP**)&pcnt);
if (FAILED(hr)) return -2;
for (LONG i = 1; i != ResultPolygon.num_contours; i++)
   hr = SafeArrayCopy(pcnt[0].Vertexes, &pcnt[i].Vertexes);


Но без этого не выполняется вот это:
Код

SAFEARRAYBOUND ContourBound;                    
ContourBound.cElements = ResultPolygon.contour[i].num_vertices;
ContourBound.lLbound = 0;
hr = SafeArrayRedim(pcnt[i].Vertexes, &ContourBound);


И тогда возникает вопрос: если так делать нельзя, то как тогда можно сделать, что бы был корректный результат? Сейчас по крайней мере у меня в VBA после выполнения в функции DLL в массиве Master содержатся все необходимые элементы именно в том виде, в котором они и должны быть...

P.S. равно также работает если делать SafeArrayCopy(*Master, Result); и потом уже работать с Result. Поэтому даже вдвойне непонятно - почему это неправильно?

Это сообщение отредактировал(а) Dementor - 17.2.2016, 20:21
PM MAIL   Вверх
xvr
Дата 18.2.2016, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(Dementor @  17.2.2016,  18:23 Найти цитируемый пост)
Предположим, что вот это делать нельзя:

Вот как раз так делать можно: SafeArrayCopy(pcnt[0].Vertexes, &pcnt[i].Vertexes). А вот так pcnt[i].Vertexes=pcnt[0].Vertexes - нельзя

Цитата(Dementor @  17.2.2016,  18:23 Найти цитируемый пост)
P.S. равно также работает если делать SafeArrayCopy(*Master, Result); и потом уже работать с Result. Поэтому даже вдвойне непонятно - почему это неправильно?

Это правильно. А *Result=*Master - нет

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


Шустрый
*


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

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



xvr, спасибо большое за пояснение, а то я думал, что и с таким подходом я не прав. Просто я конечно должен был уточнить, что я имел ввиду под копированием и тогда не было бы недопонимания. Еще раз большое спасибо за помощь и объяснения!  smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

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

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

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

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


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

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


 




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


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

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