mozdev.org

Delphi 

projects:
resources:
Zip

Delphi 4 Lizard Taming

By Dave Murray <irongut at vodafone dot net>

The Mozilla ActiveX Control can be used to display html in Delphi 4 applications but there is a VCL bug and other problems to overcome. This article provides solutions to these problems and a reworked GeckoBrowser framework for Delphi 4. I am assuming that you have already read my article Taming the Lizard with Delphi.

Import ActiveX
Figure 1 - Import ActiveX Dialog

Installing the Control

Installing the Mozilla ActiveX Control is the same for Delphi 4 as for later versions. For this article I've used the Mozilla ActiveX Control v1.6 package from Adam Lock. It installs the GRE and the necessary support files and then registers the control.

The Mozilla ActiveX Control is imported into Delphi in the normal way: Component | Import ActiveX Control | Mozilla Control 1.0 Type Library | Install. The control will appear on the ActiveX page of the Component Palette as TMozillaControl.

Rebuilding the Browser Framework

The GeckoBrowser project from Taming the Lizard with Delphi was written with Delphi 6 and due to changes between versions I can't just open it in Delphi 4. The most obvious problem is that the *.dfm file format is different. It would be time consuming to redo the forms from scratch but I have a cunning plan... I start a new project in Delphi 4 and add two forms to it then right-click on the forms and select View as Text from the menu. I then open my Delphi 6 *.dfm files for GeckoBrowser in a text editor and copy the text to replace that in the forms in Delphi 4. I then save those forms, overwriting the Delphi 6 ones, and 'hey presto!' they've been magically downgraded.

Now, opening the GeckoBrowser project in Delphi 4 causes a few error messages about missing components and incorrect property values. They are noted and ignored to get the project to load. The error messages are because TLabeledEdit and the TForm.Position property that I used did not exist in Delphi 4. The property value errors are easily sorted by changing TfrmOpen.Position and TfrmPrefs.Position to poDesktopCenter. There are two TLabeledEdit components on TfrmPrefs, edtCustomStartPage and edtHomePage. I have replaced them with two TEdit components that are also named edtCustomStartPage and edtHomePage and a pair of similarly named TLabels.

There are two other minor changes that need to be made. The Variants unit doesn't exist in Delphi 4 so it must be removed from the uses clauses of all the *.pas files in the project. And, the location of the throbber animation is slightly different in each version of Delphi (Delphi4\Demos\CoolStuf\Cool.avi).

TfrmMain
Figure 2 - TfrmMain

Compiling the project at this point produced several 'Not enough actual parameters' errors. This is because when Delphi 4 produced MOZILLACONTROLLib_TLB.pas from the type library contained in the Mozilla ActiveX Control it did not provide overloaded methods for optional parameters but just one method taking all the parameters.

i.e. Delphi 4 produces:
procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant);

But Delphi 6 produces:
procedure Navigate(const URL: WideString); overload;
procedure Navigate(const URL: WideString; var Flags: OleVariant); overload;
procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant); overload;
procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant); overload;
procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant); overload;

In each method where I call Navigate or ExecWB (which have optional parameters) I've declared a local variable temp : OleVariant which is assigned to null. Then where I'm not using a parameter that should be optional I pass that variable. e.g. :

procedure TfrmMain.edtAddressKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
{navigate to current address}
var
  temp : OleVariant;
begin
  if (Key = VK_RETURN) then mzGecko.Navigate(WideString(edtAddress.Text), temp, temp, temp, temp);
end; {procedure TfrmMain.edtAddressKeyDown}


Floating Point Exceptions

Having adapted the GeckoBrowser framework for Delphi 4 I can now move on to a meatier problem. Namely, that Delphi 4 applications cause floating point exceptions in Gecko. To be more precise, using one of the Delphi 4 VCL's common dialogs (TOpenDialog, TSaveDialog, etc) can cause random floating point exceptions in various Gecko dlls. Thankfully, this problem has been solved by Nick Bradbury, creator of TopStyle.

FP Exception
Figure 3 - Floating Point Exception

The problem is that after any common dialog is displayed, Delphi 4 changes the FPU control word. This is done because some libraries (Microsoft's) want the FPU to be set in 64 bit precision, whereas Delphi expects 80 bit precision. This call causes Gecko to crash. The offending code is in the TCommonDialog.TaskModalDialog method in dialogs.pas and has been fixed in Delphi 5 and later. To fix this you need to alter dialogs.pas and recompile it which is more awkward than you'd expect. Here is the fixed TCommonDialog.TaskModalDialog with the original code commented out:

function TCommonDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
type
  TDialogFunc = function(var DialogData): Bool stdcall;
var
  ActiveWindow: HWnd;
  WindowList: Pointer;
  FPUControlWord: Word; // GECKO
begin
  ActiveWindow := GetActiveWindow;
  WindowList := DisableTaskWindows(0);
  try
    Application.HookMainWindow(MessageHook);
    asm // GECKO
      FNSTCW FPUControlWord // GECKO
    end; // GECKO
    try
      CreationControl := Self;
      Result := TDialogFunc(DialogFunc)(DialogData);
// ORIGINAL    Set8087CW(Default8087CW);
    finally
      asm // GECKO
        FNCLEX // GECKO
        FLDCW FPUControlWord // GECKO
      end; // GECKO
      Application.UnhookMainWindow(MessageHook);
    end;
  finally
    EnableTaskWindows(WindowList);
    SetActiveWindow(ActiveWindow);
  end;
end;

Here's the process for fixing this bug in your Delphi 4 VCL:


Conclusion

This article shows how to fix a problem in the Delphi 4 VCL that causes floating point exceptions when using the Mozilla ActiveX Control. It also provides a workaround for problems with the inadequate header file Delphi 4 produces from the control's type library. The source code accompanying this article is a basic browser framework that can be used to demonstrate or test the Mozilla ActiveX Control with Delphi 4. Feel free to use and abuse it as you wish.

References

Mozilla ActiveX Control
Taming the Lizard with Delphi


Zip Download the source code archive.
Or get the source via CVS.

Refer this page to a friend!

The delphi project can be contacted through the mailing list or the member list.
Copyright © 2000-2017. All rights reserved. Terms of Use & Privacy Policy.