unit PdxAddIn;

{ 
  This unit supplies support services for Paradox add-ins written in
  Delphi.  To write a Paradox add-in, you must:

  1) Make your project a DLL.
  2) USE this unit.
  3) Call Paradox.RegisterMenu for each set of menu items you want to place on
     Paradox's menu (each set should be built as a TPopupMenu).  Note that the
     total number of (visible) menu nodes under any one classification must be under 50
     FOR ALL ADDINS COMBINED!
  4) Call Paradox.RegisterForm for each form (class) you want to make available.  Also,
     these forms must descend from TParadoxForm (in the PdxForms unit).
  5) Call Paradox.RegisterDataModule for each Data Module you want to be available
     in Paradox.

  You don't need to register service routines (Procedures or Functions) per se.
  Instead just export them and call them the way you would any other DLL (you
  still need to set up the uses clause in ObjectPAL).  You can also set up
  classes (OLE Automation Servers) based on TAutoObject, register them with
  OLE, and then use them with the OLEAuto class in ObjectPAL.

  Menu Handling Tips:

  1) You can use Delphi's Menu Builder to build a popup menu (on a dummy form),
     create the form (invisible) and then call Paradox.RegisterMenu to place
     each sub-menu on the Paradox menu.

  2) Set the visible property on menu items to false to delete them from the
     Paradox menu without actually removing them.

  3) When Paradox initializes the menu for display, it will call any routine
     attached to the OnMenuInit event (with the new menu state).
     You can then enable/disable/hide or otherwise modify the menu nodes.

  Form Tips:

  1) Forms can be single instance or multi-instance.
     When Paradox needs a multi-instance form, it always
     creates a new copy.  However, when Paradox needs a single instance
     form, it first checks to see if one already exists, and
     if so uses it (forms will automatically be brought to the top of the Z-Order).

  2) To register a multi-instance form call the RegisterFormClass function,
     for example:

        Paradox.RegisterFormClass( 'MyForm', TForm1 );  -  Register Form1 as Multi-Instance

  3) To register a single-instance form call the RegisterForm function with
     a pointer to the instance variable (typically the variable Delphi
     automatically created), for example:

        Paradox.RegisterForm( 'MyForm', TForm1, Form1 );  -  Register Form1 as Single-Instance

     If you are using single instance forms, you should add code to your form's
     OnDestroy event (or destructor) that resets the instance variable
     (e.g. Form1 := Nil).  Otherwise, Paradox won't realize it needs to
     create the form and will crash trying to access a form that no longer exists.
}

interface

Uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, StdCtrls, ExtCtrls,
  PdxForms, iAddIn;

Type
  TParadoxAddIn = Class
    Private
      fParadoxInterface:IParadox;

      Function GetDesktopHandle:HWND;
      Function GetDesktopClientHandle:HWND;
    Protected
      Function GetMenuCount:Integer;
      Function GetFormCount:Integer;
    Private
      Constructor Create;
      Destructor Destroy; Override;

    Public
      { These are the functions the developer calls to make their resources
        available inside Paradox }
      Procedure RegisterMenu( aMenuNode:TPdxMenuNode;
                                  aMenu:TMenu );
      Procedure RegisterForm( aName:String; aFormClass: TParadoxFormClass; Var aInstanceVariable{:PParadoxFormVar} );
      Procedure RegisterFormClass( aName:String; aFormClass: TParadoxFormClass );
      { No Toolbar support at present }
      Procedure ClearMenus;
      Procedure ClearForms;

      { These functions provide some control over/information about Paradox }
      Property ParadoxInterface:IParadox read fParadoxInterface;

      Property DesktopHandle:HWND read GetDesktopHandle;
      Property DesktopClientHandle:HWND read GetDesktopClientHandle;

      Procedure ResetStatusRegions;
      Procedure SetStatusRegions(Regions:Array of Integer);
      Procedure SetStatusText(nRegion:Integer; RegionText:String);
    End;

Function Paradox:TParadoxAddIn;
Function IsParadox:Boolean;
Function ParadoxRegisterAddin(ParadoxInterface:IParadox):IPdxAddin; StdCall; Export;

{ -------------------------------------------------------------------------- }
implementation
{ -------------------------------------------------------------------------- }

Uses
  uAddIn;

