Передача массива объектов из С++ в C#
От: amOK Беларусь  
Дата: 25.03.04 19:16
Оценка:
Есть COM объект, который юзается из C#. Нужно мне из него вернуть массив объектов IMyClass, вернее не сами объекты, а ссылки на них, физически они должны хоститься в моём COM-сервере. Как бы это грамотнее сделать? Я думаю юзать SAFEARRAY и VT_DISPATCH, только не совсем понятно, как их принимать в C#, и что при маршалинге будет...
Re: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 09:57
Оценка:
Здравствуйте, amOK, Вы писали:

OK>Есть COM объект, который юзается из C#. Нужно мне из него вернуть массив объектов IMyClass, вернее не сами объекты, а ссылки на них, физически они должны хоститься в моём COM-сервере. Как бы это грамотнее сделать? Я думаю юзать SAFEARRAY и VT_DISPATCH, только не совсем понятно, как их принимать в C#, и что

при маршалинге будет...

Можно вот так.

interface IArrayTest : IDispatch{
    [id(1), helpstring("method ArrayTest")] HRESULT ArrayTest([out,retval] VARIANT* array);
};



Тогда в анменеджед создаешь сейфаррей и пихаешь в вариант. А на шарпе ты приводишь к нужному типу.

Можно так


   interface IIdentifiable : IDispatch {
        HRESULT straray([in] SAFEARRAY(BSTR) array);
        [id(0x60020003)]
        HRESULT strreturn([out, retval] SAFEARRAY(BSTR)* pRetVal);
    };


А вообще есть панацея. Пишешь на шарпе класслайбари а в ней такие интрефейсы, как тебе надо. Потом регистришь regasm /tlb и смотришь, что в tlb будет.

Выдираешь IDL для интерфейса и имплементишь его у себя на С++.

Все.
Re[2]: Передача массива объектов из С++ в C#
От: amOK Беларусь  
Дата: 26.03.04 17:20
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Здравствуйте, amOK, Вы писали:


OK>>Есть COM объект, который юзается из C#. Нужно мне из него вернуть массив объектов IMyClass, вернее не сами объекты, а ссылки на них, физически они должны хоститься в моём COM-сервере. Как бы это грамотнее сделать? Я думаю юзать SAFEARRAY и VT_DISPATCH, только не совсем понятно, как их принимать в C#, и что

PE>при маршалинге будет...

PE>Можно вот так.


PE>
PE>interface IArrayTest : IDispatch{
PE>    [id(1), helpstring("method ArrayTest")] HRESULT ArrayTest([out,retval] VARIANT* array);
PE>};
PE>



PE>Тогда в анменеджед создаешь сейфаррей и пихаешь в вариант. А на шарпе ты приводишь к нужному типу.


PE>Можно так



PE>
PE>   interface IIdentifiable : IDispatch {
PE>        HRESULT straray([in] SAFEARRAY(BSTR) array);
PE>        [id(0x60020003)]
PE>        HRESULT strreturn([out, retval] SAFEARRAY(BSTR)* pRetVal);
PE>    };
PE>


PE>А вообще есть панацея. Пишешь на шарпе класслайбари а в ней такие интрефейсы, как тебе надо. Потом регистришь regasm /tlb и смотришь, что в tlb будет.


PE>Выдираешь IDL для интерфейса и имплементишь его у себя на С++.


У меня возникла такая проблема: я объявляю в idl тип как SAFEARRAY(IDispatch*), или SAFEARRAY(IMyClass*). Но в С++ при создании этого массива с помощью SafeArrayCreateVectorEx(VT_DISPATCH, ...) и при попытке туда чего-нить запихнуть SafeArrayPutElement(...) летит исключение. Если же я создаю SafeArrayCreateVectorEx(VT_VARIANT, ...), то массив нормально заполняется, но потом шарп, ругается, что не правильный тип.
Я попробовал объявить SAFEARRAY(VARIANT) и получил Array из __ComObject, но как их привести к IMyClass я не знаю ????
Re[3]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 17:26
Оценка: +1
Здравствуйте, amOK, Вы писали:

OK> Я попробовал объявить SAFEARRAY(VARIANT) и получил Array из __ComObject, но как их привести к IMyClass я не знаю ????


HRESULT TestSuperMethod(
                [in] SAFEARRAY(IInterface*) arrayofinterfaces, 
                [out, retval] SAFEARRAY(IInterface*)* pRetVal);



Повторяю еще раз.

1. Создаешь проект ClassLibrary
2. Пишешь такой интерфейс, который хочешь видеть в дотнете
3. Экспортируешь в COM
4. Смотришь, что получилось
5. Вставляешь себе ва проект на С++
Re[4]: Передача массива объектов из С++ в C#
От: amOK Беларусь  
Дата: 26.03.04 17:32
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Здравствуйте, amOK, Вы писали:


OK>> Я попробовал объявить SAFEARRAY(VARIANT) и получил Array из __ComObject, но как их привести к IMyClass я не знаю ????


PE>
PE>HRESULT TestSuperMethod(
PE>                [in] SAFEARRAY(IInterface*) arrayofinterfaces, 
PE>                [out, retval] SAFEARRAY(IInterface*)* pRetVal);
PE>



PE>Повторяю еще раз.


PE>1. Создаешь проект ClassLibrary

PE>2. Пишешь такой интерфейс, который хочешь видеть в дотнете
PE>3. Экспортируешь в COM
PE>4. Смотришь, что получилось
PE>5. Вставляешь себе ва проект на С++

Собственно, я это делал, он мне сказал SAFEAARRAY(IMyClass*). Но я писал, что не могу создать такой массив в С++.
Re[5]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 17:35
Оценка:
Здравствуйте, amOK, Вы писали:

OK>Собственно, я это делал, он мне сказал SAFEAARRAY(IMyClass*). Но я писал, что не могу создать такой массив в С++.


В с++ это будет просто SAFEARRAY. Получи IDL файл и напусти на него MIDL. Там посмотришь, в каком виде это будет в С++.

Можно написать мекого клиента на С++, что бы посмотреть, как к тебе это приходит со стороны дотнет.
А потом сделаешь тож самое, только на с++.
Re[6]: Передача массива объектов из С++ в C#
От: amOK Беларусь  
Дата: 26.03.04 18:01
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Здравствуйте, amOK, Вы писали:


OK>>Собственно, я это делал, он мне сказал SAFEAARRAY(IMyClass*). Но я писал, что не могу создать такой массив в С++.


PE>В с++ это будет просто SAFEARRAY. Получи IDL файл и напусти на него MIDL. Там посмотришь, в каком виде это будет в С++.


PE>Можно написать мекого клиента на С++, что бы посмотреть, как к тебе это приходит со стороны дотнет.

PE>А потом сделаешь тож самое, только на с++.

Дык собственно в С++ это будет в виде SAFEARRAY ** pArray. В том то и весь затык тут, что не понятно, как его правильно сделать, чтобы и С++ и С# поняли!
Re[6]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 18:03
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Можно написать мекого клиента на С++, что бы посмотреть, как к тебе это приходит со стороны дотнет.

PE>А потом сделаешь тож самое, только на с++.

Я так и сделал.

Приходит Сейфаррей с таким флагом FADF_UNKNOWN | FADF_HAVEIID
Все пучком

Что бы создать такой нужно прочитать это


An array that has an IID identifying interface. When set there will be a guid at negative offset 16 in the safearray descriptor. Flag is set only when FADF_DISPATCH or FADF_UNKNOWN is also set.



      virtual HRESULT __stdcall raw_TestSuperMethod (
        /*[out,retval]*/ SAFEARRAY * * pRetVal ) = 0;



        public IInterface [] TestSuperMethod()
        {
            Test [] arr = new Test [2];

            arr[0] = new Test();
            arr[1] = new Test();

            return arr;
        }


