Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Агрегирования интерфейсов - помогите пожалуйста!  (Прочитано 8760 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
Red Line
Гость
« : 29-03-2004 13:36 » 

Есть простотой внутрипроцесный COM-сервер, который реализует интерфейс IX. Компонент поддерживает агрегирование. Данный пример взят из книги "Основы технологии COM". Пример работает, но я не могу понять почему. Насколько я понял, при агрегировании необходимо, чтобы внешний компонент возвращал указатель на агрегируемый интерфейс внутреннего компонента. Внутренний компонент содержит два интерфейса IUnknown - делегирующий  и не делегирующий. Если компонент агрегируется, то делегирующий IUnknown внутреннего компонента перенаправляет вызовы IUnknown внешнего компонента, если не агрегируется, то IUnknown внутреннего компонента перенаправляет вызовы не делегирующему IUnknown внутреннего компонента.
Привожу фрагмент кода внутреннего компонента:

Код:
#include <iostream>
#include <objbase.h>
#include "iface.h"
#include "register.h"

using namespace std;

void trace(const char* msg)|cout << msg << endl;}

//Aeiaaeu
static HMODULE g_hModule  = NULL; //iienaoaeu iiaoey DLL
static long g_cComponent  = 0;   //eie-ai aeoeaiuo eiiiiiaioia
static long g_cServerLoks = 0;   //n??o?ee aeiee?iaie

//a?o?anoaaiiia eiy eiiiiiaioa
const char g_szFriendlyName[] = "Inside COM, Nhapter 7 Example";
//ia caaenyuee io aa?nee ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap07";
//ProgID
const char g_szProgID[] = "InsideCOM.Chap07.1";

//Ia aaeaae?o?uee IUnknown
struct INondelegatingUnknown
{
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv) = 0;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegatingRelease() = 0;
};



//Eiiiiiaio
class CA : public IX, /*public IY,*/ public INondelegatingUnknown
{
public:
//IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
//INondelegatingUnknown
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall NondelegatingAddRef();
virtual ULONG __stdcall NondelegatingRelease();
//IX
virtual void __stdcall Fx();
//IY
//virtual void __stdcall Fy();
CA(IUnknown* pUnknownOuter);
~CA();
private:
IUnknown* m_pUnknownOuter;
long m_cRef;
};

CA::CA(IUnknown* pUnknownOuter) : m_cRef(1)
{
InterlockedIncrement(&g_cComponent);

if(pUnknownOuter == NULL)//eiiiiiaio ia aa?aae?oaony
{
trace("Component no agrgation, use internal IUnknown");
m_pUnknownOuter = reinterpret_cast <IUnknown*>
              (static_cast <INondelegatingUnknown*> (this));
INondelegatingUnknown* pX1 = static_cast <INondelegatingUnknown*> (this);

}
else //eiiiiiaio aa?aae?oaony
{
trace("Agrgation, delegating outer IUnknown");
m_pUnknownOuter = pUnknownOuter;
}
}

CA::~CA()
{
trace("\t\tDestroying componet");
InterlockedDecrement(&g_cComponent);
}

//?aaeecaoey aaeaae?o?uaai IUnknown
HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
}
trace("Delegating QueryInterface()");
return m_pUnknownOuter->QueryInterface(iid, ppv);
}

ULONG __stdcall CA::AddRef()
{
trace("Delegating AddRef()");
return m_pUnknownOuter->AddRef();
}

ULONG __stdcall CA::Release()
{
trace("Delegating Release()");
return m_pUnknownOuter->Release();
}

//?aaeecaoey INondelegatingUnknown
HRESULT CA::NondelegatingQueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
*ppv = static_cast <INondelegatingUnknown*> (this);
}
else if (iid == IID_IX)
{
*ppv = static_cast<IX*> (this);
}
//else if (iid == IID_IY)
//{
//*ppv = static_cast <IY*> (this);
//}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast <IUnknown*> (*ppv)->AddRef();/* Вот здесь мне и не ясно. Почему этот вызов передаёт управление в CA::NondelegatingAddRef(), ведь указатель ppv приведён к типу IUnknown* и указывает соответственно на Iunknown  - это вроде бы ясно. Но при вызове reinterpret_cast <IUnknown*> (*ppv)->AddRef();
управление передаётся в  CA::NondelegatingAddRef(), - это логически правильно - но ПОЧЕМУ ПРОИСХОДИТ передача управления я CA::NondelegatingAddRef() не могу понять. */

   return S_OK;
}

ULONG CA::NondelegatingAddRef()
{
return InterlockedIncrement(&m_cRef);
}

