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

Pass-trough function with array of TVarRec

edited February 2003 in RAP
Hi,

I need to create pass-through function for function with signature ():

function CallIntegerFunction(aValue1: string; aValue2: string; aParams:
array of const): integer;

Is it possible? I don't know how to work with the last parametr of this
function.

Petr Slipek
slipek.at.dosli.cz

Comments

  • edited February 2003
    Hi Petr,

    use a 'TStringList' or a 'TList' as ("open array") parameter.

    HTH,
    Chris Ueberall;
  • edited February 2003
    Hi,

    I tried your sugesstion and it works with one exception. I created class
    TdoExecuteStringFunction as described in help with TStringList parametr.

    When I preview the report - code executes OK. But if I run end-user report
    designer and preview report in the report designer the execution of
    pass-throught function failed with acess violation at line marked with
    "!!!!!" in the code below.


    In RAP I assign code to events OnCreate, OnDestroy and Variable1OnCalc;

    Now I really don't understand what's going on.

    Petr Slipek
    Dosli

    *************START RAP CODE****************
    global var
    glParams: TStirngList;

    procedure GlobalOnCreate;
    begin
    glParams := TStringList.Create;
    end;

    procedure GlobalOnDestroy;
    begin
    glParams.Free;
    glParams := nil;
    end;

    procedure Variable1OnCalc(var Value: Variant);
    begin
    glParams.Clear;
    glParams.Add(doWeldBase_sznKGroups['TypKurzuCustID']);
    Value := ExecuteStringFunction('doWeldBase', 'KurzTypName', glParams);
    end;
    *************START INTERFACE***************
    TdoSystemFunction = class (TraSystemFunction)
    public
    class function Category: string; override;
    end;

    TdoExecuteStringFunction = class (TdoSystemFunction)
    public
    procedure ExecuteFunction(aParams: TraParamList); override;
    class function GetSignature: string; override;
    class function HasParams: Boolean; override;
    end;

    *************START IMPLEMENTATION***************
    procedure TdoExecuteStringFunction.ExecuteFunction(aParams: TraParamList);
    var
    lModuleName: string;
    lFunctionName: string;
    lParams: TStringList;
    lArray: array of TVarRec;
    I: Integer;
    lVarRec: TVarRec;
    lResult: string;
    begin
    lResult := '';
    if Assigned(doAppServices) then
    begin
    GetParamValue(0, lModuleName);
    GetParamValue(1, lFunctionName);
    GetParamValue(2, lParams);
    if (lModuleName = '') or (lFunctionName = '') or (not Assigned(lParams))
    then
    Exit;
    !!!!! SetLength(lArray, lParams.Count);
    for I := 0 to lParams.Count - 1 do
    begin
    lVarRec.VType := vtPChar;
    lVarRec.VPChar := PChar(lParams[I]);
    lArray[I] := lVarRec;
    end;
    try
    lResult := doAppServices.CallStringFunction(nil, lModuleName,
    lFunctionName, lArray);
    except
    on Exception do lResult := '';
    end;

    end;
    SetParamValue(3, lResult);
    end;

    class function TdoExecuteStringFunction.GetSignature: string;
    begin
    result := 'function ExecuteStringFunction(aModuleName: string;
    aFunctionName: string; aParams: TStringList): string;';
    end;

    class function TdoExecuteStringFunction.HasParams: Boolean;
    begin
    result := True;
    end;
    ****************END






    "Chris Ueberall [TeamDM]" p??e v diskusn?m
  • edited February 2003
    Hi,

    I forgot to write that it failed only on the first attempt to show preview.
    Second time is all ok.

    Petr Slipek
    Dosli
  • edited February 2003
    After some investigation I has an idea what is wrong, but I am not sure if
    it helps.


    If I modified rap code for Variable1:

    *********** START RAP************
    procedure Variable1OnCalc(var Value: Variant);
    begin
    glParams.Clear;
    glParams.Add(doWeldBase_sznKGroups['TypKurzuCustID']);
    ShowMessage('Mess1: Inside RAP before Execute');
    Value := ExecuteStringFunction('doWeldBase', 'KurzTypName', glParams);
    end;
    ***********END RAP************

    and modified procedure TdoExecuteStringFunction.ExecuteFunction(aParams:
    TraParamList);


    **********START IMPLEMENTATION********
    procedure TdoExecuteStringFunction.ExecuteFunction(aParams: TraParamList);
    var
    ...
    begin
    ShowMessage('Mess2: Inside Delphi RAP execution');
    lResult := '';
    ....
    end;
    *********EDN IMPLEMENTATION************

    When the error doesn't occur, the sequence of messages is: Mess1 --> Mess2
    as expected,
    but when I preview report in end-user designer while running application the
    first showed message is Mess2 and next the params are invalid and causes
    access violation exception.

    Please help. It looks like something called
    TdoExecuteStringFunction.ExecuteFunction without running my RAP code.

    Thanks,

    Petr Slipek
    Dosli
  • edited February 2003
    Petr,


    I tested your pass-through function without any AV!
    Message1 was always shown before Message2.
    I would place additional messages for 'Create' and 'Destroy' of the stringlist.
    Use a new report.

    HTH,
    Chris Ueberall;
  • edited February 2003
    Thanks for your time,

    I tried, but it shows correctly. Another thing is, that I have ppViewer,
    ppReport, ppDesigner on one form. Before calling ppDesigner.ShowModal i
    preview report in ppViewer. Can it be in conflict with preview panel in
    designer? Strange is that it only happens in designer preview panel. Never
    in ppViewer.

    Petr Slipek
    Dosli


    "Chris Ueberall [TeamDM]" p??e v diskusn?m
  • edited February 2003
    Hi Petr Slipek,


    sorry, but I have no idea what causes the AV on your side. If I pass nil the functions returns immediately as it should.
    You tested with a new report so there should be no other call before the stringlist is created. Any infos from the call stack available?
    I used the standard previewer and the designer preview.
  • edited February 2003
    Hi,

    I tried new empty report and it doesn't help. I used CodeSite to see what is
    happening. I modified RAP code to:

    ****START
    procedure Variable1OnCalc();
    var
    glParams: TStringList;
    begin
    csEnterMethod('Variable1OnCalc');
    glParams := TStringList.Create;
    csSendMsg('After Creating glParams');
    glParams.Clear;
    csSendMsg('After Clearing glParams');
    glParams.Add('0');
    csSendMsg('After Adding glParams');
    csSendInteger('before ExecuteStringFunction is glParams.Count in RAP = ',
    glParams.Count);
    Value := ExecuteStringFunction('doWeldBase', 'TypKurzuNazev', glParams);
    csSendInteger('after ExecuteStringFunction is glParams.Count in RAP = ',
    glParams.Count);
    csSendMsg('Before Freeing glParams');
    glParams.Free;
    csSendMsg('After Freeing glParams');
    csExitMethod('Variable1OnCalc');
    end;
    ****END

    and modified delphi code to:

    ****START
    .....
    CodeSite.SendInteger('before execute lParams.Count', lParams.Count);
    lResult := doAppServices.CallStringFunction(nil, lModuleName,
    lFunctionName, lArray);
    CodeSite.SendInteger('after execute lParams.Count', lParams.Count);
    ....
    ****END

    After runnig report I received this sequence of messages

    ****START
    ->Variable1OnCalc
    After Creating glParams
    After Clearing glParams
    After Adding Item to glParams
    before ExecuteStringFunction is glParams.Count in RAP = 1
    -> TdoExecuteStringFunction.ExecuteFunction
    before execute Delphi call is lParams.Count = 1
    after execute Delphi call is lParams.Count = 1
    <- TdoExecuteStringFunction.ExecuteFunction
    after ExecuteStringFunction is glParams.Count in RAP = 1
    Before Freeing glParams
    After Freeing glParams
    <-Variable1OnCalc
    ->Variable1OnCalc
    After Creating glParams
    After Clearing glParams
    After Adding Item to glParams
    before ExecuteStringFunction is glParams.Count in RAP = 1
    -> TdoExecuteStringFunction.ExecuteFunction
    before execute Delphi call is lParams.Count = 0
    // look at this line - why 0 - it should be 1
    after execute Delphi call is lParams.Count = 0
    <- TdoExecuteStringFunction.ExecuteFunction
    after ExecuteStringFunction is glParams.Count in RAP = 0
    Before Freeing glParams
    *******STOP

    Calling glParams.Free in RAP, in second runnig causes AV. I don't have
    source to rap to see, why lParams.Count in secon run is 0 in Delphi code
    altought in RAP is 1.

    Petr Slipek
    Dosli

    P.S. Inside ExecuteFunction is call stack empty. - no source for RAP.


    "Chris Ueberall [TeamDM]" <Ueberall@NOSPAM.osd.de> p??e v diskusn?m
  • edited February 2003
    To avoid AV, I removed glParams.Free in RAP and I added logging for
    glParams[0] before execute pass-through function and for logging lParams[0]
    in Delphi ExecuteFunction. And as you can see, delphi function always
    receiving older reverence to glParams. Look at the log.


    ->Variable1OnCalc
    After Creating glParams
    After Clearing glParams
    glParams[0] = 0
    before ExecuteStringFunction is glParams.Count in RAP = = 1
    ->TdoExecuteStringFunction.ExecuteFunction
    lParams[0] = '0'
    before execute lParams.Count = 1
    after execute lParams.Count = 1
    <-TdoExecuteStringFunction.ExecuteFunction
    after ExecuteStringFunction is glParams.Count in RAP = = 1
    Before Freeing glParams
    After Freeing glParams
    <-Variable1OnCalc
    ->Variable1OnCalc
    After Creating glParams
    After Clearing glParams
    glParams[0] = 3
    before ExecuteStringFunction is glParams.Count in RAP = = 1
    ->TdoExecuteStringFunction.ExecuteFunction
    lParams[0] = '0' <====== should be 3
    before execute lParams.Count = 1
    after execute lParams.Count = 1
    <-TdoExecuteStringFunction.ExecuteFunction
    after ExecuteStringFunction is glParams.Count in RAP = = 1
    Before Freeing glParams
    After Freeing glParams
    <-Variable1OnCalc

    Petr Slipek
    Dosli
  • edited February 2003

    The RAP global OnCreate and OnDestroy are going to fire differently when
    you preview from the ReportDesigner than when you preview from the
    preview form. There is going to be a difference in timing.

    If you would like to create a simple example report using DBDemos and
    RAP, and send to support@digital-metaphors.com, we can check it out
    here.





    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited February 2003
    Done

    Petr Slipek
    Dosli

    "Nard Moseley (Digital Metaphors)" p?se v
This discussion has been closed.