Getting More Out of Your Browser Control
by
, 12-Mar-2011 at 04:50 AM (13770 Views)
Since the introduction of COM in Visual DataFlex, around Visual DataFlex version 5, there has been a example application that contains an ActiveX object that represents Microsoft's Internet Explorer. In the example, that loads a default web-page, you can enter another address, click on a hyper-link which loads a new page, go back or forward, all the usual operations you can do with Internet Explorer itself too. While this example is good you can do much more and this blog is informing you about that, encouraging you to take advantage.
Tip of the Day
If you have installed Visual DataFlex 15.0 or higher (and why not) you must have seen the "Did You Know" dialog of Database Explorer.
The dialog is a standard ModalDialog object with 2 buttons BUT with a Internet Explorer browser control in it which shows the light-bulb picture, the text "Did You Know?" and a tip text itself. The reason to mention this dialog in this blog is that the control over the contents of the object is fully done in memory and it requires no HTML page on disk that needs to be loaded, which is a requirement of the cWebBrowser control class.
If you look for a method to display dynamic content in the cWebBrowser class you will not find one since it simply does not exist. It is not a method we left out when the class was generated but it is not present in the control itself. So how can Database Explorer do this?
Generate Code
To get access to that level of access in Internet Explorer you need to generate COM classes from another library that Microsoft installed on your computer. It is the MSHTML type library. In the Import ActiveX dialog in Visual DataFlex Studio
it is named "Microsoft HTML Object Library". If you generate the package of this library you get a stunning 268,625 lines of Visual DataFlex source code! Ehh, did you want to write a small program? Forget it... or not? Yes it is or not because you do not need all the code. For a lot of your work you only need a couple of classes and not even all the methods in those classes.
In fact if your goal is to "just" display dynamically built HTML you only need one class and 5 methods from that class. You need the cComHTMLDocument class. So find this class in the huge cComScriptlet.pkg and copy it into a new package which you want to use.
Note that I left off the usual Import_Class_Protocol statements for COM objects beingCode:// CoClass // ProgID: htmlfile // CLSID: {25336920-03F9-11CF-8FD0-00AA00686F13} Class cComHTMLDocument is a cComAutomationObject Procedure Construct_Object Forward Send Construct_Object Set psProgID to "{25336920-03F9-11CF-8FD0-00AA00686F13}" Set psEventId to "{3050F260-98B5-11CF-BB82-00AA00BDCE0B}" Set peAutoCreate to acNoAutoCreate End_Procedure End_Class
I did this because we only need a couple of methods from the cComDispHTMLDocument class and none of the methods of the cComHTMLDocumentEvents class. All the methods we need we copy from the cComDispHTMLDocument class directly into our class. This way we can keep the code small and compact.Code:Import_Class_Protocol cComDispHTMLDocument Import_Class_Protocol cComHTMLDocumentEvents
Building Up
As this blog is about extending your browser control ActiveX you should already have an object of the cComWebBrowser class in your component (e.g. dbView). Make sure a default page is loaded. This does not have to be a real page on disk or from a URL but can be the blank page known as "about:blank". So the code could be something like:
We need to add an object of the cComHTMLDocument class to the oDHTML object. Technically the Visual DataFlex proxy object does not need to be a child object of oDHTML but in this case we simply put it inside the object.Code:Object oDHTML is a cComWebBrowser Set Size to 308 569 Set Location to 5 5 Set peAnchors to anAll // Initialize the browser with an empty page Procedure OnCreate Send ComNavigate "about:blank" 0 0 0 0 End_Procedure End_Object
The change is shown in a red color.Code:Object oDHTML is a cComWebBrowser Set Size to 308 569 Set Location to 5 5 Set peAnchors to anAll // Object that helps us displaying the dynamic content Object oHTMLDocument is a cComHTMLDocument End_Object // Initialize the browser with an empty page Procedure OnCreate Send ComNavigate "about:blank" 0 0 0 0 End_Procedure End_Object
The oHTMLDocument is of course our access point to get the dynamic contents shown. Before this object can be used its COM counter part needs to be created and needs to be connected to the oDHTML object. You do this by coding:
inside a method like OnCreate, Activating or a self named method of the oDHTML object.Code:Variant vDocument Get ComDocument to vDocument Set pvComObject of oHTMLDocument to vDocument
To be able to get our information shown the documentation says we need to open the document. You do this with:
To wrap it up the code is now:Code:Get ComOpen of oHTMLDocument "text/html" "replace" Nothing True to vDocument Set pvComObject of oHTMLDocument to vDocument
The change is shown in a red color.Code:Object oDHTML is a cComWebBrowser Set Size to 308 569 Set Location to 5 5 Set peAnchors to anAll // Object that helps us displaying the dynamic content Object oHTMLDocument is a cComHTMLDocument End_Object Procedure ConnectItAll Variant vDocument Get ComDocument to vDocument Set pvComObject of oHTMLDocument to vDocument Get ComOpen of oHTMLDocument "text/html" "replace" Nothing True to vDocument Set pvComObject of oHTMLDocument to vDocument End_Procedure // Initialize the browser with an empty page Procedure OnCreate Send ComNavigate "about:blank" 0 0 0 0 End_Procedure End_Object
HTML
The basics of HTML are very simple. You need to have an openings tag and a closing tag. Inside these outer tags you need at minimum a element. Inside this inner tag we can place the information to be shown. For example:
In Visual DataFlex source code this can be:HTML Code:This is a test
Show HTMLCode:Procedure DisplayTest String sHTML Move 'This is a test ' to sHTML End_Procedure
Now how do we get this text into the control? You need to use the Write and Close methods. The Close is very simple, the Write is more complex. The Write message takes a variant array as argument. Sounds simple... or not? Indeed it is not simple because it needs to be an array of BSTR characters. This means that we need to convert the normal Visual DataFlex OEM string into a UNICODE string. We do this with the following method:
Then we need to convert this result into an array of UChar values. You do this with:Code:// Function : StrToWStr // Purpose : Converts a OEM string to a Unicode string Function StrToWStr Global String sData Returns String Integer iLength iResult String sBuffer // Get size of buffer Move (MultiByteToWideChar(CP_OEMCP,0,AddressOf(sData),-1,0,0)) to iLength If (iLength = 0) Function_Return "" // Create output buffer Move (Repeat(Character(0),iLength*2)) to sBuffer // Do actual conversion Move (MultiByteToWideChar(CP_OEMCP,0,AddressOf(sData),-1,AddressOf(sBuffer),iLength)) to iResult If (iResult = 0) Function_Return "" Function_Return sBuffer End_Function
Finally we can use this result with the ComWrite message. I like to split my code in smaller parts and thus I wrote:Code:Function StrToUCharArray Global String sDataIn Returns UChar[] Integer iLength UChar[] ucResult Address aResult Move (Length (sDataIn)) to iLength Move (ResizeArray (ucResult, iLength)) to ucResult Move (AddressOf (ucResult)) to aResult Move sDataIn to aResult Function_Return ucResult End_Function
And the Close method? This depends on whether you want to write again or not. If you send Close you would need the Open again if you want to do more writing.Code:// Display an HTML string in the browser Procedure DisplayHTML String sHTML UChar[] ucHTML Move (StrToWStr (sHTML)) to sHTML Move (StrToUCharArray (sHTML)) to ucHTML Send ComWrite of oHTMLDocument ucHTML End_Procedure
In a next blog I will continue with more extensions... keep tuned.