// MSHCTX [in] void *pvDestCtx,
// reserved // зарезервировано [in] DWORD mshlflags,
// normal vs. table // нормальный или табличный маршалинг
[out] IMarshal **ppMarshal); // ptr to std. Marshal
// указатель на стандартный маршалер
Предположим, что объект использует технологию специального маршалинга, которая работает только на локальном хосте, но не при связи с внехостовыми апартаментами. Реализация объектом метода
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;
}
В этом фрагменте кода не показано, как писать инициализационное сообщение для случая, когда действительно желателен специальный маршалинг. Дело в том, что не существует стандартной реализации каждого из методов
Маршалинг по значению наиболее удобен для таких объектов, которые после инициализации никогда не изменяют своего состояния. Обертки СОМ для структур – вот типичный пример объекта, который просто инициализирован, передан другому объекту для запроса и затем уничтожен. Такой объект является первым кандидатом для специального маршалинга. При реализации маршалинга по значению реализация объекта почти всегда является внутрипроцессным сервером. Это позволяет объекту и заместителю разделять один и тот же класс реализации. Идея маршалинга по значению состоит в том, что специальный заместитель становится клоном исходного объекта. Из этого следует, что маршалированная объектная ссылка должна содержать все состояние исходного объекта, а также (для простоты) то, что 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
};
Для поддержки маршалинга по значению метод
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);
}
Если допустить, что класс объекта реализован как внутрипроцессный сервер, то специальный заместитель может стать просто вторым экземпляром того же класса, из чего вытекает следующая реализация
STDMETHODIMP Point::GetUnmarshalClass(REFIID, void *, DWORD, void *, DWORD, CLSID *pclsid)
{
*pclsid = CLSID_Point;
// this class's CLSID
// CLSID этого класса return hr;
}
Для обеспечения того, чтобы для инициализационного сообщения было выделено достаточно места, методу объекта
STDMETHODIMP Point::GetMarshalSizeMax(REFIID, void *, DWORD, void *, DWORD, DWORD *pcb)
{
*pcb = 3 * sizeof (DWORD);