Сущность технологии COM


         

Специальный маршалинг - часть 5


Для поддержки маршалинга по значению метод MarshalInterface класса должен преобразовать состояние объекта в последовательную форму в качестве инициализационного сообщения для заместителя:

STOMETHODIMP Point::MarshalInterface(IStream *pStm, REFIID, void *, DWORD, void *, DWORD) { // write out endian header // переписываем завершающий заголовок DWORD dw = OxFF669900; HRESULT hr = pStm->Write(&dw, sizeof(DWORD), 0); if (FAILED(hr)) return hr; dw = m_x; hr = pStm->Write(&dw, sizeof(DWORD), 0); if (FAILED(hr)) return hr; dw = m_y; return pStm->Write(&dw, sizeof (DWORD), 0); }

Если допустить, что класс объекта реализован как внутрипроцессный сервер, то специальный заместитель может стать просто вторым экземпляром того же класса, из чего вытекает следующая реализация GetUnmarshalClass:

STDMETHODIMP Point::GetUnmarshalClass(REFIID, void *, DWORD, void *, DWORD, CLSID *pclsid) { *pclsid = CLSID_Point; // this class's CLSID // CLSID этого класса return hr; }

Для обеспечения того, чтобы для инициализационного сообщения было выделено достаточно места, методу объекта GetMarshalSizeMax требуется возвратить правильное количество байт:

STDMETHODIMP Point::GetMarshalSizeMax(REFIID, void *, DWORD, void *, DWORD, DWORD *pcb) { *pcb = 3 * sizeof (DWORD); // m_x + m_y + header return hr; }

Когда маршалированная объектная ссылка демаршалируется с помощью CoUnmarshalInterface, тот факт, что она была маршалирована специальным образом, вызовет создание нового специального заместителя. Объектная ссылка содержит CLSID специального заместителя, возвращенный исходным объектом в своем методе GetUnmarshalClass. Когда создан новый специальный заместитель, его метод UnmarshalInterface получает инициализационное сообщение, которое объект записал в своей реализации MarshalInterface:

STDMETHODIMP Point::UnmarshalInterface(IStream *pStm, REFIID riid, void ** ppv) { *ppv = 0; // 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; // read m_x and m_y // читаем m_x и m_y hr = pStm->Read(&dw, sizeof(DWORD), &cbRead); m_x = dw; if (FAILED(hr) cbRead != sizeof(DWORD)) return RPC_E_INVALID_DATA; hr = pStm->Read(&dw, sizeof(DWORD), &cbRead); m_y = dw; if (FAILED(hr)) cbRead != sizeof(DWORD)) return RPC_E_INVALID_DATA; // byte swap members if necessary // байт переставляет свои биты, если необходимо if (bSwapEndian) byteswapdata(&m_x, &m_y); // return pointer to this object // возвращаем указатель на этот объект return this->QueryInterface(riid, ppv); }

Отметим, что реализация MarshalInterface и UnmarshalInterface должна позаботиться о том, чтобы маршалированное состояние могло читаться на любой платформе. Это означает ручную работу по выравниванию, расстановке байтов и учету различий в размерах типов данных.

Приведенная здесь реализация UnmarshalInterface просто возвращает указатель вновь созданному специальному заместителю. Для простого объекта, маршалированного по значению, это может быть приемлемо. Однако более типичные реализации UnmarshalInterface могут захотеть найти несколько демаршалированных указателей, соответствующих одной и той же идентификационной единице СОМ, и возвратить указатель на заместитель той же единицы, чтобы установить отношение идентичности заместителя объекту. Это может не только сэкономить ресурсы, но также повысить чистоту программы.




Содержание  Назад