« »

search

Art Of Creation – Dynamics AX Blog

 The everyday life of a Dynamics AX developer

  • Change security permissions for admin group

    April 23, 2009 at 22:51  (1 comment)

    In Dynamics AX, it is not possible to change the user group permissions for admin group. This is because users in this group should always have full control over the Dynamics AX setup.

    But sometime, you’ll have to change it, whatever you reason may be. One reason why you might need to change these, is because the user group permissions setup has been messed up by adding one or more new security keys, or by importing them from an xpo file. The security keys will be set to ‘No access’, and because you can’t change these for the admin group, this poses a problem.

    This can easily be solved by changing the method isAdmin() on the form SysUserGroupSecurity to return false.

    #admin
    boolean isAdmin()
    {
       /*if (userGroupInfo.Id == #AdminUserGroup &&
          (domainInfo.Id    == #AdminDomain || !useDomains))
       {
           return true;
       }*/

       return false;
    }

    Alternatively, if you don’t want to change your code, you can put a breakpoint on the ‘return true’ statement, and then drag/drop the pointer to return false.

  • AOS crashed when importing XPO

    April 22, 2009 at 23:26  (1 comment)

    A colleague came up to me today with a problem. She was trying to import an xpo file, and when she ticked the check box ‘Show details’ in order to compare the objects in the xpo file, the Dynamics AX client crashed. No message was shown, the application just quit. It was also impossible to reconnect to the Application Object Server because the AOS had crashed as well. When you restarted the AOS, you could easily reproduce this scenario by repeating the above steps.

    Sometimes, the following message was logged in the event log on the client, basically informing you that the AX client had crashed:

    Faulting application ax32.exe, version 5.0.1000.52, stamp 490c41fb, faulting module unknown, version 0.0.0.0, stamp 00000000, debug? 0, fault address 0x0bbf0b3c.

    In the event log on the server an other message was logged, but not every time the AOS crashed:

    Object Server 16: RPC error: Client provided an invalid session ID 3

    From what I understand, this message is logged when a client sends an RPC request to a server that has ended the session for this client, which would be the case if the AOS crashed.

    Once again, the event log is pretty useless. The real problem lies in the application files, more specifically the Microsoft Dynamics AX Label Index files. These are the files that have the extension .ali. For some reason, one or more of these index files are corrupt, and this causes the import process to fail, and the AOS to crash. At the time, the AOS server was low on diskspace, and that could be the cause of the corrupt index files. Luckily, index files such as ali files can be deleted when the AOS is down, and will be rebuilt when the AOS is started.
    After all label index files were deleted, and the AOS restarted, the xpo could be imported, and the AOS didn’t crash anymore.

    So, when the AOS crashed when you are trying to import an xpo file, stopping the AOS, deleting the ali files from the application directory and restarting the AOS might be the solution.

  • Debugging trick number one: Info.Add()

    April 14, 2009 at 21:00  (1 comment)

    Now and then, someone comes up to you and says “Could you take a look? There’s an error on my screen”. Mostly, it’s an infolog. And most of the time, you can double click on the message, AX will open the code editor and place the cursor on the line where the message originated. Then, it is either very clear why the message is shown, or you can place a breakpoint to debug the problem.

    But sometimes, when you double click on the message, a help window will pop up in stead of the code editor. For example when an error is thrown by the kernel. This can make it difficult to find out where exactly the problem occurs.

    Luckily, for every messages that is added to the infolog, the code in the class Info, method Add() is executed. When you put a breakpoint in Info.Add(), the debugger will pop up when a message is added to the infolog, even if they originate in the kernel.

    In my opinion, this is the most handy “debugging trick” in AX.

  • WinAPI, RPC 1702 and FindFirstFileW

    April 8, 2009 at 23:39  (46 comments)

    A very common scenario when doing interfaces with other applications, is to have a directory where one application places files, and the other one picks those up and processes them.
    Let’s say some application want to interface with Dynamics AX, one way, from that application to AX. That application will drop files of a specific format, say *.txt, in a directory. You’ll want to have a batch job in AX that checks that directory every 5 minutes for those files. When your batch job finds those files, it will open them and do something with that data, then move them to an other directory, so you don’t process them twice.

    Now the first thing you’ll probably think of (well, I did…), is to use the class WinAPI. This class has some useful static methods for checking if folders or files exist, finding files with a filename of a certain format. Just the kind of thing we’re looking for. Your code might look like this:

    static void loopfilesWinApi(Args _args)
    {
        str fileName;
        int handle;
        str format = "*.txt";
        ;

        if(WinApi::folderExists("C:\\Temp\"))
        {
            [handle,fileName] = WinApi::findFirstFile("
    C:\\Temp\" + format);
            while(fileName)
            {
                //currentfileName = fileName;
                info(filename);
                filename = WinApi::findNextFile(handle);
            }
            WinApi::closeHandle(handle);
        }
    }

    That’s perfect. It checks a directory, in this cas C:\temp, for files with the extension txt… until you try to run this in batch. Your batch will have the status error, and there will be an entry in the event log saying:

    RPC error: RPC exception 1702 occurred in session xxx

    That error message is very misleading, but Florian Dittgen has a nice blog entry about this, that explains why this goes wrong: WinAPI methods a static and run on client. In batch, you can not use these client methods.
    But hey! There is a class called WinAPIServer, surely this runs on server, right? Correct, but a lot of the methods available in WinAPI are missing in WinAPIServer. You can however extend the WinAPI server class by copying methods from the WinAPI class and modifying them a bit. Let’s try that.

    This is what the WinAPI::FindFirstFile() method looks like:

    client static container findFirstFile(str filename)
    {
        Binary data = new Binary(592); // size of WIN32_FIND_DATA when sizeof(TCHAR)==2
        DLL _winApiDLL = new DLL(#KernelDLL);
        DLLFunction _findFirstFile = new DLLFunction(_winApiDLL, 'FindFirstFileW');

        _findFirstFile.returns(ExtTypes::DWord);

        _findFirstFile.arg(ExtTypes::WString,ExtTypes::Pointer);

        return [_findFirstFile.call(filename, data),data.wString(#offset44)];
    }

    As you can see, this method uses the function FindFirstFileW from the Kernel32 dll located in the folder C:\WINDOWS\system32. Let’s copy this method to WinAPIServer and modify it to look like this:

    server static container findFirstFile(str filename)
    {
        #define.KernelDLL('KERNEL32')
        #define.offset44(44)

        InteropPermission interopPerm;
        Binary data;
        DLL _winApiDLL;
        DLLFunction _findFirstFile;
        ;

        interopPerm = new InteropPermission(InteropKind::DllInterop);
        interopPerm.assert();

        data = new Binary(592); // size of WIN32_FIND_DATA when sizeof(TCHAR)==2
        _winApiDLL = new DLL(#KernelDLL);
        _findFirstFile = new DLLFunction(_winApiDLL, 'FindFirstFileW');

        _findFirstFile.returns(ExtTypes::DWord);

        _findFirstFile.arg(ExtTypes::WString,ExtTypes::Pointer);

        return [_findFirstFile.call(filename, data),data.wString(#offset44)];
    }

    Three things have changed here:

    1. “Client” has been change to “Server” so it can run on server;
    2. The code has been changed to use the InteropPermission class; this is required because the code runs on server;
    3. Initialization of the variables is moved to after assertion of the InteropPermission.

    When you test this in batch (running on server), this will work, and you can do this for all WinAPI methods in the examples above… until you try this on a x64 architecture. You’ll receive a message saying that an error occurred when calling the FindFirstFileW function in the Kernel32 DLL (the exact message slipped my mind).
    The problem is described on the Axapta Programming Newsgroup. You can code your way around this problem, but I think the message is clear: don’t use WinAPI.

    Instead, use the .NET Framework System.IO namespace (watch out for lowercase/uppercase here), in our case in specific, System.IO.File and System.IO.Directory.
    I get this nice code example from Greg Pierce’s blog (modified it a bit):

    static void loopfilesSystemIO(Args _args)
    {
        // loop all files that fit the required format
        str fileName;
        InteropPermission interopPerm;

        System.Array files;
        int i, j;
        container fList;
        ;

        interopPerm = new InteropPermission(InteropKind::ClrInterop);
        interopPerm.assert();

        files = System.IO.Directory::GetFiles(@"C:\temp", "*.txt");
        for( i=0; i<ClrInterop::getAnyTypeForObject(files.get_Length()); i++ )
        {
            fList = conins(fList, conlen(fList)+1, ClrInterop::getAnyTypeForObject(files.GetValue(i)));
        }

        for(j=1;j&lt;= conlen(fList); j++)
        {
            fileName = conpeek(fList, j);
            info(fileName);
        }
    }

    This will run on client and on server without any problems. To have clean code, you could create your own class, just like WinAPI, but using the System.IO namespace. That way, you can reuse this code and save time.

    Conclusion: abandon WinAPI, and use System.IO instead.

  • Wrong argument types in variable assignment – Part 2

    April 7, 2009 at 22:04  (4 comments)

    In the article Wrong argument types in variable assignment, I wrote about how you can solve this error by using compile forward, but doing that won’t always fix the problem, e.g. when using AnyType.

    Anytype is great. It’s a primitive data type can use as a placeholder for any other data type, and comes in handy on many occasions. But don’t use it as a silver bullet, it might backfire.

    Consider the next example.

    static void AnyType_Test_1(Args _args)
    {
        utcDateTime dateTime;
        AnyType     value;
        ;

        value = datetimeutil::utcNow();
        dateTime = value;

        info(strFmt("%1", dateTime));
    }

    We are assigning the current date and time to the AnyType variable, than back to a utcDateTime, and sending it to te screen. This neatly produces following output:

    7/04/2009 19:27:15

    Now consider the following example.

    static void AnyType_Test_2(Args _args)
    {
        utcDateTime dateTime;
        AnyType     value;
        ;

        value = "Here comes today's date";

        value = datetimeutil::utcNow();
        dateTime = value;

        info(strFmt("%1", dateTime));
    }

    This produces the following output:

     

    Yes, that’s a blank line. Weird, isn’t it, or is it? MSDN has the answer:

    The anytype data types can be automatically converted to dates, enums, integers, reals, strings, guids, int64s, extended data types (records), classes, and containers by assigning a value to the type. […] However, after you have converted the anytype data type, you cannot then change it to another data type.

    In the second example it failed to convert the utcDateTime because we assigned a string to the AnyType variable. This is fault very subtle, because no error or warning is shown when compiling such code, and can easily be overlooked.

    Not only can (incorrect) use of AnyType cause faulty output, it can also trigger stack traces.
    The following example is inspired by Greg.

    static void AnyType_Test_3(Args _args)
    {
        AnyType     value;
        ;

        value = NoYes::Yes;
        value = datetimeutil::utcNow();
    }

    This will show the following error message and stack trace:

    Error executing code: Wrong argument types in variable assignment.

    It gets even nastier in the next example:

    static void AnyType_Test_4(Args _args)
    {
        utcDateTime dt;
        AnyType value = "string";
        ;

        value = 3;
        dt = value;
    }

    This will show you a message box saying:

    Internal error number 25 in script.

    Note: if you are looking to solve the error above (you can encounter it when trying to send an email from code), you can find the links to the hotfixes for ax 2009 here.

    And also the error and stack trace we saw before:

    Error executing code: Wrong argument types in variable assignment.

    Conclusion: Use AnyType with caution, preferably as argument or return type, and remember that the type can not be change once it has been assigned a value.

  • Wrong argument types in variable assignment

    April 4, 2009 at 12:46  (9 comments)

    While doing some modifications to the class SalesFormLetter, I ran into something very strange. I did two simple things:

    Adding an object member variable to the class declaration.

    JournalId journalId;

    Creating a parameter method for this variable.

    Public JournalId parmJournalId(JournalId _journalId = journalId)
    {
        ;
        journalId = _journalId;

        return journalId;
    }

    On compilation, this didn’t show any errors, but when the code was executed, the debugger popped up, and the following error was thrown upon assignment:

    Wrong argument types in variable assignment

    I recompiled it, ran it again, same error. A colleague took a look at my code and couldn’t find anything wrong with it either, and suggested to stop the AOS and rebuild the .aoi file, but that didn’t do it either.
    When I debugged I noticed the the object member journalId didn’t sow up in the list of members in the debugger. A moment after that my colleague asked if I had tried compile forward yet, and I immediately knew that would solve the problem. It did.

    MSDN states on several occasions:

    It is important to compile forward from the parent class when adding a variable to a classDeclaration of a class that is inherited by other classes.

    This was the case with the SalesFormLetter modifications I did.

    So always remember to use compile forward when modifying super classes, and it will save you a lot of trouble.

  • Writing a quine

    April 1, 2009 at 19:53  (1 comment)

    While reading through Wikipedia, I came across something called a quine, and here is its definition:

    In computing, a quine is a computer program which produces a copy of its own source code as its only output.

    I was inspired by this and decided to make a quine in X++, the programing language of Microsoft Dynamics AX.

    static void quine(Args _args)
    {
        #AOT;
        print TreeNode::findNode(strfmt(#JobPath,"quine")).AOTgetSource();
        pause;
    }

    It’s a job that finds it’s own tree node in the AOT, gets the source of that node and prints it. I originally wrote it all on one line, because I like the look of that better, but I didn’t do that here for readability.

    Now I’m not entirely sure if this qualifies as a quine, because a quine can have no input, and using the method AOTgetSource could be seen as cheating. But anyway, it reproduces itself,  it’s short, and it made me happy.

  • « Previous Page

     

Best value on tickets: wickedthemusicaltickets.top 100% guaranteed tickets: luke bryan concert tickets Discount Broadway Tickets - hamiltonmusicaltickets.top View dates for upcoming Billy Joel concert tour - http://billyjoeltourtickets.top Discount Tickets for Broadway, find cheap Hamilton Broadway Tickets Tickets On Sale For All Dates - Eric Church Tour 2017 Major League Baseball Tickets. Get your SF Giants Tickets and save Search all sellers and save on cheap Indians Tickets

Wordpress // Photon theme // Copyright © Klaas Deforche