Как подцепить в свой IE протокол IInternetProtocolInfo?
От: Rcorp Россия  
Дата: 19.11.04 19:14
Оценка:
Ничего не могу понять.
Работаю с примером из http://www.rsdn.ru/article/inet/pluggprotocol.xml
Автор(ы): Вадим Макутин
Дата: 12.06.2004
Разбирается создание и работа собственного интернет-протокола, приводится пример приложения, использующего такой протокол.

Делаю следующие щаги:
Добавляю в карту COM IInternetProtocolInfo:

BEGIN_COM_MAP(CMyProtocol)
    COM_INTERFACE_ENTRY_IID (IID_IInternetProtocol        , CMyProtocol)
    COM_INTERFACE_ENTRY_IID (IID_IInternetProtocolRoot    , CMyProtocol)
    COM_INTERFACE_ENTRY_IID (IID_IInternetProtocolInfo    , CMyProtocol)
END_COM_MAP()

Потом добавляю методы IInternetProtocolInfo:

HRESULT STDMETHODCALLTYPE CombineUrl(          LPCWSTR pwzBaseUrl,
    LPCWSTR pwzRelativeUrl,
    DWORD dwCombineFlags,
    LPWSTR pwzResult,
    DWORD cchResult,
    DWORD* pcchResult,
    DWORD dwReserved
){AfxMessageBox("Запуск");return E_NOTIMPL;}

HRESULT CompareUrl(LPCWSTR pwzUrl1,
    LPCWSTR pwzUrl2,
    DWORD dwCompareFlags
){return E_NOTIMPL;}

HRESULT ParseUrl(          LPCWSTR pwzUrl,
    PARSEACTION ParseAction,
    DWORD dwParseFlags,
    LPWSTR pwzResult,
    DWORD cchResult,
    DWORD* pcchResult,
    DWORD dwReserved
){return E_NOTIMPL;}

HRESULT QueryInfo(          LPCWSTR pwzUrl,
    QUERYOPTION OueryOption,
    DWORD dwQueryFlags,
    LPVOID pBuffer,
    DWORD cbBuffer,
    DWORD* pcbBuf,
    DWORD dwReserved
){return E_NOTIMPL;}

Но почему-то не работает.
Происходит ошибка в IInternetProtocolRoot->Start
m_pIProtSink = pOIProtSink
pOIProtSing=1 (это то указатель)

Подскажите, где я туплю. С COM никогда не разбирался и тонкостей не знаю.
Re: Как подцепить в свой IE протокол IInternetProtocolInfo?
От: Rcorp Россия  
Дата: 23.11.04 07:11
Оценка:
Ну что, никто не значет, в чем проблема?
Re[2]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 06.11.06 01:09
Оценка:
Здравствуйте, Rcorp, Вы писали:

R>Ну что, никто не значет, в чем проблема?


... Прошло два года ...

И я наступаю на те же грабли

Ситуация такая же.

Для начала прототипы двух функций из IInternetProtocol и IInternetProtocolInfo соответственно:
HRESULT STDMETHODCALLTYPE CMyProtocol::Start(
    /* [in] */ LPCWSTR szUrl, 
    /* [in] */ IInternetProtocolSink __RPC_FAR  *pOIProtSink,
    /* [in] */ IInternetBindInfo __RPC_FAR *pOIBindInfo,
    /* [in] */ DWORD grfPI,
    /* [in] */ DWORD dwReserved)



HRESULT STDMETHODCALLTYPE CMyProtocol::ParseUrl( 
    /* [in] */ LPCWSTR pwzUrl,
    /* [in] */ PARSEACTION ParseAction,
    /* [in] */ DWORD dwParseFlags,
    /* [out] */ LPWSTR pwzResult,
    /* [in] */ DWORD cchResult,
    /* [out] */ DWORD *pcchResult,
    /* [in] */ DWORD dwReserved)



Долгое ковыряние хелпа и и глубокий дебуг выяснили следующее:

1. Если мы реализуем свой протокол IInternetProtocolInfo, то первым(!!!) методом должен вызваться ParseUrl (прочитайте в MSDN про асинхронные плуг-протоколы), а не Start из IInternetProtocolRoot!!!

2. Теперь посмотрим на параметры функции Start, когда мы в нее попадаем.

R>Происходит ошибка в IInternetProtocolRoot->Start

m_pIProtSink = pOIProtSink
pOIProtSing=1 (это то указатель)

Ага равен 1. А вы не пробовали смотреть чему pOIProtSink равен при последующих вызовах? (Ну если закоментировать присвоение). Он "пляшет" в дипазоне от 1 до 16. Прикольно, правда?

