Accessing a Table Buffer when it is not passed as a parameter


David Meego - Click for blog homepageThis is a reposting of an article I originally wrote on my Developing for Dynamics GP blog.

This post is a follow up to the previous posts on the Three Trigger Technique. If you have not read the posts explaining this technique, please use the links below:

The idea of the three trigger technique is to use a trigger on an unrelated function or procedure call to get the timing you require for your code.  The 1st and 2nd triggers are used to ensure that the 3rd trigger is only used when it is called from your desired parent script.

This post discusses a method that can be used in conjunction with the three trigger technique. In the example code supplied in the part 2 post, we were able to capture a reference to the table buffer we needed because the table was passed as a parameter to the parent script.  But, what happens when the table buffer you need is not available as a parameter?


Before we get to the actual code I should clarify that while I can write code to use a table which is defined in Dynamics.dic, or use pass through code with the execute() function to use a table in a third party dictionary. However, the table buffer used will be a new private instance created for the duration of the code.  To use the same table buffer as the original code requires a reference to the table buffer to be captured and stored.  Then this reference can be used or passed as a parameter.

We will discuss three methods that can be used to capture that all important table reference:

Method 1: When the table is a parameter to another function or procedure called prior to your triggering point.

You can add a fourth trigger to your scripts running before the original code of the function or procedure that passes the table as a parameter.  This trigger’s purpose is just to capture the table reference so it can be used in our code later.

Example Trigger handler script

inout table XYZ_Table;

{ If not inside the three trigger code, do not continue }
if not 'MBS Trigger Active' of globals then
    abort script;
end if;

{ Capture Table Reference }
assign 'MBS Table Reference' of globals as reference to table XYZ_Table;

Method 2: When the table is attached to a form.

The following scripts demonstrate how to capture the table buffer reference after the first get table or change table command is issued against that table.  By using a global integer variable to store the trigger tag returned when registering, we are able to enable and disable the table trigger as needed.  The trigger is disabled once the reference is captured so that it does not affect performance.

Global Procedure: Startup

{Turn off the warning for literal strings}
pragma(disable warning LiteralStringUsed);

{ Check not in Test mode and 3rd Party XYZ installed }
if not empty(Launch_GetFileName()) then
    if Launch_GetProdPosition(MBS_PROD_XYZ) >= 1 then

        if Trigger_RegisterDatabaseByName(MBS_PROD_XYZ, "XYZ_Table", "XYZ_Form", TRIGGER_ON_DB_READ+TRIGGER_ON_DB_READ_LOCK, script MBS_XYZ_Table_READ, 'MBS Table Trigger Tag' of globals) <> SY_NOERR then
            warning "Trigger After table XYZ_Table READ Registration Failed.";
        else
            { Disable Trigger for now, triggers below will re-enable }
            Trigger_DisableSingle('MBS Table Trigger Tag' of globals);

            if Trigger_RegisterFocusByName(MBS_PROD_XYZ, "form XYZ_Form", TRIGGER_FOCUS_PRE, TRIGGER_BEFORE_ORIGINAL, script MBS_XYZ_FORM_PRE) <> SY_NOERR then
                warning "Trigger Before form XYZ_Form PRE Registration Failed.";
            end if;

            if Trigger_RegisterFocusByName(MBS_PROD_XYZ, "form XYZ_Form", TRIGGER_FOCUS_POST, TRIGGER_AFTER_ORIGINAL, script MBS_XYZ_FORM_POST) <> SY_NOERR then
                warning "Trigger After form XYZ_Form POST Registration Failed.";
            end if;
        end if;

    end if;
end if;

{Turn the literal string warning back on}
pragma(enable warning LiteralStringUsed);

Global Procedure: MBS_XYZ_FORM_PRE

{ Enable Table Trigger }
Trigger_EnableSingle('MBS Table Trigger Tag' of globals);

Global Procedure: MBS_XYZ_FORM_POST

{ Disable Table Trigger, if not already disabled }
Trigger_DisableSingle('MBS Table Trigger Tag' of globals);
{ Clear Table Reference }
clear 'MBS Table Reference' of globals;

Global Procedure: MBS_XYZ_Table_READ

inout anonymous table XYZ_Table;
in integer IN_Operation;{ Capture Table Reference }

assign 'MBS Table Reference' of globals as reference to table XYZ_Table;

{ Disable Table Trigger now that we have table reference captured }
Trigger_DisableSingle('MBS Table Trigger Tag' of globals);

Method 3: When the table is a local instance created in a function or procedure.

This method is similar to the method above, but uses triggers on the function or procedure and has to use an unrestricted table trigger (i.e. not linked to a form).

Global Procedure: Startup

{Turn off the warning for literal strings}
pragma(disable warning LiteralStringUsed);{ Check not in Test mode and Copier Series installed }

if not empty(Launch_GetFileName()) then
    if Launch_GetProdPosition(MBS_PROD_XYZ) >= 1 then

        if Trigger_RegisterDatabaseByName(MBS_PROD_XYZ, "XYZ_Table", "", TRIGGER_ON_DB_READ+TRIGGER_ON_DB_READ_LOCK, script MBS_XYZ_Table_READ, 'MBS Table Trigger Tag' of globals) <> SY_NOERR then
            warning "Trigger After table XYZ_Table READ Registration Failed.";
        else
            { Disable Trigger for now, triggers below will re-enable }
            Trigger_DisableSingle('MBS Table Trigger Tag' of globals);

           if Trigger_RegisterProcedureByName(MBS_PROD_XYZ, "XYZ_Script", TRIGGER_BEFORE_ORIGINAL, script MBS_XYZ_Script_PRE) <> SY_NOERR then
               warning "Trigger Before XYZ_Script Registration Failed.";
           end if;

           if Trigger_RegisterProcedureByName(MBS_PROD_XYZ, "XYZ_Script", TRIGGER_AFTER_ORIGINAL, script MBS_XYZ_Script_POST) <> SY_NOERR then
               warning "Trigger After XYZ_Script Registration Failed.";
           end if;
       end if;

    end if;
end if;

{Turn the literal string warning back on}
pragma(enable warning LiteralStringUsed);

Global Procedure: MBS_XYZ_Script_PRE

{ Enable Table Trigger }
Trigger_EnableSingle('MBS Table Trigger Tag' of globals);</div>

Global Procedure: MBS_XYZ_Script_POST

{ Disable Table Trigger, if not already disabled }
Trigger_DisableSingle('MBS Table Trigger Tag' of globals);
{ Clear Table Reference }
clear 'MBS Table Reference' of globals;

Global Procedure: MBS_XYZ_Table_READ

inout anonymous table XYZ_Table;
in integer IN_Operation;{ Capture Table Reference }
assign 'MBS Table Reference' of globals as reference to table XYZ_Table;

{ Disable Table Trigger now that we have table reference captured }
Trigger_DisableSingle('MBS Table Trigger Tag' of globals);

Hope you find this technique a useful addition to your arsenal.

David

This article was originally posted on the Developing for Dynamics GP Blog and has been reposted on http://www.winthropdc.com/blog.

3 thoughts on “Accessing a Table Buffer when it is not passed as a parameter

Please post feedback or comments

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.