For a long time our operators have been asking for multi-monitor support in our InTouch application, they want to be able to have alarms showing on one monitor and a substation on another for example. InTouch does support multiple monitors, but it makes you do a lot of work to get things the way you want. In our case we wanted to have two independent monitors, each showing a different window in the application. Additionally we wanted to have a history of windows for each screen that you could scroll back through like a web browser, and for the application to work when scaled for monitors on different resolutions.
These are some of the things that you need to be aware of when developing a multi monitor application:
This is a rough guide as to how I went about achieving these goals.
You need to configure InTouch to use multiple monitors, you do this in the win.ini file, but here's the trick - there are two win.ini files! The one in C:\Users\<user>\AppData\Wonderware\win.ini is used by view and window maker, but the wwtechsp.dll library uses the system win.ini file, the location of which varies by operating system and other settings. The correct file to use is which ever one has been modified by the InTouch installer.
Append/add a configuration section such as the below to these files, using the appropriate figures for your monitors, NOT your application design resolution (although on the machine you develop the application, these will be the same).
[InTouch] MultiScreen=1 MultiScreenWidth=1920 MultiScreenHeight=1080
Create all the windows as if they were going to be on the first monitor, for our example we will use a nominal screen resolution of 1920*1080. Because of the small amount of room taken up by the menu bar at the top of the screen, the actual window size is 1920*1060. I like to obscure the application menu at runtime, so I create a popup window called TitleBlock1 that goes over the top, preventing users from accessing the menu unless they login first.
There are some window viewer options that makes things much easier when developing a multi-monitor application. The first one is "Hide Title Bar" which gets rid of the main window border (which shows up when using multiple monitors), if you don't tick this option you will need to add some logic to handle the different screen sizes between single and multiple monitors due to the additional window border. The second option is "Always Maximize" which blocks the taskbar at runtime, and prevents moving the application window around. Actually I don't recommend this one anymore, it can create issues on some systems.
For InTouch standalone, to get the multiscreen working properly the following setting needs to be enabled in the Intouch.ini
EnableScreenResolution=1
For some reason this option seems to be set for Managed Applications but not standalone applications.
When the application starts, it needs to work out how many monitors there are, and what to show on them. The first one is taken care of by the default window, but if there is a second (or more) monitor, you need to deal with this at startup. We also need to check if our monitors are using the design resolution, or if they are scaled. In our case we are only going to have two monitors to deal with, so we use this simple snippet:
{Detect if we are Multimonitor, and if so show the second home screen} SysMonitors = WWMultiMonitorNode(); SysMonitorHeight = WWPrimaryMonitorHeight(); SysMonitorWidth = WWPrimaryMonitorWidth(); SysNativeResolutionX = 1920; SysNativeResolutionY = 1080; IF SysMonitors == 2 THEN ShowTopLeftAt("Alarms", SysMonitorWidth, 0); Show("TitleBlock2"); ENDIF;
This QF replaces the Show Window animation, and the various Show functions. It shows a specified window on the monitor from which it was navigated to. Note you have to tailor this function to your potential monitor arrangements. In our case we will assume a maximum of two monitors, and that they will be side by side. In the event that we try to open a window that is already open on another monitor, we simply show a default window on the other monitor to prevent it being orphaned.
MMShow(WindowName AS Message)
DIM WinState AS INTEGER; DIM DefaultWindow AS MESSAGE; DefaultWindow = "Default"; WinState = WindowState(WindowName); IF WinState == 2 THEN RETURN 0; ENDIF; CALL MMAddWindowHistory(WindowName); IF SysMonitors ==2 THEN IF $ObjHor > SysMonitorWidth THEN ShowTopLeftAt(WindowName, SysMonitorWidth,0); IF WinState == 1 THEN ShowTopLeftAt(DefaultWindow, 0, 0); ENDIF; ELSE ShowTopLeftAt(WindowName, 0, 0); IF WinState == 1 THEN ShowTopLeftAt(DefaultWindow, SysMonitorWidth,0); ENDIF; ENDIF; ELSE Show WindowName; ENDIF;
To show a window, just use CALL MMShow("WindowName");
in an action script. Using the Show Window animation will not produce the desired results and should not be used anywhere in the application unless you want to show a window on a fixed monitor.
Another QF is required for popup windows:
MMPopupAt(WindowName AS Message, X As Real, Y AS Real)
DIM WinState AS INTEGER; DIM DefaultWindow AS MESSAGE; DefaultWindow = "Default"; WinState = WindowState(WindowName); IF WinState == 2 THEN RETURN 0; ENDIF; IF SysMonitorWidth <> SysNativeResolutionX THEN X = X / SysNativeResolutionX * SysMonitorWidth; Y = Y / SysNativeResolutionY * SysMonitorHeight; ENDIF; IF $ObjHor > SysMonitorWidth THEN ShowTopLeftAt(WindowName, SysMonitorWidth+X,Y); ELSE ShowTopLeftAt(WindowName, X, Y); ENDIF;
This simply takes the offset as if it were for the first monitor, and if the click originated from the second monitor it adds to the offset so that is shows relative to the second monitor.
There are several possibilities for handling page history. Once option is to use overlay windows, and just hide the front most window to go back to the previous one. I didn't like that idea due to the additional memory requirements of having many windows open at once, and the issue of windows being lost from the history if they were opened on another monitor. The option I went for was to store the names of the windows in message tags, this meant creating 20 tags (10 for each monitor) and quite a lot of scripting but I was quite satisfied with the result.
There are two scripts that handle the history, one to add a window to the history stack and another to navigate to a previous window.
MMAddWindowHistory(WindowName AS Message)
IF $ObjHor > SysMonitorWidth THEN IF WindowName == SysMonitor2Window1 THEN {Two windows in a row with the same name will be bad} RETURN 0; ENDIF; SysMonitor2Window10 = SysMonitor2Window9; SysMonitor2Window9 = SysMonitor2Window8; SysMonitor2Window8 = SysMonitor2Window7; SysMonitor2Window7 = SysMonitor2Window6; SysMonitor2Window6 = SysMonitor2Window5; SysMonitor2Window5 = SysMonitor2Window4; SysMonitor2Window4 = SysMonitor2Window3; SysMonitor2Window3 = SysMonitor2Window2; SysMonitor2Window2 = SysMonitor2Window1; SysMonitor2Window1 = WindowName; ELSE IF WindowName == SysMonitor1Window1 THEN {Two windows in a row with the same name will be bad} RETURN 0; ENDIF; SysMonitor1Window10 = SysMonitor1Window9; SysMonitor1Window9 = SysMonitor1Window8; SysMonitor1Window8 = SysMonitor1Window7; SysMonitor1Window7 = SysMonitor1Window6; SysMonitor1Window6 = SysMonitor1Window5; SysMonitor1Window5 = SysMonitor1Window4; SysMonitor1Window4 = SysMonitor1Window3; SysMonitor1Window3 = SysMonitor1Window2; SysMonitor1Window2 = SysMonitor1Window1; SysMonitor1Window1 = WindowName; ENDIF;
MMBackWindow
IF $ObjHor > SysMonitorWidth THEN {Monitor2} IF (SysMonitor2Window2 <> "") THEN SysMonitor2Window1 = SysMonitor2Window2; SysMonitor2Window2 = SysMonitor2Window3; SysMonitor2Window3 = SysMonitor2Window4; SysMonitor2Window4 = SysMonitor2Window5; SysMonitor2Window5 = SysMonitor2Window6; SysMonitor2Window6 = SysMonitor2Window7; SysMonitor2Window7 = SysMonitor2Window8; SysMonitor2Window8 = SysMonitor2Window9; SysMonitor2Window9 = SysMonitor2Window10; SysMonitor2Window10 = ""; CALL MMShow(SysMonitor2Window1); ENDIF; ELSE {Monitor1} IF (SysMonitor1Window2 <> "") THEN SysMonitor1Window1 = SysMonitor1Window2; SysMonitor1Window2 = SysMonitor1Window3; SysMonitor1Window3 = SysMonitor1Window4; SysMonitor1Window4 = SysMonitor1Window5; SysMonitor1Window5 = SysMonitor1Window6; SysMonitor1Window6 = SysMonitor1Window7; SysMonitor1Window7 = SysMonitor1Window8; SysMonitor1Window8 = SysMonitor1Window9; SysMonitor1Window9 = SysMonitor1Window10; SysMonitor1Window10 = ""; CALL MMShow(SysMonitor1Window1); ENDIF; ENDIF;
Multimonitor demo app
I have created a sample application (which has since been improved a bit from the functions above), you can download it here. Included is a standalone InTouch application and a managed app IDE package - exported using the 2017 Update 2 build. Also included are the required script function libraries (Cursor Function Library, WW Tech Support Library, and HCInTouch Utilities Library) - you will need to install them into your InTouch Program Files directory for this application to work correctly.
March 20th, 2017 at 12:35 am
Hi, Thanks for your article this is very good / useful information....
Multi-Monitor System - optimization of an existing project (1 monitor)
We have an existing client-server project on the IDE (Intouch-Managed application)
One server + two clients ...,
I would like to abandon the client-server architecture (in this project it is not needed, one operator sits behind two computers),
And go to one project / computer with two monitors, i.e. Connect to the existing server a second monitor (one video card with two outputs ... monitors like Extend ...) and save the existing functional
The question is how to do this with minimal changes to the existing project (which was designed for one monitor) ... ???
Ideally. One project that can work both on one monitor and two (in Extend mode) ...
I read tech.noty ... 307, 811, 968 ... about
ScaleForResolution = 0 and editing Win.ini ... this is understandable ... .and it works ...
But in order for me to realize this way, I need to rewrite the project ... to change
Coordinates of windows? If the main picture is 1280x1024 (with navigation buttons) ... and I want this picture to be displayed on two monitors at once ... do I need to make a copy of the picture and change the initial coordinates on the second one?
For example, on WinCC for this there is a special tool
OS Project Editor-> Monitor configuration .... A pair of clicks and the system is configured from the basic project ...
Honeywell has a special program SafeView ...
What is Intouch (or maybe some kind of third-party program) ???
March 20th, 2017 at 10:00 pm
Hi, firstly: the same window can only be open once, ie you cannot have the same window on two monitors at once. If you want this then you will need to create duplicate windows which might get a bit messy. The code and sample application the I have developed is aimed at the situation where there is one distinct window displayed on each screen at a time, plus a small popup window which covers up the title bar. In theory this title bar could be repurposed as a toolbar. Each window is developed as if it were deployed on the primary monitor, the additional quick functions will move the window position onto the other monitors as appropriate. I suggest you try out my demo application - I have a slightly later version available that contains a number of bug fixes - I will upload this some time in the next few days.
August 1st, 2017 at 9:16 am
Very helpful summary thanks
Does anyone know of any similar articles dealing with the implications of running the SAME Intouch Project on DIFFERENT PCs?
February 14th, 2019 at 1:08 am
Hi
I am working on Intouch app on two screen. Is is possible to show same window on both Screens ?
February 14th, 2019 at 9:35 pm
Unfortunately not - a window can only be shown once. If you try to show it again at new coordinates it will disappear from where it was. You could probably create a duplicate window and show that instead with some fancy logic, but that would mean every time you change the window you have to copy the changes to the duplicate.
October 10th, 2019 at 11:40 am
Hi Raggles, would it be possible to get your sample application. The link says its no longer available. Thanks.
October 10th, 2019 at 5:54 pm
Apologies for the broken link, should be fixed now.
November 1st, 2019 at 2:43 am
Hi Raggles,
Could you fix the link of the sample application again?
Thanks
November 1st, 2019 at 6:02 pm
The link in the main post is fine - I've removed all the other comments with dead links. cheers
November 5th, 2019 at 7:31 pm
Hi Raggles,
How do i install the script function libraries? Do I just copy them to my program file directory?
Thanks,
Felix
November 5th, 2019 at 8:21 pm
Yes that's right, same folder as view.exe
November 6th, 2019 at 8:52 am
The quick function MMaddWindowHIstory isn't defined, where can i get this from?
November 6th, 2019 at 10:01 am
Hi Raggles,
I found the MMaddWindowHistory QF, sorry for that.
I can't seem to get my application to work. When i open a window in the second screen, it opens on the primary screen. And when i try open the same window on the primary screen nothing happens. Would you be able to see my application by any chance? My set-up is the same as yours, two monitors next to each other exept the screen resolution is 1680x1050.
Unfortunately i can't open your sample application as im running a older version of intouch.
Thanks,
Felix
November 7th, 2019 at 8:50 am
Hi Raggles,
I figured out why it didn't work, the multiscreen wasn't properly enables in the win.ini file in C:\Windows\win.ini. I was wondering if the application is setup for 3 screens, would it work for 2 screens? or if it was setup for 2 screens, would it work for 1 screen.
Thanks,
Felix
November 7th, 2019 at 9:02 pm
Ok great, with this code one screen should always work regardless of the win.ini settings. For multiple screens I think you will need the correct settings in win.ini
November 15th, 2019 at 9:25 am
Trying this on an application in WW 2017 and every time I copy and your MMShow script, WW keeps saying "expecting right parentheses". What am I doing incorrectly?
November 18th, 2019 at 7:39 pm
Bit hard to say without seeing your system, maybe a script function library is missing? The easiest way is to import the example package.
November 19th, 2019 at 3:27 am
Good Morning Raggles. did you have to use a special video card to get Windows Viewer extend across both monitors?
November 19th, 2019 at 6:37 pm
Hi, I don't use any particular card, it has worked on all video cards that I have used so far
January 13th, 2020 at 2:49 pm
Hi
am I able to get t copy of your demo app??
the link seems to be missing. Also thank for the great instructions will save a lot of time.
January 13th, 2020 at 4:55 pm
Hi, the link is in the last paragraph, but here it is again https://mega.nz/#!WJcUjYKb!u95oAZHDyVbRCCxqApMFNyjZzK9tRNIxSNHiAwYL0EM Cheers
January 31st, 2020 at 6:00 am
Hi Raggles, I was trying to add the 3rd monitor using ur code. Unable to make it work. Could you please, help me with that. Thank You
.
January 31st, 2020 at 8:14 am
Hi, I'm afraid that I don't really have any time to spare at the moment - the complexity of adding a third screen will depend on what your screen layout is. If you are trying to merge this into an existing application then be aware that you need to change all your 'open window' actions to action scripts that call MMShow("window name here") which can be a big task. If it's a new application then I'd probably recommend using InTouch OMI instead as this handles screen layouts natively. If you decide you do want to use this, then I'd probably start by properly commenting all the code to make sure you understand what it does - once you do it should just be a matter of extending the existing logic. If you are stuck on what a particular bit of the code does then I can help there but I can't offer much more than that.
January 31st, 2020 at 5:08 pm
i'm working on the existing application, trying to edit the current script to add third monitor. already "open window" is with the action scripts "MMShow("window_name")" ... so trying to plug in one more IF statement to make the third screen.... resolutions will be 0, 1920 and 3840 right???
February 1st, 2020 at 12:11 pm
Yes that's correct, assuming you have three monitors side by side and the left monitor is the primary
May 19th, 2020 at 3:54 am
Hi Raggles,
I am working on creating a multimonitor Intouch application with one monitor at 1920X1080 resolution and other one at 1024X768 resolution. I referred to your article for doing the same.
First step I did is to enable Multiscreen and specify resolution in win.ini file. Next step I wrote application startup script per your article to identify 2 monitors and tested it. When I start Window Viewer with two monitors of resolution 1920X1080, script identifies number of monitors as 2. If I set one monitor at 1920X1080 and second one at 1024X768, script identifies number of monitors as only 1 instead of 2. Am I missing something in my steps? Do you have any recommendations on how to make this work? Thank you.
May 19th, 2020 at 9:00 pm
Sorry I have never attempted to use different screen sizes and I don't know if this is supported or not.
August 19th, 2020 at 7:55 pm
Hey, im working on multiple monitor application. I've got same parameters as you, two monitors with resolution 1920x1080. But i've got a problem with application startup script. I can't see 2 different screens at one time. Script is the same as yours:
SysMonitors = WWMultiMonitorNode();
SysMonitorHeight = WWPrimaryMonitorHeight();
SysMonitorWidth = WWPrimaryMonitorWidth();
SysNativeResolutionX = 1920;
SysNativeResolutionY = 1080;
IF SysMonitors == 2 THEN
ShowTopLeftAt("Wykresy", SysMonitorWidth, 0);
Show("Wykres_PID");
ENDIF;
Do you know what might be the reason? ( i did change win.ini twice as you mentioned )
Thank you
August 26th, 2020 at 9:07 pm
this snippet will only show a page on the second monitor, it assumes you have a home page set which will show on the first monitor. In this case the code is designed to work with monitor one on the left and monitor two on the right. You will need to make changes for other configurations. If you want this code to show a page on both monitors you could change it to:
SysMonitors = WWMultiMonitorNode();
SysMonitorHeight = WWPrimaryMonitorHeight();
SysMonitorWidth = WWPrimaryMonitorWidth();
SysNativeResolutionX = 1920;
SysNativeResolutionY = 1080;
{ show something on monitor one }
ShowTopLeftAt("Page1", 0, 0);
{ show something on monitor two }
IF SysMonitors == 2 THEN
ShowTopLeftAt("Page2", SysMonitorWidth, 0);
ENDIF;
September 16th, 2020 at 12:21 am
I am using a dual monitor setup using two touchscreens. The problem Im having is when I use a mouse and click an item on the second screen that needs a keyboard input, the keyboard opens on the correct monitor , the second one. When I try to use the touchscreen and click an item that needs a keyboard input on the second monitor the keyboard open on the first monitor.
Am Im missing something? I made the changes to both .ini files and with a mouse it works fine. It just doesnt work correctly using my touchscreen input.
October 11th, 2020 at 8:19 pm
Hi, sorry for the late reply. I'd suggest inspecting the $ObjHor and $ObjVer variables, I'm guessing that these will correspond to the first monitor, and that your touchpad driver is sending window messages directly to the user control when you touch/click it to give it focus without moving the mouse. And InTouch probably decides which screen to show the keyboard based on the mouse position. In which case I don't think there much that could be done (easily). Probably worth raising as an enhancement with AVEVA product development team.
December 3rd, 2020 at 2:19 am
Thank you for the reply. I was able to figure out my problem.
I had to configure the touchpanels in Windows. Like This...
Right-click Start, go to Control Panel
Select Hardware and Sound
Select Tablet PC Settings (or just use the search box to find it instantly)
Select Setup
This only shows up if you have a touchpanel connected and the driver loaded. Once I did this and had both touchpanel monitors hooked up Wonderware keyboards starting behaving correctly.
December 24th, 2021 at 7:51 pm
Thanks for the Wiki, followed all your steps got the 2 monitors working but even if i open a different window on the second monitor it close the other window on the first monitor. If i then attempt to open another window on the first monitor it closes the window on the second monitor again.
I then went and made all my graphics 1 pixel smaller than monitor with (1919 by 1008) and used showtopleftat(window1,0,61) for monitor 1 and showtopleeftat(window2,1921,61) for monitor 2 my navigation window is from 0 - 60 and each screen is 1920 by 1080. Runtime app size set to 3840 by 1080
But that still only allows me to show 1 window at a time on both monitors (well technically 2 windows including my navigation window wich is spread over both monitors at the top all the time)
Any idea what could cause this issue?
Running aplication manager 17.3.100 5450.1213.17340.1
Intouch Version: 17.3.100 3770.1121.1394.1
December 26th, 2021 at 12:05 pm
@Leon I think your problem is that the Y coordinate for your main window isn't 61, but 61 + the height of the window border\menu area. On my system, the title bar and application border takes up 75 pixels, so I need to show the window at 0, 136. To find out how tall the window border\menu area is I put a button at the top of the window, displaying the analog value $ObjVer which will show you the Y value on mouseover or click.
January 11th, 2022 at 8:02 pm
Thanks for the info.
In my case there was another script that was using the aagraphics property to open the window in the correct place and that script caused my other window to close. When I removed that script it all worked fine.