Home General
New Blog Posts: Merging Reports - Part 1 and Part 2

Using reports in run-time packages

edited June 2005 in General
Hi,

I had a report that was very long to generate. According to Nard Moseley,
using Delphi event-handler are faster than RAP event-handler, so I built a
run-time package and put every RAP code in event-handlers.

-Run-Time Package
- DataModuleReport (TDataModuleReport)
- Report (TppReport)

I have a exported function "GetModuleClass", that returns the TDataModule
descendant class.

interface

type
TDataModuleClass = class of TDataModule;

TDataModuleReport = class(TDataModule)
...
...

function GetModuleClass: TDataModuleClass; stdcall;

implementation
{$R *.dfm}

function GetModuleClass: TDataModuleClass;
begin
Result := TDataModuleReport;
end;

exports
GetModuleClass;

initialization
RegisterClasses([TDataModuleReport]);

finalization
UnregisterClasses([TDataModuleReport]);

I load the package, call the package function GetModuleClass and create an
instance of TDataModuleReport, which contains my Report. Then, I retrieve
the Report using FindComponent and bind my DataPipeLine, DataSet and
DataSource... everything seems to work fine, but I get an Access Violation
after a few seconds on an OnCalc event.

I don't expect anybody to solve my problem, but I just would like to have
some feedback from people that used run-time packages for report deployment.
The main goal of this is to reduce the exe size and avoiding to always
rebuild my application. Thanks!

David Caouette

Comments

  • edited June 2005

    The idea behind packages is that you separate the classes (i.e. code) into
    discreet compilable units (packages). However, there is usually not a .dll
    style export function required.

    You simply build your application with the 'build with runtime' packages
    option enabled and it will build the smaller .exe.

    The challenge is organizing the code into packages. No unit should ever be
    compiled into more than one package. And units compiled into the .exe should
    not be included any packages.

    When package B contains units that 'use' classes defined in package A, then
    package B 'requires' package A. The .pas units use the standard Delphi
    'uses' clause approach.

    Simple example:

    I create a new unit called myClass and add ppClass to the 'uses' clause.

    ppClass is a ReportBuilder unit included in the rbRCL package.

    Therefore if I compile myClass into myPackage.dpk, then it will 'require'
    rbRCL.

    If I use myClass in myApp, then I should build with run-time packages of
    myPackage and rbRCL.















    --
    Nard Moseley
    Digital Metaphors Corporation
    http://www.digital-metaphors.com



    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited June 2005
    Hi Nard,

    thanks for the example. The way I've built the package is that it can be
    dynamically loaded on report demand and unloaded afterward. I've tried to
    use a kind of "plug-in" approach. Thanks for your answer.

    David

  • edited June 2005

    For a plug-in, a typical approach would be to have the plug-in make one or
    more registration calls in the Initialization section of the unit. You see
    this quite a bit in our code. For an example see RBuilder\Demos\RCL.

    You typically declare an abastract ancestor class and a class factory

    PlugInHost.pas
    ----------------
    TmyPluginClass - abstract ancestor
    TmyPluginFactory - class factory.


    The create your plug-in descendant class that will implement the
    functionality (and can be placed in a separate package).

    FirstPlugIn.pas
    -----------------
    TmyFirstPlugin - descendant that resides in a different package

    Initialization
    TmyPlugInFactory.Register(TMyFirstPlugin);

    Finalization
    TmyPlugInFactory.UnRegister(TMyFirstPlugin);







    --
    Nard Moseley
    Digital Metaphors Corporation
    http://www.digital-metaphors.com


    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited June 2005
    Hi Nard,

    I think I misexplained what I was trying to do. My application is actually
    distributing report templates. TppDBPipeLine, TDataSource and our custom
    TDataSet descendant are created and executed on-the-fly, based upon report;

    ex: Master - Subreport = 2 dbpipeline, 2 dataset
    Master(section), Master - SubReport = 3 DBPipeLine, 3 dataset

    Everything is working fine, except that now, I have some huge reports with a
    lot of event-handlers (at least 70). You suggested me to build a Delphi
    event-handler version instead of RAP event-handler, because it's faster. The
    problem is that I don't want to include this report in a unit that is
    statically linked to my application, so, I use run-time packages.

    But, each time I would need to design a new report in a package, I would
    need to rebuild my application using "Build with run-time packages",
    including my report run-time package. So, I just built my application using
    ReportBuilder run-time packages and I load my run-time package dynamically
    using LoadPackage function. That's what I meant by "plug-in approach". Maybe
    I should have said "modular approach".

    Thanks anyway for your answer, I for sure will have to use it sooner or
    later.

    David Caouette



This discussion has been closed.