using EmbeddedWB and :OnBeforeNavigate2 to open URL in another browser - delphi

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.

Related

TWebBrowser and URL

I'm working on a software to verify the problem of porting it from D5 to XE5. In D5, TWebBrowser.BeforeNavigate2 was call each time the user click on the submit button of a displayed form. In XE5, it's not the case. I figured out it is because the URL for the submit contain http:/aDirectory/ExecToBeCall.exe. If I add an extra / after: the event is fire.
Under D5 the URL is change for:
http ://localhost/aDirectory/ExecToBeCall.exe (space added to break the link in the post)
That behavior of TWebBrowser under D5 to fire anyway and change the URL is important for the software and I cannot change the HTML (about 2000 files) to contain 2. It allowed us to know if the submit was made inside Delphi or from a outside Browser. I tried other and newer events of TWebBrowser and none are fire.
How can I be informed of a problematic URL, check it and change it into a localhost URL? A small and clean method would be preferable.
Thanks for your help and suggestions
TWebBrowser is just a thin wrapper around Internet Explorer's ActiveX object, so it is IE itself, not TWebBrowser, that is behaving differently.
http:/aDirectory/ExecToBeCall.exe is actually a valid URL. Since the : is not followed by //, there is no authority portion in the URL, and thus no explicit hostname. localhost is used as an implicit hostname, and the path is /aDirectory/ExecToBeCall.exe. That is what the URL is being changed to in D5, which is correct behavior. Changing the URL to http://aDirectory/ExecToBeCall.exe is incorrect, as that creates an authority portion of the URL and thus the hostname is explicitly set to aDirectory and the path is set to /ExecToBeCall.exe, which is not what you want.
Why the URL is not changing in XE5, I have no clue. Sounds like a bug in whatever version of IE is being used in that version of TWebBrowser.
In any case, it is IE that is triggering the event, so if it is not triggering for a URL it does not like, there is nothing you can do about that, short of using the browser's DOM interfaces to handle the onsubmit event of the HTML webform directly.
If you want to redirect unexpected url instead of navigating to it, you can start with TEmbeddedWB project or you can DIY by extending TWebBrowser class with IDocHostUIHandler, which has an interesting method TranslateURL.
function TAdvWebBrowser.TranslateURL(const dwTranslate: DWORD; const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HRESULT;
var
Url: string;
BufferSize: Integer;
begin
Url := PChar(pchURLIn);
if GetSafeUrlFor(Url) then
begin
ppchURLOut := CoTaskMemAlloc(BufferSize);
CopyMemory(ppchURLOut, PChar(Url), BufferSize);
// redirects to new location
Result := S_OK;
end
else
// no redirection
Result := S_FALSE;
end;
// You can change the function to add more complex redirection rules
function GetSafeUrlFor(var Url: string): Boolean;
begin
Result := Url.EndsWithText('.exe');
if Result then
Url := 'http://localhost/';
end;

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;

Delphi DDE Open url in active tab

I want to open url in already existing, active opera/IE/FF tab using delphi.
I tried:
ShellExecute(hw,'open',pchar(url),nil,nil,SW_SHOWNORMAL);
where hw is handle of web browser and url is string variable with url I want to open, but it opens new tab instead of using active tab.
I also tried:
procedure SetURL(Browser, URL: String);
var
Client_DDE: TDDEClientConv;
begin
Client_DDE := TDdeClientConv.Create(nil);
with Client_DDE do
begin
SetLink( Browser, 'WWW_Activate' );
RequestData('0xFFFFFFFF');
SetLink( Browser, 'WWW_OpenURL' );
RequestData(URL);
CloseLink;
end;
Client_DDE.Free;
end;
And SetURL('Opera', url); in buttonclick procedure, but it also opens url in new tab. When I use RequestData(URL + ',-1'); in SetURL procedure then it opens url in new window. Any ideas how to open url in already existing browser tab?
I have Delphi 7.
Unfortunately, that isn't possible. Take a look at similar question: Open link in same browser tab

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.

Detect TWebBrowser refresh event in Delphi 2009

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;

Resources