Var
  fPdxAddIn :TPdxAddin; { Interface called by Paradox, down here for clean linkage }
  fParadox :TParadoxAddIn;

Function Paradox :TParadoxAddIn;
Begin
  if not assigned(fParadox) then
    fParadox := TParadoxAddIn.Create;
  Result := fParadox;
End;

Function IsParadox:Boolean;
Begin
  Result := assigned(fParadox) and assigned(fParadox.fParadoxInterface);
End;

Function ParadoxRegisterAddin(ParadoxInterface:IParadox):IPdxAddin; StdCall; Export;
Begin
  Try
    Paradox  { Make sure class exists }
      .fParadoxInterface := ParadoxInterface; { And assign interface pointer }
    Result := fPdxAddIn; { Return Interface called by Paradox }
    Result.AddRef(); { Paradox will release }
    ParadoxInterface.AddRef();
  Except
    Result := Nil;
  End;
End;

Exports ParadoxRegisterAddin;

{ These are the functions the developer calls to make their resources
  available inside Paradox }
Procedure TParadoxAddIn.RegisterMenu( aMenuNode:TPdxMenuNode; aMenu:TMenu );
Begin
  fPdxAddIn.MenuList.Add( aMenuNode, aMenu );
End;

Procedure TParadoxAddIn.RegisterForm( aName:String; aFormClass: TParadoxFormClass; Var aInstanceVariable{:PParadoxFormVar} );
Begin
  fPdxAddIn.FormList.Add( aName, aFormClass, @aInstanceVariable );
End;

Procedure TParadoxAddIn.RegisterFormClass( aName:String; aFormClass: TParadoxFormClass );
Begin
  fPdxAddIn.FormList.Add( aName, aFormClass, Nil );
End;

Procedure TParadoxAddIn.ClearMenus;
Begin
  fPdxAddIn.MenuList.Clear;
End;

Procedure TParadoxAddIn.ClearForms;
Begin
  fPdxAddIn.FormList.Clear;
End;

{ -------------------------------------------------------------------------- }
Function TParadoxAddIn.GetDesktopHandle:HWND;
Begin
  if assigned(fParadoxInterface) then
    Result := fParadoxInterface.GetDesktopHandle
  else
    Result := 0;
End;

Function TParadoxAddIn.GetDesktopClientHandle:HWND;
Begin
  if assigned(fParadoxInterface) then
    Result := fParadoxInterface.GetDesktopClientHandle
  else
    Result := 0;
End;

Procedure TParadoxAddIn.ResetStatusRegions;
Begin
  if assigned(fParadoxInterface) then
    fParadoxInterface.SetStatusRegions(0, Nil);
End;

Procedure TParadoxAddIn.SetStatusRegions(Regions:Array of Integer);
Begin
  if assigned(fParadoxInterface) then
    fParadoxInterface.SetStatusRegions( High(Regions)+Low(Regions)+1, @Regions[0] );
End;

Procedure TParadoxAddIn.SetStatusText(nRegion:Integer; RegionText:String);
Begin
  if assigned(fParadoxInterface) then
    fParadoxInterface.SetStatusText( nRegion, PChar(RegionText) );
End;


{ -------------------------------------------------------------------------- }

Function TParadoxAddIn.GetMenuCount:Integer;
Begin
  Result := fPdxAddIn.MenuList.GetCount;
End;

Function TParadoxAddIn.GetFormCount:Integer;
Begin
  Result := fPdxAddIn.FormList.GetCount;
End;

{ ----------------------------------------------------------------- }
Constructor TParadoxAddIn.Create;
Begin
  if assigned(fParadox) then
    Raise Exception.Create('TParadoxAddIn class can only have a single instance');
  Inherited Create;
  fPdxAddIn := TPdxAddin.Create; { Interface called by Paradox }
End;

Destructor TParadoxAddIn.Destroy;
Begin
  fPdxAddIn.Release;
  if assigned(fParadoxInterface) then
    fParadoxInterface.Release;
  Inherited Destroy;
End;

{ ----------------------------------------------------------------- }
{ Delayed initialization allows unit to be used for just types }
Initialization
  fPdxAddIn := nil;
  fParadox := nil;

Finalization
  if assigned(fParadox) then
    fParadox.Free;

end.

