Code Gurus only - Single page instance
ondercin
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:

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
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:

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
0
Answers
-
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
xStepa0 -
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.0 -
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.0 -
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.0 -
edit: nvm : ) posted to fast0
-
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
xStepa0 -
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 OnOpenPageINIT INSERT;
in OnClosePageDELETE
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 OnOpenPageIF 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;SlawekSlawek Guzek
Dynamics NAV, MS SQL Server, Wherescape RED;
PRINCE2 Practitioner - License GR657010572SG
GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-030
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.6K Microsoft Dynamics NAV
- 18.7K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 322 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions

