QueryInterface в .NET
От: Starlight США  
Дата: 19.08.03 13:17
Оценка:
Есть набор классов, связанных между собой COM-образным способом. Т.е. все наследуются от IUnknown и содержат в себе виртуальную QueryInterface(GUID* id, void** ppInterface).
Также есть статические factory-функции, создающие определенный класс: CreateSomeClass(void** ppClass).
Каким образом можно использовать эти функции и классы в C#? Я описал интерфейсы в C#-модуле, обозвал factory-функии в C-модуле как экспортируемые, но не могу понять, как написать в C# конструкции вида "void**". Пусть будет не void, а object или IUnknown, неважно. Что нужно написать вместо двойного указателя?
... << RSDN@Home 1.1 beta 1 >>
Re: QueryInterface в .NET
От: Ведмедь Россия  
Дата: 19.08.03 13:20
Оценка:
Здравствуйте, Starlight, Вы писали:

S>Есть набор классов, связанных между собой COM-образным способом. Т.е. все наследуются от IUnknown и содержат в себе виртуальную QueryInterface(GUID* id, void** ppInterface).

S>Также есть статические factory-функции, создающие определенный класс: CreateSomeClass(void** ppClass).
S>Каким образом можно использовать эти функции и классы в C#? Я описал интерфейсы в C#-модуле, обозвал factory-функии в C-модуле как экспортируемые, но не могу понять, как написать в C# конструкции вида "void**". Пусть будет не void, а object или IUnknown, неважно. Что нужно написать вместо двойного указателя?


extern static void CreateSomeClass( out object ppClass );


Вроде так
Да пребудет с тобой Великий Джа
Re[2]: QueryInterface в .NET
От: mihailik Украина  
Дата: 19.08.03 13:37
Оценка:
В>
В>extern static void CreateSomeClass( out object ppClass );
В>


В>Вроде так


А если более "человечно", то:

В>
В>extern static object CreateSomeClass();
В>


Хотя это и меньше похоже на оригинал, но более принятый вид.
... << RSDN@Home 1.1 beta 1 >>
Re[3]: QueryInterface в .NET
От: Ведмедь Россия  
Дата: 19.08.03 13:44
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>
В>>extern static void CreateSomeClass( out object ppClass );
В>>


В>>Вроде так


M>А если более "человечно", то:


В>>
В>>extern static object CreateSomeClass();
В>>


M>Хотя это и меньше похоже на оригинал, но более принятый вид.


Не совсем, хотя могу ошибаться. Разве в случае DllImport так можно делать? Вот если бы описывал это как метод интерфейса, тогда

HRESULT CreateSomeClass( [out,retval] IUnknown**ppClass );

Перешло бы в

extern static object CreateSomeClass( );

А так я не понимаю, как это может в случае DllImport
Да пребудет с тобой Великий Джа
Re[4]: QueryInterface в .NET
От: mihailik Украина  
Дата: 19.08.03 14:09
Оценка:
В>>>
В>>>extern static object CreateSomeClass();
В>>>


В>Не совсем, хотя могу ошибаться. Разве в случае DllImport так можно делать?


Несомненно можно. Для stdcall-функций это равнозначно.
... << RSDN@Home 1.1 beta 1 >>
Re[3]: QueryInterface в .NET
От: Starlight США  
Дата: 19.08.03 14:13
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>
В>>extern static void CreateSomeClass( out object ppClass );
В>>


В>>Вроде так


M>А если более "человечно", то:


В>>
В>>extern static object CreateSomeClass();
В>>


M>Хотя это и меньше похоже на оригинал, но более принятый вид.


В том-то и дело, что должно быть очень "похоже" на оригинал
Допустим, что нет возможности переделать исходные C-коды. Можно ли использовать в этом случае "out object" вместо "void**"?
Кстати, поясните, пожалуйста, а чем отличается "out object" от "ref object"?
... << RSDN@Home 1.1 beta 1 >>
Re[5]: QueryInterface в .NET
От: Ведмедь Россия  
Дата: 19.08.03 14:13
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>>>
В>>>>extern static object CreateSomeClass();
В>>>>


В>>Не совсем, хотя могу ошибаться. Разве в случае DllImport так можно делать?


M>Несомненно можно. Для stdcall-функций это равнозначно.


А если будет такая stdcal-функция

void CreateSomeClass( LPVOID** ppClass1, LPVOID** ppClass2 );?
Да пребудет с тобой Великий Джа
Re: QueryInterface в .NET
От: Starlight США  
Дата: 19.08.03 14:19
Оценка:
Чтобы было понятнее, приведу примеры кода:

Class1.cs
using System;
using System.Runtime.InteropServices;

namespace CS
{
    interface iunknown
    {
        void qi(ref object punk);
    };
    interface imesh : iunknown {
    };
    class cmesh : imesh {
        public void qi(ref object punk) 
        {
            punk = this;
        }
    };
    class Class1
    {
        [DllImport("dll.dll")]
        public static extern object createmesh();
        //public static extern void createmesh(out object punk);
        [STAThread]
        static void Main(string[] args)
        {
            object punk;
            punk = createmesh();
            imesh pmesh = (imesh) punk;
        }
    }
}


DLL.h
class iunknown {
public:
    virtual void qi(void** punk) = 0;
};

class imesh : public iunknown {
public:
    void qi(void** punk);
};

extern "C" DLL_API void createmesh(void** punk);


DLL.cpp
void imesh::qi(void** punk)
{
    *punk = (void*)this;
}

DLL_API void createmesh(void** punk)
{
    *punk = new imesh;
}


При вызове createmesh в Main() вылетают разные ошибки, смотря как я объявил DllImport.
... << RSDN@Home 1.1 beta 1 >>
Re[4]: QueryInterface в .NET
От: desperado_gmbh http://www.livejournal.com/users/tolstopuz
Дата: 19.08.03 14:56
Оценка:
Здравствуйте, Ведмедь, Вы писали:

В>>>extern static object CreateSomeClass();

В>А так я не понимаю, как это может в случае DllImport

[DllImport(..., PreserveSig = false)]
Re[4]: QueryInterface в .NET
От: mihailik Украина  
Дата: 20.08.03 10:33
Оценка:
S>В том-то и дело, что должно быть очень "похоже" на оригинал
S>Допустим, что нет возможности переделать исходные C-коды. Можно ли использовать в этом случае "out object" вместо "void**"?

Да.
Стоит посмотреть в MSDN описание DllImportAttribute и MarshalAsAttribute. Конкретно, параметру out object нужно приставить атрибут, что это будет не VARIANT, а указатель. По умолчанию out object рассматривается в интеропе как вариант.

S>Кстати, поясните, пожалуйста, а чем отличается "out object" от "ref object"?


В параметр ref нужно будет передавать инициализированное значение, а в out — не обязательно. В данном случае других различий нет.
... << RSDN@Home 1.1 beta 1 >>
Re[6]: QueryInterface в .NET
От: mihailik Украина  
Дата: 20.08.03 10:33
Оценка:
В>А если будет такая stdcal-функция

В>void CreateSomeClass( LPVOID** ppClass1, LPVOID** ppClass2 );?


Равнозначно:

LPVOID** ppClass2 CreateSomeClass( LPVOID** ppClass1 );
... << RSDN@Home 1.1 beta 1 >>
Re[7]: QueryInterface в .NET
От: Starlight США  
Дата: 20.08.03 11:09
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>А если будет такая stdcal-функция


В>>void CreateSomeClass( LPVOID** ppClass1, LPVOID** ppClass2 );?


M>Равнозначно:


M>LPVOID** ppClass2 CreateSomeClass( LPVOID** ppClass1 );


Интересно. А приведи, пожалуйста, пример C#-кода, как эту функцию можно импортировать из DLL и вызвать?
... << RSDN@Home 1.1 beta 1 >>
Re[5]: QueryInterface в .NET
От: Starlight США  
Дата: 20.08.03 12:02
Оценка:
Здравствуйте, mihailik, Вы писали:

S>>В том-то и дело, что должно быть очень "похоже" на оригинал

S>>Допустим, что нет возможности переделать исходные C-коды. Можно ли использовать в этом случае "out object" вместо "void**"?

M>Да.

M>Стоит посмотреть в MSDN описание DllImportAttribute и MarshalAsAttribute. Конкретно, параметру out object нужно приставить атрибут, что это будет не VARIANT, а указатель. По умолчанию out object рассматривается в интеропе как вариант.

Указатель в C#? Может я чего-то недопонимаю, но как это написать?

S>>Кстати, поясните, пожалуйста, а чем отличается "out object" от "ref object"?


M>В параметр ref нужно будет передавать инициализированное значение, а в out — не обязательно. В данном случае других различий нет.


Понятно. Спасибо.
... << RSDN@Home 1.1 beta 1 >>
Re[5]: QueryInterface в .NET
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.08.03 22:51
Оценка:
Здравствуйте, desperado_gmbh, Вы писали:

