search

Art Of Creation – Dynamics AX Blog

 The everyday life of a Dynamics AX developer

  • Pages

    • AX links
    • Contact
  • Popular Posts

    • Microsoft Dynamics AX 2009 Development Cookbook
    • Axapta 3 menu in AX 2009
    • Launching Dynamics AX using Launchy
    • Lookup() override does not work
    • Check what application and database you are connected to
  • Recent Comments

    • Ismael on Protected new and construct – Part 2
    • Paja42 on Problem solving in AX
    • Alex on X++ and Notepad++
    • Philippe V on Axapta 3 menu in AX 2009
    • Luegisdorf on Lookup() override does not work
  • Tags

    AIF AOS Application Batch bookmarks Books CLR Compiler Configuration Database Data Types Debug Dynamics AX Editorscripts Error Event Log Extensions Fun Google Inheritance Job link lookup Nice-to-haves Noepad++ Patterns RPC security SQL String System.Diagnostics System.IO TechDays Tools Wallpaper WinAPI X++
  • Ax Dev Twitter

    • Updated my blog with "Rename an AX company on SQL": http://tinyurl.com/yl36t7a
    • Don't query, be happy.
    • Microsoft Confirms Dynamics AX Compatibility with Windows 7: http://tinyurl.com/ykewlvh
    • There is *only one* article about "Dynamics Ax" on slashdot.org
    • Remember to use compile forward when modifying classes that are inherited by other classes!
    • X++ editor: pressing ctrl + space on a label to know the text is much faster than using the label editor.
    • Microsoft released hotfixes for Ax 2009 that fix "Internal error 25 in script". KB973902 and KB948130 for more information.
    • X++ editor: double click on text between double quotes and only the text will be selected, with single quotes, the quotes get selected too.
    • Each line of a stack trace starts with (S) or (C). (S) indicates the code was running on the server, (C) that it was running on the client.
    • In the X++ code editor, Ctrl + L will delete a complete line of code.
  • AIF: The path %1 does not exist or is not accessible from an AOS server. Always use a UNC path.

    December 8, 2009 at 18:03  (no comments)

    Hi guys,

    It seems like I’m going to be doing a lot of AIF in the future, so I’d like to share the first AIF error I came across:

    The path C:\AIF does not exist or is not accessible from an AOS server. Always use a UNC path.

    You can get this error when setting up channels.
    While I immediately know what the problem was (you have to use shares), my less technical-minded colleague didn’t know what to do.

    This is what Wikipedia has to say about ‘UNC path’:

    The Microsoft Windows UNC, short for Universal Naming Convention or Uniform Naming Convention, specifies a common syntax to describe the location of a network resource, such as a shared file, directory, or printer. The UNC syntax for Windows systems has the generic form:

    \\ComputerName\SharedFolder\Resource

    So there you have it, you have to use a shared folder in stead of a local folder.
    This is logical, as AIF runs on server, and the AOS can not access your local folders.

  • Show AOS in status bar

    November 26, 2009 at 20:04  (no comments)

    There is an option on the ’status bar’ tab of the options screen (AX button – Extra – Options), that some people think that doesn’t work: Show AOS name.
    You can see what I mean on the screenshot below.

    Show AOS name

    Show AOS name


    As you can see, the AOS is clearly displayed at the bottom of the screen in the status bar.
    If the option doesn’t work for you, it is because you did not specify the Instance Name in your client configuration, as shown on the screenshot below.
    Instance name

    Instance name


    You’ll have to restart AX for this to be visible in the status bar.

    Also note that this doesn’t really show the AOS you are connected to, it merely shows the value you specified in the instance name field in your configuration.

    So does this functionality work? Yes, but not as you’d expect.

  • Run multiple jobs

    November 5, 2009 at 18:34  (no comments)

    I’ve noticed some people are visiting this blog looking for code that runs multiple jobs, so here’s a job that does just that.

    static void KlFor_runMultipleJobsContainer(Args _args)
    {
        #AOT                    // macro for treenode paths
        Container   jobCont;    // container for jobs
        int         i;          // counter for loop
        ;

        // add jobs to the container
        jobCont = conins(jobCont, conlen(jobCont) + 1, "klforjob2");
        jobCont = conins(jobCont, conlen(jobCont) + 1, "klforjob3");
        jobCont = conins(jobCont, conlen(jobCont) + 1, "klforjob2");    // run klforjob2 again

        // loop all elements of the container
        for(i = 1; i <= conlen(jobCont); i++)
        {
            // check if the job exists to avoid errors
             if(TreeNode::findNode(strfmt(#JobPath, conpeek(jobCont, i))))
            {
                // run job
                TreeNode::findNode(strfmt(#JobPath, conpeek(jobCont, i))).AOTrun();
            }
        }
    }

    Easy enough :) .

  • Append text from one file to an other

    October 31, 2009 at 08:28  (1 comment)

    This method will append all text from the original file to the destination file.
    While this is a very easy task, the method shows many of the things you come across when you are working with files in AX, like:

    - Using the #File macro
    - Asserting FileIOPermission to be able to access files
    - Asserting InteropPermission to be able to use .NET Interop
    - Using a set to assert multiple permissions at once
    - Using .NET Clr Interop in AX (better than winapi and winapiserver)
    - Optional cleaning up after you’re done using reverAssert()

    void AppendFileToFile(FileName original, FileName distination)
    {
        #File
        FileIOPermission    FileIOPermissionA   = new FileIOPermission(distination, #io_append);
        FileIOPermission    FileIOPermissionR   = new FileIOPermission(original, #io_read);
        InteropPermission   InteropPermission   = new InteropPermission(InteropKind::ClrInterop);
        Set                 permissionset       = new set(types::Class);
        ;

        // create permissionset
        permissionset.add(FileIOPermissionA);
        permissionset.add(FileIOPermissionR);
        permissionset.add(InteropPermission);
        // assert permissions
        CodeAccessPermission::assertMultiple(permissionset);
        // append text from source file to destination file
        System.IO.File::AppendAllText(distination, System.IO.File::ReadAllText(original));

        // limit the scope of the assert
        CodeAccessPermission::revertAssert();
    }

    Because all permissions are taken care of, this code will run client side as well as server side.

  • Check up on compilation status

    October 30, 2009 at 19:32  (no comments)

    A (little) trick in between. I thought everyone was using this method, but I apparently I was wrong, so here you go.

    Doing a full compile takes a long time, and because of that, it’s handy to be able to check how much of the process is done and how much remains.
    Luckily, when doing a full compile, the Compiler Output form appears at the bottom of the screen where you can see what is currently being compiled.

    The only problem is that most of the time, the AX client hangs and is not responsive during the compilation process, so you can’t see that information.

    The solution to this is to press Crtl + Break.
    You will see a window that says:

    Are you sure that you want to cancel this operation?
    To start the Debugger for Microsoft Dynamics, press and hold SHIFT while you click No.

    While this screen is active, the Compiler Output form will update so you can check up on the status. When you’re done, be sure to click “No” to resume the full compile. Don’t click “Yes” because then the compilation will not resume and you’ll have to start again.

  • Dynamics AX Wallpaper

    October 29, 2009 at 21:26  (1 comment)

    I was looking for a Dynamics themed wallpaper for my desktop, and couldn’t find one, so I made one myself.
    It’s so much nicer to have something AX related on your desktop when you’re doing demo’s and such.

    Dynamics Ax Wallpaper 1920x1080

    Dynamics Ax Wallpaper 1920x1080

    If you like it, don’t hesitate to use it. It’s free of logo’s (except for the Dynamics one of course), so you can put your own ones on it.

  • An instance of Microsoft Dynamics AX Configuration is already running

    October 28, 2009 at 19:00  (1 comment)

    When you start the Microsoft Dynamics AX Configuration Utility, you might get the following message:

    An instance of Microsoft Dynamics AX Configuration is already running. Only one instance can be run at a time.

    You get this message because, obviously, the utility is already running, and you can’t start two instances. So, just click ok, look in the task bar for the Configuration Utility, and go from there.

    But… but… There is no AX configuration utility active!
    Most likely, you are logged into a machine using remote desktop, where an other user has the configuration utility active.

    You can check this in using the Task Manager.
    1. Right click the Task Bar and start the Task manager,
    2. On the processes tab, make sure you see the processes for all users (there’s a checkbox or a button at the bottom) ,
    3. Now look for the process called AxCliCfg.exe,
    4. You can contact the user to ask him to close the Configuration Utility, or you can kill the process yourself.

  • Application file extensions

    October 27, 2009 at 20:00  (1 comment)

    Dynamics AX uses a lot of file extensions, but luckily, there is a logic to them, so you can easily identify their purpose.

    Most of these files are located in the application folder (AX 2009):
    C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\[your_application]

    The extensions have 3 characters:
    The first character indicates the owner of the file:

    a: application
    k: kernel

    The second character indicates the content of the file:

    l: label
    o: object
    t: text
    d: developer documentation
    h: help

    And the third character indicates the type of file:

    d: data
    i: index
    c: cache
    t: temporary

    Using this logic, we can easily name all file extensions, and understand their purpose.

    In the application folder:
    ALD extension: Application Label Data files
    These files contain the labels and label comments for a specific language of a label file.

    ALC extension: Application Label Cache files
    These files contain the application label cache. These files can be deleted when the AOS is stopped.

    ALI extension: Application Label Index files
    The .ali files contain an index to the .ald files. These files can be deleted when the AOS is stopped.

    ALT extension: Application Label Temporary files
    These files contain new labels before they are committed to the .ald file.

    AOI extension: Application Object Index file
    The AOI file contains an index to the AOD files. You can delete this file when the AOS is stopped. Be sure to delete this when you have copied layers from one AX installation to an other.

    ADD extension: Application Developer Documentation Data files
    These files contain the documentation that is found under the Application Developer Documentation node. These files are localized, just like label files.

    ADI extension: Application Developer Documentation Index files
    This is the index to the ADD file.

    AHD extension: Application Help Data files
    The AHD file contains the documentation aimed at the end user. In the AOT, this is found in the “Application Documentation” node.

    AHI extension: Application Help Index files
    This is the index to the AHD file.

    AOD extension: Application Object Data file
    This is the ‘AX layer file’, each of these files represents one layer.

    KHD extension: Kernel Help Documentation files
    These files contain the kernel help documentation you can find in the AOT in the tree node System Documentation.

    KHI extension: Kernel Help Index files
    The KHI file is the index to the Kernel Help file.

    Located in Server/bin:
    KTD extension: Kernel Text Data file
    This file contains system text strings. These are used in the interface of AX and for system messages.

    KTI extension: Kernel Text Index file
    This is the index to the KTD file.

    Client side (not following the naming logic):
    AUC extension: Application Unicode Object Cache file (as from AX 4.0)
    This file is created on the client side, and is used to improve performance by caching AX objects. When you are in the situation where an AX client keeps using ‘old code’, or where something works on one client and not on the other, removing the AUC file might be the solution.
    You can find this file in the directory C:\Documents and Settings\[USERNAME]\Local Settings\Application Data for xp, or C:\Users\USERNAME\AppData\Local for vista.
    More information about object caching on Axaptapedia

    AOC extension: Axapta Object Cache file (Untill Axapta 3)
    This is the ‘old’ version of the AUC file but serves the same purpose.

    Further reading:
    MSDN: Application files architecture
    DAXcoder: Axapta Filename Extension Naming Conventions

  • While select firstonly

    October 22, 2009 at 22:11  (2 comments)

    Some months ago, I had this ‘aha! moment’, when I saw something like this in my code:

    while select firstonly custTable
    {
        // do something
    }

    I had modified a singe select statement into a loop, but forgot to remove the ‘firstonly’ qualifier.
    Then it hit me that the over example is actually the same as writing the following:

    select firstonly custTable;

    if(custTable.recId)
    {
        // do something
    }

    I really liked the idea of the while loop, and I think I’ve used it once or twice where I thought it was appropriate, until I bothered Googling the statement. You get 9 results from Google, which isn’t much, and the first is on msdn:

    Do not use while select firstOnly.

    However, this result is followed by 2 others from msdn (1 and 2), where they do use “while select firstonly”. The last one, is on a page titled “Top Best Practices to Consider”.

    I can think of a couple of reasons why you shouldn’t use such a statement, one of which is performance, and an other readability, but apparently, Microsoft uses it anyway. Also, you can’t use it in cases where you need an ‘else’ branch.

    I, for one, have changed my code and won’t be writing code like this anymore. “While select firstonly” was short lived.

  • Five nice-to-haves in Dynamics AX

    October 20, 2009 at 21:06  (2 comments)

    Here a some functionalities that I think are nice-to-haves in future versions of AX from a developer point of view. I hope they make sense :) .

    1. Select table where field in set
    Consider a situation where you have a set or container filled with recId’s. When you want to loop all records that have one of these recId’s, it would be nice to be able to write something like this:

    Set         set = new Set(Types::Int64);
    CustTable   custTable;
    ;

    set.add(5637166082);
    set.add(5637166083);

    while select custTable
    where custTable.RecId IN set // this will not compile!
    {
    // do stuff
    }

    The only problem is that there is no ‘in’ operator in AX. You will either have to loop the set and select each record one at the time, or you’ll have to use the Query and QueryBuildRange classes to make this work.
    The above example would be much nicer in my opinion.

    2. Throwable exception classes
    It would be nice to be able to create your own exceptions.
    Java, for example, has Throwable and Exception classes that can be extended.
    I won’t say that I completely understand these java classes (I’m not a Java guy), but I believe it would force developers to catch only exceptions they can handle, and not just all exceptions.
    It would also make it possible to have more information as to why an exception has occoured when you catch it.

    3. Try – catch – finally
    This is a classic: the try-catch-finally is not supported in AX. When we look at C# for example, a try-catch can have a ‘finally’ block at the end. The code in this block is always executed, even if an exception occoured.

    4. Events using CLR Interop
    CLR Interop does not support event handling in AX. It would be nice to be able to assign an event handler to an event, so an event can trigger functionality in AX without complicated workarounds involving .NET wrapper classes, infinite loops, services or other creative solutions. (I’m thinking about things like FileSystemWatcher).

    5. Code refactoring
    When you rename an object in AX (Table, field, class, method, etc), there is no refactoring option. You have to manually rename all other instances of that object.
    For example: it would be nice if, when you rename a field, AX had the option to automatically update all methods, forms, etc, where this field was used.

  • Dynamics AX and Google

    September 9, 2009 at 13:00  (no comments)

    This is an article I wanted to write for some time now, and it’s about two things: Dynamics AX, and Google.
    The goal here is to try to know what lives in the Dynamics AX world.

    A nice feature Google search has is autocomplete. It comes in handy when you have to write hard to write words, or when you just want to search faster.

    It’s also a nice way to discover what people are querying for about a certain subject, for example Dynamics AX. Here’s a list of item Google suggests when you type “Dynamics AX ” in the search box.

    dynamics ax 2009
    dynamics ax jobs
    dynamics ax training
    dynamics ax certification
    dynamics ax modules
    dynamics ax blog
    dynamics ax workflow
    dynamics ax 4.0
    dynamics ax aif
    dynamics ax demo

    I don’t want to make an opinion piece out of this, so I’ll just break this up in groups without further comment.

    General: 2009, 4.0, modules & demo
    Jobs and Certification: training, certification & jobs
    Functionality: workflow & AIF
    Community: Blog

    While you don’t know the context of these queries, it’s nice to know what people are interested in.
    Try it for a few subjects, and you might find out some interesting things.

  • Site news: AX link page

    August 31, 2009 at 21:49  (no comments)

    Hi all,

    A new page has been added: AX links.
    Be sure to check it out, there are some really helpful and interesting links in that list.

    If you have bookmarks that you would like to share that are related to AX, just comment and I’ll add them to the list.

  • Editorscripts: create parm method from class declaration

    August 27, 2009 at 13:55  (2 comments)

    I’ve always found it annoying that when you want to create a parm method using the editorscripts, you have to fill in two fields on a dialog (variable name and type). Most of the time, you’ve already declared the variable in the class declaration of your class, so it would be nice if you could just right click on that and create a parm method from there.

    Below is a (quick and dirty) editorscript that allows you to do that.

    public void template_method_parmfromCD(Editor editor)
    {
        int endLine   = editor.selectionEndLine();
        str line;
        str firstCol;
        str secondCol;
        int linecount;
        str source;
        container cont;
        XppSource xppSource;
        TreeNode tn;
        TreeNode childNode;

        boolean contains(str s, str findStr)
        {
            if(strscan(s, findStr, 1, strlen(s)) > 0)
                return true;

            return false;
        }

        str replace(str s, str findStr, str replStr)
        {
            int pos = strscan(s, findStr, 1, strlen(s));

            while(pos > 0)
            {
                s = strdel(s, pos, strlen(findStr));
                s = strins(s, replStr, pos);

                pos = strscan(s, findStr, pos + strlen(replStr), strlen(s));
            }
            return s;
        }
        ;

        editor.firstSelectedLine();
        while (editor.moreLines() && endline > editor.lineNo())
        {
            line = strltrim(editor.getLine());
            while(contains(line, "  " ))
            {
                line = replace(line, "  ", " " );
            }

            cont = str2con(line, " ");

            firstCol = conpeek(cont, 1);
            secondCol = conpeek(cont, 2);
            secondCol = strrem(secondCol, ";=");

            editor.nextSelectedLine();

            tn = EditorScripts::getApplObjectNode(editor);
            if(firstCol != "0" && secondCol != "0")
            {
                if(!tn.AOTfindChild(strfmt("parm%1", strupr(substr(secondCol,1,1))+substr(secondCol,2,strlen(secondCol)))))
                {
                    if(tn.AOTfindChild("Methods"))
                        tn = tn.AOTfindChild("Methods");

                    childNode = tn.AOTadd(strfmt("parm%1", strupr(substr(secondCol,1,1))+substr(secondCol,2,strlen(secondCol))));

                    xppSource = new XppSource();
                    source = xppSource.parmMethod(firstcol,secondCol);
                    childNode.AOTsetSource(source, false);
                    tn.AOTsave();
                }
                else
                {
                    error(strfmt("Parm method %1 already exists", strfmt("parm%1", strupr(substr(secondCol,1,1))+substr(secondCol,2,strlen(secondCol)))));
                }
            }
        }
    }

    Some code from Greg Pierce’s awesome String class was used for the inner methods.
    I tested it on classes, form and reports, and it works very well.

    To install this editorscript, copy the code above in a new method of the class EditorScripts.
    To use it, in the classDeclaration, simply select one or more declarations, then right click and choose Scripts – template – method – parmfromCD.

  • Remove leading zeros

    August 3, 2009 at 10:49  (no comments)

    Sometimes, you’ll want to add leading zeros, but other times, you’ll have to remove leading zeros from a string.
    Here the code that does just that:

    static void RemoveLeadingZeros(Args _args)
    {
        str text = "0000A1337";
        ;

        while(substr(text, 1, 1) == "0")
        {
            text = substr(text, 2, strlen(text) - 1);
        }
        info(text);
    }

    The above example will work for any alphanumeric string.

    When you’re sure you’re dealing with numeric strings, you can use this example:

    static void RemoveLeadingZeros2(Args _args)
    {
        str text = "00001337";
        ;

        if(strrem(text, "0123456789") == "")
            info(int2str(str2int(text)));
        else
            error("text is not numeric");
    }

    You should build in a check because the str2int() function doesn’t throw an error when the input isn’t numeric.

    An example I found online also removes leading zeros from a string, but it fails if the first character after the zeros isn’t numeric:

    static void RemoveLeadingZeros3(Args _args)
    {
        str text = "0000A1337"; // doesnt work
        // str text = "00001A337"; // works
        ;

        info(strdel(text, 1, strfind(text, "123456789", 1, strlen(text)) - 1));
    }

    Conclusion:
    The first example works best, but you should still be careful when converting the resulting string to other types, as you could get unexpected results.

  • Writing in the event log from Dynamics AX

    June 19, 2009 at 13:14  (1 comment)

    Writing to the event log in Windows using AX is very easy when you use the EventLog class from the System.Diagnostics namespace. The following job demonstrates how to use the EventLog class.

    static void EventViewer(Args _args)
    {
        System.Diagnostics.EventLog eventlog;
        #Define.LogSource("Dynamics AX")
        #Define.LogName("Dynamics AX Log")
       
        ;
        // check if the log already exists
        if(!System.Diagnostics.EventLog::SourceExists(#LogSource))
        {
            // create new log
            System.Diagnostics.EventLog::CreateEventSource(#LogSource, #LogName);
        }

        eventlog = new System.Diagnostics.EventLog();
        eventlog.set_Source(#LogSource);

        // write info entry
        eventlog.WriteEntry("Just writing in the event viewer.");
        // write error entry
        eventlog.WriteEntry("Error! Please check the stack trace below. \n\n" +
            con2str(xSession::xppCallStack()), System.Diagnostics.EventLogEntryType::Error);
        // write warning entry
        eventlog.WriteEntry("Job finished." , System.Diagnostics.EventLogEntryType::Warning);
       
        info("Check the event viewer!");
    }

    A possible use for this is when monitoring batch jobs.
    Tested using AX 2009, XP Pro.

  • « Previous Page

    Next Page »

     

Wordpress // Photon theme // Copyright © Klaas Deforche