Тебе для имплементации надо делать с точностью до наоборот. Будут вопросы — спрашивай.
Re[7]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 18:04
Оценка:
Здравствуйте, amOK, Вы писали:

OK>Дык собственно в С++ это будет в виде SAFEARRAY ** pArray. В том то и весь затык тут, что не понятно, как его правильно сделать, чтобы и С++ и С# поняли!


Сам сейфаррей не знаешь, чем заполнить ?
Re[7]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 18:11
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Приходит Сейфаррей с таким флагом FADF_UNKNOWN | FADF_HAVEIID

PE>Все пучком

PE>Что бы создать такой нужно прочитать это



PE>

PE>An array that has an IID identifying interface. When set there will be a guid at negative offset 16 in the safearray descriptor. Flag is set only when FADF_DISPATCH or FADF_UNKNOWN is also set.


Для этого есть функции

SafeArrayAllocDescriptor
SafeArrayAllocData
SafeArraySetIID
SafeArrayPutElement

Вроде все, что надо. Какие проблемы ?
Re[8]: Передача массива объектов из С++ в C#
От: amOK Беларусь  
Дата: 26.03.04 18:30
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Здравствуйте, amOK, Вы писали:


OK>>Дык собственно в С++ это будет в виде SAFEARRAY ** pArray. В том то и весь затык тут, что не понятно, как его правильно сделать, чтобы и С++ и С# поняли!


PE>Сам сейфаррей не знаешь, чем заполнить ?


Тип того. Короче такой код:

CComObject<CTTHelperClientItem> *pClient1 = NULL;
hr = CComObject<CTTHelperClientItem>::CreateInstance(&pClient1);

if (FAILED(hr))
  return hr;

CComObject<CTTHelperClientItem> *pClient2 = NULL;
hr = CComObject<CTTHelperClientItem>::CreateInstance(&pClient2);

if (FAILED(hr))
  return hr;

SAFEARRAY * sa;
sa = SafeArrayCreateVectorEx(VT_DISPATCH, 1, 2, (void**)&__uuidof(ICTTHelperItem));
        
long index = 1;

VARIANT var;
V_VT(&var) = VT_DISPATCH;

pClient1->QueryInterface(IID_ICTTHelperItem, (void **)&V_DISPATCH(&var));
SafeArrayPutElement(sa, &index, &var);

index ++;

pClient2->QueryInterface(IID_ICTTHelperItem, (void **)&V_DISPATCH(&var));
SafeArrayPutElement(sa, &index, &var);


ICTTHelperClientItem наследуется от ICTTHelperItem.
Вот на первом вызове SafeArrayPutElement летит исключение. Если поставить в SafeArrayCreateVectorEx VT_VARIANT, то тут всё нормально, но в С# не хочет приводится к нужному интерфейсу.
Re[9]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 18:40
Оценка:
Здравствуйте, amOK, Вы писали:

OK>Тип того. Короче такой код:


OK>

OK>SAFEARRAY * sa;
OK>sa = SafeArrayCreateVectorEx(VT_DISPATCH, 1, 2, (void**)&__uuidof(ICTTHelperItem));

А зачем вектор ?
Нужно создать этой фунцыей SafeArrayAllocDescriptor 
Потом указать размерность
Потом сделать SafeArrayAllocData
Потом SafeArraySetIID 

И в конце делаешь

pClient2->QueryInterface(IID_ICTTHelperItem, (void **)&V_DISPATCH(&var));
SafeArrayPutElement(sa, &index, &var);

OK>
Re[10]: Передача массива объектов из С++ в C#
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.04 18:43
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

OK>>
OK>>SAFEARRAY * sa;
OK>>sa = SafeArrayCreateVectorEx(VT_DISPATCH, 1, 2, (void**)&__uuidof(ICTTHelperItem));
OK>>


Если вектор, то надо тип VT_UNKNOWN и сделать SafeArraySetIID
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.