Wednesday, 17 December 2014

Macros in AX 2012



Microsoft Dynamics Ax Macros
In MorphX macros are not commonly used. A few places make use of macros such as keeping track of the list of fields stored when using dialogs. It is recommended only to use macros to define constants. Also supports code, but is not recommended as reusing code from macros is not flexible.
The main difference between a macro and a method is that a macro has no variable declaration part, and the code in a macro is not validated for errors before executed from a method. This is another reasons for not putting code in macros.

When using macros in your code, the macros must be declared after the variable declaration. And the common place to put the definition is in the ClassDeclaration of a class, form or a report. This will make the macro definition available for all parts of the object.
 
Macro commands: 
For writing macros a set of simple macro commands are used. Below are few examples.

Command
Description
#define
Used to define a constant.

AxExample: See macro HRMConstants.

Syntax: #define.myConstant100('100')

#if.empty

Will return true if the macro has not been called with the parameter validated in the statement.

#if.notempty

Will return true if the macro has been called with the parameter validated in the statement.

AxExample: See macro InventDimJoin

Syntax: #if.notempty(%3)
print %3;
#endif

#endif

Ends a #if.empty or a #if.notempty statement.

AxExample: See macro InventDimJoin

Syntax: #endif (following any if statement)

#globalmacro

No difference whether declaring the start of a macro with #localmacro or #globalmacro. #globalmacro is not used in the standard package, consider using #localmacro instead.

#localmacro

Specify the start of a local macro.

AxExample: See macro BOM

Syntax: #localmacro.BOMDateSelect
(((BOM.fromDate <= %1 || ! BOM.fromDate) && (BOM.toDate >= %1  || ! BOM.toDate))  || ! %1 )
#endmacro

#endmacro

Ends a #LOCALMACRO or a #GLOBALMACRO.

#linenumber

Returns the current line number of the macro. Can be used while debugging, but not of must use.

#macrolib

Used to load an AOT macro from code.

AxExample: See class method BOMHierarchy.searchDownBOM()

Syntax: #macrolib.MyMacro

#undef

Undefine a constant declared with #DEFINE. A defined constant cannot be used if #undef is called with the define name.

Syntax: #define.MyConstant(100)
print #MyConstant;
#undef.MyConstant
print #MyConstant; // will fail, as #MyConstant is not defined.


Defining Constants:Instead of using text in your code it is strongly recommend defining your text as constants. Often you will need an integer or a text for setting a value. If you are going to set RGB color it is not easy to read the following:
            myStringColor(255, 255, 255)
Instead you should consider defining a constant with a descriptive name:
myStringColor(#RBGColorWhite)

Using a macro as a constant rather than entering the value in code makes it easier to maintain. A good way to organize the constants used in your modifications is by creating a macro in the AOT for keeping all your constants in one place, one good example is HRMConstants.

Creating Macros:
Macros are either created directly in the code, or put in an AOT macro and then the AOT macro is declared in the code.

Example(1): #localmacro created in the code
static void Macros_LocalMacro(Args _args)
{
CustTable custTable;
;
#localmacro.selectCustTable  //Macro definition starts here
#ifnot.empty(%1)
while select %1
#ifnot.empty(%3)
order by %3
#endif
{
info(queryValue(%1.%2));
}
#endif
#if.empty(%1)
info("No table specified.");
#endif
#endmacro  //Macro definition ends here
#selectCustTable(CustTable, accountNum)  //Calling Macro with valid parameters
#selectCustTable  //Calling Macro with no parameters – output will be text “No table specified” as per the validation.
}
The macro will select records from a table ‘CustTable’ and print a field from the same as the table to be fetched, and the fields (%1, %2, %3) to be printed are specified in the parameters for the first Macro call.
In the second Macro call, the table has not been specified so text will be printed to the Infolog.
As you cannot declare variables in a macro, integer values prefixed with a percentage sign such as %1 are used instead. This is the common way of using the macros. The validations must be before calling the macro. Notice that you can call a macro without entering the parentheses after the macro name.
 
Example(2): Create and use an AOT Macro
If your macro is going to be used in several places it would make sense creating the macro in the AOT as you will then be able to reuse the macro.
To create a new macro in the AOT:
1.       Unfold the Macro node, right-click and choose New Macro.
2.      A new empty macro node will be created. You can rename the new macro by opening the property sheet to “MyFirstMacro”
3.      Now paste the code of the #localmacro (from above) to your new macro.
4.      Save the Macro, and it is ready to use. 

To use the macro created in the AOT the macro command #macrolib is used. Here the AOT macro is name MyFirstMacro, and it can be used in the code as shown below.
static void Macros_MacroLib(Args _args)
{
CustTable custTable;
;
#macrolib.MyFirstMacro
#selectCustTable(CustTable, accountNum)
#selectCustTable
}
Even this will result in the same output as explained above, the only difference is that we are calling a Macro created in AOT using #macrolib command.

No comments:

Post a Comment

Calculate ledger balance by dimension set in X++ in AX2012/Dynamics 365 FO

There are a variety of ways users can view balances in the general ledger. Some of the most common options are: 1. Trial balance 2. Financia...