Wednesday, December 3, 2008

Executing external x++ code

Executing external x++ code
runbuf() executes x++ code passed to it. The code must be defined as a function and can return a value. Parameters passed to runbuf() will be forwarded, but default parameters won’t work. To show how it works, I am going to use this function to execute code read from an external file. Not very useful and you probably wouldn’t want to allow it, it’s just to show that it can be done (easily). 

static void ExecuteCodeFromFile(Args _args) 
#File 
AsciiIo asciiIo = new AsciiIo("c:\\temp\\findCustomer.xpp",#io_read); 
XppCompiler xppCompiler = new XppCompiler(); 
Sourcesource; 
strline; 
CustTable custTable; 
if (asciiIo) 
asciiIo.inFieldDelimiter(#delimiterEnter); 
[line] = asciiIo.read(); 
while (asciiIo.status() == IO_Status::Ok) 
source += #delimiterEnter; 
source += line; 
[line]= asciiIo.read(); 
if (!xppCompiler.compile(source)) 
error (xppCompiler.errorText()); 
custTable = runbuf(source,'4000'); 
print CustTable.Name; 
else 
print "Could not open file"; 
pause; 
The external file c:\temp\findCustomer.xpp: 
CustTable findCustomer(CustAccount _accountNum) 
return CustTable::find(_accountNum); 
First the file c:\temp\findCustomer.xpp is read into source. Source is then compiled and if that goes okay it is executed. As you can see ‘4000’ is passed as a parameter simply by adding it to the runbuf() call. You can also see runbuf returns the function’s return value. 
I had trouble getting code compiled that I had written using notepad. As it turns out, the compiler does not accept the tab character. So if you are going to try this out, watch out for that. 

Productivity tip: classes EditorScripts & xppSource
Did you ever notice that little service icon in the Axapta source editor? When you open it, it reveals some tools like commenting a source-block or inserting a template. That can for example be a while() loop or an if() block. 

It is actually surprisingly easy to hook your own little scripts up to this menu. 
All you need is a method in Classes\EditorScripts. comments_insertHeader() is one of the standard methods, but you can add your own methods. Use the underscore to define the menu path. 

Having defined a method you need to add some task. The example I will show here is adding a block to iterate a map. I will add the template to \Classes\xppSource and call it from my EditorScripts method. And that's it. You are ready to use your new tool.  This is the template we will build: 
miMap = new mapIterator(map); 
miMap.begin(); 
while (miMap.more()) 
miMap.next() 
..and this is how we do it: 
\Classes\EditorScripts 
void template_flow_iterateMap(Editor editor) 
xppSource xppSource = new xppSource(editor.columnNo()); 
editor.insertLines(xppSource.iterateMap()); 
\Classes\xppSource 
Source iterateMap(Source _mapName = 'map') 
str miMapName = "mi"+StrUpr(substr(_mapName,1,1))+substr(_mapName,2,strlen(_mapName)); 
source += strfmt("%1 = new mapIterator(%2);",miMapName,_mapName); 
source += '\n'; 
source += this.indent(); 
source += strfmt("%1.begin();",miMapName); 
source += '\n'; 
source += this.indent(); 
this.while(strfmt("%1.more()",miMapName),strfmt("%1.next()",miMapName)); 
return source; 
Now obvisouly there’s some room for improvement here. We could search the code for defined maps / mapIterator and use those etc. This is just to show how it works in general. 

No comments:

How to identify the user that was used to change an object from AOT in AX2012

Get the object name for which we need to track these (user and date&time) information's. Login to SQL Server Management Studio an...