Detect TWebBrowser refresh event in Delphi 2009 - delphi

I am using a TWebBrowser component which I use to load XML documents into which are linked to a XSL file.
I have a default page I display when no XML document is loaded. However, if the user deletes the XML file whilst it is open in the browser and then refreshes I get the standard resource could not be found error. What I would like to do instead is if the page cannot be loaded, check that the file exists, and if it doesn't just load the default page again.
I have tried using the OnNavigateError and OnBeforeNavigate2 events however they does not seem to trigger on a refresh.
Any idea's?

There is an onRefresh event which is exposed by the TWebBrowser replacement TEmbeddedWB. This version also exposes many other features which are otherwise hidden by the TWebBrowser component.

This is a bit of a cludge but it works in my tests, using the standard TWebBrowser component.
What I did was override the F5 key in the form's OnKeyUp event. By setting the form's KeyPreview property to True, you can call your own refresh. Seeing as the TWebBrowser.Refresh method doesn't appear to call any of the navigation events (as you said in your question), I call the TWebBrowser.Navigate event myself, which does fire the events.
You need to store the URL, which I imagine you're already doing. But if not, then in the BeforeNavigate2 event, you are given the URL as a parameter. So store this in a variable or on-screen control. Then, when F5 is pressed (or the Refresh button if you have put one on screen), simpy navigate to that URL again. The OnBeforeNavigate2, OnNavigateComplete2 and OnDocumentComplete events are all fired again, allowing you the opportunity to perform your test and put your placeholder page up instead of IEs default error page.
procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
Headers: OleVariant; var Cancel: WordBool);
begin
Edit1.Text := URL;
end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key = VK_F5) then
begin
WebBrowser1.Navigate(Edit1.Text);
end;
end;

Related

Delphi: Webbrowser.Document -> check existence of Element by ID

I've got a TWebbrowser Component and some Buttons doing stuff. This works well so far, but during one procedure I want to click on a button on the website to display additional Information, which should be clicked on as well.
So I've got this:
WebBrowser1.OleObject.Document.GetElementByID('linkDtlC0-0').Click();
WebBrowser1.OleObject.Document.GetElementByID('linkDtlC0-1').Click();
WebBrowser1.OleObject.Document.GetElementByID('linkDtlC0-2').Click();
Then I have to click a Button on the website to display the next three elements to click on. No Problem so far, but after clicking the button the site takes a few Seconds to display the three elements.
My Problem:
When I try to click the elements immediately after clicking the Button clearly it results in an error saying that there is no element (yet) to click on with this name. Of course I could make my program wait a few seconds (more) just be be sure and then try to click, but I do not want to waste time so my question is:
Is there a way to check, whether an element (by name) exists on the Document inside the TWebbrowser?
Check, whether an element exists:
uses
MSHTML;
procedure TForm1.WebBrowser1DocumentComplete(ASender: TObject; const pDisp: IDispatch; const URL: OleVariant);
var
Element: IHTMLElement;
begin
if pDisp = TWebBrowser(ASender).ControlInterface then
begin
Element := (WebBrowser1.Document as IHTMLDocument3).getElementById('linkDtlC0-3');
if Assigned(Element) then
Element.click;
end;
end;

using EmbeddedWB and :OnBeforeNavigate2 to open URL in another browser

I need to open another browser sometimes if users click a link.
I am using CHtmlView::OnBeforeNavigate2 to cancel the integrated web browser from opening the specific URL; and instead I will open it in another firefox.
However this does not seem to be a good place to do this.
For some reason OnBeforeNavigate is also called, when user does not click a link at all.
The OnBeforeNavigate2 event is the best place to cancel the ongoing navigation. Just, if you want to detect if this event was triggered by a hyperlink click (since it fires e.g. for frames when they are loaded), you can determine if the Flags parameter contains the navHyperlink value, like this e.g.:
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
Headers: OleVariant; var Cancel: WordBool);
begin
if ((Flags and navHyperlink) <> 0) and (URL = 'http://example.com') then
begin
Cancel := True;
// the user clicked a link to http://example.com and the navigation is
// going to be cancelled; now do whatever else you need here
end;
end;
I cannot tell you which versions of Internet Explorer passes this value, but I can tell you for sure, that the MSDN documentation for web browser is almost completely outdated.

How do I detect when TWebBrowser finishes downloading a page?

How to know if the TWebBrowser already finished to download the page?
My problem is: I can't know when my page was completely downloaded so it can be shown.
I request one page to my webbrowser and I want to show the response only when the page was completely downloaded.
You could try handling the OnDocumentComplete event.
If the site uses scripting to trigger downloading of additional data, you may have to employ more sophisticated methods since the event will fire before the page finishes running all its scripts. In general, the task begins to look like the halting problem. You might wish to refine your definition of "completely downloaded" to exclude certain difficult-to-detect cases.
source: http://www.delphifaq.com/faq/delphi/network/f264.shtml
Indeed, in case of multiple frames, OnDocumentComplete gets fired multiple times. Not every frame fires this event, but each frame that fires a DownloadBegin event will fire a corresponding DocumentComplete event.
How can the 'real completion' be recognized?
The OnDocumentComplete event sends parameter pDisp: IDispatch, which is the IDispatch of the frame (shdocvw) for which DocumentComplete is fired. The top-level frame fires the DocumentComplete in the end.
So, to check if a page is done downloading, you need to check if pDisp is same as the IDispatch of the WebBrowser control.
That's what the code below demonstrates:
procedure IForm1.WebBrowser1Documentccmplete(Sender: Iobject:
const pDisp: Inispatch; var URL: OLEvariant):
var
Curwebrowser : IWebBrowser:
IopWebBrowser: IWebBrowser:
Document : OLEvariant;
WindowName : string:
begin { TForm1.WebBrowser1DocumentComplete }
Curwebrowser := pDisp as IWebBrowser:
TopWebBrowser := (Sender as IWebBrowser).DefaultInterface;
if CurWebrowser=TopWebBrowser then
begin
ShowMessage('Document is complete.')
end
else
begin
Document := CurWebrowser.Document;
WindowName := Document.ParentWindow.Name:
ShowMessage('Frame ' + WindowName + ' is loaded.')
end:
end;

Open new pages also in TWebBrowser

I have created an app with a twebBrowser in it. Problem is when i click on some link, in say gmail, it opens in a new window of my default browser( which is IE). how do i make it work like firefox or chrome etc. which opens the clicked links in their windows. The url's should open in the TWebBrowser's window. Must i create a new Form at runtime with TWebBrowser in it at runtime for that? Code not needed as such, ideas will do
Thanks in Advance.
P.S. My org blocks Gmail, Facebook etc. , However through my TWebBrowser, i can open them. Can my QA ppl see that in their log? My guess will be no, since then they would block it. What is your comment on this
TWebBrowser has an OnNewWindow2 event. Assuming the form holding the TWebBrowser is named Form1 and the web-control itself is named WebBrowser1, write a handler like this:
procedure TForm1.WebBrowser1NewWindow2(ASender: TObject; var ppDisp: IDispatch; var Cancel: WordBool);
var NF: TForm1;
begin
NF := TForm1.Create(Application);
NF.Visible := True;
NF.WebBrowser1.RegisterAsBrowser;
ppDisp := NF.WebBrowser1.DefaultInterface;
end;
This will create a new window, with a new TWebBrowser when the "click" is supposed to lead to a new window.

A way to redirect keypresses from TWebBrowser to the ParentForm

First question. Help format it, if needed, please.
Context
I have a TWebBrowser in the main form that is used to behave like it was a printer.
So I load some HTML text in it as user do some commands in the real printer...
I want the user to be able to click and select text from the WebBrowser.
Problem
When the user clicks in the WebBrowser some of the shortcuts registered from the actions don't work anymore. For example, there is an action with shortcut F7. If the user clicks in the WebBrowser and presses F7, it does not invoke my shortcut.
I know that this is by design of the WebBrowser.
So, I thought: I want to send every key combination back to the form.
The question is: How?
If it was another control, I could use a perform(WM_KeyDown,...) in the OnKeyDown event.
Alternatives or suggestions would be appreciated too. I am very tired these past 2 days, so I could be missing something.
Derivate TWebBrowser with an implementation of IDocHostUIHandler or use the famous EmbeddedWB
Implement the interface with an event OnTranslateAccelerator called in TranslateAccelerator
Set the event on your brwoser instance
Detect your key(s) like this:
function TBrowserPageIE.DoTranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT;
begin
result := S_FALSE;
if lpMsg.message = WM_KEYDOWN then begin
if lpMsg.wParam = VK_F7 then begin
// do something here...
result := S_OK;
end;
end;
end;
An option that I tested and worked is to trap the key_code on HTML/javascript and then send that to the form using changing the document title. I will let it here hoping that help someone...
You will need add the javascript to trap the keys in the Header of the HTML page like this:
<script = ''javascript''>
function keypresed() {
var tecla=window.event.keyCode;
document.title = "Command"+tecla;
event.keyCode=0;
event.returnValue=false;
}
document.onkeydown=keypresed;
</script>
Then in Webbrowser you use the onTitleChangeEvent to use the key.
var
s:string;
begin
if Copy(Text,0,7) = 'Command' then
begin
//get the key...
s:= Copy(Text,8,Length(Text));
// if before the webbrowser get the focus edit1 was the focused control, you will need remove that focus first...
dummy.setfocus;
edit1.setfocus;
//perform keydown
keybd_event(StrToInt(s), 1,0,0)
end;
end;
Well, this can be used to perform any other custom command. :)

Resources