45825 (Перехват методов COM интерфейсов), страница 5

2016-07-31СтудИзба

Описание файла

Документ из архива "Перехват методов COM интерфейсов", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "45825"

Текст 5 страницы из документа "45825"

Рисунок 5. Буфер с in-параметрами вызова

Работа с параметрами вызова в обработчике

В примере выше мы делегировали работу по преобразованию стека вызова в бинарный буфер перехватчику. Бинарные буферы с параметрами вызова отлично подходят для многих видов транспорта – RPC, MSMQ. Однако если бы мы захотели использовать SOAP для передачи вызова компоненту, такое бинарное представление было бы неприемлемо, так как SOAP-сообщение представляет собой XML-текст, содержащий значения каждого из in-параметров по отдельности. Подробнее о протоколе SOAP и формате SOAP-сообщений можно прочитать в статье: “Использование протокола SOAP в распределенных приложениях Microsoft SOAP Toolkit 3.0”.

В этой статье был рассмотрен способ создания Proxy, работающей через ранее связывание (SOAP Toolkit использует IDispatch и позднее связывание для вызовов). Proxy поддерживала интерфейс:

interface ISoapProxy : IDispatch

{

[id(1), helpstring("method Initialize")]

HRESULT Initialize([in]BSTR wsdl, [in]BSTR wsml,

[in]BSTR service, [in]BSTR port);

[propget, id(2), helpstring("property ConnectorProperty")]

HRESULT ConnectorProperty([in]BSTR prop, [out, retval] VARIANT *pVal);

[propput, id(2), helpstring("property ConnectorProperty")]

HRESULT ConnectorProperty([in]BSTR prop, [in] VARIANT newVal);

[propget, id(3), helpstring("property ProxyProperty")]

HRESULT ProxyProperty([in]BSTR prop, [out, retval] VARIANT *pVal);

[propput, id(3), helpstring("property ProxyProperty")]

HRESULT ProxyProperty([in]BSTR prop, [in] VARIANT newVal);

[id(4), helpstring("method GetOperation")]

HRESULT GetOperation([in]BSTR name, [out,retval]IWSDLOperation** ppOp);

[id(5), helpstring("method Execute")]

HRESULT Execute([in]IWSDLOperation* pOp);

};

Для каждого из интерфейсов/методов был написан код, перенаправляющий вызовы Proxy, которая, в свою очередь, использовала низкоуровневые компоненты из SOAP Toolkit для передачи вызова SOAP-серверу.

Например, реализация одного из методов выглядела так:

STDMETHOD(KillProcess)(LONG processID)

{

try

{

// получаем описание операции KillProcess

IWSDLOperationPtr spOp =

m_spSoapProxy->GetOperation(L"KillProcess");

IEnumSoapMappersPtr spEnum;

// заполняем значения входных параметров

spOp->GetOperationParts(&spEnum);

while(true)

{

long l = 0;

ISoapMapperPtr spMap;

spEnum->Next(1, &spMap, &l);

if(l == 1)

{

if(spMap->PartName == _bstr_t(L"processID"))

spMap->ComValue = processID;

}

else

break;

}

// передаем вызов серверу

m_spSoapProxy->Execute(spOp);

}

catch(_com_error & e)

{

return e.Error();

}

return S_OK;

}

ПРИМЕЧАНИЕ

В этом коде m_spSoapProxy – экземпляр Proxy (описание интерфейса см. выше)

Реализации для разных методов различались лишь названиями методов (или операций, в терминах SOAP) и названиями параметров. Вместо того, чтобы писать однотипный код, можно создать перехватчик для нужного интерфейса CoGetInterceptor, а в методе ICallFrameEvents::OnCall, напрямую манипулируя с параметрами вызова, создать SOAP-сообщение.

Получить значение параметра позволяет метод ICallFrame::GetParam:

HRESULT GetParam(

ULONG iparam,

VARIANT * pvar

);

Нам нужен номер параметра, который можно получить из описания SOAP-операции ISoapMapper::get_CallIndex:

[propget] HRESULT callIndex([out, retval] long* par_lCallIndex);

После вызова метода нам потребуется метод для задания нового значения out-параметра в стеке ICallInfo::SetParam и метод для задания результата выполнения метода ICallInfo::SetReturnValue:

HRESULT SetParam(

ULONG iparam,

VARIANT * pvar

);

HRESULT SetReturnValue(

HRESULT hr

);

И, наконец, нужно отличать in- и out-параметры. Сделать это можно вызовом ISoapMapper::get_IsInput.

Полный код реализации обработчика вызова приведен ниже:

STDMETHOD(OnCall)(ICallFrame* pFrame)

{

LPWSTR lpszItf ,lpszMethod;

HRESULT hr = pFrame->GetNames(&lpszItf, &lpszMethod);

CoTaskMemFree(lpszItf);

// получаем описание SOAP-операции из WSML

CComPtr spOp;

hr = m_spProxy->GetOperation(CComBSTR(lpszMethod) , &spOp);

CoTaskMemFree(lpszMethod);

if(SUCCEEDED(hr))

{

CComPtr spEnum;

hr = spOp->GetOperationParts(&spEnum);

if(SUCCEEDED(hr))

{

// перебираем все параметры

while(hr == S_OK)

{

CComPtr spMapper;

long lFetched = 0;

hr = spEnum->Next(1, &spMapper, &lFetched);

if(!lFetched || hr != S_OK)

break;

long idx = 0;

smIsInputEnum paramType;

hr = spMapper->get_IsInput(¶mType);

// для in-параметров берем значения из стека

if(paramType == smInput || paramType == smInOut)

{

hr = spMapper->get_callIndex(&idx);

if(SUCCEEDED(hr) && (idx >= 0))

{

CComVariant value;

hr = pFrame->GetParam(idx, &value);

hr = spMapper->put_ComValue(value);

}

}

}

if(SUCCEEDED(hr))

{

// выполняем вызов

hr = m_spProxy->Execute(spOp);

}

}

if(SUCCEEDED(hr))

{

// перебираем все параметры

spEnum->Reset();

while(hr == S_OK)

{

CComPtr spMapper;

long lFetched = 0;

hr = spEnum->Next(1, &spMapper, &lFetched);

if(!lFetched || hr != S_OK)

break;

smIsInputEnum paramType;

hr = spMapper->get_IsInput(¶mType);

// для out-параметров устанавливаем новое значение

if(paramType == smOutput || paramType == smInOut)

{

long idx = 0;

hr = spMapper->get_callIndex(&idx);

if(SUCCEEDED(hr) && idx >= 0)

{

CComVariant value;

hr = spMapper->get_ComValue(&value);

hr = pFrame->SetParam(idx, &value);

}

}

}

}

else

{

// если вызов завершился с ошибкой – устанавливаем return value

pFrame->SetReturnValue(hr);

}

}

return hr;

}

Приведенный выше код работать не будет. :с))

Во-первых, вызов ISoapMapper::get_callIndex всегда возвращает -1, независимо от параметра.

Во-вторых, вызов ICallFrame::SetParam возвращает ошибку E_NOTIMPL, т.е. он попросту не реализован для перехватчика.

Обходной путь для первой проблемы заключается в использовании другого метода – IsoapMapper::get_ParameterOrder, возвращающего порядковый номер параметра в описании WSML. Как правило, порядковый номер в описании WSML соответствует порядковому номеру параметра в сигнатуре метода.

ПРИМЕЧАНИЕ

По крайней мере, стандартный генератор WSML из SOAP Toolkit генерирует WSML именно так. Возможно, в будущих версиях SOAP Toolkit эта проблема будет исправлена, и мы сможем использовать более уместный в данном случае метод callIndex.

Решение второй проблемы не так очевидно. Необходимо каким-либо образом поместить в стек вызова значение out-параметра, но единственный подходящий для этих целей метод ICallFrame::SetParam возвращает E_NOTIMPL.

Разумеется, мы могли бы остановиться на этом. Наш пример корректно работает с in-параметрами, но не умеет передавать out-параметры.

Но все же есть способ добраться до местоположения адреса нужного параметра в стеке. Можно узнать адрес стека вызова с помощью ICallFrame::GetStackLocation:

PVOID GetStackLocation(void);

А также получить информацию о параметре метода, его местоположение в стеке:

typedef struct {

BOOLEAN fIn;

BOOLEAN fOut;

ULONG stackOffset;

ULONG cbParam;

} CALLFRAMEPARAMINFO;

HRESULT GetParamInfo(

ULONG iparam,

CALLFRAMEPARAMINFO * pInfo

);

Теперь, если сложить адрес первого аргумента в стеке вызова и смещение нужного параметра CALLFRAMEPARAMINFO::stackOffset, мы получим адрес параметра в стеке. Код, заполняющий out-параметр выглядел так:

CComVariant value;

hr = spMapper->get_ComValue(&value);

hr = pFrame->SetParam(idx, &value);

Мы перепишем его так:

CComVariant value;

hr = spMapper->get_ComValue(&value);

PVOID pStack = pFrame->GetStackLocation();

CALLFRAMEPARAMINFO info = {0};

hr = pFrame->GetParamInfo(idx, &info);

if(SUCCEEDED(hr) && info.cbParam == sizeof(long*))

{

long** pParam = reinterpret_cast(

reinterpret_cast(pStack) + info.stackOffset);

if(!IsBadReadPtr(*pParam, sizeof(long)))

{

VARIANT var = {};

value.Detach(&var);

**pParam = var.lVal;

}

}

ПРИМЕЧАНИЕ

Такой способ не выглядит изящным, к тому же он не будет работать, если размер параметра в стеке отличается от 4.

Заключение

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5173
Авторов
на СтудИзбе
436
Средний доход
с одного платного файла
Обучение Подробнее