ULONG CA::NondelegatingRelease()
{
if ( InterlockedDecrement(&m_cRef) == 0 )
{
delete this;
return 0;
}
return m_cRef;
}

//?aaeecaoey IX
void __stdcall CA::Fx()
{
trace("Fx");
}

//?aaeecaoey IY
//void __stdcall CA::Fy()
//{
//trace("Fy");
//}

//Oaa?eea eeanna
class CFactory : public IClassFactory
{
public:
//IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();

//IClassFactory
virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
                                         const IID& iid,
                                         void** ppv);

virtual HRESULT __stdcall LockServer(BOOL bLock);
CFactory();
~CFactory();
private:
long m_cRef;
};

//Eiino?oeoi?
CFactory::CFactory() : m_cRef(1)
{
}

//Aano?oeoi?
CFactory::~CFactory()
{
trace("Destroying class factory...");
}

//?aaeecaoey IUnknown aey oaa?eee eeanna
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown || iid == IID_IClassFactory)
{
*ppv = static_cast <IClassFactory*> (this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast <IUnknown*> (*ppv)->AddRef();
return S_OK;
}

ULONG __stdcall CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef);
}

ULONG __stdcall CFactory::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}

//?aaeecaoey IClassFactory
HRESULT __stdcall CFactory::CreateInstance(IUnknown *pUnknownOuter,
   const IID &iid,
   void **ppv)
{
trace("CFactory: \t\tcreating component");

if ( (pUnknownOuter != NULL) && (iid != IID_IUnknown) )
{
return CLASS_E_NOAGGREGATION;
}

//Nicaaou eiiiiiaio
CA* pA = new CA(pUnknownOuter);
if(pA == NULL)
{
return E_OUTOFMEMORY;
}
//Aa?ioou cai?ioaiiue eioa?oaen
HRESULT hr = pA->NondelegatingQueryInterface(iid, ppv);
pA->NondelegatingRelease();
return hr;
}

//LockServer
HRESULT __stdcall CFactory::LockServer(BOOL block)
{
if (block)
{
InterlockedIncrement(&g_cServerLoks);
}
else
{
InterlockedDecrement(&g_cServerLoks);
}
return S_OK;
}

////////////////////// Yenii?oe?oaiua ooieoee \\\\\\\\\\\\\\\\\\\\\\\

//Ii?ii ee aua?o?aou DLL...
STDAPI DllCanUnloadNow()
{
if( (g_cComponent == 0) && (g_cServerLoks == 0) )
{
return S_OK;
}
else
{
return S_FALSE;
}
}

STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)
{
//if(clsid != CLSID_Component1)
//{
//return CLASS_E_CLASSNOTAVAILABLE;
//}
CFactory* pFactory = new CFactory;
if(pFactory == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}

STDAPI DllRegisterServer()
{
return RegisterServer(CLSID_Component1,
  (HMODULE)g_hModule,
  g_szFriendlyName,
  g_szVerIndProgID,
  g_szProgID);
}

STDAPI DllUnregisterServer()
{
return UnRegisterServer(CLSID_Component1,
g_szVerIndProgID,
g_szProgID);
}


//
BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD dwReason,
                      void* lpReserved)
{
if(dwReason == DLL_PROCESS_ATTACH)
{
g_hModule = (HMODULE)hModule;
}
return true;
}


Помогите разобраться с этим моментом пожалуйста. Заранее благодарен!
« Последнее редактирование: 25-11-2007 15:56 от Алексей1153++ » Записан
Anonymous
Гость
« Ответ #1 : 29-03-2004 22:41 » 

в примере я не нашел, как объявлен интерфейс IX. теоретически, он должен быть потомком IUnknown, который объявляется раньше других наследуемых классов (для построения vtable).
т.е., чтобы у тебя таблица была следующая:
vtable->
1. QI
2. AddRef
3. Release
4. ... прочие виртуальные методы

попробуй объяви:
class CA : public IUnknown, public IX, public INondelegatingUnknown ...
или
struct INondelegatingUnknown: public IUnknown...

а так, здесь все норма. просто через reinterpret... ты получаешь указатель на свой vtable. что, мол, твой объект является экземпляром класса IUnknown и построен на базе его vtable. номером 2 (я считал с 1  Отлично ) в vtable интерфейса IUnknown стоит AddRef, а у тебя NondelegatingAddRef. ты просто пудришь мозги компилятору. проще говоря, он и вызывет метод 2 и попадает на NondelegatingAddRef.
Записан
Red Line
Гость
« Ответ #2 : 30-03-2004 07:36 » new

Цитата
в примере я не нашел, как объявлен интерфейс IX. теоретически, он должен быть потомком IUnknown, который объявляется раньше других наследуемых классов (для построения vtable).
т.е., чтобы у тебя таблица была следующая:
vtable->
1. QI
2. AddRef
3. Release
4. ... прочие виртуальные методы

Так и есть:

Код:
//
// Iface.h
//

// Interfaces
interface IX : IUnknown
{
virtual void __stdcall Fx() = 0 ;
} ;

interface IY : IUnknown
{
virtual void __stdcall Fy() = 0 ;
} ;

interface IZ : IUnknown
{
virtual void __stdcall Fz() = 0 ;
} ;

// Forward references for GUIDs
extern "C"
{
extern const IID IID_IX ;
extern const IID IID_IY ;
extern const IID IID_IZ ;
extern const CLSID CLSID_Component1 ;
}

Цитата
а так, здесь все норма. просто через reinterpret... ты получаешь указатель на свой vtable. что, мол, твой объект является экземпляром класса IUnknown и построен на базе его vtable. номером 2 (я считал с 1  ) в vtable интерфейса IUnknown стоит AddRef, а у тебя NondelegatingAddRef. ты просто пудришь мозги компилятору. проще говоря, он и вызывет метод 2 и попадает на NondelegatingAddRef.

Я проверил - reinterpret_cast <IUnknown*> (*ppv)->AddRef(); не изменяет адреса записанного в *ppv. Т.е он как бы говорит компилятору смотреть на указатель так, как будто бы он указывает на IUnknown. Выходит, что имена для компилятора не имеют значения - он производит вызовы по индексу в vtbl.
Но я не могу понять, почему в данном случае reinterpret_cast не изменил адрес указателя. В моём виденье должно быть так:

Объект CA:
____________

vtbl-> (фрагмент от IX)
0. QI();
1. AddRef();
2. Release();
3. Fx();
vtbl-> (фрагмент от InondelegatingUnknown)
0. InondelegatingQI();
1. InondelegatingAddRef();
2. InondelegatingRelease();
Фрагмент от CA
QI()
AddRef()
Release()
Fx()
InondelegatingQI();
InondelegatingAddRef();
InondelegatingRelease();

В дебагере я вижу что this = &InondelegatingUnknown - т.е их адреса совпадают... не понимаю почему так...

Теперь про reinterpret_cast <IUnknown*> (*ppv)->AddRef();
Я думал так (исходя из логики работы reinterpret_cast):
если указатель указывает на vtbl InondelegatingUnknown, то после
reinterpret_cast <IUnknown*> (*ppv) он будет содержать адрес IUnknown, но этого не происходит - почему?

Те же самые вопросы  и по конструктору CA::CA(IUnknown* p);

Код:
CA::CA(IUnknown* pUnknownOuter) : m_cRef(1) 
{
   InterlockedIncrement(&g_cComponent);

   if(pUnknownOuter == NULL)//если компонент не агрегируется
   {
      trace("Component no agrgation, use internal IUnknown");
      m_pUnknownOuter = reinterpret_cast <IUnknown*>
                       (static_cast <INondelegatingUnknown*> (this));
      INondelegatingUnknown* pX1 = static_cast <INondelegatingUnknown*> (this); //Здесь то же reinterpret_cast не изменяет адрес, выходит, что он просто заставляет трактовать данный указатель как IUnknown*, который на самом деле является INondelegatingUnknown*, а вызовы методов выполняются по индексу в vtbl. Это и есть полиморфизм :D  Так я понял? Но почему в данном случае reinterpret_cast не изменяет адрес хоть убей не понимаю - неужели компилятор сам обо всём догадывается  :?:
   
   }
   else
   {
      trace("Agrgation, delegating outer IUnknown");
      m_pUnknownOuter = pUnknownOuter;
   }
}

« Последнее редактирование: 25-11-2007 15:59 от Алексей1153++ » Записан
um
Гость
« Ответ #3 : 30-03-2004 19:36 » 

из msdn:
Цитата

reinterpret_cast Operator
C++ Specific —>

reinterpret_cast < type-id > ( expression )

The reinterpret_cast operator allows any pointer to be converted into any other pointer type, and it allows any integral type to be converted into any pointer type and vice versa. Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired conversion is inherently low-level, you should use one of the other cast operators.

END C++ Specific

т.е. он реально никакими махинациями с vtable не занимается. а "...allows any pointer to be converted..." означает, что любой указатель можно привести к любому типу и никакой проверки на валидность этой операции не производится.

кстати, в msdn можно посмотреть дополнительную инфу по указателю "static_cast type conversion operator" - вылезет статейка как раз по приведению типов.
попробуй через dynamic_cast - он использует RTTI.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines