Options

Getting error from Navision

LioLio Member Posts: 10
Hello.

I have some problem.
I connecting with Navision using sockets and I run some codeunit, which insert some data. If this codeunit cause an error i want to catch this error im my application. How I can get this error in nav?

Is there some function like GetLastError or something like this?

This error can't be shown in navision. How i can do this ?

I know how send it to/from navision.

Thanks

Comments

  • Options
    kinekine Member Posts: 12,562
  • Options
    LioLio Member Posts: 10
    Thanks.

    This is shame that in product like Navision there isn't a possibility to catch an error... :cry:
  • Options
    janpieterjanpieter Member Posts: 298
    Indeed it is ... :cry:
    In a world without Borders or Fences, who needs Windows and Gates?
  • Options
    DenSterDenSter Member Posts: 8,304
    Well there is a kind of a workaround for this, but you have to experiment a little with it. A codeunit has a return value that you can evaluate. If there is an error inside the codeunit, it will return FALSE, if everything is alright, it returns TRUE.

    So if you do this:
    IF NOT MyCodeunit.RUN THEN
      MESSAGE('I found an error!!');
    
    Your code will execute without aborting anything, even though MyCodeunit raises an error. The trick becomes how you want to catch the actual error. I've done something like this:

    In one codeunit (called MyCodeunit):
    MyText := 'Error during posting date validation';
    MySalesHeader.VALIDATE("Posting Date",'error'); //this will raise an error, since 'error' is not a date
    
    You also need a function to get the value of MyText:
    GetErrorText(VAR parText : Text[30])
    parText := MyText;
    

    Then you can call this codeunit from another codeunit inside an IF statement:
    IF NOT MyCodeunit.RUN THEN BEGIN
      MyCodeunit.GetErrorText(locTextVariable);
      MESSAGE(locTextVariable);
    END;
    
    And this will run fine without errors, even if MyCodeunit errors out.

    You can get pretty fancy with this, just play around with it. The real pity is that if a record variable causes an error, Navision destroys it, so you can't catch the value straight from the record variable, you need to anticipate the error. Let me know if you need more help on this.
  • Options
    LioLio Member Posts: 10
    I know this way but...

    I insert into navision Sales Headers and Sales Line from other application and I can't evaluate every field! There is to much possible errors.

    There should be a function GetLastError. Micro$oft probably intentionally don't implemented it :)

    See ya.
  • Options
    DenSterDenSter Member Posts: 8,304
    There should, but there isn't :whistle:

    Remember that Microsoft did not create this product, Navision did. When they did, they put the emphasis on the functionality (creating a great ERP system) instead of cool development features. Of course we can debate whether error catching is a cool feature or a necessity, but the quality of the IDE was not the number 1 priority.
  • Options
    janpieterjanpieter Member Posts: 298
    I think they just want to disencourage programmers to make their own programs that can call C/ALL coding form external applications so they can sell more NAS licenses ... :evil:
    In a world without Borders or Fences, who needs Windows and Gates?
  • Options
    ara3nara3n Member Posts: 9,255
    1 NAS license comes free with 3.70. So it's not selling NAS licenses that they didn't create getlasterror functionality.
    Ahmed Rashed Amini
    Independent Consultant/Developer


    blog: https://dynamicsuser.net/nav/b/ara3n
  • Options
    pdjpdj Member Posts: 643
    The userportal uses the NAS and is able to show a web-user the error that happended in Navision. I don't know how it is made, but then there must be a way. One method could be reading the last event the the eventlog from the NAS...
    Regards
    Peter
  • Options
    jreynoldsjreynolds Member Posts: 175
    Navision comes with several timer DLL's: CGTimer, CPTimer, and NTimer. If you declare an automation variable using NTimer and set the WithEvent property to TRUE then two triggers are created: Timer and TimerError. The Timer trigger fires with a frequency established through several properties (Interval and Enabled) and the TimerError fires when ever an error occurs during the running of the Timer trigger. The good part is that TimerError is passed a 1024 character string containing the text of the error message that would be displayed in a GUI environment. I have used this with NAS to automate various processes (such as posting) and have been able to trap specific error messages and log them to a table that the users can examine.
  • Options
    LioLio Member Posts: 10
    jreynolds wrote:
    Navision comes with several timer DLL's: CGTimer, CPTimer, and NTimer. If you declare an automation variable using NTimer and set the WithEvent property to TRUE then two triggers are created: Timer and TimerError. The Timer trigger fires with a frequency established through several properties (Interval and Enabled) and the TimerError fires when ever an error occurs during the running of the Timer trigger. The good part is that TimerError is passed a 1024 character string containing the text of the error message that would be displayed in a GUI environment. I have used this with NAS to automate various processes (such as posting) and have been able to trap specific error messages and log them to a table that the users can examine.

    Yeah!! This is great, but it cause another problem ;)
    I can catch error message in TimerError trigger, but this error is first display in Navision. I know, I can use:

    IF Table.Insert THEN...

    but in this case TimerError doesn't catch this message!

    What can I do ?
    I want catch message only in TimeError and don't show it in Navision...
  • Options
    jreynoldsjreynolds Member Posts: 175
    Lio wrote:
    [What can I do ?
    I want catch message only in TimeError and don't show it in Navision...

    I have only used this with NAS where there is no GUI and so this is not an issue. I don't know if there is a way to suppress the error message in Navision, but I would guess that there is not.
  • Options
    janpieterjanpieter Member Posts: 298
    You could, you would have to build a VB or C++ Application. I have seen in Spy++ that comes with .Net that you can just search for the message window and read text from the following message types:

    - error
    - message
    - runmodal
    - confirm

    too bad; this does not work for a dialog screen.

    Then you can automate a button click to remove the message.

    Hope i will have some time to work on this, it shouldn't be that difficult if youre familiar with API programming.
    In a world without Borders or Fences, who needs Windows and Gates?
  • Options
    pduckpduck Member Posts: 147
    i realized this for c/front with delphi ... if an error box comes up the programm reads its label and then sends a close-event to the message box ... if somebody is interested i can send him the code so you mustn't fight with the windows handles like i did :)
  • Options
    janpieterjanpieter Member Posts: 298
    Yeah, i think i'm interested in that. Saves me some time ... If you and your company doesn't mind sharing it \:D/
    In a world without Borders or Fences, who needs Windows and Gates?
  • Options
    pduckpduck Member Posts: 147
    That's it ...

    EnumWinProc runs through all Window-Handles and will be fired by a Timer-Component every 10 seconds.

    First you must get your own Process ID ... because C/Front is embedded as an OCX in my Application the C/Front message has the same PID as my Application.

    The WindowClassName of Windows created by Navision is always #32770, the hell knows why :)

    The Window Text of the C/Front Messages is always an empty String, so after checking the PID, the WindowClass and the Window Text i am sure that the current handle is the C/Front Message Window Handle.

    Then I try to get the handle of the Text Control inside the Message Box. I tested it with the Program WinspectorSpy and the Label ID was always $FFFF.

    At least you must send a Get-Message to the Window to get the Label's text. After that I send a Close-Event to close the Message Window and kill the line breaks in the Message Text.
    function EnumWinProc(Wnd: HWnd): boolean; stdcall;
    var myProcessID, ProcessID       : longint;
        LabelHandle : HWnd;
        TXTbuffer : array[0..255] of Char;
    begin
      Result := TRUE;
      GetWindowThreadProcessID(Application.Handle,@myProcessID);
      GetWindowThreadProcessID(wnd,@ProcessID);
      if ProcessID = myProcessID then begin
        GetClassName(Wnd, TXTbuffer, 255);
        if TXTbuffer = '#32770' then begin
          GetWindowText(Wnd, TXTbuffer, 255);
          if TXTbuffer = '' then begin
            LabelHandle := GetDlgItem(Wnd, $FFFF);
            SendMessage(LabelHandle, WM_GETTEXT, sizeof(TXTbuffer), Integer(@TXTbuffer));
            if CloseErrors then
              SendMessage(Wnd, WM_SYSCOMMAND, SC_CLOSE, 0);
            LastErrorDialog := StringReplace(String(TXTBuffer),#10,'',[rfReplaceAll, rfIgnoreCase]);
            LastErrorDialog := StringReplace(String(LastErrorDialog),#13,'',[rfReplaceAll, rfIgnoreCase]);
          end;
        end;
      end;
    end;
    
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
    EnumWindows(@EnumWinProc, 0);
    end;
  • Options
    janpieterjanpieter Member Posts: 298
    hmmm, interesting. Thanks pduck.

    I will try to use this system with automation and not C/Front, but i think the principles will be the same.

    Maybe then we could create a C/AL error procedure which fires instead of a message popping up.

    I used Spy++ to look up these parameters, but there is no way to distinguish a message from an error is there?

    anyway many thanks O:)
    In a world without Borders or Fences, who needs Windows and Gates?
  • Options
    kinekine Member Posts: 12,562
    What about bitmap ID or something??? (each dialog have another icon...)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • Options
    LioLio Member Posts: 10
    Thanks to all !

    I used jreynolds way. It's great and it's work.

    I can catch all errors and show it in my application. I must change some chars to my encoding but it is easy ;)

    Thanks again.
  • Options
    ldreamslldreamsl Member Posts: 33
    jreynolds wrote:
    Navision comes with several timer DLL's: CGTimer, CPTimer, and NTimer. If you declare an automation variable using NTimer and set the WithEvent property to TRUE then two triggers are created: Timer and TimerError. The Timer trigger fires with a frequency established through several properties (Interval and Enabled) and the TimerError fires when ever an error occurs during the running of the Timer trigger. The good part is that TimerError is passed a 1024 character string containing the text of the error message that would be displayed in a GUI environment. I have used this with NAS to automate various processes (such as posting) and have been able to trap specific error messages and log them to a table that the users can examine.

    I have try this procedure, but the Errore message PopUp, and the Trigger TimerError don't show the message.

    Why???
    God does not play dice with the universe. [Albert Einstein]
  • Options
    kinekine Member Posts: 12,562
    The error popup is problem if you are using Navision Timer in Navision client. If you use it in Navision Application Server, this is no problem because there are no popups... :-) And the OnError is running ok on client too, but you can not use the statement "if codeunit.run then..." - in this case, no OnError is called...
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • Options
    nasonaso Member Posts: 11
    For catching errors when running NAS see the documentation for the Communication Component wich is also a dll that comes standard with the Navision product CD
  • Options
    ldreamslldreamsl Member Posts: 33
    I do not use NAS, this is the problem, and wanted to have an instrument that it captured the errors, so as "OnError Resume Next" of the "Visual Basic".

    With the procedure of "pduck", I succeed to close the window of PopUP, but the Crach of the Application (Report,CodeUnit,...,..) already has happened.

    Do Not exist the way to capture the errors, and manage all from program and to manage all from program.

    Visual Basic Version of "pduck" Procedute


    Public Function EnumWindowProc(ByVal hwnd As Long, ByVal lParam As Long) As Long

    --Dim nSize As Long
    --Dim sTitle As String
    --Dim sClass As String
    --Dim sIDType As String
    --Dim TextBuff As String

    --If GetParent(hwnd) <> 0& And IsWindowVisible(hwnd) Then
    ----sTitle = GetWindowIdentification(hwnd, sIDType, sClass)
    ----If sClass = "#32770" Then

    GetWindowText hwnd, TextBuff, 255
    If TextBuff = "" Then
    SendMessage hwnd, WM_SYSCOMMAND, SC_CLOSE, NILL
    End If
    ----End If
    --End If
    --EnumWindowProc = True
    End Function
    God does not play dice with the universe. [Albert Einstein]
  • Options
    kinekine Member Posts: 12,562
    If you mean to be able to catch error and continue the process to catch all errors, it is not possible, because error is situation, when application do not know what to do... :-) how can you continue for example, if you have variable.get to some value which does not exists and you assume that it exists (because you have no if around the .GET)? 8)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • Options
    janpieterjanpieter Member Posts: 298
    I couldn't think of any way to build in an

    "on error resume next"

    Into C/AL. Seems impossible to me. I don't think you want this kind of behavior in a database program.

    The error sink however is possible if you extend your code and add an event and rais the event when the error is catched.
    In a world without Borders or Fences, who needs Windows and Gates?
Sign In or Register to comment.