Title: Load TWebBrowser's document content from stream or string
Question: I hate to face the fact that TWebBrowser does not come with Lines property and LoadFromStream/LoadFromFile method as we all familiar working with TMemo. To create temporary file and then call Navigate/Navigate2 method seems quite awful way.
Answer:
Here I want to show you how to reverse what was done by TWebBrowser.Document's IPersistStreamInit implementation in my previous article. Beside Save() method, it also has Load() method. As you might guess from the method name, the later allows you to load the content from any object that implements IStream.
Here's how to do it:
procedure LoadDocFromStream(WB: TWebBrowser; Stream: TStream);
var
PersistStreamInit: IPersistStreamInit;
StreamIntf: IStream;
StreamAdapter: TStreamAdapter;
begin
PersistStreamInit := WB as IPersistStreamInit;
StreamAdapter := TStreamAdapter.Create(Stream);
StreamIntf := StreamAdapter as IStream;
PersistStreamInit.Load(StreamIntf);
end;
After knowing which doing what from each statement above, now it is the time to reduce your typing task :)
procedure LoadDocFromStream(WB: TWebBrowser; Stream: TStream);
begin
(WB.Document as IPersistStreamInit).Load(
TStreamAdapter.Create(Stream,soReference));
end;
That's all the way to do it. Quite simple eh? If you have a string variable holds your HTML content, simply create TStringStream from it and pass it to second function parameter.
But wait, there's another way to work with string source! For you JavaScript guys whom play often with IE DOM should familiar with this script code:
document.write("Hello World!/BODY");
document.close();
//--
Yes, that can be done with Delphi and TWebBrowser too. The main difference is the type of involved object. The first method is using TWebBrowser.Document's IPersistStreamInit implementation (IPersistStreamInit is IPersistStream descendant which is actually exposes Save() and Load() methods). The second is using its IHTMLDocument2 implementation method.
Here's how to do it:
procedure LoadDocFromString(WB: TWebBrowser; const HTMLString: string);
var
v: OleVariant;
HTMLDocument: IHTMLDocument2;
begin
HTMLDocument := WB.Document as IHTMLDocument2;
v := VarArrayCreate([0, 0], varVariant);
v[0] := HTMLString;
HTMLDocument.Write(PSafeArray(TVarData(v).VArray));
HTMLDocument.Close;
end;
Remember to put ActiveX and MSHTML units to your uses clause (IHTMLDocument2 is declared inside the later unit). If your Delphi version does not come with it, you'll need to import "Microsoft HTML Object Library" from your Delphi IDE or use command line tool $(DELPHI)\bin\tlibimp.exe. In this case, you'll get MSHTML_TLB.pas.
There is a preliminary condition should be met though. All methods above will fail if WebBrowser does not contain valid document. You must load initial document (call it "dummy document") for the first time before using the functions above. I love to hear if anyone knows how to assign a dummy document better than my workaround below. Here's the snippet code:
if not Assigned(WebBrowser.Document) then
LoadBlankDocAndWaitUntilDocLoaded;
LoadContentFromStringOrStream;
Finally to include the document validity checking, I rewrote all those above and make the final 'ready to use' code:
procedure LoadBlankDoc(WB: TWebBrowser);
begin
WB.Navigate('about:blank', EmptyParam, EmptyParam, EmptyParam, EmptyParam);
while WB.ReadyState READYSTATE_COMPLETE do
begin
Application.ProcessMessages;
Sleep(0);
end;
end;
procedure CheckDocReady(WB: TWebBrowser);
begin
if not Assigned(WB.Document) then
LoadBlankDoc(WB);
end;
procedure LoadDocFromStream(WB: TWebBrowser; Stream: TStream);
begin
CheckDocReady(WB);
(WB.Document as IPersistStreamInit).Load(TStreamAdapter.Create(Stream));
end;
procedure LoadDocFromString(WB: TWebBrowser; const HTMLString: string);
var
v: OleVariant;
HTMLDocument: IHTMLDocument2;
begin
CheckDocReady(WB);
HTMLDocument := WB.Document as IHTMLDocument2;
v := VarArrayCreate([0, 0], varVariant);
v[0] := HTMLString;
HTMLDocument.Write(PSafeArray(TVarData(v).VArray));
HTMLDocument.Close;
end;
Suggestions, corrections, and/or comments are welcome.
Enjoy!