Showing posts with label Kernel functions. Show all posts
Showing posts with label Kernel functions. Show all posts

Thursday, September 23, 2010

Tutorial: Undocumented behavior of kernel functions min()/max()

I was recently reviewing some code written to be shipped with AX6, and noticed an unfamiliar pattern being used in it. I investigated a bit deeper, and turns out it actually works fine on previous versions of AX as well.

I am talking about 2 kernel functions for finding the maximum or minimum of the specified values.
The signature of these methods is shown on the below image:

As you can see, it takes 2 arguments of anytype, and returns an anytype which is the largest of the two values. But it can accept much more than 2 arguments, even though it is not documented as such.

I wrote a small job to showcase this behavior. The code is provided below. You can also download it from my SkyDrive Dynamics AX share.
static void Tutorial_MinMaxFunctions(Args _args)
{
#define.ArraySize(11)

Random rand = new Random();

int counter;
int arrayInt[#ArraySize];
str arrayIntAsString;
int arrayIntMaxValue;
int arrayIntMinValue;
;

for (counter = 1; counter <= #ArraySize; counter++)
{
arrayInt[counter] = rand.nextInt();
if (arrayIntAsString)
arrayIntAsString += ', ';
arrayIntAsString += int2str(arrayInt[counter]);
}
info("Generated array of integers: " + arrayIntAsString);

info("The typical way to find a maximum is by looping through all the values one by one, calling the comparison function multiple times");
arrayIntMaxValue = minint();
arrayIntMinValue = maxint();
for (counter = 1; counter <= #ArraySize; counter++)
{
arrayIntMaxValue = max(arrayIntMaxValue, arrayInt[counter]);
arrayIntMinValue = min(arrayIntMinValue, arrayInt[counter]);
}
info(strfmt("Max.value: %1 and Min.value: %2", int2str(arrayIntMaxValue), int2str(arrayIntMinValue)));

info("Using max and min with 11 arguments works just as well");
arrayIntMaxValue = minint();
arrayIntMinValue = maxint();
arrayIntMaxValue = max(arrayInt[1], arrayInt[2], arrayInt[3], arrayInt[4], arrayInt[5], arrayInt[6], arrayInt[7], arrayInt[8], arrayInt[9], arrayInt[10], arrayInt[11]);
arrayIntMinValue = min(arrayInt[1], arrayInt[2], arrayInt[3], arrayInt[4], arrayInt[5], arrayInt[6], arrayInt[7], arrayInt[8], arrayInt[9], arrayInt[10], arrayInt[11]);
info(strfmt("Max.value: %1 and Min.value: %2", int2str(arrayIntMaxValue), int2str(arrayIntMinValue)));

info("Note that comparing an integer and a real also works, as well as outputing the results straight into an infolog message");
info(max(12, 12.001));
}

Another interesting point is that it can actually accept different types of arguments, for example, a real and an integer, as shown above. And it actually returns an anytype, which implicitly gets converted to a string when sent to the infolog.

Disclaimer: Since this is not a documented feature, it can theoretically change in the future releases, but I doubt it in this particular case.

Thursday, April 22, 2010

Tool: User preferred startup menu for Dynamics AX 2009

In AX 2009, the user has no control over which menu is opened in the navigation pane and address bar when AX client is started.
Most of the time you simply get the Home page, which is frustrating for a number of users. Another thing that is frustrating for them is the company account the application opens with.

The latter can actually be setup using standard application functionality in the User options form. Just set the 'Start company accounts' to the account you want for the user by default.

I wrote a small tool, that allows the user to select a preferred startup menu, ensuring that this menu is the one open every time AX client is started. Something similar existed in Axapta 3.0 application.

You can download the xpo for this tool from my SkyDrive.

Note, that it contains minor changes to a number of existing application objects.
I suggest that you compare the xpo from the import dialog and ensure that you don't override any of your changes during import - the best thing would be to re-implement these minor changes manually. Below is a list of changes that I am referring to above:
  • SysUserInfo table - 1 new field was added
  • SysUserSetup form - 1 new control was added. Lookup method on datasource field overridden
  • Info class - startupPost method changed

In order to enable the functionality, simply select one of the menus in the User options, as shown in the below screenshot. Next time you start AX, the selected menu will be open by default.

Start Menu in User options, Microsoft Dynamics AX 2009

Below is a short listing of "code patterns" used in the project, that can serve as examples for your future projects:
  • SysTableLookup - for displaying a lookup form with a list of menus
  • infolog.globalCache() - for storing a global reference to the navigator class
  • TreeNode iteration - for finding all menu references in MainMenu
  • QueryBuild classes - for constructing and filtering a list of menu references in MainMenu, used in the lookup form
  • infolog.addTimeOut() method - for scheduling execution of another method in a set period of time

Thursday, December 3, 2009

Correct KernelFunctions xpo

Hey, guys.

Just a small update on my previous post on Kernel Functions for those interested.
I have now corrected the link to point to the right xpo.
It was previously pointing to a parser class I used to get some of the functions in.

Sorry about that :)
The uploaded xpo is compatible with AX 2009

Wednesday, November 25, 2009

Kernel functions exposed through BC.NET

BC.NET is a great feature of Dynamics AX. It allows to access the AX application from any external application that supports .NET, and provides a rather rich functionality out of the box.
But one feature that is missing in BC.NET is the ability to call AX kernel functions, like fieldId2Name, num2str, decRound, etc.

I needed to use these functions in my code recently, and in order to access them, I created a class in X++, that simply wraps the useful functions in static methods, kinda like the ones that exist in class Global.

Download Class_KernelFunctions.xpo

You need to import it into AX before using, of course. This can be automated, if you don't want to include this XPO as part of the package you deliver to your customers.

Now you can call it through the Business Connector the following way:

Axapta ax = new Axapta();
ax.Logon("ext", null, "localhost", null);
// num2str(123.45, -1, 2, 1, 1);
Convert.ToDouble(ax.CallStaticClassMethod("KernelFunctions", "num2str", 123.45m, -1, 2, 1, 1));