// получаем размер специально маршалированной объектной ссылки (CoGetMarshalSizeMax)
HRESULT GetMarshalSizeMax( [in] REFIID riid, [in, iid_is(riid)] void *pv, [in] DWORD dwDestCtx, [in] void *pvDestCtx, [in] DWORD mshlflags, [out] DWORD *pSize);
// write out custom marshaled objref (CoMarshalInterface)
// выполняем контрольное считывание специально маршалированной объектной ссылки (CoMarshalInterface)
HRESULT MarshalInterface([in] IStream *pStm, [in] REFIID riid, [in, iid_is(riid)] void *pv, [in] DWORD dwDestCtx, [in] void *pvDestCtx, [in] DWORD mshlflags);
// read objref and return proxy (CoUnmarshalInterface)
// читаем объектную ссылку и возвращаем заместитель (CoUnmarshalInterface)
HRESULT UnmarshalInterface([in] IStream *pStm, [in] REFIID riid, [out, iid_is(riid)] void **ppv);
// revoke a marshal (CoReleaseMarshalData)
// аннулируем маршалер (CoReleaseMarshalData)
HRESULT ReleaseMarshalData([in] IStream *pStm);
// tear down connection-state (CoDisconnectObject)
// разрываем связь между объектами (CoDisconnectObject)
HRESULT DisconnectObject([in] DWORD dwReserved);
}
Комментарии, предваряющие определения методов, показывают, какие именно API-функции вызывает каждый из них.
Когда метод CoMarshalInterface вызывается на объект, поддерживающий специальный маршалинг, маршалированная объектная ссылка имеет несколько другой (формат, как показано на рис. 5.7. Заметим, что после стандартного заголовка MEOW маршалированная объектная ссылка просто содержит CLSID, используемый для создания специального заместителя и непрозрачного байтового массива, предназначенного для инициализации этого специального заместителя. CoMarshalInterface находит CLSID специального заместителя посредством вызова на объект метода IMarshal::GetUnmarshalСlass . CoMarshalInterface заполняет непрозрачный байтовый массив, вызывая реализацию метода IMarshal::MarshalInterface объекта. Именно в MarshalInterface объект получает свой первый и единственный шанс послать инициализационное сообщение новому специальному заместителю, просто записав его в подаваемый байтовый поток.
При вызове CoUnmarshalInterface это сообщение будет передано вновь созданному специальному заместителю через его метод IMarshal::UnmarshalInterface . Это означает, что и объект, и специальный заместитель должны реализовать IMarshal . Метод объекта MarshalInterface записывает инициализационное сообщение. Метод заместителя UnmarshalInterface читает инициализационное сообщение. Когда метод UnmarshalInterface возвращается, СОМ больше не участвует ни в каких связях заместитель/объект. Реализация интерфейсных методов семантически корректным способом является делом специального заместителя. Если нужно произвести удаленный вызов метода на объект, то сделать это – задача заместителя. Если же метод может быть реализован в апартаменте клиента, то заместитель может сделать и это.
Преимуществом специального маршалинга является то, что клиент не имеет понятия о его использовании. Фактически клиент не может достоверно определить, является ли интерфейс стандартным заместителем, специальным заместителем или настоящим объектом. Специальный маршалинг является решением на уровне объект-объект. Два экземпляра одного и того же класса могут независимо друг от друга избрать стандартный или специальный маршалинг. Если объект выбирает реализацию специального маршалинга, то он должен делать это для всех интерфейсов. Если объект желает специально маршалировать только для части всех возможных контекстов, подлежащих маршалингу – например, внутрипроцессный, локальный, с другой машины, – то он может получить экземпляр стандартного маршалера и направить его методы IMarshal для маршалинга неподдерживаемых контекстов, так чтобы могли поддерживаться все контексты. Если бы объект мог безоговорочно направить все методы IMarshal к стандартному маршалеру, то он практически всегда использовал бы стандартный маршалинг.
Для получения указателя на стандартный маршалер объекты могут вызывать метод CoGetStandardMarshal :
HRESULT CoGetStandardMarshal( [in] REFIID riid,
// type of itf marshaled?
// тип, которым маршалирован интерфейс?
[in, iid_is(riid)] IUnknown *pUnk,
// the itf to marshal
// интерфейс для маршалинга
[in] DWORD dwDestCtx,
// 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!
// если контекст поддерживается, то действуем!
Читать дальше