Remote Raw Printing from VirtualUI-Enabled Apps (1)

remote raw printsModern web browsers have been designed to protect end-users from malicious or unwanted access to computer’s local resources. Typically, web browsers have none or limited access to disk units, USB devices and peripherals devices attached to the local computer.

Local printers are not an exception; they are restricted to printing web content only. But what if our VirtualUI-enabled application needs to send raw print commands and data to a matrix or label printer such as Zebra, Epson, etc.?

This article will demonstrate how to access a printer connected to the web browser from our application so we can generate RAW prints remotely as if the remote application and the printer were available in the same environment.

Continue reading

Using the Javascript ClientSettings Object

Javascript ClientSettingsPreviously, we presented you with an article about ClientSettings, an additional interface available in the Thinfinity VirtualUI Library. This interface allows developers to know and programmatically define, from their own software applications, some browser environment layout and behavior settings. In this post, we are presenting the Javascript version of ClientSettings. Continue reading

Add Actions to extend the Remote Desktop’s Toolbar

Thinfinity Remote Desktop's toolbarThe Thinfinity Remote Desktop‘s toolbar allows users to perform some of the actions which are essential for a complete remote user experience, such as sharing the current sessions, accessing the file transfer manager, changing option settings, etc. In a previous post we discussed how to remove toolbar options. In this opportunity we will show you how to extend the Remote Desktop’s toolbar with new “Send Key…” actions. Continue reading

Applying global Custom Settings to z/Scope Anywhere

Applying custom settings in zScope AnywhereIn addition to using the Configuration Manager, z/Scope Anywhere offers a new way to easily set global parameters using custom settings.

Setting global parameters through a custom settings file is not new to our product line. We’ve already published an article presenting this functionality for Thinfinity Remote Desktop, and another one where we show how to configure its toolbar menu. Now, this feature will be included in z/Scope Anywhere as of the next release, due to come out really soon. Today, we will show you how we can use it for a very specific purpose, modifying the global security parameters. Continue reading

Thinfinity jsRO remote events in C++

Thinfinity jsRO remote events in C++

Thinfinity jsRO allows programmers to get a better integration between a VirtualUI-extended desktop application and the web browser Javascript world.

We first presented the jsRO Delphi and .Net native interfaces when Thinfinity VirtualUI was launched, and we wrote several articles about it. Some months ago we implemented the jsRO native interface for C++. Today we will share with you how to create custom events in your application and replicate them in the web page.

Continue reading

Passing command line arguments to VirtualUI apps

VirtualUI command-line argumentsAn application can accept command line arguments when invoked. This allows the user to send additional information to the application when it is executed.

When an application is launched, the OS passes the command line arguments to the application as a collection of string values, using a white-space as separator.

Applications receive external arguments on a regular basis: when you open a document by clicking on its icon, the OS selects the associated executable program and calls it, sending the full document filename to the program as an argument.

Thinfinity VirtualUI allows you to send external arguments to applications in a transparent way, which works exactly like sending arguments from the command line.

Continue reading

Customize the Thinfinity Remote Desktop Toolbar

Thinfinity Remote Desktop Toolbar customizationIn a previous post we discussed how to apply general custom settings to Thinfinity Remote Desktop Server. Today, we will learn how to customize the Thinfinity Remote Desktop Server toolbar in depth.
By default, the toolbar displays the wider range of options within reach for the end users. But, as an administrator or integrator, you might want to restrict the end user from accessing some of these options, or all of them. Thinfinity Remote Desktop has a method for applying settings to the toolbar so you can tweak it according to your preferences. These settings will be applied before the connection occurs and will affect all users and all connections in the Thinfinity Remote Desktop server installation.

Continue reading

Applying general custom settings to Thinfinity® Remote Desktop

Customizing Thinfinity Remote Desktop

Besides being a powerful cross-device, cross-browser remote access tool, Thinfinity Remote Desktop Server also excels in its integration capabilities and its flexible and easy customization.

A little known fact for those working with Thinfinity Remote Desktop is the existence of customSettings.js. This file provides a way to easily define some global parameters for all remote access connections, regardless of the selected profile. This file, located in the webrdp folder of the installation directory, is an editable javascript that contains a global variable called customSettings. Continue reading

How to send cross-domain messages using Javascript

 
Thinfinity  - Cross-Domain Messages

A basic rule in Web security holds that there is no direct javascript access between different windows loaded in a browser unless these windows are from the same origin.

This means that the windows must share protocol, host and port or it will not be possible to access a value or object on another page from the JavaScript code, or to add content. So, how can we establish and maintain the communication between different pages loaded in a cross-domain environment?

Fortunately, benefiting from the window.postMessage API, the windows can send non intrusive messages to each other via javascript in a cross-domain environment. These messages can be text, or an object in JSON format (JavaScript Object Notation) —something already available in most of modern web browsers.

In this article we will show how to apply this API to send cross-domain messages using Javascript in a secure way.

 

The window.postMessage API

In order to send a message to another window, one must invoke a postMessage() method, introduced below:

targetWindow.postMessage(message, targetDomain, [extra])

where:

targetWindow Reference to the window that will receive the message.
message JSON object or text that will be sent to the target window.
targetDomain Domain to which the message should be posted.
It can also be written “*” not to limit messages to a particular domain, although this is not recommended —unless absolutely necessary.
extra A sequence of extra —optional— objects that could be transferred with the message. The ownership of these optional objects is no longer on the sending side, but is transferred to the destination one.

But if a tree falls in a forest and nobody’s around to hear it, does it make a sound? In other words, it is useless to send the message if no one is prepared to listen to it. In order to be heard, the event message must be attended. Although most modern web browsers employ the addEventListener() method to add the treatment of the event, old IE versions makes use of its own; so we will cover both alternatives:

if (window.addEventListener){
    addEventListener("message", listenerFunction, false)
} else {
    attachEvent("onmessage", listenerFunction)
}

Where listenerFunction will be used to process the message coming from another window. This function will receive the message in the data attribute of the event received:

function listenerFunction(e) {
    if (typeof e.data == "string") {
        console.log(“The message is a text: ” +  e.data);
    } else {
        console.log(“The message is a JSON object:” + JSON.stringify(e.data));
    }
}

 

Some considerations regarding security

Cross-window messaging security model is two-sided. In the event of knowing the domains of the both parties involved —which is usually the case—, and in order to make the exchange of information between different domains safer, it is recommended to check, both when sending and receiving, the domains that participate in the messaging exchange. The sender ensures that the receiving domain is targetDomain. If the sender tries to send a message to a domain different to targetDomain, an error will occur.

The receiver can check the origin attribute of the received message event object to make sure that this came from a valid origin. Therefore, if the domain of origin does not match a valid domain, it can be ignored.

 

Let’s do it!

The following example implements cross-domain communication between two pages: one loaded in the localhost domain, and the other one in IP 127.0.0.1. To handle the exchange of messages we will create two javascript classes (MessageSender and MessageReceiver).

The MessageSender class has a single published method (sendMessage) and, during its creation, it will receive the window to where the message should be sent (targetWindow, mandatory) and the domain to which the message should be directed (targetDomain, optional), which if not received will be replaced by “*”. Both arguments are sent within a JSON object.

var MessageSender = function(args) {
    args = args || {};
    var targetWindow = args.targetWindow;
    var targetDomain = args.targetDomain || "*";
    var ready = false;
    var sendMessage = function(message) {
        targetWindow.postMessage(message, targetDomain);
    }
    return {
        "sendMessage": sendMessage
    }
}

The MessageReceiver class has two published methods. The start method initiates the listening of the message, while the stop method ends it. Both methods could receive a callback function to do an additional processing in the start/stop messaging. This class, when instantiated, is capable of receiving a JSON object with a pair of attributes, both optional. The first is a callback function to process the message; the other, a validOrigin string that indicates the domain from which it would be valid to receive messages. Should any of these parameters is not sent, the first one will be replaced by a default message processor , while the other, by the same page’s domain (i.e., it will not be cross-domain and will only receive messages from its own domain). In case you do not want to control the origin of the message, the validOrigin attribute must explicitly assert “*”.

var MessageReceiver = function (args) {
    args = args || {};
    var started = false;
    var validOrigin = args.validOrigin || window.location.origin;
    var defaultMsgProcessor = function (e) {
        if (typeof e.data == "string") {
            alert("The message is test:\n'" + e.data + "'");
        } else {
            alert("The message is a JSON object:\n" + JSON.stringify(e.data));
        }
    }

    var msgProcessor = args.callback || defaultMsgProcessor;
    var processMessage = function (e) {
        if (validOrigin == "*" || validOrigin == e.origin) {
            msgProcessor(e);
        }
    };
    var startListening = function (onStartCallback) {
        if (!started) {
            if (window.addEventListener) {
                window.addEventListener("message", processMessage, false);
            } else {
                attachEvent("onmessage", processMessage);
            }
            started = true;
            if (onStartCallback) onStartCallback();
        }
    }
    var stopListening = function (onStopCallback) {
        if (started) {
            if (window.removeEventListener) {
                window.removeEventListener("message", processMessage);
            } else {
                window.detachEvent("onmessage", processMessage);
            }
            started = false;
            if (onStopCallback) onStopCallback();
        }
    }
    return {
        "start": startListening,
        "stop": stopListening
    };
};

Both classes will be included in the same javascript file, which we will call crossDomainMessenger.js.

In order to use these classes, we will create two html pages. The first one, crossDomainSource.html, includes the crossDomainMessenger.js file and displays, on the top part, a line containing a text field (where the messages to be sent will be added) and some buttons to send messages. At the bottom of this page, the second page will load in an iframe, which would receive the messages.

From javascript, it will create both a MessageSender and a MessageReceiver; the first one to send messages triggered by the buttons to the page loaded in the iframe; and the last one to address messages that could be sent to the internal page.

This second page will also create a MessageSender and MessageReceiver, with the difference that in this case, the important work that will done by the latter.

The page also has buttons to toggle the message listener; a button to clear the list of messages received; and, a last button to send a message to the other page, which would close the communication circuit between the two windows.

Below you will find the code for the two pages of the example:

crossDomainSource.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Cross domain message example - Sender</title>
    <style>
        html, body { height: 100%; margin: 0px; padding: 0px; }
        #divmsg { height: 50px; line-height: 50px; vertical-align: middle; padding-left: 10px; padding-right: 10px; }
        #divtarget, #targetWindow {display: block; position: absolute; }
        #divtarget { top: 51px; bottom: 5px; left: 5px; right: 5px; border: solid 1px; box-sizing: border-box; }
        #targetWindow { width: 100%; height: 100%; border: none; }
    </style>
    <script type="text/javascript" src="crossDomainMessenger.js"></script>
    <script type="text/javascript">
        var msgSender = null;
        var msg = null;

        function init() {
            var targetDomain = window.location.protocol + "//127.0.0.1:" + window.location.port;
            var tw = document.getElementById("targetWindow");
            tw.src = targetDomain + "/crossDomainTarget.html";
            msgSender = new MessageSender({ "targetWindow": window.frames["target"], "targetDomain": targetDomain });
            msg = document.getElementById("txtmsg");

            // Creates a MessageReceiver that accepts messages from targetDomain only
            new MessageReceiver({ "validOrigin": targetDomain }).start();
        }

        function sendText() {
            msgSender.sendMessage(msg.value);
        }

        function sendObject() {
            msgSender.sendMessage({ "message": msg.value, "currentDate": new Date().toJSON() });
        }

        function sendClear() {
            msgSender.sendMessage({ "cmd": "CLEAR" });
        }
    </script>
</head>
<body onload="init()">
    <div id="divmsg">
        <label for="txtmsg">Message:</label>
        <input type="text" id="txtmsg" size="30" />
        <input type="button" value="send text" onclick="sendText()"/>
        <input type="button" value="send object" onclick="sendObject()"/>
        <input type="button" value="send clear" onclick="sendClear()"/>
    </div>
    <div id="divtarget">
        <iframe id="targetWindow" name="target"></iframe>
    </div>
</body>
</html>

crossDomainTarget.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Cross domain message example - Receiver</title>
    <style>
        html, body { height: 100%; margin: 0px; padding: 0px; }
        #msgPanel > div { border-bottom: dashed 1px #808080; }
    </style>
    <script type="text/javascript" src="crossDomainMessenger.js"></script>
    <script type="text/javascript">
        var msgSender = null;
        var msgReceiver = null;
        var msgPanel = null;
        function init() {
            msgPanel = document.getElementById("msgPanel");
            // This MessageReceiver accepts messages from localhost only.
            msgReceiver = new MessageReceiver({
                "validOrigin": window.location.protocol + "//localhost:" + window.location.port,
                "callback": function (e) {
                    if (typeof e.data.cmd != "undefined" && e.data.cmd == "CLEAR") {
                        clearMsgs();
                    } else {
                        addMessage("The message is " +
                            ((typeof e.data == "string") ?
                                "test:\n'" + e.data + "'" :
                                "a JSON object:\n" + JSON.stringify(e.data)));
                    }
                }
            });
            start();
            msgSender = new MessageSender({ "targetWindow": window.parent });
        }

        function start() {
            msgReceiver.start(function () { addMessage("*** msgReceiver was started!") });
        }

        function stop() {
            msgReceiver.stop(function () { addMessage("*** msgReceiver was stopped!"); });
        }

        function clearMsgs() {
            msgPanel.innerHTML = "";
        }

        function sendHellow() {
            msgSender.sendMessage(window.location.origin + " says Hello!");
        }

        function addMessage(message) {
            var newmsg = document.createElement("div");
            newmsg.innerHTML = message;
            msgPanel.appendChild(newmsg);
        }
    </script>
</head>
<body onload="init()">
    <div>
        <input type="button" value="start" onclick="start()"/>
        <input type="button" value="stop" onclick="stop()"/>
        <input type="button" value="clear" onclick="clearMsgs()"/>
        <input type="button" value="send msg to opener window" onclick="sendHellow()" />
    </div>
    <div id="msgPanel"></div>
</body>
</html>

This is enough to understand how the messaging between windows works, even when they are in different domains. In upcoming posts we will demonstrate how to use this technique to establish a smooth communication between Thinfinity VirtualUI or Thinfinity Remote Desktop with other applications to which they are integrated.

 

Browser within the browser: breaking the Matryoshka effect.

When the browsers are nested.
image01

It has become increasingly common to expect desktop applications to be capable of integrating to the web to incorporate available external information. There are several ways this could be achieved: by consuming web services to get the raw data; or, by simply including a browser component within the application, in the form of a panel. In this second case, we’ll be capable of navigating to sites displaying up-to-date information or external multimedia content, such as maps, videos, images and sound —as an example, visit Fish Facts, a live demo that shows basic GUI virtualization capabilities as well as an integration with the web browser and external web resources.

Once we transform these applications with Thinfinity® VirtualUI™, and we invoke them from the web, an effect similar to the famous Russian Nested Dolls case occurs: we run from the browser an application that contains within itself another browser. In short, we surf to an application that internally re-surfs. This is not bad in itself, but we can take advantage of already being in the web to access the final resource directly from the main browser. By doing this we will avoid a roundabout that, among other things, would unnecessarily increase the consumption of resources.

Let’s take a look at the diagrams of the same application running from the desktop…

Matryoshka-image1

… and from the Web:

Matryoshka-image2

As we can see, when we run the application from the desktop we must necessarily navigate through an embedded Webbrowser component. The application is the one that connects to the desired web address, and this webpage is seen in an internal panel, within the application.

But once we load the application from a browser we would experience the aforementioned effect. As a result, the application browses on its own, and the visible result of that surfing is re-transferred to our browser.

If we transfer that navigation to the only browser we need to use, we will access the intended resource without delay or additional bandwidth, processing, or time consumption.

image00

The demo application

The application we use in the example (whose complete source can be found here) attempts to break this browser-within-the-browser effect, simply by using the internal browser only when the application is accessed from the desktop. If the application is being accessed from the web, instead of using that component, the app would load the desired page in an iframe created on the fly. To achieve this integration (which requires a little bit more interaction between the application and the browser) we will add a jsRO object, which will control the remote iframe from the application.

The first addition to our application will be the adding of VirtualUI and its initialization:

using System;
using System.Windows.Forms;

namespace matryoshka
{
   static class Program
   {
       /// <summary>
       /// The main entry point for the application.
       /// </summary>
       [STAThread]
       static void Main()
       {
           new Cybele.Thinfinity.VirtualUI().Start();
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           Application.Run(new Form1());
       }
   }
}

Let’s now see what we have to add to the main form code, which it only has a panel where to enter the browsing URL and another one where the WebBrowser component is located.

The following is the application code before adding the changes:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace matryoshka
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // Sets Google Maps URL to run in the embedded browser
            txtURL.Text = "https://maps.google.com";
            Navigate();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            Navigate();
        }

        private void txtURL_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (Convert.ToInt32(e.KeyChar) == 13)
            {
                Navigate();
            }
        }

        private void Navigate()
        {
            if (!txtURL.Text.Equals(""))
            {
                if (!txtURL.Text.StartsWith("http"))
                {
                    txtURL.Text = "http://" + txtURL.Text;
                }
                webBrowser1.Navigate(new Uri(txtURL.Text));
            }
            else {
                webBrowser1.Navigate(new Uri("about:_blank"));
            }
        }
    }
}

As a first step, we will add to the class the objects in the Cybele.Thinfinity library:

using System;
using System.Drawing;
using System.Windows.Forms;
using Cybele.Thinfinity;

namespace matryoshka
{
    public partial class Form1 : Form
    {

        private VirtualUI vui = new VirtualUI();
        private IJSObject mRemoteLayout = null;

        public Form1()
        ...

This demo application loads a Google Map. To be run embedded in an iframe, Google Maps needs a different URL from the one used on a full page. We know that it will run embedded in the iframe (using VirtualUI) and directly when loaded into the internal browser.

public Form1()
{
    InitializeComponent();
    if (vui.Active)
    {
        // Code executed only when the application runs with Thinfinity VirtualUI
        // Sets Google Maps URL to run embedded in an iframe
        txtURL.Text = "https://www.google.com/maps/embed";
    }
    else
    {
        //* Code executed only when the application runs from desktop 
        // Sets Google Maps URL to run in the embedded browser
        txtURL.Text = "https://maps.google.com";
    }
}

Additionally, we must also make some changes to Navigate( ):

private void Navigate()
{
    string sURL = "";
    if (txtURL.Text.Equals("")){
        sURL = "about:_blank";
    } 
    else
    {
        sURL = txtURL.Text;
        if (!sURL.StartsWith("http"))
        {
            sURL = "http://" + sURL;
        }
    }
    if (vui.Active) {
        mRemoteLayout.Properties["url"].AsString = sURL;
    }
    else {
        webBrowser1.Navigate(new Uri(sURL));
    }
} 

The last (but not least important) addition is the one concerning the jsRO object management: the first method, for its instantiation and definition of their getters; the other one, for the later updating of the iframe’s bounds.

private void Form1_Shown(object sender, EventArgs e)
{
    // Creates jsRO object for iframe control
    mRemoteLayout = new JSObject("layout");
    mRemoteLayout.Properties.Add("windowId").AsString =
                String.Format("virtualui_canvas_{0}", Handle);
    mRemoteLayout.Properties.Add("url").AsString = txtURL.Text;
    mRemoteLayout.Properties.Add("bounds")
        .OnGet(new JSBinding(        // Adds a "getter" to bounds
            delegate(IJSObject AObj, IJSProperty AProp)
            {
                // Returns a JSON object
                Point p = pnlNav.PointToScreen(new Point(0, 0));
                p.Offset(-Left, -Top);
                AProp.AsJSON = "{" + String.Format("\"left\":{0}, \"top\":{1}, \"width\":{2}, \"height\":{3}",
                     p.X, p.Y, pnlNav.Width, pnlNav.Height) + "}";
            }));
    mRemoteLayout.ApplyModel();
}

private void pnlNav_Resize(object sender, EventArgs e)
{
    // Updates all mRemoteLayout's properties "getters"
    if (mRemoteLayout != null)
    {
        mRemoteLayout.ApplyChanges();
    }
}

We can now introduce the additional information that must be included, at javascript level, to the HTML page.

What follows is the base page to which we will be adding the functionality:

 

We will now create three global variables for the VirtualUI and jsRO objects, and for the iframe created on the fly.

<script type="text/javascript">
var virtualUI = null;
var jsro = null;
var nav = null;

$(document).ready(function () {
    ...

We will add three functions intended to create the iframe and keep it updated:

...
$(document).ready(function () {

    var navigate = function(url) {
        nav.src = url;
    }

    var applyBounds = function(bounds) {
        nav.style.left = bounds.left + "px";
        nav.style.top = bounds.top + "px";
        nav.style.width = bounds.width + "px";
        nav.style.height = bounds.height + "px";
    }

    var createNav = function () {
        nav = document.createElement("iframe");
        nav.id = "nav";
        nav.style.position = "absolute";
        nav.style.display = "none";
        nav.style.zIndex = 2;
        nav.style.border = "none";
    }
    ...

We will now instantiate the VirtualUI object, configure its events, and then connect to the application:

var createNav = function () {
   ...
   ...
}

virtualUI = new Thinfinity.VirtualUI();

virtualUI.onError = function (errorMsg) {
    alert("Application load failed");
};

virtualUI.onLoading = function () {
    console.log((virtualUI.devMode) ? "Waiting for application..." : "Loading...");
};

virtualUI.onClose = function (url) {
    if ((typeof url != 'undefined') && (url != '') && (url != null)) {
        if ((virtualUI.devMode != true) || (window.top.opener)) {
           window.top.close();
        }
        window.top.location.href = url;
        return;
    }
    if (virtualUI.devMode) { location.reload(); }
    if ((virtualUI.devMode != true) || (window.opener)) { window.close(); }
    if ((window.top == window) && (document.referrer) && (location.href != document.referrer)) {
        location.href = document.referrer;
    } 
    else {
        if (nav) { nav.style.display = "none"; }
        alert("Application closed");
    }
};

// -- Connect to server...
virtualUI.connect();

Finally, we will create the jsRO object instance. Please note that it’s in the creation of the layout jsRO model (defined in the application) where the iframe is injected into the application window. The other two events are used to keep both the URL and the inserted iframe bounds updated:

...
virtualUI.connect();

// Defining Javascript Remote Objects Elements
jsro = new Thinfinity.JsRO();

jsro.on('model:layout', 'created', function (obj) {
    layout = jsro.model.layout;
    if (nav == null) {
        createNav();
        document.getElementById(layout.windowId).appendChild(nav);
        nav.style.display = "inline-block";
    }
    applyBounds(layout.bounds);
});

jsro.on('model:layout.url', 'changed', function (obj) {
    navigate(obj.value);
});

jsro.on('model:layout.bounds', 'changed', function (obj) {
    applyBounds(layout.bounds);
});

With this procedure, we’ve been able to break the “Matryoshka Effect”. From now on, the embedded browser will be used from the desktop, while the external one will be used from the web —but always being controlled by the remote application.

 

Running the application from the browser

To see the end result, we must first add the application to the list of registered apps in the Thinfinity VirtualUI Server and configure its home page, making sure it points to the page modified by us in this tutorial.

Once this is done, we can access the application from the browser. If we are running the application from the Thinfinity VirtualUI Development Lab, we must change the virtual path’ address so as to match the one defined in the configuration —in the VirtualUI’s manager.