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.
  • Rename an AX company on SQL

    February 24, 2010 at 22:57  (no comments)

    A while ago, I talked about deleting an AX company on SQL, but of course, you can also use the sp_MSforeachtable stored procedure to rename a company (= change the DataAreaId of a company).

    In the next example, I rename CEE to CEA:

    exec sp_MSforeachtable 'update ? set DataAreaID = "CEA" where ?.DataAreaID = "CEE"'

    UPDATE DataArea SET ID = 'CEA' WHERE DataArea.ID = 'CEE'
    UPDATE CompanyDomainList SET CompanyID = 'CEA' WHERE CompanyID = 'CEE'
  • X++ and Notepad++

    February 18, 2010 at 18:13  (1 comment)

    I notice that a lot of people are looking for a way to syntax color their xpo’s when viewing them in Notepad++.

    There is an article on Axaptapedia that covers this, that includes a sample xml snippet you can use.

    For some reason though, when you google “x++ notepad++”, the Axaptapedia page is nowhere to be found.

    I’ve also created a custom language based on the one on wikipedia, that uses colors that resemble the ones in the X++ editor a bit more:

        <UserLang name="XPP_XPO" ext="xpo">
            <Settings>
                <Global caseIgnored="no" />
                <TreatAsSymbol comment="no" commentLine="no" />
                <Prefix words1="no" words2="no" words3="no" words4="no" />
            </Settings>
            <KeywordLists>
                <Keywords name="Delimiters">&quot;&apos;0&quot;&apos;0</Keywords>
                <Keywords name="Folder+">SOURCE { CLASS METHODS PROPERTIES CONTROL CONTAINER ARRAY INDEX FORM OBJECTBANK DATASOURCE OBJECTPOOL FIELDLIST JOINS DESIGN TYPEELEMENTS TYPEREFERENCES USERTYPE FIELDS GROUPS GROUPFIELDS GROUP DATAFIELD INDICES INDEXFIELDS REFERENCES REFERENCE FIELDREFERENCES DELETEACTIONS BEGINNODE MENUITEM MENU</Keywords>
                <Keywords name="Folder-">ENDSOURCE } ENDMETHODS ENDCLASS ENDPROPERTIES ENDCONTROL ENDCONTAINER ENDARRAY ENDFORM ENDOBJECTBANK ENDDATASOURCE ENDOBJECTPOOL ENDFIELDLIST ENDJOINS ENDDESIGN ENDTYPEELEMENTS ENDTYPEREFERENCES ENDUSERTYPE ENDFIELDS ENDGROUPS ENDGROUPFIELDS ENDGROUP ENDINDEXFIELDS ENDINDICES ENDFIELDREFERENCES ENDREFERENCE ENDREFERENCES ENDDELETEACTIONS ENDTABLE ENDNODE ENDPROJECT ENDDATAFIELD ENDMENUITEM ENDMENU</Keywords>
                <Keywords name="Operators">&apos; ! &quot; ?</Keywords>
                <Keywords name="Comment">1/* 2*/ 0//</Keywords>
                <Keywords name="Words1">Formatversion: Configuration: language directory company user client fetchahead opencursors database dsn sqluser hint sqlbuffer log hassqlpwd sqlpwd sqlparm retry dbserversqltrace haswarnings warnings share bindir startupmsg servermask localappl localappldoc locallabel localsysdoc applshare applexclusive doclanguage startupcmd logdir hascompwd compwd hasserveridletimeout serveridletimeout connectionidletimeout querytimelimit extracmdline port createdsn createdsn_tcpipport aos allowunauth exposeserverprers useserverprers sqlformliterals sqlcomplexliterals sqloraclefirstrowsfix ignoredatasourceindex aosencryption xppdebug dbcli ociconnectservice ociservice ocihost ocidbid ocitcpipport ociuser hasocipwd ocipwd preloadthresholdmsec preloadthresholdrecords dbunicodeenabled newconnectionretrydelayms newconnectionretrycount cachesynctime _clientmode _clientadname application broadcast internet aol aolcode sql native dbserver sqltrace exposeserverprinters useserverprinters ***Element FRMVERSION str container int select firstonly where while for Filename if return void public super element Return Yes No Delayed&#x0D;&#x0A; First Auto Default Normal Watch Vertical NoAccess Main Column width None Outside Opaque Button face View Grid Window background Highlight text Left Right only Text info run Version Else error Args Raised height Horizontal flush right boolean Common QueryRun FormTreeItem class Set FormTreeControl map anytype Dialog SysDictField this New new Query QueryBuildRange else QueryBuildDataSource Array mapiterator ttsbegin ttscommit FileName SaxReader SaxErrorHandler SaxAttributes TextBuffer protected catch try Called from classDeclaration Arrow USERTYPEVERSION TABLEVERSION FIELD Integer Absolute AutoReport AutoLookup REFERENCETYPE NORMAL static Miscellaneous Delete Not specified String Memo Cascade PROJECTVERSION SHARED JOBVERSION NoYes private null count Map DictTable break ttsBegin ttsCommit Error Exception true sum server DictField Counter throw join abstract extends endif index continue false switch case Version Restricted InnerJoin Active Standard Display VERSION MNUVERSION</Keywords>
                <Keywords name="Words2">Text Int Name Table Index Company CounterField AllowCheck AllowEdit AllowCreate AllowDelete StartPosition AutoSearch AutoNotify AutoQuery OnlyFetchActive JoinSource LinkType DelayActive InsertAtEnd InsertIfEmpty Left Top Width Height Visible Caption TitleDatasource Frame WindowResize WindowType SaveSize SaveSize HideToolbar SetCompany ColorScheme CssClass ShowWebHelp BackgroundColor ImageName ImageResource Imagemode Mode SubmitMethod SupportReload LocalWebMenu AllowDocking Font FontSize Italic Underline Bold CharacterSet LabelFont LabelFontSize LabelItalic LabelUnderline LabelBold LabelCharacterSet DataSource TopMargin BottomMargin LeftMargin RightMargin ArrangeWhen ArrangeMethod Columns Columnspace ArrangeGuide HideIfEmpty AlignChildren AlignChild AllowUserSetup NeededAccessLevel AutoDeclaration VerticalSpacing Enabled Skip AlignControl HelpText ConfigurationKey SecurityKey DragDrop FrameType FramePosition BackStyle FrameOptionButton OptionValue DataGroup AutoDataGroup MultiSelect VisibleCols VisibleRows ShowColLabels ShowRowLabels HighlightActive ActiveBackColor ActiveForeColor GridLines LookupButton ReplaceOnLookup LimitText DisplayLength DisplayHeight Border Value Alignment SignDisplay RotateSign ShowZero DisplaceNegative AllowNegative ForegroundColor LabelForegroundColor ShowLabel Label LabelWidth LabelHeight LabelPosition LabelAlignment DataField Mandatory ArrayIndex SearchMode PasswordStyle ChangeCase MultiLine ExtendedDataType DataMethod ButtonDisplay NormalImage NormalResource DisabledImage DisabledResource ShowShortCut DefaultButton SaveRecord Tabs Tab TabAppearance ShowTabs TabPlacement TabLayout SelectControl TabAutoChange Extends RunOnFormHelp ArrayLength FormHelp ButtonImage StringSize Adjustment GroupPrompt SaveContents AliasFor AllowEditOnCreate FieldUpdate Type OldName AllowDuplicates Validate Field RelatedField TitleField1 TitleField2 Temporary TableContents Systemtable MaxAccessMode CreateRecIdIndex SaveDataPerCompany TableGroup PrimaryIndex ClusterIndex ModifiedDate ModifiedTime ModifiedBy ModifiedTransactionId CreatedDate CreatedTime CreatedBy CreatedTransactionId DeleteAction FormRef CacheLookup FILETYPE UTILTYPE UTILOBJECTID NODETYPE NAME EnumType Style RunOn AllowAdd Selection HideFirstEntry ComboType AppendNew SizeWidth SizeHeight MenuItemType MenuItemName DateValue DateFormat DateSeparator DateYear DateMonth DateDay RealValue ThousandSeparator DecimalSeparator NoOfDecimals AutoInsSeparator FormatMST Class Object Parameters EnumTypeParameter EnumParameter Web WebAccess WebSecureTransaction WebPage CountryConfigurationkey WebConfigurationkey WebTarget ProjectGroupType GroupMask PreventEditProperties</Keywords>
                <Keywords name="Words3">FRM GRID INTEDIT STRINGEDIT BUTTON TAB TABPAGE CLS CLSVERSION || &amp;&amp; UTI INT UTS STRING DBT TABLE PRN PROJECT END \ JOB ENUM COMBOBOX CHECKBOX STATICTEXT BUTTONGROUP MENUITEMBUTTON MENUBUTTON WINDOW DATEEDIT REALEDIT SEPARATOR FTM MNU UTE</Keywords>
                <Keywords name="Words4">@</Keywords>
            </KeywordLists>
            <Styles>
                <WordsStyle name="DEFAULT" styleID="11" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="FOLDEROPEN" styleID="12" fgColor="FF8040" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="FOLDERCLOSE" styleID="13" fgColor="FF8040" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="KEYWORD1" styleID="5" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD2" styleID="6" fgColor="007F00" bgColor="FFFFFF" fontName="" fontStyle="2" />
                <WordsStyle name="KEYWORD3" styleID="7" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="KEYWORD4" styleID="8" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="COMMENT" styleID="1" fgColor="007F00" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="COMMENT LINE" styleID="2" fgColor="007F00" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="NUMBER" styleID="4" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="10" />
                <WordsStyle name="OPERATOR" styleID="10" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="1" />
                <WordsStyle name="DELIMINER1" styleID="14" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="DELIMINER2" styleID="15" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="0" />
                <WordsStyle name="DELIMINER3" styleID="16" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
            </Styles>
        </UserLang>

    This is how it looks in Notepad++:

    Syntax coloring X++ in Notepad++

    Syntax coloring X++ in Notepad++

    Links:
    Notepad++ homepage
    Notepad++ on Axaptapedia

  • Protected new and construct – Part 2

    at 18:06  (1 comment)

    In part 1, we talked about the use of a protected new method and a static constructor, and how it helps improve your classes.

    Now let’s see how it helps you maintain you code better when extending classes.

    In the previous example, we printed some general information about a record to the screen.
    Let’s say that, in case of CustTable we want to have information printed to to screen that is specific to this record, like the AccountNum or Name field.

    We will need to create a new class that extends the class we created earlier.

    1. ClassDeclaration KLFShowRecordInfo_CustTable
    In the ClassDeclaration, we include the keyword ‘extends’ to specify that our new class extends the functionality of the class KLFShowRecordInfo.

    class KLFShowRecordInfo_CustTable extends KLFShowRecordInfo
    {
    }

    2. Construct method KLFShowRecordInfo_CustTable
    We will also add a construct method to this class. This will create an instance of this class for us, and set the parm method.
    Because we extend a class that contains this parm method, we don’t need to add it to this class again.

    public static KLFShowRecordInfo_CustTable construct(Common _record)
    {
        KLFShowRecordInfo_CustTable kLFShowRecordInfo_CustTable;
        ;

        kLFShowRecordInfo_CustTable = new KLFShowRecordInfo_CustTable();
        kLFShowRecordInfo_CustTable.parmRecord(_record);

        return kLFShowRecordInfo_CustTable;
    }

    3. Run method KLFShowRecordInfo_CustTable
    In the run method, we print data from the CustTable record to screen.

    void run()
    {
        CustTable custTable;
        ;

        custTable = this.parmRecord();

        info(custTable.AccountNum);
        info(custTable.Name);
    }

    You could call the super() method if you want the general information to be printed as well.

    4. Construct method KLFShowRecordInfo
    The only thing we need to change to the existing class is the construct method.
    Modify it like this:

    public static KLFShowRecordInfo construct(Common _record)
    {
        KLFShowRecordInfo kLFShowRecordInfo;
        ;

        switch (_record.TableId)
        {
            case tablenum(CustTable):
                kLFShowRecordInfo = KLFShowRecordInfo_CustTable::construct(_record);
            break;
            default :
                kLFShowRecordInfo = new KLFShowRecordInfo();
                kLFShowRecordInfo.parmRecord(_record);
            break;
        }

        return kLFShowRecordInfo;
    }

    The switch will check which table is being processed, and will create an instance of KLFShowRecordInfo_CustTable in case of CustTable. For all other tables, it will construct an instance of KLFShowRecordInfo.

    5. TestJob
    Let’s test it:

    static void KLF_TestRecordInfo(Args _args)
    {
        CustTable custTable;
        VendTable vendTable;
        ;

        select firstonly custTable;
        select firstonly vendTable;

        // custTable:
        KLFShowRecordInfo::construct(custTable).run();
        info("----");
        // vendTable:
        KLFShowRecordInfo::construct(vendTable).run();
    }

    Output:

    00000001
    IKEA
    —-
    VendTable

    Conclusion
    This concludes my articles about the protected new and construct methods. I realise that the examples are very simple, but the principle will remain the same, even in more complex scenarios.

    To sum up:
    My basic recommendations when creating classes are:
    - Use a protected new method
    - Use a construct method
    - Use parm methods
    - Create a run method that contains your business logic
    - Instead of modifying existing classes, create new ones that extend existing

    If you disagree, be sure to leave a comment :) .

  • Run AIF inbound and outbound manually

    February 17, 2010 at 18:51  (no comments)

    To have AIF import and export message, you have to have 4 batch tasks running (all about it here on TechNet). However, when developing, it is inefficient (and also tad tedious) to wait for those batches.

    Here are two jobs to run inbound and outbound messages manually, so you don’t have to wait for the batches to pick them up.

    Inbound:

    static void KlForrunAIFInbound(Args _args)
    {
        ;
        // read the messages
        new AifGateWayReceiveService().run();

        // process the messages in queue
        new AifInboundProcessingService().run();

        info("done");
    }

    Outbound:

    static void KlForrunAIFOutbound(Args _args)
    {
        ;
        // process messages in queue
        new AifOutboundProcessingService().run();

        // send messages
        new AifGateWaySendService().run();

        info("done");
    }

    Ofcourse, you can put this code in classes, or combine them so they are executed together. Because inbound messages can trigger outbound messages, it’s better to process the inbound messages before the outbound messages.

  • Protected new and construct – Part 1

    February 15, 2010 at 10:16  (no comments)

    In this post I want to show you the use of the new() and construct() method when instantiating classes using a simple example class. This is a design that is used a lot an AX.

    It is best practice to set the new method as protected (MSDN), and it is also best practice to have a construct method in your class (MSDN). So let’s see how we should implement these best practices.

    Like a good recipe, a good class has a few important ingredients:
    - Parm methods for variables
    - A protected new method
    - A static contructor
    - A run method

    1. ClassDeclaration

    As an example, we will create a new class: KLFShowRecordInfo
    The function of the class will be to display some information about a record.

    class KLFShowRecordInfo
    {
        Common record;
    }

    This class has one variable, a record. The type is Common so we can store any record in this variable.

    2. Parm method

    First thing is to create a parm-method for this variable (created using parmFromCD editorscript):

    public Common parmRecord(Common _record = record)
    {
    ;
        record = _record;

        return record;
    }

    Your code will be much cleaner and easier to debug when you use parameter methods.

    3. New Method

    Next, we will override the new method and make it protected:

    protected void new()
    {
    }

    Methods that are declared as protected can only be called from methods in the class and in subclasses of the class where the protected method is declared. When we want to create an instance of this class from an other class, we’ll have to call the construct method.
    When calling the new() method in any other class, we would get the following compiler error:

    The method is declared protected and may only be called from methods in classes derived from KLFShowRecordInfo.

    4. Construct method

    When using the editorscript to create a construct() method (Right click – Scripts – template – method – construct), it will look like this:

    public static KLFShowRecordInfo construct()
    {
        return new KLFShowRecordInfo();
    }

    However, I always rewrite it like like this because it is easier to extend afterwards:

    public static KLFShowRecordInfo construct()
    {
        KLFShowRecordInfo kLFShowRecordInfo;
        ;

        kLFShowRecordInfo = new KLFShowRecordInfo();

        return kLFShowRecordInfo;
    }

    Now we’ll have to modify the construct method to receive a parameter, and use the parm method to set the variable in our class:

    public static KLFShowRecordInfo construct(Common _record)
    {
        KLFShowRecordInfo kLFShowRecordInfo;
        ;

        kLFShowRecordInfo = new KLFShowRecordInfo();
        kLFShowRecordInfo.parmRecord(_record);

        return kLFShowRecordInfo;
    }

    5. Run method
    All we need now is some logic to add to this class. Most of the time, I name the method ‘run’, but you can give it any name you like. The method will display the name of the table of the record you pass to it.

    void run()
    {
        ;
        info(tableid2name(this.parmRecord().TableId));
    }

    6. Test job
    Next, a job to test it:

    static void KLF_TestRecordInfo(Args _args)
    {
        CustTable custTable;
        ;
       
        select firstonly custTable;
       
        // this will not work because the new method is protected
        // kLFShowRecordInfo = new KLFShowRecordInfo();
       
        KLFShowRecordInfo::construct(custTable).run();
    }

    You can see that we only need one line of code to call our class, and we don’t need a variable, which makes the code cleaner.

    Output:

    CustTable

    Conclusion
    When creating a class, start with declaring the new method as protected. This will force you to use a static construct() method. This in turn will force you to think twice about the structure of your class, and will result in cleaner/better code with a more ‘AX-y’ feel.

    In part 2 (coming soon), I will demonstrate how this design principle helps you to maintain your code when extending functionality.

  • Microsoft TechDays 2010 Antwerp

    February 5, 2010 at 14:46  (no comments)

    On March 31 and April 1, I will be attending Microsoft TechDays 2010 conference in Antwerp, Belgium. Me and my colleagues will be wearing a T-shirt that says RealDolmen (no doubt followed by a catchy slogan the PR people will come up with).

    With over 80 sessions from international speakers to choose from, it will be difficult to pick the most interesting ones.

    See you at TechDays.

    Link: Microsoft TechDays 2010

  • Str2int and IsInteger

    February 4, 2010 at 12:16  (no comments)

    Here’s a little ‘be-aware’ I’d like to share.

    The function str2int() that converts a string to an integer will return ‘0′ if the input string is not an integer, so it is necessary to check if the string is an integer before casting it.

    The function that does this is not IsNumeric() like in SQL or VB, but IsInteger().
    Alternatively, you can also use str2IntOk(). Both are found in the global class.

    I’ve seen people searching for this method (including me), so I just thought I’d share.

    Here’s some sample code:

    static void klforStr2intAndIsIntegerTest(Args _args)
    {
        str input_notint    = "abc123";
        str input_int       = "123";
       
        int ret;
        ;
       
        // be aware, str2int will convert 'non integers' to '0'
        // without warning
        info(strfmt("%1", str2int(input_notint)));
        info(strfmt("%1", str2int(input_int)));
       
        // you can check if a string is an integer with
        // the isInteger() function from the global class
        // or you the str2IntOk() function
        info(strfmt("%1", isInteger(input_notint)));
        info(strfmt("%1", isInteger(input_int)));
       
        // check if integer
        if(isInteger(input_notint))
        {
            // cast to integer
            ret = str2int(input_notint);
        }
        else
        {
            throw error(strfmt("'%1' is not an integer", input_notint));
        }
    }
  • Delete an AX company on SQL

    February 3, 2010 at 21:03  (no comments)

    This week, we were shrinking a database of a development environment by deleting some companies.
    Here a nice little SQL statement that uses the sp_MSforeachtable stored procedure to delete all records of a specific company (CEU in this case) from all tables.

    exec sp_MSforeachtable 'delete from ? where ?.DataAreaID = "CEU"'

    Certainly fast(er than AX) and gets the job done.
    Use at your own risk ;-)

    Update:
    You’ll want do do some cleaning up to:
    delete the company id from the DataArea table and from the CompanyDomainList table

    DELETE FROM DataArea WHERE DataArea.ID = 'CEU'
    DELETE FROM CompanyDomainList WHERE CompanyDomainList.CompanyID = 'CEU'
  • Axapta 3 menu in AX 2009

    January 28, 2010 at 18:58  (1 comment)

    Are you one of those people who always minimize the content pane in AX 2009?
    Are you one of those people who don’t know what the breadcrumb on top of the AX screen is for?
    Do you already execute a job to disable the content pane on startup?

    Then you might feel totally nostalgic when you see the Axapta 3 menu appearing after you run the following job in AX 2009.

    static void Axapta30Nostalgia(Args _args)
    {
        Menu menu;
        #admin
        ;
       
        menu = new Menu(#MainMenu);
        menu.AOTrun();
    }
  • Microsoft Dynamics AX 2009 Development Cookbook

    January 12, 2010 at 19:11  (no comments)

    A new book written by Mindaugas Pocius about AX development was published last month: Microsoft Dynamics AX 2009 Development Cookbook.

    The book contains step-by-step instructions along with screenshots and aims at Dynamics AX developers of beginner and intermediate level.

    To give you an idea, here are the chapters:
    Chapter 1: Processing Data
    Chapter 2: Working with Forms
    Chapter 3: Working with Data in Forms
    Chapter 4: Building Lookups
    Chapter 5: Processing Business Tasks
    Chapter 6: Integration with Microsoft Ofice

    You can buy the book, eg on Amazon.com or at Packt Publishing.

    You can also download the sample code used in the book.

  • Lookup() override does not work

    January 9, 2010 at 11:03  (1 comment)

    I had this situation where overriding the lookup() method on a field on a form was not working.
    The problem was the AutoDatagroup property on the field group on my grid.
    When this property is set to Yes, the lookup override will not work.

    AutoDataGroup

    Also, when you change this property from ‘No’ to ‘Yes’ when methods have been added or overridden on the fields, the methods wil be cleared and you will loose your code.

    Update: see comment by Luegisdorf about overwriting this method in datasource in stead of the control.

  • Get folders and subfolders

    January 8, 2010 at 19:34  (no comments)

    Someone on the Microsoft AX newsgroups asked how to get a list of directories and subdirectories given a folder. Here a job that does that:

    static void KlForLoopFoldersSystemIO(Args _args)
    {
        int                 k;                  // counter for result loop
        container           dirs;               // container for result
        filePath            path = @"C:\temp";  // input path

        container getDirectories(str _dir, boolean _inclSubDirs = true)
        {
            container           dList;          // container to cast array into
            int                 i;              // counter for array loop
            System.Array        directories;    // array for result from .NET call
            #Define.Pattern("*")                // input pattern: * = all
            ;

            // assert interoppermissions for .NET interop
            new InteropPermission(InteropKind::ClrInterop).assert();

            // get directories using .NET interop
            if(_inclSubDirs)
            {
                // include subdirectories
                directories = System.IO.Directory::GetDirectories(_dir, #Pattern, System.IO.SearchOption::AllDirectories);
            }
            else
            {
                // only top directory
                directories = System.IO.Directory::GetDirectories(_dir, #Pattern, System.IO.SearchOption::TopDirectoryOnly);
            }

            // loog .NET array and put the values in a container for easier use in x++
            for( i=0;i<ClrInterop::getAnyTypeForObject(directories.get_Length()); i++ )
            {
                dList = conins(dList, conlen(dList)+1, ClrInterop::getAnyTypeForObject(directories.GetValue(i)));
            }

            // revert assertion to prevent multiple calls to the assert() method
            CodeAccessPermission::revertAssert();

            // return result container
            return dList;
        }
        ;

        // get directories
        dirs = getDirectories(path);

        // use optional parameter to disable sub directories
        // dirs = getDirectories(path, false);

        // print the result
        for(k=1;k<= conlen(dirs); k++)
        {
            // print the result to screen
            info(conpeek(dirs, k));
        }

        // we're done
        info("done");
    }
  • Check what application and database you are connected to

    January 4, 2010 at 19:27  (no comments)

    If you want a quick way to check to what database and application folder you are connected, you can use the ‘Upgrade checklist’ form:

    Administration – Setup – System – Checklists – Upgrade checklist.

    It shows you:
    - Database server
    - Database name
    - Application folder
    - Layers in the application

    Upgrade Checklist

    Upgrade Checklist

  • Launching Dynamics AX using Launchy

    December 29, 2009 at 13:18  (1 comment)

    There are a few tools I use daily that I really couldn’t live without. One of them is Launchy, by Josh Karlin (launchy.net).

    From the website:

    Launchy is a free windows and linux utility designed to help you forget about your start menu, the icons on your desktop, and even your file manager.

    And it really does just that. You won’t be using the Start menu anymore once you’ve installed this tool.

    You can download it here.

    Once you’ve installed it, you will see… nothing, untill you hold Alt and tap Space.
    Then you see something like this:

    Once you start typing, say “Dynami…”, Launchy searches for programs that match the string you are typing. Tap Enter to launch the program.

    You can use Launchy to launch specific AX configurations by creating a folder that contains axc files.

    Go to the AX Client Configuration Tool, create your configurations and export them using Manage – Safe configuration file to store them in a folder.

    You can setup Launchy to monitor this folder by holding Alt, tapping Space, right clicking on the Launchy window and clicking Options. On the tab Catalog, you should see something like the screenshot below. As you can see, I have already added the folder and the extension axc to the list.

    Launchy options screen

    Launchy options screen

    Now you only need to click the Rescan Catalog button, and you’re set to go.

    The end result should be something like this:

    You should be able to launch right into any AX application with minimal effort now.
    And of course, you can use Launchy to launch any other program as well.

    Links:
    Launchy website: launchy.net
    Inspiration for this post: SmartStart 3000 Central

  • New AX blog: ax@luegisdorf

    December 28, 2009 at 10:37  (no comments)

    There is a new AX blog in the blogosphere by Patrick Kränzlin, nicknamed Luegisdorf. Patrick is very active on the Dynamics AX newsgroups, and is also the author of SmartStart 3000 Central, a tool for managing and launching Dynamics AX configurations and applications.

    Be sure to check out his website, and his first post about reflection:
    How to ignore Private, Protected and Abstract modifiers.

  • Next Page »

     

Wordpress // Photon theme // Copyright © Klaas Deforche