// MSHCTX [in] void *pvDestCtx,

// reserved // зарезервировано [in] DWORD mshlflags,

// normal vs. table // нормальный или табличный маршалинг

[out] IMarshal **ppMarshal); // ptr to std. Marshal

// указатель на стандартный маршалер

Предположим, что объект использует технологию специального маршалинга, которая работает только на локальном хосте, но не при связи с внехостовыми апартаментами. Реализация объектом метода GetMarshalSizeMax могла бы выглядеть примерно так:

STDMETHODIMP CustStd::GetMarshalSizeMax(

ULONG *pcb, REFIID riid, void *pv, DWORD dwDestCtx, void *pvDestCtx, DWORD mshlflags) {

// if context is supported, do work!

// если контекст поддерживается, то действуем!

if (dwDestCtx == MSHCTX_LOCAL || dwDestCtx == MSHCTX_INPROC) return this- >MyCustomMarshalingRoutine(pcb);

// unsupported context, delegate to std marshal

// контекст не поддерживается, обращаемся к стандартному маршапингу

IMarshal *pMsh = 0;

HRESULT hr = CoGetStandardMarshal (riid, pv, dwDestCtx, pvDestCtx, mshlflags, &pMsh);

if (SUCCEEDED(hr)) {

hr = pMsh->GetMarshalSizeMax(pcb, riid, pv, dwDestCtx, pvDestCtx, mshlflags);

pMsh->Retease();

}

return hr;

}

В этом фрагменте кода не показано, как писать инициализационное сообщение для случая, когда действительно желателен специальный маршалинг. Дело в том, что не существует стандартной реализации каждого из методов IMarshal (отсюда и термин специальный (custom) маршалинг). Существует, однако, несколько общих сценариев, в которых специальный маршалинг чрезвычайно выигрышен и реализация IMarshal в этих сценариях – довольно обычное явление. Безусловно, наиболее общим приложением IMarshal является реализация маршалинга по значению (marshal-by-value).

Маршалинг по значению наиболее удобен для таких объектов, которые после инициализации никогда не изменяют своего состояния. Обертки СОМ для структур – вот типичный пример объекта, который просто инициализирован, передан другому объекту для запроса и затем уничтожен. Такой объект является первым кандидатом для специального маршалинга. При реализации маршалинга по значению реализация объекта почти всегда является внутрипроцессным сервером. Это позволяет объекту и заместителю разделять один и тот же класс реализации. Идея маршалинга по значению состоит в том, что специальный заместитель становится клоном исходного объекта. Из этого следует, что маршалированная объектная ссылка должна содержать все состояние исходного объекта, а также (для простоты) то, что CLSID специального заместителя должен быть тем же, что и у исходного объекта.

Представим следующее определение класса СОМ-обертки вокруг простой двумерной точки:

class Point : public IPoint, public IMarshal

{

long m_x;

long m_y;

public:

Point(void) : m_x(0), m_y(0) {}

IMPLEMENT_UNKNOWN (Point)

BEGIN_INTERFACE_TABLE(Point)

IMPLEMENTS_INTERFACE(IPoint)

IMPLEMENTS_INTERFACE(IMarshal)

END_INTERFACE_TABLE()

// IPoint methods

// методы IPoint

// IMarshal methods

// методы IMarshal

};

Для поддержки маршалинга по значению метод 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);

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату