Поскольку только что описанное поведение является полезным для большого класса объектов, в СОМ предусмотрена агрегируемая реализация IMarshal, выполняющая в точности то, что было описано. Эта реализация называется маршалером свободной поточной обработки (FreeThreaded Marshaler - FTM) и может быть осуществлена с помощью вызова API-функции CoCreateFreeThreadedMarshaler:
HRESULT CoCreateFreeThreadedMarshaler( [in] IUnknown *pUnkOuter, [out] IUnknown **ppUnkInner);
Класс, который желает использовать FTM, просто агрегирует экземпляр либо во время инициализации, либо по требованию при первом запросе QueryInterface об интерфейсе IMarshal. Следующий класс заранее обрабатывает FTM во время построения.
class Point : public IPoint { LONG m_cRef; IUnknown *m_pUnkFTM; long m_x; long m_y; Point(void) : m_cRef(0), m_x(0), m_y(0) { HRESULT hr = CoCreateFreeThreadedMarshaler(this,&m_pUnkFTM); assert(SUCCEEDED(hr)) ; } virtual ~Point(void) { m_pUnkFTM->Release(); } };
Соответствующая реализация QueryInterface просто запросила бы интерфейс IMarshal из FTM:
STDMETHODIMP Point::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown riid == IID_IPoint) *ppv = static_cast<IPoint*>(this); else if (riid == IID_IMarshal) return m_pUnkFTM->QueryInterface(riid, ppv); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown* )*ppv)->AddRef(); return S_OK; }
Поскольку используется FTM, не понадобится никаких заместителей, как бы ни маршалировались через внутрипроцессные границы апартамента ссылки на объекты Point. Это применимо к явным вызовам CoMarshalInterface / CoUnmarshalInterface, а также в случаях, когда ссылки на объекты Point передаются как параметры метода на внутрипроцессные заместители объектов, не являющихся объектами Point.