3. Уж не знаю как я этого добился, но в какой-то момент у меня вдруг начал вызываться ParseUrl, а не Start . Причем первый вызов нормальный — приходит урл, а во втором параметре 1 () — это значение PARSE_CANONICALIZE в параметре ParseAction. Здесь я по всем правилам делаю разбор строки и возвращаю необходимое в параметрах UrlMon'у. Там нужно заполнить строковый буфер своими значениями. Здесь внимание(!): идут два параметра: указатель на буфер и его размер (он равен 2048 — ровненько 2к). Потом сразу следует второй вызов ParseUrl. И вот тут начинается дурдом, очень похожий на ваш случай с pOIProtSing=1. В параметре ParseAction сидит какая-то лабуда (что-то вроде адреса, но не как не одно из значений из PARSEACTION енума).

4. Потыкавшись дальше, у меня опять начал вызываться первым Start И вот тут я обратил внимание на значения параметров в функции Start. Они один в один похожи на вызов ParseUrl Да!!! :

pOIProtSing=1 — это PARSEACTION ParseAction из ParseUrl
DWORD dwReserved=2048 — это DWORD cchResult оттуда же

Внимательно всмотритесь в порядок следования параметров обеих функций — они точь в точь совпадают!!!

Т.е. UrlMon не может разобраться где тут ParseUrl, а где Start, а точнее для него укзатели на эти функции имеют одинаковое значение. Он сначала думает, что вызывает ParseUrl (а в действительности "лупит" по адресу Start), а потом вызывает Start (здесь он прав — это действительно Start).

Вывод: Что-то криво с декларацией самого CMyProtocol. Адреса функций "слипаются". В ATL я тоже не спец, надеюсь на помощь тех, кто в нем шарит.

Скорее всего трабла здесь:

