Code Gurus only - Single page instance

ondercinondercin Member Posts: 15
So I really need to prevent users from opening one of our custom NAV2016 pages more than once.
The page is in direct communications with a PLC controller and if it's opened (by accident) more than once causes issues.
If you open (for example) the General Journal multiple times it looks like this in the Task Manager:
fpjrrbe9mn2o.jpg

Using the DotNet variables I am able to detect the Microsoft.Dynamics.Nav.Client, but I am unable to see each of the 7 processes to detect that the General Journal - CORR-Correction is opened 6 times.

Code:
Process := Process.GetCurrentProcess;
MySession := Process.SessionId;

MyProcessList := process.GetProcessesByName('Microsoft.Dynamics.Nav.Client');

lfile.TEXTMODE := TRUE;
lFile.WRITEMODE := TRUE;
lFile.CREATE('TestOutput.txt');

FOR I:=0 TO (MyProcessList.Length()-1) DO
BEGIN
Process := MyProcessList.GetValue(I);
IF MySession = Process.SessionId THEN
lFile.write('Process ID: ' + FORMAT(Process.Id) + ' MainWindowTitle: ' + Process.MainWindowTitle + ' Process: ' + Process.ToString);
END;
lFile.CLOSE;



Output File:
Process ID: 6764 MainWindowTitle: Edit - General Journal - CORR-Correction Process: System.Diagnostics.Process (Microsoft.Dynamics.Nav.Client)


Now it appears as though it has returned the correct result, but all it has done is returned the first page.. If I opened the Item Card and ran my routine I'd see the Item Card and not the other 7 pages running the General Journal.

Anyone have any luck returning the grouped processes?

Thanks in advance,

John

Answers

  • xStepaxStepa Member Posts: 106
    Why do you need your code on a page? Maybe a single instance codeunit with functions called from your Page would be better.
    Sorry if I understand it wrong way ...
    Regards
    xStepa
  • ondercinondercin Member Posts: 15
    No worries not understanding, the more info the better :)

    This custom page is what we use to record Production.
    The page reads the PLC controllers to determine what speed the machine is processing at. If the machine goes down for a length of time the page shows the downtime duration and the user needs to enter a reason for this downtime.
    So at the end of the users shift, NAV knows what Production Order was used, how much Finished Goods were made, how much raw material was consumed, Shift Length, Setup Duration, Downtime Duration, and the reasons for the Downtime/Setup.

    So you can see having two of these pages open causes me grief.
  • SilverXSilverX Member Posts: 134
    I like to emphasize xStepas answer. Is it possible for you to establish the communication in a single instance Codeunit and let multiple pages show and enter data using this single connection?

    Or you can use a single instance Codeunit to set a marker for the session if the page opens and remove it if it closes. Check the value before opening the page and close it when it is already open.

    While I still like the first option, you can also save the open state in a table... Your choice.
    Cheers
    Carsten


    ==> How To Ask Questions The Smart Way

    This post is my own opinion and does not necessarily reflect the opinion or view of my employer.
  • ondercinondercin Member Posts: 15
    So yes in theory that will work unless they have two sessions of the NAV Client opened. That is why I was looking to get the Tasks currently running for a specific user.
    ** In the short-term I can use a single instance codeunit and that will at least limit half the duplicate page opens.
  • foo_barfoo_bar Member Posts: 91
    edited 2017-08-24
    edit: nvm : ) posted to fast
  • xStepaxStepa Member Posts: 106
    edited 2017-08-24
    Still not sure that I've got it ;)
    But you can try to use some kind of semaphore - create a table and then try something like this:
    Semaphore.LOCKATBLE;
    Semaphore.GET(USERID, 'PLC_GUARD');
    // or
    Semaphore.GET(GetComputerName(), 'PLC_GUARD');
    // or
    Semaphore.GET('PLC_GUARD'); // if the communication should be 1:1 sided
    

    The second session will throw an error (after some time), which you can handle by TRY function (I hope) ...
    Regards
    xStepa
  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    No need to look into current process list, even if you manage to get the detailed information about NAV process and its threads it won't help anyway with many sessions opened from different machines.

    xStepa nailed the idea pretty much, not sure if GET alone without MODIFY will lock the record.

    What you need is a table where you will insert a single record in OnPageOpen and delete it in OnPageClose.

    Assuming that your page is based on PageSemaphore table having just one field:

    in OnOpenPage
    INIT
    INSERT;
    
    in OnClosePage
    DELETE
    
    That's about it. the first user will open the page, insert a blank record, any subsequent attempt of opening the page will fail on INSERTing the same record.

    A bit more code would be needed to handle cases when client crashes while page is open and the record does not get deleted - that can be handled by storing in the semaphore table current session unique ID (but not in the primary key), checking it in OnOpenPage in Active Sessions table and if the session still exists throwing an error, if not deleting the record and insert new one.

    in OnOpenPage
    IF GET THEN BEGIN
      AciveSessions.SETRANGE("Session Unique ID", "Page Opened In Session");
      IF AciveSessions.FINDFIRST THEN
        ERROR('Page already opened from %1...', ActiveSessions."Client Computer Name");
      DELETE;
    END
       
    INIT
    "Page Opened In Session" := GetCurrSessionUniqueID();//get it from Active Session table
    INSERT;
    
    Slawek
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
Sign In or Register to comment.