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

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Ручной маршалинг  (Прочитано 17554 раз)
0 Пользователей и 1 Гость смотрят эту тему.
WDMclient
Гость
« : 26-01-2010 09:50 » 

Третий день не могу овладеть техникой custom (ручного) маршалинга.

Не помогает ни Дональдс Бокс, ни  Дейл Роджерсон, ни RSDN.

В плане описания, как это делать я бы им уши пооткручивал ими не доволен.
(Беретесь учить, так не надо халтурить)

Вообще, что касается COM, спасибо только случайным статьям неизвестных маэстро от практики.

Граждане, может, кто владеет такой техникой, поделитесь?

У меня задача: передать объект по значению.

Например, на сервере есть объект KOT
class KOT
{
   methodKot()  {cout<<"Hello KOT"<<endl;}
}

клиент получает от сервера этот объект, рвет связь с сервером и проводит этот  methodKot сам у себя.
« Последнее редактирование: 30-01-2010 07:56 от Sel » Записан
WDMclient
Гость
« Ответ #1 : 30-01-2010 05:43 » 

В общем, не догоняю чегоо,  решил сперва не передавать объект,
попытаться просто вызывать тот же метод(methodKot) интерфейса(InterfaceKot), что
при стандартном маршалинге , но перевести его на ручной маршалинг


--------------------------------------------------------------------------------------
SERVER.exe
Сервер самый обычный  так сказать классический    SERVER.EXE

CLSID_ObjectKot       -        компонент ObjectKot    (и его же  надо передать - абсолютная задача)
IID_InterfaceKot   -        есть у Кота   один интерфейс -  InterfaceKot



Клиент делает простой вызов
Код:
//------------------------------------------------------------------------------
// CLIENT.exe  - клиент

CoInitialize(0);

CoGetClassObject(  CLSID_ObjectKot , CLSCTX_LOCAL_SERVER,   NULL,
                                     IID_IClassFactory, (void **) &pClassFactory);


InterfaceKot  * i_kot=NULL;

  hr=pClassFactory->CreateInstance(
 NULL ,
 IID_InterfaceKot,
 (void**)&i_kot );


на сервере один компонет и один интерфейс
Код:
-----------------------------------------------------------------------------
SERVER.exe

//========IUnknown_kot   тот же  IUnknown ,   что бы не было накладок  ,
//========а то IMarshal тоже использует IUnknown
class IUnknown_kot  
{
public:
virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppAny)=0;
virtual STDMETHODIMP_(ULONG) AddRef()=0;
virtual STDMETHODIMP_(ULONG) Release()=0;
};

//=====интерфейс
interface  InterfaceKot        :public IUnknown_kot
{
 virtual HRESULT __stdcall   methodKot ()=0;
};

//=====компонент
class   ObjectKot     : public IMarshal , public   InterfaceKot
{
public:
    ObjectKot();
   ~ObjectKot();
  // IUnknown
  ................QueryInterface , addRef , Release тут
  //  IMarshal
  .......................GetUnmarshalClass
  .......................GetMarshalSizeMax
  .......................MarshalInterface
  .......................UnmarshalInterface
  .......................ReleaseMarshalData
  .......................DisconnectObject
 //  InterfaceKot
 virtual HRESULT __stdcall  methodKot (){ cout<<"Hello  Kot"<<endl;}

//variables
static long active_component;  //глобальный счетчик всех компонентов
ULONG m_refCount;                 //приватный счетчик одного компонента
};
---------------------------------------------------------------------



Один момент,  надо учесть  в   QueryInformation   riid == IID_IMarshal

Код:
STDMETHODIMP ObjectKot::QueryInterface(REFIID riid, void ** ppAny)
{
      //---------------------------------------------
          if(riid == IID_IUnknown) {      *ppAny = this;  }

  else if(riid == IID_InterfaceKot) {   *ppAny =(InterfaceKot*) this;  }

  else if(riid == IID_IMarshal)     { *ppAny = (IMarshal*) this;     }

     else{          *ppAny = NULL;              
              return E_NOINTERFACE;
            }
      //---------------------------------------------      
((IUnknown *)(*ppAny))->AddRef();

    return S_OK;
}


Теперь надо пройтись по методам IMarshal    в   ObjectKot

Код:
и первый метод который получит вызов
при ручном маршалинге GetUnmarshalClass
тут нужно передать CLSID объекта который вроде бы как должен будет
появиться  у клиента и  создать и передать указатель на интерфейс , или объект или данные какие)
Тут так запутано что нигде толком я не нашел объяснения что это за CLSID

STDMETHOD(GetUnmarshalClass)
 (REFIID riid, void * pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags, CLSID* pCid )
{
   //===ВАРИАНТЫ ТАКИЕ:
      *pCid =   CLSID_ObjectKot;  // по идее это должен быть ObjectKot
     //   *pCid =IID_InterfaceKot; // а могет быть и это
     //*pCid =  CLSID_какого_еще_Proxy????;     //  какой то неизвестный мне вариант??????  
return S_OK;
}



Следующий вызовется метод  GetMarshalSizeMax

Код:
STDMETHOD(GetMarshalSizeMax)
(REFIID riid, void * pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags, ULONG* pSize )
{
//  передаем размер желаемого буфера
// sizeof(ЗАГОЛОВОК) + sizeof(active_component) +  sizeof(m_refCount) ;

*pSize = 3 * sizeof (DWORD);

return S_OK;
}

и теперь очередь дойдет до MarshalInterface
Система выделила уже буфер-Stream, и  мы положим туда значения переменных  ObjectKot и заголовок
Код:
Упрощенно это выглядит так

STDMETHOD(MarshalInterface)  
(IStream* pStm, REFIID riid, void *pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags)
{    
       AddRef();

   DWORD dw = 0xFF669900; //ЗАГОЛОВОК
   pStm->Write(&dw, sizeof(DWORD), 0);
 
   dw = this->m_refCount;  
   hr = pStm->Write(&dw, sizeof(DWORD), 0);

   dw = this->active_component;
   return pStm->Write(&dw, sizeof (DWORD), 0);

}


Обратная распаковка  данных из Stream ,  на стороне клиента(с проверкой Endian)
Код:
Но почему[color=red][b]-т[/b][/color]о она уже не срабатывает  ???????????????

STDMETHOD(UnmarshalInterface)(IStream* pStm, REFIID riid, void ** ppv )
{
 *ppv = 0;
 DWORD dw; ULONG cbRead;
   // read endian header
   // читаем заключительный заголовок
   DWORD dw;
   ULONG cbRead;
   HRESULT hr = pStm->Read(&dw, sizeof (DWORD), &cbRead);
   if (FAILED(hr) || cbRead != sizeof(DWORD)) return RPC_E_INVALID_DATA;
   //============
   bool bSwapEndian = dw == 0x009966FF;
  
   hr = pStm->Read(&dw, sizeof(DWORD), &cbRead);
   this->m_refCount  = dw;
   if (FAILED(hr) || cbRead != sizeof(DWORD)) return RPC_E_INVALID_DATA;

   // ============
   hr = pStm->Read(&dw, sizeof(DWORD), &cbRead);
   this->active_component = dw;
   if (FAILED(hr) || cbRead != sizeof(DWORD)) return RPC_E_INVALID_DATA;
   // ============
   // byte swap members if necessary
   // байт переставляет свои биты, если необходимо
   if (bSwapEndian)  MessageBox(0 , "UnMarshalInterface","1-2",0);//byteswapdata(&m_x, &m_y);
   // return pointer to this object

}

Два последних метода, соответственно, тоже не вызываются?Не понял??

Код:
STDMETHOD (ReleaseMarshalData)(IStream *pStm)
{

return S_OK;
}
 
    STDMETHOD (DisconnectObject)(DWORD dwReserved)
{

return S_OK;
}



Короче не работало и не работает
« Последнее редактирование: 30-01-2010 07:54 от Sel » Записан
WDMclient
Гость
« Ответ #2 : 30-01-2010 05:56 » new

Пока интересует вопрос

чей СLSID передается в GetUnmarshalClass

Код:
STDMETHOD(GetUnmarshalClass)
 (REFIID riid, void * pv, DWORD dwDestContext, void * pvDestContext, DWORD mshlFlags, CLSID* pCid )
{
   //===ВАРИАНТЫ ТАКИЕ:
      *pCid =   CLSID_ObjectKot;  // по идее это должен быть ObjectKot
     //   *pCid =IID_InterfaceKot; // а могет быть и это
     //*pCid =  CLSID_какого_еще_Proxy????;     //  какой то неизвестный мне вариант??????   
return S_OK;
}
Записан
WDMclient
Гость
« Ответ #3 : 30-01-2010 07:41 » 

Интересно что кто то считает технологию COM или СОRBA сложной.

На самом деле сложных технологий в программироании не бывает.

Есть обычное отсуствие информации о конкретной технологии.Со стороны
разработчиков этой технологии.

Если бы я писал приложение тока для себя я бы реализовал этот COM

на ассемблере  максимум за неделю с его моникерами и маршалами и DCOMами.

Но тут нужно придерживаться стандартных протоколов , а какие они на самом деле
узнать не-где.

P.S.
Перечитал штук 30 статей и 3-4 книги по COM.
Впечатление тягостное.
Мозги требуют информации.
Пойду пива банку опрокину. :=))
Записан
WDMclient
Гость
« Ответ #4 : 03-02-2010 17:56 » 

Отчет о проделанной работе.

еще 4 дня пил пиво ведрами.

просмотрел 200 или 300 сайтов , статей , монографий.

был приятно удивлен количеству невменяемой информации.(Ни одного примера на С++)

Зародилось подозрение ,  COM - это новоя , революционно-свежая технология ,
мало кому известная.
Странно даже , те кто ее хоронят почти ничего про нее не знают.
« Последнее редактирование: 03-02-2010 17:58 от WDMclient » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 03-02-2010 17:58 » 

я, кстати, тоже абсолютно ничего не знаю про COM ))) Пока не было проблем.
Записан

WDMclient
Гость
« Ответ #6 : 03-02-2010 18:00 » 

я, кстати, тоже абсолютно ничего не знаю про COM ))) Пока не было проблем.


Я пока не знал , тоже проблем вроде не было.
%=))

Начал копать , появились (и сразу жисть наполнилась смыслом).
« Последнее редактирование: 03-02-2010 18:13 от WDMclient » Записан
WDMclient
Гость
« Ответ #7 : 10-02-2010 13:36 » 

блин уже дня 4 как забыл отписать.

Короче маршалинг этот оказался на редкость простой , НАДЕЖНОЙ И МУДРОЙ штукой.
Я то думал надо целый кусок памяти (данные и исполняемый код(функции класса))
отсылать клиенту , а потом заниматься лично его инжектингом , а на самом деле просто работает еще одна ДЛЛ-ка , и вот именно это proxy DLL подгружается к  клиенту ,
и содержит в простом случае копию компонента KOT что я использую в своем EXE-сервере. это именно его CLSID надо указать в  GetUnmarshalClass для exe-сервера.

STDMETHOD(GetUnmarshalClass)
                     (REFIID riid,
                      void * pv,
                      DWORD dwDestContext,
                      void * pvDestContext,
                      DWORD mshlFlags,
                      CLSID* pCid )
{
  
      *pCid =   CLSID_ObjectKotProxyDLL;  // вот этот компонент будет создан уже в
                                          //  proxy  в клиенте
//то бишь подгрузиться DLL ка с кодом для энтого объекта
    
return S_OK;
}


 UnmarshalInterface будет вызван только для компонента в PROXY_DLL (уже в клиенте) ,
 а конкретно для objectKotProxy  , и в этой функции можно создать и передать указатель
на любой (какой ни пожелаешь) объект или интерфейс


   STDMETHOD(UnmarshalInterface)(IStream* pStm, REFIID riid, void ** ppv )
   {
      
      *ppv = (InterfaceKot*)this; // можно так
            return S_OK;      
      
        //return  QueryInterface(riid, ppv); //или так , как положено
      
   }

Да тут вообще вариантов много (но в итого тупо просто и однотипно)


P.S.
Дейлу Роджерсону - уши окручивать не буду , потому как он хорошо показал
как многопоточность регулировать.
« Последнее редактирование: 11-02-2010 17:13 от WDMclient » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines