Creating a multimonitor application in InTouch

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:

  • Each window can only be shown on one monitor at a time (InTouch limitation)
  • If you try to show a window that is already open on a different monitor, it will close the window on the monitor it was originally on, leaving you with a blank screen.
  • $ObjHor and $ObjVer are given in pixels, offset from the top left corner of the view window client area.  This is important as when you are viewing the application on a monitor with a different resolution to the design resolution this must be taken into account.
  • When using the Show* functions on a monitor of different resolution to the design resolution, same applies as above.
  • Calling windowstate() on a window right after (ie in the same script) showing or closing the same window will not return the result you are expecting!

This is a rough guide as to how I went about achieving these goals.

 Modify win.ini (twice!)

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.

  • C:\Users\<user>\WINDOWS\win.ini
  • C:\Windows\win.ini

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 some windows, and set Window Viewer options

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.

Add some code to the application startup script

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;

Create quick functions to show windows on the correct monitors

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.

Window History

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;

Sample application

Multimonitor demo app

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 7th, 2016 | Posted in SCADA |

32 Responses to “Creating a multimonitor application in InTouch”

  1. Oleksandr Says:

    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) ???

  2. Raggles Says:

    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.

  3. mikebinz Says:

    Very helpful summary thanks

    Does anyone know of any similar articles dealing with the implications of running the SAME Intouch Project on DIFFERENT PCs?

  4. Srikanth Says:

    Hi

    I am working on Intouch app on two screen. Is is possible to show same window on both Screens ?

  5. Raggles Says:

    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.

  6. Felix Says:

    Hi Raggles, would it be possible to get your sample application. The link says its no longer available. Thanks.

  7. Raggles Says:

    Apologies for the broken link, should be fixed now.

  8. Rodrigo Says:

    Hi Raggles,
    Could you fix the link of the sample application again?
    Thanks

  9. Raggles Says:

    The link in the main post is fine - I've removed all the other comments with dead links. cheers

  10. Felix Cheah Says:

    Hi Raggles,

    How do i install the script function libraries? Do I just copy them to my program file directory?

    Thanks,

    Felix

  11. Raggles Says:

    Yes that's right, same folder as view.exe

  12. Felix Cheah Says:

    The quick function MMaddWindowHIstory isn't defined, where can i get this from?

  13. Felix Cheah Says:

    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

  14. Felix Cheah Says:

    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

  15. Raggles Says:

    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

  16. JB Says:

    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?

  17. Raggles Says:

    Bit hard to say without seeing your system, maybe a script function library is missing? The easiest way is to import the example package.

  18. Howie Li Says:

    Good Morning Raggles. did you have to use a special video card to get Windows Viewer extend across both monitors?

  19. Raggles Says:

    Hi, I don't use any particular card, it has worked on all video cards that I have used so far

  20. Elliot D Says:

    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.

  21. Raggles Says:

    Hi, the link is in the last paragraph, but here it is again https://mega.nz/#!WJcUjYKb!u95oAZHDyVbRCCxqApMFNyjZzK9tRNIxSNHiAwYL0EM Cheers

  22. Nirmal Kumar Says:

    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
    .

  23. Raggles Says:

    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.

  24. Nirmal Kumar Says:

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

  25. Raggles Says:

    Yes that's correct, assuming you have three monitors side by side and the left monitor is the primary

  26. BH Says:

    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.

  27. Raggles Says:

    Sorry I have never attempted to use different screen sizes and I don't know if this is supported or not.

  28. Buster Says:

    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

  29. Raggles Says:

    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;

  30. Eugene Jones Says:

    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.

  31. Raggles Says:

    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.

  32. Eugene Jones Says:

    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.

Leave a Reply