Страницы: 1
Добрый день. Есть необходимость добавить в свое расширение, написанное на VC++, обработчик событий браузера (в частности, чтобы отлавливать переход пользователя по ссылке). В книжке "Creating XPCOM Components" описывается пример плагина (WebLock), который, по-видимому, содержит данный функционал, но к сожалению исходного кода к нему я не нашел, а того, что есть в книге, мне оказалось недостаточно.
Если я правильно понял для решения моей задачи нужно:
1) создать собственный класс, реализующий интерфейс nsIWebProgressListener и реализовать в нем метод onLocationChange
2) запросить интерфейс nsIWebBrowser и передать в его методе addWebBrowserListener экземпляр собственного класса и IDD nsIWebProgressListener
так?
Как бы то ни было, проверить эту схему мне пока не удалось, поскольку не удается даже скомпилировать проект: во-первых, на сколько я понял, необходимо самому реализовать методы nsISupport в своем классе, или это можно сделать каким-нибудь макросом? во-вторых, компилятор ругается на абстрактные классы nsIURI и nsIRequest, которые используются в параметрах функций интерфейса nsIWebProgressListener, как быть с ними?
Отсутствует
Схема, наконец-то, начала компилироваться, однако, конечно же, пока не работает!
Есть пара подозрительных мест в реализации, но какие именно работают некорректно - не понятно. Может у кого будут идеи? Вот эти места:
1) класс-обработчик, который я создаю не является полноценным XPCOM объектом (т.е. у него нету ID, и методы nsISupport реализуются вручную)
2) недостаточно полная реализация всех методов, требующихся для регистрации подписки
В итоге ниже приведенные код падает с Access Violation на строке вызова AddWebBrowserListener:
CWebProgressListener *wpl = new CWebProgressListener(); nsCOMPtr<nsIWebBrowser> webBrowser; nsresult nsRes; webBrowser = do_GetService("@mozilla.org/embedding/browser/nsWebBrowser;1",&nsRes); if (NS_SUCCEEDED(nsRes)) { nsCOMPtr<nsIWeakReference> listener( do_GetWeakReference(static_cast<nsIWebProgressListener*>(wpl),&nsRes)); if (NS_SUCCEEDED(nsRes)) { PRBool bRes = webBrowser->AddWebBrowserListener(listener, NS_GET_IID(nsIWebProgressListener)); } }
При этом под дебаггером наблюдается интересная вещь: функция do_GetWeakReference сначала взывает метод wpl.QueryInterface, потом реализованную заглушку wpl.OnStateChange (по-видимому это тестирование, о котором упоминается в исходниках мозиллы), а потом wpl.Release. Что бы это значило? Тестирование завершилось неудачей? (однако nsRes = True, иначе до AddWebBrowserListener я бы даже не дошел)
Отсутствует
помимо WeakRefernce надо зарегистрироваться в xpcom-startup
типа такого. собственно говоря подобный код есть в примерах веблока
static NS_METHOD UrlCatcherFFRegistration( nsIComponentManager *aCompMgr, nsIFile *aPath, const char *registryLocation, const char *componentType, const nsModuleComponentInfo *info) { nsresult rv; nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsICategoryManager> catman; rv = servman->GetServiceByContractID( NS_CATEGORYMANAGER_CONTRACTID, NS_GET_IID(nsICategoryManager), getter_AddRefs(catman)); if (NS_FAILED(rv)) return rv; char* previous = nsnull; rv = catman->AddCategoryEntry( NS_XPCOM_STARTUP_CATEGORY, URLCATCHERFF_CLASSNAME, URLCATCHERFF_CONTRACTID, PR_TRUE, PR_TRUE, &previous); if (previous) nsMemory::Free(previous); return rv; } static NS_METHOD UrlCatcherFFUnregistration( nsIComponentManager *aCompMgr, nsIFile *aPath, const char *registryLocation, const nsModuleComponentInfo *info) { nsresult rv; nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsICategoryManager> catman; rv = servman->GetServiceByContractID( NS_CATEGORYMANAGER_CONTRACTID, NS_GET_IID(nsICategoryManager), getter_AddRefs(catman)); if (NS_FAILED(rv)) return rv; rv = catman->DeleteCategoryEntry( NS_XPCOM_STARTUP_CATEGORY, URLCATCHERFF_CLASSNAME, PR_TRUE); return rv; } static nsModuleComponentInfo components[] = { { URLCATCHERFF_CLASSNAME, URLCATCHERFF_CID, URLCATCHERFF_CONTRACTID, CUrlCatcherFFConstructor, UrlCatcherFFRegistration, UrlCatcherFFUnregistration } }; NS_IMPL_NSGETMODULE("UrlCatcherFFModule", components)
Отсутствует
Elexander, интерфейсы nsISupportsWeakReference и nsIWeakReference у меня реализуются, но под дебаггером я в них еще ни разу не попадал. Может быть я не правильно их реализую:
NS_METHOD CWebProgressListener::QueryReferent(const nsIID & uuid, void **result) { *result = this; return NS_OK; } NS_METHOD CWebProgressListener::GetWeakReference(nsIWeakReference **_retval) { *_retval = this; return NS_OK; }
дизасемблер места падения:
01117549 push offset `nsISupportsWeakReference::GetIID'::`2'::iid (11292B4h) 0111754E mov dword ptr [ebp-0Ch],eax 01117551 lea eax,[ebp-10h] 01117554 push eax 01117555 lea ecx,[ebp+8] 01117558 call nsCOMPtr_base::assign_from_qi_with_error (1117496h) 0111755D mov eax,dword ptr [ebp+8] 01117560 test eax,eax 01117562 je NS_GetWeakReference+43h (1117571h) 01117564 mov ecx,dword ptr [eax] 01117566 lea edx,[ebp-8] 01117569 push edx 0111756A push eax 0111756B call dword ptr [ecx+0Ch] 0111756E mov dword ptr [ebp-4],eax <- 01117571 lea ecx,[ebp+8] 01117574 call nsCOMPtr_base::~nsCOMPtr_base (1117431h)
т.е. падает где-то в NS_GetWeakReference()
myasoex, Вы уверены, что я должен создать полноценный XPCOM объект конкретно для моего обработчика и регистрировать его в стартапе? Дело в том, что я добавляю код к рабочему компоненту, который уже содержит полноценный XPCOM объект и в том числе регистрацию в стартапе. Т.е. сам компонент грузится при запуске FF. Не работает пока только часть, реализующая обработчик. Другое дело, если уже FF где-то сам захочет создать экземпляр моего объекта через ID - тогда будет проблема; но если он будет работать только с экземпляром передаваемого объекта, то необходимости регистрации я не вижу.
Отредактировано Delivron (04-03-2010 11:04:49)
Отсутствует
Мне сложно что-то посоветовать, потому что я подключаю перехватчик прогресса по другому. Я передаю свой nsIWebProgressListener экземпляру nsIWebProgress. Это поле webProgress в browser. А browser получаю так:
browser = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebNavigation) .QueryInterface(Components.interfaces.nsIDocShellTreeItem) .rootTreeItem .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIDOMWindow).getBrowser();
У меня были проблемы с получением browser в XPCOM, по этому я его получаю в JavaScript и передаю в бинарный компонент ссылку. У каждой вкладки свой browser. Нужно реагировать на открытие новой вкладки и каждый раз подключаться. При закрытии, соответственно, отключаться. У вас, я так понял, какой-то универсальный метод, но я так не пробовал. Посоветовать нечего.
Отсутствует
Решил пойти по другому пути. В исходниках мозиллы нашел некий класс CWebBrowserContainer. Этот класс, похоже, используется объектом CMozillaBrowser для получения каких-то событий. По крайней мере, я нашел в нем конструкцию подключения, схожую с моей. Однако, CWebBrowserContainer не реализует интерфейсы nsISupportsWeakReference и nsIWeakReference, вместо этого он просто наследует класс nsWeakReference. Я добавил исходники nsWeakReference в свой проект, занаследовал от него свой класс и это чудо не только скомпилировалось но и... не завалилось. Но теперь я просто получаю в nsCOMPtr<nsIWeakReference> listener нуль. Вопрос: может ли это быть из-за того, что я линкую библиотеки старого XPCOM SDK? (правда Unresolved Externals не возникают, а новое SDK подключать проблематично)
Отсутствует
Добился нормального получения nsCOMPtr<nsIWeakReference> listener и даже AddWebBrowserListener возвращает True. Однако уведомления о событиях все равно не приходят... Как бы проверить, что еще может быть не так? Как, например, проверить, что у меня рабочая ссылка на nsIWebBrowser (помимо возвращенного положительного результата от do_GetService)?
Отсутствует
Страницы: 1