| | | | |
Полный текст материала
Другие публикации автора: Сергей Осколков
Цитата или краткий комментарий: «... Поводом для написания этой статьи послужил один вопрос на Круглом Столе. В нём автор хотел, чтобы по щелчку на изображении на странице TWebBrowser он мог бы как-то получать адрес (URL) этого изображения. ...» |
Важно:- Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
- Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
- При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
- Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.
Добавить свое мнение.
| | Содержит полезные и(или) интересные сведения | [1] | 4 | 100% | | | | Ничего особенно нового и интересного | [2] | 0 | 0% | | | | Написано неверно (обязательно укажите почему) | [3] | 0 | 0% | | Всего проголосовали: 4 | | | Все понятно, материал читается легко | [1] | 1 | 33.3% | | | | Есть неясности в изложении | [2] | 2 | 66.7% | | | | Непонятно написано, трудно читается | [3] | 0 | 0% | | Всего проголосовали: 3 |
Отслеживать это обсуждение
Всего сообщений: 2726-05-2008 10:00>И еще,
>Затем (... as IHTMLImgElement).onclick := {экземпляр нашего класса}
>у меня корректно работало, когда я объявлял переменную не как экземпляр
>класса, а как интерфейс (как это обычно с интерфейсами с управляемым
>временем жизни и бывает).
Спасибо, очень помогли!
Что странно, на компьютере, где писал первоначально - работало и через указатель на экземпляр класса, на другом - нет. И там и там IE7... |
|
27-07-2007 04:06сообщение от автора материала Ребята! Есть значительно более простое решение. У любого элемента на веб-странице есть события - никто не мешает их перекрывать. И незачем будет изобретать велосипед, используя синки - слишком сложное решение для весьма простой задачи.
А по поводу TBaseSink - я не говорил, что это простенький класс, как раз очень даже наобарот. Я имел ввиду необходимо написать наследника от TInterfacedObject и в нем реализовывать обработку события.
Да, действительно, я попробовал, описанный вами метод работает. Спасибо за информацию. Но по поводу простоты, пара замечаний. TBaseSink - готовый класс. Вы также используете готовый класс TInterfacedObject, который реализует часть того же, что и TBaseSink. Поэтому сравнивать по сложности нужно не TBaseSink, а тот наследник от него, который только и нужно написать.
Он в чем-то немного сложнее, чем описанный вами вариант и нужно покопаться в интерфейсах - указать тип события и его ID, и больше нужно написать, если нужно перейти к другому событию другого объекта, но в чем-то он проще - не нужно реализовывать методы интерфейса IDispatch: GetTypeInfoCount, GetTypeInfo, GetIDsOfNames - они уже реализованы в TBaseSink. Но часть сложности описанного мной метода возникает за счет того, что этот способ дает дополнительные возможности, которых нет в описанном вами способе - получать и передавать назад параметры события.
Для информации если кто будет пользоваться, эти два метода по разному взаимодействуют с собственной обработкой событий javascript'ом на странице. Описанный вами метод подменяет имеющуюся обработку, тот, который описал я - добавляет свою обработку после обработки на странице.
И еще,
Затем (... as IHTMLImgElement).onclick := {экземпляр нашего класса}
у меня корректно работало, когда я объявлял переменную не как экземпляр класса, а как интерфейс (как это обычно с интерфейсами с управляемым временем жизни и бывает).
type TEventMethod = class(TInterfacedObject, IDispatch)
....
В форме:
EvtMethod: IDispatch;
...
EvtMethod := TEventMethod.Create; |
|
23-07-2007 09:36Да, пробовал. В моем браузере именно так скачиваются картинки. А по поводу TBaseSink - я не говорил, что это простенький класс, как раз очень даже наобарот. Я имел ввиду необходимо написать наследника от TInterfacedObject и в нем реализовывать обработку события. Смысл в том, что необходим класс, реализующий методы интерфейсов IUnknown и IDispatch. |
|
23-07-2007 09:09сообщение от автора материала Все, что необходимо - это написать простенький класс от IUnknown и IDispatch (TInterfacedObject).
Интересно. А вы пробовали это делать? У меня почему-то не получалось динамически переключать процедуры, прикрепленные к событиям, в самом Javascript на странице. Попробую после работы.
Кстати говоря, по поводу простоты:
TBaseSink = class(TObject, IUnknown, IDispatch) (из примера к статье) - это не подходит под "простенький класс от IUnknown и IDispatch"? :) |
|
23-07-2007 08:54Ребята! Есть значительно более простое решение. У любого элемента на веб-странице есть события - никто не мешает их перекрывать. И незачем будет изобретать велосипед, используя синки - слишком сложное решение для весьма простой задачи.
Все, что необходимо - это написать простенький класс от IUnknown и IDispatch (TInterfacedObject).
Затем (... as IHTMLImgElement).onclick := {экземпляр нашего класса}
После этого по клику на картинке, для которой мы выполнили строчку выше будет вызван Invoke нашего экземпляра. Однако не стоит забывать, что в (...).onclick могло быть что-то до нас и это что-то лучше вызвать после нашей обработки, а то мало ли...... вдруг там был нужный скриптик, а мож и эксплоит какой-нить :)) ктож его знает :) |
|
07-07-2007 08:39
06-07-2007 02:17Зато с gmail.com не работает - форма отправки письма не вызывает Invoke :( |
|
06-07-2007 02:10О теперь и с google.com работает :) Но не всегда - чудеса какие-то вообще :( |
|
06-07-2007 01:50Сергей, скажите пожалуйста у Вас получается Вашим кодом словить событие onsubmit на форме запроса на
http://www.google.com/
? |
|
05-07-2007 10:10сообщение от автора материала Кстати, у нас с Вами День Рождения в один день :)
:^) |
|
05-07-2007 09:54Да я уже разобрался - оказывается мой код работал (только не для всех форм). Для некоторых форм интерфейс с евентами вроде как поддерживался, но не вызывался - еще буду разбираться почему.
И еще - я вообще работаю не с activex веб браузером - а работаю изнутри ie - как плагин и на disconnect получаю ошибку OleError 80040200 на Unadvise(FCookie)
:(( |
|
05-07-2007 09:20сообщение от автора материала У меня сейчас на работе кода нет, дома сейчас проблемы с интернетом, а завтра я собираюсь уехать в отпуск. :(
Сначала загружаете страницу, потом находите нужную форму в документе, например через Document.forms. Потом создаете сток и подключаете его к этой форме. Должно бы работать. Правда я использовал интерфейсы IHtmlFormElement и HtmlFormEvents, там в событии OnSubmit нет параметра, поэтому я по этому событию просто обращался к форме, т.к. ссылку на нее уже получил раньше (см. 2-ое предложение а этом ответе). |
|
05-07-2007 08:04Сергей, а можете показать свой код по подключению к форме для события onsubmit полностью, в то у меня метод Invoke не вызывается, хотя коннект к IHTMLFormElement проходит. Ничего не понимаю :( |
|
05-07-2007 05:45Ладно, буду пробовать, спасибо.
Кстати, у нас с Вами День Рождения в один день :) |
|
05-07-2007 04:36сообщение от автора материала function onsubmit(const pEvtObj: IHTMLEventObj): WordBool; dispid 1007;
Это из какого интерфейса? Видимо HTMLFormElementEvents2? Тогда вероятно параметр в конструкторе CreateConnected Должен быть типа IHtmlFormElement2 (точно не знаю, возможно пройдет и IHtmlFormElement);
? Я не совсем понимаю как нужно вытягивать параметры из этой структуры.
Как это сделано у меня в примере, TMainForm.DocOnDblClick. Посмотрите интерфейс IHTMLEventObj, там есть свойство srcElement.
POleVariant(VarResult)^ := DoOnSubmit(IHTMLEventObj(dps.rgvarg^[pDispIds^[0]].dispval))
где
function DoOnSubmit(const pEvtObj: IHTMLEventObj): WordBool; safecall;
Подозреваю, что нет. DoOnSubmit возвращает WordBool, а вам нужно OleVariant. Я в сообщении 04-07-2007 12:15 специально ввел локальную переменную Rslt.
Коннектиться, понятно, нужно, когда документ загрузился,
а отконнективаться имхо в любой момент (это сходу я так думаю насчет отконнективаться). |
|
05-07-2007 04:21И последний вопрос - в какой момент нужно коннектиться/отконнективаться от событий документа? в OnDocumentComplete? |
|
05-07-2007 04:15Я написал так:
case DispID of
1007:
POleVariant(VarResult)^ := DoOnSubmit(IHTMLEventObj(dps.rgvarg^[pDispIds^[0]].dispval))
где
function DoOnSubmit(const pEvtObj: IHTMLEventObj): WordBool; safecall;
это корректно ?
|
|
05-07-2007 04:05А скажеите еще какие параметры надо передать в OnSubmit ?
Вот ее описание
function onsubmit(const pEvtObj: IHTMLEventObj): WordBool; dispid 1007;
pEvtObj это будет что
dps.rgvarg^[pDispIds^[0]].dispVal
? Я не совсем понимаю как нужно вытягивать параметры из этой структуры.
|
|
05-07-2007 02:01сообщение от автора материала Я так понимаю, что это указатель на OleVariant, по адресу которого нужно поместить результат функции.
Не очень корректно я выразился. Наверное точнее будет сказать не "по адресу указателя" (это будет адрес самой переменной-указателя, а не куда она указывает), а "указатель на адрес, куда нужно поместить результат функции, причем тип результата должен быть OleVariant." |
|
05-07-2007 01:40
04-07-2007 12:15сообщение от автора материала там есть результат функции и непонятно что писать в DoInvoke, чтобы вернуть этот результат.
Среди параметров метода есть VarResult.В MS Platform SDK из Turbo Delphi написано:
HRESULT Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult, ------ ВОТ ОН!
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr
);
и в пояснениях
pVarResult
Pointer to the location where the result is to be stored, or NULL if the caller expects no result. This argument is ignored if DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF is specified.
Я так понимаю, что это указатель на OleVariant, по адресу которого нужно поместить результат функции. Попутавшись некоторое время, пришел к положительному результату в виде (для интерфейса IHtmlFormElement и интерфейса событий HtmlFormEvents).
(это содержимое DoInvoke).
var Rslt: OleVariant;
begin
Result := DISP_E_MEMBERNOTFOUND;
try
case DispId of
1007: if Assigned(FOnSubmit)
then begin
Rslt := FOnSubmit();
POleVariant(VarResult)^ := Rslt;
Result := S_OK;
end;
end;
except
Result := E_UNEXPECTED;
end;
end;
Действительно если возвращаешь результат "ложно", то форма не отсылается. |
|
04-07-2007 03:45Сергей а подскажите пожалуйста как перекрыть ивент onsubmit ? там есть результат функции и непонятно что писать в DoInvoke, чтобы вернуть этот результат. |
|
22-06-2007 05:22сообщение от автора материала Описанным способом нельзя. Описанным способом вы можете только добавить обработку события на Web-странице, загруженной в TWebBrowser, в своем приложении, содержащем этот TWebBrowser.
|
|
22-06-2007 01:24Это все прекрасно, но только со стороны Delphi. В обработчик {onclick и др.} нет прямой возможности вписать другой код, уже имеющийся на странице. на пример:
Имеется onclick="UploadMailFromServer()<!-- Delphi -->"; исправить на onclick="return false"; нет возможности, если я не прав, то исправьте мну... ИМХО )))) |
|
08-06-2007 11:57А, просмотрел, что он от TObject, а не от TInterfacedObject. |
|
08-06-2007 11:25сообщение от автора материала а это автоматически вызовет также деструктор самого sink'а
TBaseSink = class(TObject, IUnknown, IDispatch) - sink унаследован от TObject и не уничтожается автоматически. Вообще, если Вы посмотрите реализацию методов _AddRef и _Release, они просто возвращают 1. Так что объект стока не будет автоматически уничтожен. У меня в примере он уничтожается при закрытии главной формы.
|
|
08-06-2007 09:02Есть сильное подозрение, что в Вашем примере, если вы обнулите ссылку на IHtmlDocument2 до того, как вызовите Free для sink'а, и попытаетесь обратиться к sink'у - получите AV. В силу того, что:
1. при создании sink'a его RefCount будет равен 0 - т.к. с точки зрения Delphi это объект, а не интерфейс;
2. при присоединении его к IHtmlDocument2 тот его "запомнит" у себя внутри и увеличит RefCount на 1 (RefCount станет равен 1) - т.к. sink с точки зрения IHtmlDocument2 является интерфейсос;
3. при обнулении ссылки на IHtmlDocument2 вызовется его деструктор, который (наверняка) обнулит у себя внутри ссылку на sink - сделает RefCount равным 0 - т.к. sink с точки зрения IHtmlDocument2 является интерфейсом - а это автоматически вызовет также деструктор самого sink'а - при том, что собственно указатель на него с точки зрения Delphi валидный
4. при попытке в Delphi обратиться к указателю на sink - получаем AV (ну или что еще, не менее "приятное").
На мой взгляд, в данном случае надо либо sink в переменных/полях класса объявлять именно как интерфейс, либо после создания принудительно делать ему _AddRef. |
|
|
|