Почему QueryInterface () завершится ошибкой, если интерфейс обязательно реализован и имеет встроенный маршаллер в Windows?

У меня есть следующие настройки. Там's COM-сервер, который установлен в COM + (для запуска в отдельном процессе) и имеет следующее определение интерфейса:

[object, uuid("InterfaceIdHere"), nonextensible, oleautomation, hidden]
interface IMyInterface : IUnknown {
   HRESULT MyMethod( [in] IUnknown* param );
};

Звонящий звонит так:

HRESULT callComObject(IStream* stream)
{
    return comObject->MyMethod(stream);
}

Обратите внимание, что здесьIStream* косвенно повышен доIUnknown*, Это сделано потому, что объявление параметра типаIStream* в IDL вызвало некоторые проблемы, которые я могуне помню сейчас. Во всяком случае этовсегда действительныйIStream* это передается вместо.IUnknown*

На стороне COM-сервера есть такая реализация:MyMethod()

STDMETHODIMP CServer::MyMethod(IUnknown* param)
{
    if(param == 0) {
       return E_INVALIDARG;
    }   
    ATL::CComQIPtr stream(param);
    if(stream == 0) {
       return E_INVALIDARG;// control passes HERE
    }
    // whatever
}

Так что яIStream* перешел вcallComObject() на стороне клиента, которая неявно подталкивается кIUnknown* и последний передается маршаллеру СОМ. МаршаллIUnknown* достигает сервера в другом процессе и тамIUnknown* получается и тогдасQueryInterface() позвонить маршалуIStream* от того же объекта иQueryInterface() выходит из строя.

Это выглядит безумно, потому что сортировкаIStream* должен просто работать всегда - тамМаршаллер для этого интерфейса предварительно установлен в Windows.

Почему это может не сработать и как мне найти причину?

 sharptooth16 мая 2013 г., 17:52
@SimonMourier: я полагаюсь на маршаллера OleAut, тамНет собственного прокси / заглушки. "
 Remy Lebeau16 мая 2013 г., 16:34
ВызовQueryInterface() непосредственно вместо использованияCComQIPtr и тогда вы можете проверить, чтоHRESULT значение это на самом деле возвращается.
 sharptooth17 мая 2013 г., 10:11
@MSalters: мой код также является своего рода сервером, которыйS откуда-то вызывается и что-то управляетIStream*объект Поэтому я думаю, что ответ - я понятия не имею о времени жизни объекта. Я полагаю, звоню дополнительноAddRef() не повредит.
 sharptooth16 мая 2013 г., 16:40
@RemyLebeau: HRESULT есть.E_NOINTERFACE
 Simon Mourier16 мая 2013 г., 17:05
Вы используете неявный маршалер OLEAUT? или пользовательский прокси / заглушка? Является ли стандартный маршалер OLEAUT маршалом для чего-то еще, кроме типов Variant, если этоне знает (например: если idl / typelib не 'ничего не скажешь об этом)
 MSalters17 мая 2013 г., 00:32
IStream * неявно преобразуется в IUnknown * ", Если вы сделали это через COM, то есть черезIStream::QueryInterface(IID_IUnknown), вы'буду иметь AddRef 'Редактировал новый интерфейс. Вы случайно не выпускаете поток слишком рано?

Ответы на вопрос(3)

го предков) вручную в своем собственном IDL (просто убедитесь, что для него используется стандартное значение IID). Тогда вы можете использовать IStream вместо IUnknown в качестве типа вашего параметра и не беспокоиться оQueryInterface() больше.

его метода. На мой взгляд, на самом деле сервер имеет заглушку вместо самого потока, поскольку он находится в другом процессе.

это всего лишь предположение

надеюсь, это поможет

 sharptooth16 мая 2013 г., 16:41
Да, есть только заглушка, ноQueryInterface() должен быть перенаправлен на клиентскую сторону, получить правильный интерфейс и вернуть его обратно.
 loic16 мая 2013 г., 21:20
@sharptooth извиняюсь, тысовершенно верно
Решение Вопроса

который соответствует поведению, следующий:

ты нене должно быть никакого маршалинга между абонентом и вызываемым абонентомуказатель интерфейса действителенОднако объект, который реализуетIStream, не имеет соответствующегоCOM_INTERFACE_ENTRY запись карты и не делает доступным интерфейс, вызывающий абонент мог получить указатель не-COM-способом, например, прямое приведение C ++

Это легко проверить поQueryInterfaceПередача потока на стороне вызывающего абонента перед вызовом.

Вызываемый в этом сценарии может простоreinterpret_cast вIStream и это хорошо работает.

 MSalters17 мая 2013 г., 00:26
Это'Это действительно хорошая идея, чтобы проверить, если вы можете QIIStream* в отсутствие сортировки.

Ваш ответ на вопрос