В>>А так я не понимаю, как это может в случае DllImport


_>
_>[DllImport(..., PreserveSig = false)]
_>


И? Он тебе не даром про HRESULT сказал. Только HRESULT автоматом в исключение можно превратить, да и то если он стандартный или ассоциировано IErrorInfo.
... << RSDN@Home 1.1 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: QueryInterface в .NET
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.08.03 22:51
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>void CreateSomeClass( LPVOID** ppClass1, LPVOID** ppClass2 );?


M>Равнозначно:


M>LPVOID** ppClass2 CreateSomeClass( LPVOID** ppClass1 );


Пробавал?
... << RSDN@Home 1.1 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: QueryInterface в .NET
От: Ведмедь Россия  
Дата: 21.08.03 07:02
Оценка:
Здравствуйте, mihailik, Вы писали:

В>>А если будет такая stdcal-функция


В>>void CreateSomeClass( LPVOID** ppClass1, LPVOID** ppClass2 );?


M>Равнозначно:


M>LPVOID** ppClass2 CreateSomeClass( LPVOID** ppClass1 );


А почему не

LPVOID** ppClass1 CreateSomeClass( LPVOID** ppClass2 );

( в смысле object CreateSomeClass( out object ppClass2 );
или
object CreateSomeClass( out object ppClass1 );
, есть некоторая путаница, правда?
)

По каким правилам выбирается параметр, который помещяется как возвращяемое значение? Я до сих пор считал, что для этого параметр должен быть помечен как retval. И здесь есть аналогия с VB, в котором параметро [out,retval] IUnknown** ppRet переходит в возвращяемое значение. Или я не прав?

И можно ли функция, описанную в IDL так

HRESULT Function( [out] IUknown** ppObject );

в С# декларировать как

object Function();
, не смотря на то что не поставлено retval?

Опять же есть два написания

void Function( IUnknown** ppObject );

как
void Function( ref object ppObject )

и

void Function( out object ppObject)

И если функция требует, что бы ей передавили валидный указатель, то будь любезен поставить ref а в таком варианте не может быть написания как object Function();
Да пребудет с тобой Великий Джа
Re[6]: QueryInterface в .NET
От: desperado_gmbh http://www.livejournal.com/users/tolstopuz
Дата: 21.08.03 07:06
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>И? Он тебе не даром про HRESULT сказал. Только HRESULT автоматом в исключение можно превратить, да и то если он стандартный или ассоциировано IErrorInfo.


Автору исходного сообщения это действительно не подходит — у него возвращается void. Я прояснил Ведмедю, что превращать HRESULT в Exception можно не только в методах интерфейсов.
Re[7]: QueryInterface в .NET
От: Ведмедь Россия  
Дата: 21.08.03 07:10
Оценка:
Здравствуйте, desperado_gmbh, Вы писали:

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


VD>>И? Он тебе не даром про HRESULT сказал. Только HRESULT автоматом в исключение можно превратить, да и то если он стандартный или ассоциировано IErrorInfo.


_>Автору исходного сообщения это действительно не подходит — у него возвращается void. Я прояснил Ведмедю, что превращать HRESULT в Exception можно не только в методах интерфейсов.


Дык дело не в HRESULT, дело в возвращяемом параметре. в интерфейсах возвращяемый параметр помечается как
[out,retval], тогда как в статических функциях он никак не помечается. ПО каким правилам вычисляется тогда какой параметр сделать retval?
Да пребудет с тобой Великий Джа
Re[8]: QueryInterface в .NET
От: desperado_gmbh http://www.livejournal.com/users/tolstopuz
Дата: 21.08.03 07:23
Оценка:
Здравствуйте, Ведмедь, Вы писали:

В>Дык дело не в HRESULT, дело в возвращяемом параметре. в интерфейсах возвращяемый параметр помечается как

В>[out,retval], тогда как в статических функциях он никак не помечается. ПО каким правилам вычисляется тогда какой параметр сделать retval?

Я и сам не пойму. В роторе код обработки PreserveSig есть, но все очень запущено. Логично было бы предположить, что последний.
Re[6]: QueryInterface в .NET
От: mihailik Украина  
Дата: 21.08.03 14:47
Оценка:
S>Указатель в C#? Может я чего-то недопонимаю, но как это написать?

Вообще, чтоб не мудрить лучше прописать IntPtr. А потом методами класса Marshal оперировать с ним.
... << RSDN@Home 1.1 beta 1 >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.