/////////////////////////////////////////////////////////////////////////////
// CMyProtocol
class ATL_NO_VTABLE CMyProtocol : 
    public virtual CComObjectRootEx<CComSingleThreadModel>,
    public virtual CComCoClass<CMyProtocol, &CLSID_MyProtocol>,
    public IInternetProtocol,
    public IInternetProtocolInfo    
{


Ох уж мне это множественное наследование ...

Помогите плиз!!!
Re[3]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Tom Россия http://www.RSDN.ru
Дата: 06.11.06 09:32
Оценка:
Есть предложение вообще не реализовывать IInternetProtocolInfo, причём убрать его надо прямо из карты интерфейсов, а не возвращать E_NOTIMPLEMENTED
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[4]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 06.11.06 13:06
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Есть предложение вообще не реализовывать IInternetProtocolInfo, причём убрать его надо прямо из карты интерфейсов, а не возвращать E_NOTIMPLEMENTED

Так потребность как раз именно в нем. Дело в том, что нужно корректно обрабатывать относительные урлы вида: ../../somedir/somefile.ext. Не зная базового Урл, невозможно построить корректно абсолютный путь. Для этого, я так понимаю, и нужен IInternetProtocolInfo с функциями ParseUrl, CombineUrl, CompareUrl. Хорошо когда в примере стоит: myprot://somefile.txt. Для примера сойдет. В реальности надо чуть больше

Хотелось бы не нарушая принципа древовидности, иметь то же самое и в своем протоколе. Скидывать все в одну кучу некошерно Да и на данный момент есть большое кол-во файлов, лежащих в каталогах. Хотелось бы не нарушая логики, поместить это все куда-нибудь. Для меня идеальный вариант — zip-файл. Сохранится структура и не нужно будет перелопачивать код в поисках "где там какой относительный урл куда показывает".
Re[5]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Tom Россия http://www.RSDN.ru
Дата: 06.11.06 13:12
Оценка:
Здравствуйте, Nikolaz, Вы писали:

N>Здравствуйте, Tom, Вы писали:


Tom>>Есть предложение вообще не реализовывать IInternetProtocolInfo, причём убрать его надо прямо из карты интерфейсов, а не возвращать E_NOTIMPLEMENTED

N>Так потребность как раз именно в нем. Дело в том, что нужно корректно обрабатывать относительные урлы вида: ../../somedir/somefile.ext. Не зная базового Урл, невозможно построить корректно абсолютный путь. Для этого, я так понимаю, и нужен IInternetProtocolInfo с функциями ParseUrl, CombineUrl, CompareUrl. Хорошо когда в примере стоит: myprot://somefile.txt. Для примера сойдет. В реальности надо чуть больше

N>Хотелось бы не нарушая принципа древовидности, иметь то же самое и в своем протоколе. Скидывать все в одну кучу некошерно Да и на данный момент есть большое кол-во файлов, лежащих в каталогах. Хотелось бы не нарушая логики, поместить это все куда-нибудь. Для меня идеальный вариант — zip-файл. Сохранится структура и не нужно будет перелопачивать код в поисках "где там какой относительный урл куда показывает".


Я не вкурсе усройства протоколов, но насколько я знаю встроенный в IE http протокол не реализует данного интерфейса.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[6]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 06.11.06 13:52
Оценка:
Здравствуйте, Tom, Вы писали:


Tom>Я не вкурсе усройства протоколов, но насколько я знаю встроенный в IE http протокол не реализует данного интерфейса.

Я тоже глубоко пока эти не проникся Интересно как тогда осуществляется разбор полетов с относительными урлами. Мы ведь привыкли писать: <img src="../../somedir/picture.gif"> — это ведь значит подняться на два каталога выше, относительно(!) текущего (а им является тот каталог, где лежит файл, в котором прописана эта строчка кода) и загрузить picture.gif из каталога somedir, который в свою очередь лежит в текущем. О как

Т.е. если строчка <img src="../../somedir/picture.gif"> лежит в файле c:\temp\projects\test.htm,
то src в конце концов должен преобразоваться в c:\somedir\picture.gif,
прежде чем WebControl (или кто там етим занимается) поймет откуда в конце концов грузить эту картинку.

Кстати насчет "реализует или нет". Посмотрите функцию:
STDAPI CoInternetParseUrl(
    LPCWSTR pwzUrl,
    PARSEACTION ParseAction,
    DWORD dwFlags,
    LPWSTR pszResult,
    DWORD cchResult,
    DWORD *pcchResult,
    DWORD dwReserved
);


Если ее вызвать для урла вида myprot://.., то код сваливается прямо в реализацию интерфейса IInternetProtocolInfo в MyProtocol. Я думаю, если подергать ее со стандартными http:// урлами, то результат тоже будет (это значит, что IInternetProtocolInfo для http:// реализован). В зависимости от ParseAction вам будут возвращаться части переданного урла (урл будет парсится в зависимости от логики протокола http).
Re[7]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 07.11.06 14:18
Оценка: 2 (1) +1
Здравствуйте, Nikolaz, Вы писали:

Отвечаю сам себе. Думаю многим тоже будет интересно.

Вообщем накопал на Code Project один проект DataProtocol. Писано под Visual Studio .NET на С++. Имеет поддержку IInternetProtocolInfo. Т.е. все что нужно было при работе с ParseUrl. После недолгих манипуляций с примерами из http://www.rsdn.ru/article/inet/pluggprotocol.xml
Автор(ы): Вадим Макутин
Дата: 12.06.2004
Разбирается создание и работа собственного интернет-протокола, приводится пример приложения, использующего такой протокол.
и найденной реализацией протокола DataProtocol получил желаемое поведение:

    — Реализован собственный IInternetProtocolInfo;
    — Регистрация DataProtocol также не нужна. Загружается и работает только в рамках собственно приложения (см. TestProtocolApp пример из http://www.codeproject.com/internet/DataProtocol.asp). Собственно это и не моя заслуга Спасибо автору этой статьи!

Фактически я заменил реализацию MyProtocol в примерах из статьи http://www.rsdn.ru/article/inet/pluggprotocol.xml
Автор(ы): Вадим Макутин
Дата: 12.06.2004
Разбирается создание и работа собственного интернет-протокола, приводится пример приложения, использующего такой протокол.
на реализацию из примера на CodeProject. Почему не работал пример из статьи при попытке реализовать в нем IInternetProtocolInfo, я так и не разобрался

Завтра почищу исходники нового примера с поддержкой IInternetProtocolInfo и выложу их здесь
Re[8]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 08.11.06 22:58
Оценка: 3 (1) +1
Здравствуйте, Nikolaz, Вы писали:

N>Завтра почищу исходники нового примера с поддержкой IInternetProtocolInfo и выложу их здесь


Ну вот собственно и готовый, а точнее переработанный пример из статьи Вадима Макутина "Asynchronous Pluggable Protocol"
Автор(ы): Вадим Макутин
Дата: 12.06.2004
Разбирается создание и работа собственного интернет-протокола, приводится пример приложения, использующего такой протокол.
. Личный респект Вадиму за эту статью!

Забирать здесь.
Запускать TestProtocolApp\TestProtocolApp.sln

Собственно это и есть ответ на тему этого топика. ... ровно через два года
Re[8]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Tom Россия http://www.RSDN.ru
Дата: 09.11.06 08:43
Оценка:
N>Почему не работал пример из статьи при попытке реализовать в нем IInternetProtocolInfo, я так и не разобрался
Так это самое интересное, остальное — лирика...
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[9]: Как подцепить в свой IE протокол IInternetProtocolInf
От: Nikolaz Германия www.nikeware.com
Дата: 11.11.06 20:54
Оценка:
Здравствуйте, Tom, Вы писали:

N>>Почему не работал пример из статьи при попытке реализовать в нем IInternetProtocolInfo, я так и не разобрался

Tom>Так это самое интересное, остальное — лирика...
Лирика в том, после долгого "приколачивания" этого IInternetProtocolInfo выяснилось следующее: картинки то он нормально подгружает, а вот такое
<script language="JavaScript" src="script.js"></script>
<link rel="stylesheet" href="css/main.css">


Напрочь отказывается . Точнее он делает запросы, и я их ему оттдаю (отрабатывают и Start, и Read). И он их как-бы "забрал". Только вот ни отработки скриптов, ни отработки стилей после загрузки основной страницы не происходит

Даже и не знаю куда копать. Предполагаю, что все же неправильно реализованы методы у IInternetProtocolInfo и это как-то связано с секурностью.
Re[10]: Как подцепить в свой IE протокол IInternetProtocolIn
От: Nikolaz Германия www.nikeware.com
Дата: 12.11.06 23:36
Оценка:
Здравствуйте, Nikolaz, Вы писали:

N>Здравствуйте, Tom, Вы писали:


N>>>Почему не работал пример из статьи при попытке реализовать в нем IInternetProtocolInfo, я так и не разобрался

Tom>>Так это самое интересное, остальное — лирика...
N>Лирика в том, после долгого "приколачивания" этого IInternetProtocolInfo выяснилось следующее: картинки то он нормально подгружает, а вот такое
N>
N><script language="JavaScript" src="script.js"></script>
N><link rel="stylesheet" href="css/main.css">
N>


N>Напрочь отказывается . Точнее он делает запросы, и я их ему оттдаю (отрабатывают и Start, и Read). И он их как-бы "забрал". Только вот ни отработки скриптов, ни отработки стилей после загрузки основной страницы не происходит


Нашел

// Reads data retrieved by the pluggable protocol handler.
HRESULT STDMETHODCALLTYPE CMyProtocol::Read( 
    /* [length_is][size_is][out][in] */ void __RPC_FAR *pv,
    /* [in] */ ULONG cb,
    /* [out] */ ULONG __RPC_FAR *pcbRead)
{
    BOOL Status = FALSE;
    //set position of begin
    LARGE_INTEGER nLen1;
    nLen1.QuadPart = m_lPosition;
    if(FAILED(m_pIStream->Seek(nLen1, STREAM_SEEK_SET, NULL)))
        return INET_E_DOWNLOAD_FAILURE;
    //read data to browser
    if ( SUCCEEDED( m_pIStream->Read(pv, cb, pcbRead) ))
    {
        if (*pcbRead != 0)
        {
            Status = TRUE;
            m_lPosition += *pcbRead;
        }
        else
            return S_FALSE;
    }

      ...................................................

    if (m_pIProtSink != NULL)
    {
        m_pIProtSink->ReportData(BSCF_LASTDATANOTIFICATION, m_lSize, m_lSize);
        m_pIProtSink->ReportResult(S_OK, 0, NULL); <- ВОТ ЭТО НАДО УБРАТЬ!!!
    }
    return S_FALSE;    
}

m_pIProtSink->ReportResult(S_OK, 0, NULL); все портит.
Я не знаю для чего этот вызов стоит. Автору виднее . Но без него наоборот — все .
А так получается, что ни css, ни скрипты, ничего не работает .
Re[11]: Как подцепить в свой IE протокол IInternetProtocolIn
От: romson  
Дата: 23.04.07 16:05
Оценка: +1
Здравствуйте, Nikolaz, Вы писали:

N>m_pIProtSink->ReportResult(S_OK, 0, NULL); все портит.

N>Я не знаю для чего этот вызов стоит. Автору виднее . Но без него наоборот — все .
N>А так получается, что ни css, ни скрипты, ничего не работает .

Зря Вы это убрали. Потому что теперь у Вас не вызывается IInternetProtocolRoot::Terminate и не освобождаются ресурсы. Можете почитать про это здесь, особое внимание обратите на шаг 10. А в вышеуказанном примере достаточно в начале CMyProtocol::Read поставить

if (!m_pIStream)
  return S_FALSE;

и всё будет работать.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.