Плагин для Internet Explorer и события. С чего начать?

Тема в разделе "WASM.BEGINNERS", создана пользователем psu, 11 янв 2007.

  1. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    В данном направлении я абсолютный ноль. Необходимо написать плагин для IE, который бы фильтровал загружаемые страницы по ключевым словам ( <META name="keywords" ). С чего начать? Структуру и иерархию COM объектов представляю очень приблизительно, а времени в обрез. Ткните носом плз, что читать, где найти примеры и т.д!!!
     
  2. ring4

    ring4 New Member

    Публикаций:
    0
    Регистрация:
    19 ноя 2006
    Сообщения:
    279
    Если мне не изменяет память, по такая технология называеться BHO(Browser Helper Object) На сайте msdn, есть описание этой технологии хелперов, с примерами и всеми поддерживаемыми командами.
     
  3. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Да-да!! это оно. Но я не могу для себя уяснить с какой стороны к этому подойти. Какой-нибудь минимальный пример можна? Сейчас вообще каша в голове. Пересмотрел кучу статей, все представляется очень приблизительно :dntknw:
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Можно BHO использовать как подгрузку плагина в экземпляры IE, необходимый минимум - реализовать интерфейс IObjectWithSite. В IObjectWithSite::SetSite, которая вызывается при загрузке плагина, сохраняем указатель на интерфейс браузера и подписываемся на его события (DWebBrowserEvents2). Полный доступ к документу можно получить после DWebBrowserEvents2::lol: ocumentComplete, получаешь интерфейс IWebBrowser2 из передаваемого IDispatch, из свойства IWebBrowser2::lol: ocument берёшь IHTMLDocument и дальше уже работаешь с коллекциями html-элементов.
     
  5. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Пробую переделать пример. Он реализует кнопку на панели инструментов. Почему DllGetClassObject вызывается только после нажатия на нее, а не при загрузке плагина? В оригинале кроме IObjectWithSite класс наследовал еще и IOleCommandTarget. Я так понимаю, что второй интерфейс служит именно для работы с кнопкой?
     
  6. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Взял другой пример на переработку, немного продвинулся. Теперь уже проблема с SetSite

    Код (Text):
    1. STDMETHODIMP IMyIEExtention::SetSite(IUnknown *pUnkSite)
    2. {
    3.     if (pUnkSite)
    4.     {
    5.         IServiceProviderPtr pServProv(pUnkSite);
    6.  
    7.         HRESULT hRes;
    8.         hRes = pServProv->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2,
    9.                                     (void**)&m_pWebBrowser2);
    10. //А вот здесь нужно подписаться на события? Как?
    11.     }
    12.  
    13.     return S_OK;
    14. }
    Пробую подписаться через AtlAdvise. Получаю 0х80040202. Кажеться, проблема в том, какие интерфейсы наследует мой класс

    Код (Text):
    1. class IMyIEExtention :
    2.     public IObjectWithSite,
    3.     public IContextMenu,
    4.     public IDeskBand,
    5.     public IDispatch,
    6.     public IConnectionPointContainer
    Судя по тому, что прочитал по этой ошибке необходимо следующее:
    Код (Text):
    1. BEGIN_COM_MAP(IMyIEExtention)
    2.         COM_INTERFACE_ENTRY(IDispatch)
    3.         COM_INTERFACE_ENTRY_IID( DIID_DWebBrowserEvents2, IDispatch)
    4.     END_COM_MAP()
    Но не компилиться, синтаксическая ошибка DWebBrowserEvents2 :dntknw:
    Помогите! А то хана мне..
     
  7. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Лучше б теорию почитал, чем копать чужой код. На рсдн всё расписано.

    IServiceProvider не обязателен, можно сразу pUnkSite->QueryInterface(IID_IWebBrowser2);

    Подписываться - через IConnectionPointContainer и IConnectionPoint.
    Ну, или через AtlAdvise, если ATL используешь.

    Вообще, подписка реализуется через IDispatch. Её можно оформлять двумя способами: через реализацию соответствующего интерфейса (DWebBrowserEvents2) или просто через IDispatch. В первом случае будет "статическое" связывание и будут вызываться соответствующие функции, во втором - у тебя будет только IDispatch::Invoke и вызовы функций будешь определять по DISPID. Плюсы первого - у тебя функции как в оригинальном интерфейсе с нужными параметрами, но нужно будет реализовывать полноценный СОМ-объект. Во втором случае простота реализации, но поимеешь небольшой гемор с распаковкой аргументов из IDispatch::Invoke.
     
  8. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Ну а все же, откуда ошибка? Вот, гляньте кто-нибудь
    Внимание обратить только на SetSite и обьявление класса IMyIEExtention, все остальное "родное" осталось
     
  9. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Ну вот пример первого способа:

    Код (Text):
    1.         // используется в DISPID_FILEDOWNLOAD
    2.         static _ATL_FUNC_INFO FileDownloadInfo = {
    3.             CC_STDCALL,
    4.                 VT_EMPTY,
    5.                 2,
    6.             {
    7.                 VT_BOOL,VT_BOOL
    8.             }
    9.         };
    10.  
    11.         class ATL_NO_VTABLE CWebBrowserEvents2Sink :
    12.             public CComObjectRootEx<CComMultiThreadModel>,
    13.             public CComCoClass<CWebBrowserEvents2Sink>,
    14.             public IDispEventImpl<0,CWebBrowserEvents2Sink,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1,0>
    15.         {
    16.         public:
    17.             /** @name Защита от преждевременного разрушения */
    18.             //@{
    19.             DECLARE_PROTECT_FINAL_CONSTRUCT()
    20.             HRESULT FinalConstruct()
    21.             {}
    22.             void FinalRelease()
    23.             {
    24.             }
    25.             //@}
    26.             /** @name Карта интерфейсов СОМ */
    27.             //@{
    28.             BEGIN_COM_MAP(CWebBrowserEvents2Sink)
    29.                 COM_INTERFACE_ENTRY_IID(DIID_DWebBrowserEvents2,CWebBrowserEvents2Sink)
    30.             END_COM_MAP()
    31.             //@}
    32.  
    33.             /** @name Карта точек входа в обработчики событий DWebBrowserEvents2 */
    34.             //@{
    35.             BEGIN_SINK_MAP(CWebBrowserEvents2Sink)
    36.                 SINK_ENTRY_EX(0,DIID_DWebBrowserEvents2,DISPID_BEFORENAVIGATE2,BeforeNavigate2)
    37.                 SINK_ENTRY_EX(0,DIID_DWebBrowserEvents2,DISPID_CLIENTTOHOSTWINDOW,ClientToHostWindow)
    38. .......
    39.                 SINK_ENTRY_INFO(0,DIID_DWebBrowserEvents2,DISPID_FILEDOWNLOAD,FileDownload,&FileDownloadInfo)
    40.             END_SINK_MAP()
    41.  
    42. private:
    43.             /** @name Обработчики DWebBrowserEvents2 (объявления) */
    44.             //@{
    45.             STDMETHOD(BeforeNavigate2)(IDispatch *pDisp,VARIANT *url,VARIANT *Flags,VARIANT *TargetFrameName,
    46.                 VARIANT *PostData,VARIANT *Headers,VARIANT_BOOL *Cancel);
    47.             STDMETHOD(ClientToHostWindow)(long *&CX,long *&CY);
    48. ........
    49.             // debug assert (passed 2 parameters instead of 1) [TypeLib documented bug]
    50.             STDMETHOD(FileDownload)(VARIANT_BOOL *&ActiveDocument,VARIANT_BOOL *&Cancel);
    51. .......
    52.             STDMETHOD(WindowSetWidth)(long Width);
    53.             //@}
    54.         };
    FileDownloadInfo нужна, чтобы явно объявить параметры OnFileDownload из-за ошибки в TypeLib shdocvw.dll
     
  10. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    А пример второго можна? Желательно с реализацией SetSite
     
  11. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    А так не работает, ошибка 80004002 :dntknw:
     
  12. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Ленивый ты. Второй способ тривиален: класс, реализующий IDispatch (с реализованными методами AddRef, Release, QueryInterface и Invoke, остальным можно возвращать E_NOTIMPL).

    Либо у тебя ошибка где-то, либо в SetSite может что-то другое передаваться. Поставь проверку на запрос интерфейса IWebBrowser2 и подписывайся уже к нему.
     
  13. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Еще немного продвинулся. Теперь

    Код (Text):
    1. AtlAdvise(m_pWebBrowser2, (IDispatch*)this, DIID_DWebBrowserEvents2, &m_dwCookie);
    возвращает 80040202
     
  14. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Ура. Заработало! Продолжаю спрашивать. После загрузки документа необходимо запустить новый экземпляр браузера с заданным урлом, разммером окна и позицией на экране.

    Код (Text):
    1. CComPtr<IWebBrowser2> spBrowser;
    2.  
    3. CoInitialize( 0 );
    4. hRes = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
    5.                             __uuidof(IWebBrowser2), (PVOID *)&spBrowser);
    6.     if (SUCCEEDED(hRes))
    7.     {
    8.         VARIANT var;
    9.         var.vt = VT_EMPTY;
    10.  
    11.         spBrowser->Navigate(CComBSTR(L"http://www.rsdn.ru"), &var, &var, &var, &var);
    12.         spBrowser->put_Visible(VARIANT_TRUE);
    13.     }
    После CoCreateInstance текущий экземпляр висит довольно уверенно, потом функция возвращает E_INOINTERFACE. Если не проверять hRes, то появляется окно "Следующая надстройка была включена, когда возникла неполадка". ( надстройка моя ). В чем проблема?
     
  15. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Попап? Или именно браузер? В любом случае размер окна и позиция задаются либо через IHTMLWindow2::open, либо через соответствующие свойства IWebBrowser2.

    Какая функция?
     
  16. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    CoCreateInstance

    Нужен попап. Смотреть в сторону IHTMLWindow2?

    ...
    Получилось частично.

    Код (Text):
    1. hr = pWebBrowser->get_Document( &pDisp );
    2. if( SUCCEEDED( hr ) )
    3. {
    4.     IHTMLDocument2* doc = (IHTMLDocument2* )pDisp;
    5.     hr = doc->get_parentWindow( &Popup );
    6.     if( SUCCEEDED( hr ) )
    7.     {
    8.         IHTMLWindow2* res;
    9.         hr = Popup->open( bstr_t( "http://www.google.com" ), bstr_t( "_blank" ), bstr_t( "left=0,top=0" ), 0, &res );
    10.     }
    11. }
    на Popup->open браузер подвисает, потом возвращается E_INOINTERFACE. Весь этот код вызывается из Invoke при dispid==DISPID_DOCUMENTCOMPLETE. Может где-то здесь причина? Попробывал поменять весь этот код на m_pWebBrowser->Navigate - абсолютно то же самое в результате
     
  17. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Вот исходники. Выручайте..
     
  18. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    Неужели никто не знает? Ау!!!