COM and VC++
попробуй использовать CallCreateInstance, ей нужно передавать только имя библиотеки.
Цитата:
-----------------------------------------
CoCreateInstance
Creates a single uninitialized object of the class associated with a specified CLSID. Call CoCreateInstance when you want to create only one object on the local system. To create a single object on a remote system, call CoCreateInstanceEx. To create multiple objects based on a single CLSID, refer to the CoGetClassObject function.
STDAPI CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv
);
Parameters
rclsid
[in] CLSID associated with the data and code that will be used to create the object.
-------------------------------------------------------------------------------
А CLSID я то как раз и не знаю. Я не знаю какой объект реализует интерфейс ISmth2. Можно ли как-то по интерфейсу понять, кто его реализует?
typedef IUnknown* (*CREATEFUNCPTR;
IUnknown* CallCreateInstance(char* name)
{
// Загрузить в процесс динамическую библиотеку
HINSTANCE hComponent = ::LoadLibrary(name);
if (hComponent == NULL)
{
cout << "CallCreateInstance:\tОшибка: Не могу загрузить компонент"
<< endl;
return NULL;
}
// Получить адрес функции CreateInstance
CREATEFUNCPTR CreateInstance
= (CREATEFUNCPTR)::GetProcAddress(hComponent, "CreateInstance");
if (CreateInstance == NULL)
{
cout << "CallCreateInstance:\tОшибка: "
<< "Не могу найти функцию CreateInstance"
<< endl;
return NULL;
}
return CreateInstance;
}
По смыслу, он скорее всего получается через Smth1.
> Dim obj1 As Smth1
> Dim obj1 As ISmth2
Это не создание объектов, это простое объявление ссылок на объекты.
Аналог на C++:
ISmth1Ptr pServer1;
ISmth2Ptr pServer2;
зы
Вообщем, посмотри методы объекта smth1, один из методов скорее всего возвращает ISmth2
Да видимо прав. Интерфейс и класс - разные вещи. Из того, что ты показал не следует, что есть класс Something2.
2) если ты можешь создать объект интерфейса из VB, то объект реалиует автоматизацию (дуальные интерфейсы)
в таком случае работа идет через IDispatch::Invoke -> попробуй поискать DISP_ID для твоего интерфейса.
3) не используй _COM_SMARTPTR_TYPEDEF & директиву #import; я не понимаю начинающих - неужели так тяжело дернуть CoInitialize/CoCreateInstance зато структура программы будет понятней
Короче говоря :
тебе нужен тайплиб .tlb
интерфейс - это чисто абстрактный класс
После этого объявления
Dim obj1 As Smth1
Dim obj2 As ISmth2
почти сразу идет что-то типа
obj1 = obj2.getSmth1;
Просто у меня есть работающий код на VB, но как он работает я не могу понять. С объявлениями все ясно, видимо надо было сразу написать эту строку "Smth1 = ISmth2.getSmth2;" На самом деле код не на этой машине, поэтому пишу на память. Но вроде ключевые моменты не вру т.е. в VB почему-то можно обращаться через интерфейс к функциям. Это меня смущает. Просто я с VB почти не работал, он для меня темный лес.
#import - хорошая штука, особенно если заменить стандартные wrapper-ы на свои или atl-ные
> obj1 = obj2.getSmth1;
не верю. Где-то у тебя в описании проблемы есть неточности.
ты не поверишь, но в VC, Delphi, Java и C# тоже можно
я думаю, в твоем случае здесь имеет место аггрегация
1. А если они агрегированные то, что?
2. "если ты можешь создать объект интерфейса из VB, то объект реалиует автоматизацию" - не факт. VB может и без IDispach рботать, но огда действительно нужна библиотека типов. А вот как ее вытянуть из ДЛЛ? Попробую поискать DISPID.
3. Как можно обойтись без #import? Я всгда ее использовал.
4. Если создавать с помощью CoCreateInstance то потом нужно не забыть Release вызвать Мне наоборот кажется, что лаконичнее использовать _COM_SMARTPTR_TYPEDEF и структура программы понятнее
отчего не веришь? аргументируй
Нет. Интерфейс и то, что в COM называется CoClass, разные вещи. Один класс может иметь множество интерфейсов, но интерфейсы не могут существовать без физической сущности - класса. То что в С++ интерфейс случайно оказался абстрактным классом, ничего не значит. В данном случае проблема, видимо, в том, что имя одного интерфейса оказалось похожим на имя класса, но это ничего не меняет. Если не использовать import, который сильно облегчает работу с COM, то пришлось бы создать класс Something1 и у него потом запросить интерфейс ISomething1 или ISomething2, как нравится. По-моему дело обстоит так, или нет?
потому что по описанию из первого поста должно быть на оборот (если, конечно, vb-шный код рабочий).
Ты бы выкинул исходнички сюда (если они не очень здоровые, и если там нет ничего секретного) , а то тут постепенно разворачиваются баталии, истоки которых происходят из-за незнания, как в действительности реализованы компоненты.
Возможно тебе нужно писать не hr = pServer2.CreateInstance(__uuidof(Smth2; а hr = pServer2.CreateInstance(__uuidof(Smth1;
import только облегчает процесс создания "умных указателей", больше ничего сверхестественного он не делает.
2: Я б конечно выложил, да только они на другой машине. У меня их сейчас нет.
А что значит не получилось? hr = ENOINTERFACE или как там был равен?
>> но интерфейсы не могут существовать без физической сущности - класса
это, конечно, полный бред, прости за правду , видимо ты перепутал интерфейс и реализацию
а вообще
да, ты ошибся
Итак:
класс - одно из базовых понятий ООП
интерфейс - суть абстрактный класс, т.е. все методы чисто виртуальные
CoClass - суть класс (компонентный класс унаследованный от интерфейсов и обладающий реализацией метода QueryInterface для доступа к своим компонентам
Для создания объекта CoClass необходимо определить метод CreateInstance, либо определить иным образом фабрику класса
Создать экземпляр абстрактного класса нельзя (могу объяснить почему )
Имя интерфейса и имя класса - понятия одинаковые
объясни мне как можно обращаться к _vtable из языка, не поддердивающего указатели на функции
ты неправ
а tlb файл попробуй пошукать в других местах
из длл никак
Нет. КоКласс может быть чем угодно, даже не классом в понимании С++. QueryInterface не его метод, а метод интерфейса IUnknown, который должны реализовывать все объекты COM. И еще раз, то что в С++ интерфейс это абстрактный класс, это случайность. В C#, например, интерфейс и абстрактный класс разные вещи. Поэтому не нужно путать имя КоКласса и имя интерфейса. Разница между ними видна даже в tlb.
Итак:Это лажа.
класс - одно из базовых понятий ООП
интерфейс - суть абстрактный класс, т.е. все методы чисто виртуальные
CoClass - суть класс (компонентный класс унаследованный от интерфейсов и обладающий реализацией метода QueryInterface для доступа к своим компонентам
Для создания объекта CoClass необходимо определить метод CreateInstance, либо определить иным образом фабрику класса
Создать экземпляр абстрактного класса нельзя (могу объяснить почему )
Имя интерфейса и имя класса - понятия одинаковые
Ты напрасно отождествляешь COM и сложившуюся практику создания COM-компонент на С++.
Вообще говоря, COM-классы не имеют никакого отношения к С++ классам.
Например (при большом желании вполне можно писать комовщину на чистом С, безо всяких классов вообще.
Попробуй на досуге. Тебе, как любителю низкоуровневых API, должно понравиться.
Из VB6 можно вызывать функции не заморачиваясь с IDispatch. Точнее это он не заморачивается с ним. Это не противоречит ни чему, поскольку делается самим VB за спиной программиста, также как например это происходит при использовании import. Там тоже не нужно гемороиться с IDispatch поскольку все само генерируется.
VB может обращаться к методам интерфейса напрямую, без диспетчерского механизма. Для этого нужно, чтобы была скомпилирована библиотека типов, как раз файл c расширением tlb. Только зачастую никто tlb файлы не поставляет, они компануются вместе с DLL или там EXE сервером COM-компонента. Только есть одно необходимое условие - нужно, чтобы все типы данных были типами, поддерживаемые Automaion. Как и что VB делает с этим tlb, я не знаю. Я вообще пугаюсь VB - это страшный с необъяснимиым поведением язык.
согласен
>> QueryInterface не его метод, а метод интерфейса IUnknown, который должны реализовывать все объекты COM
согласен, большой респект за напоминание
Если еще раз перечитаешь мои посты, то имя КоКласса и имя интерфейса я не путаю.
Переубеждать и объяснять концепцию КОМ я здесь не буду, мне за это не платят (лучше помогу советом)
Приведу напоследок две цитаты из MSDN
coclass (component class)
Component object class. A top-level object in the object hierarchy.
CoClass:
The Microsoft® Component Object Model defines a class as an implementation that allows QueryInterface between a set of interfaces .
я исходил из контекста беседы
Automation - это поддержка IDispatch, т.н. дуальный интерфейс (dual)
Я не силен в теории. Я хочу лишь сказать, что в COM мы работаем только с интерфейсами, но получаем к ним доступ через создание специального объекта. И если вышло так, что этот объект называется A, а один из его интерфейсов IA, то это просто совпадение и не влечет никаких особых последствий.
я писал контроль для "HelloWorld" на С
Dim obj1 As Smth1
Dim obj2 As ISmth2
obj1 = obj2.getSmth1;
А этот код работающий. Как это можно обяснить? Ты чего-то про агрегацию говорил.
мне показалось, что ты работал с КОМом в основном на языках высокого уровня
Ты все правильно сказал. Только ты не внимательно прочитал меня, я сказал, что необходимое условие это то, что типы переменных и возвращаемых значений функций твоего интерфейcа должны быть типа данных VARIANT. Ты не обязан реализовывать IDispatch, чтобы к твоему серверу мог обратиться клиент из VB. Именно из VB. Для всех остальных языков, необходим реализация маршалера Automation с помощью интерфейса IDIspatch.
оба естественно реализуют IUnknown, но один из них перенаправляет вызовы в т.ч IU к аггрегированному объекту
это примерно как если бы ты написал dll которая заменяла бы напр. kernel32.dll и перенаправляла все ее вызовы через себя
т.е. есть аггрегат и есть аггрегированный
в моем примере аггрегат - твоя длл, аггрегируемый объект - kernel32.dll
ты можешь получить аггрегированный объект, если у тебя имеется GUID аггрегата
все IMHO
-----------------------------------------------------------------------------------------------
Я не проверял значение. Просто на проверке if(FAILED(hr вылетало.
Теорию я знаю. Нового ты к сожалению ничего не сказал, поэтому проблема остается.
до тех пор пока ты не выложишь конкретный пример
Оставить комментарий
dberezhnoy
Те, кто разбирается в Com и VC++, подскажите, что делать. Проблема в том, что не могу в VС++ создать экземпляр Сom класса, по известному интерфейсу. Напускаю в VC++ директиву #import на некоторую стороннюю DLL-ку, она естественно создает мне два фала file.tlh и file.tli. Вот что есть в tlh фале:---------------------------------------------------------------------------------
//file file.tlh
...
_COM_SMARTPTR_TYPEDEF(ISmth1, __uuidof(ISmth1;
_COM_SMARTPTR_TYPEDEF(ISmth2, __uuidof(ISmth2;
struct __declspec(uuid("f96f13a2-08fb-49c4-8590-a3627b367478"
Smth1;
// [ default ] interface ISmth1
...
// End of com1.tlh
-----------------------------------------------------------------------------------
Есть два интерфейса ISmth1 и ISmth2, но для первого есть строка
struct __declspec(uuid("f96f13a2-08fb-49c4-8590-a3627b367478"
Smth1;
// [ default ] interface ISmth1
а для второго ничего подобного нет.
Пытаюсь в сpp фале присоединиться к com серверам:
----------------------------------------------------------------------------------
//file.cpp
...
ISmth1Ptr pServer1;
ISmth2Ptr pServer2;
HRESULT hr = pServer1.CreateInstance(__uuidof(Smth1;
hr = pServer2.CreateInstance(__uuidof(Smth2;
...
//Enf of file.cpp
----------------------------------------------------------------------------------
На строке "hr = pServer2.CreateInstance(__uuidof(Smth2;" компилятор ругается, что-то типа не могу найти объекта Smth2, если эту строку заменить на строку "hr = pServer2.CreateInstance(__uuidof(ISmth2;", то компилятор ругается, что не могу создать экземпляр абстактного класса ISmth2. Тем неменее следующий код в VB проходит:
Dim obj1 As Smth1
Dim obj1 As ISmth2
Как VB создает экземпляр интерфейса, я не понимаю. А вопрос в том, что как найти COM объект реализующий интерфейс ISmth2? Или по другому: как воспользоваться функциями этого интерфейса в VC++?