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 |

19 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. Joles123 Says:

    Where can we find the HCInTouch Utilities Library?

    Do you have the updated version of your demo application?

  4. Raggles Says:

    Sorry I have temporarily removed the source for the utils library, but you can get the binaries from https://mega.nz/#!XV1lTILC!zQaDHb8ajfR8HZXmnVmIXr-3LxdsFTH_O0-5zyya6Xo. The application package is at https://mega.nz/#!PIUlXCSb!pogh71FJ1WWy6p_gVJuf4evdi-TNHv61ghzVYoEDC8U

  5. Joles1234 Says:

    Thanks for that! Got to see if we can apply a similiar approach in a SP2014R2 application where we need to cater for single, dual, and quad display setups.

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

  7. Kelvin Says:

    Have tried but get errors when trying to import your application. Wondering if you have just a zipped version and not the Intouch export file available. I am about to set up a quad system and am familiar with most of the add on tools you mention above, but wanted to experiment a little with your code and maybe learn something from it that may save me a bunch of time. Thanks,

  8. Raggles Says:

    Hi, zip version can be downloaded from https://mega.nz/#!2dNHEILQ!lh9NqkrJHZF3YmUHzeDhypJ5NoZQ6b63CLTUvpjE_A8

  9. jp Says:

    Hi, I can't seem to import the project. Would you mind exporting the project again?

  10. Raggles Says:

    There is nothing wrong with the file, which version of system platform/intouch are you using?

  11. jp Says:

    I tried to import the aapkg file and the folder, but it shows invalid. I also tried using the find application and pointed it to the unzipped folder but still no success.
    Im using intouch2014r2

  12. Anp Says:

    I am not able to download the sample project, can you please provide the download link

  13. Beaula Says:

    I tried to import the aapkg file and the folder, but it shows invalid. I also tried using the find application and pointed it to the unzipped folder but still no success.
    Im using intouch2017

  14. Raggles Says:

    I'm not sure why you can't import the file, it works fine for me. Anyways I've converted the application to Standalone InTouch (2017Update2), unfortunately I've come across a bug that only seems to affect the standalone version so once I've sorted that out I'll upload it.

  15. Raggles Says:

    The updated application is at https://mega.nz/#!fV0E3IhY!u95oAZHDyVbRCCxqApMFNyjZzK9tRNIxSNHiAwYL0EM - requires 2017 Update 2

  16. william Says:

    Hi Raggles,
    Could you please upload the latest version, suitable to 2014R2SP1? Thanks!!

  17. Raggles Says:

    I no longer maintain a 2014R2 environment sorry, you could open the application in a demo version of 2017 if you don't have a license.

  18. Srikanth Says:

    Hi

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

  19. 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.

Leave a Reply