Integrating Native Applications

Finsemble allows you to assemble different applications into a unified desktop experience. Native applications can be both visually and logically integrated.

  • Visual integration allows your application to benefit from Finsemble's UX.

  • Logical integration allows .NET, C#, and WPF applications to communicate through Finsemble's API.

This tutorial introduces the concepts needed to integrate native applications into Finsemble workflows.

Visually integrating native applications

Visually integrated applications are spawned and controlled by Finsemble. Visual integration can be extended to applications installed on a local machine or apps bundled with your Finsemble installer.

  • Visually integrated applications have windows that can snap, dock, group, tile, and tab.
  • Visually integrated applications gain workspace persistence between sessions, reloading in the same position and with the same content.

When a Finsemble-aware application is launched by Finsemble, several command line parameters are sent to the application, specified under the path object.

Assimilation: native application visual integration

Visual integration is possible even if you do not control the source code for a particular application. If you want to incorporate native components built in .EXE, Java, Flash, etc., you can use a technology we call "Assimilation." We provide this as an executable: AssimilationMain.exe. This executable acts as a bridge between native Windows events (move, minimize, maximize, etc.) and Finsemble, communicating over a WebSocket that runs on the desktop’s loopback (localhost). It is not necessary to manually install AssimilationMain.exe on user’s desktops; it can be included as a Finsemble asset and run dynamically (see below).

To activate visual integration functionality for your native windows, open configs/application/config.json, and set servicesConfig.assimilation.enabled to true:


	"servicesConfig": {
		"assimilation": {
			"useOpenFinSpawn": false,
			"enabled": true,
			"throttle": 10,
			"focusDelay": 30,
			"eventIgnore": 50
		}

Launch native applications

There are two ways to launch native applications. Refer to the components.json object block below for each scenario.

"NativeApp": {
    "window": {
        "id": "NativeApp",
				"name": "NativeApp",
				"windowTitleWhiteList": ".*(Outlook|Today).*",
				"windowTitleBlackList": "Opening.*",
        "windowType": "assimilation",
        "path": "nativeapp.exe",
        "arguments": "arg1 arg2 arg3",
        "options": {"autoShow": true},
        "addToWorkspace": true
    },
    "component": {
        "spawnOnStartup": true
    },
    "foreign": {
        "components": {
            "App Launcher": {
                "launchableByUser": true
            }
        }
    }
}
  • When a Finsemble-aware application is launched by Finsemble, several command line parameters are sent to the application specified under the path object. When updating path, you may use the application file location or simply add the file name if it is on your machine's system path.
  • Set windowType to native if you are running a .NET/WPF/C# application.
  • Set windowType to assimilation if you are running your application from a binary file that you do not have the source code for.
  • Arguments should be separated by spaces. Note that when params.argumentsAsQueryString is true, arguments should be a single string in uri format (i.e,. a=1&b=2).
Integrating the Microsoft Office Suite: Assimilation is scoped to handle single windows. Native applications that spawn separate windows (like the "loading" windows that the Microsoft Office Suite spawn) can cause problems for Assimilation. Two configs, `windowTitleWhiteList` and `windowTitleBlackList`, are included to handle this behavior. Use `windowTitleWhiteList` to specify the name of the window that you actively want to Finsemblize. Exclude extraneous windows that you do not want to integrate, like loading windows, using `windowTitleBlackList`. Both fields take regular expression strings containing match criteria for the window titles.

Bundle native applications with Finsemble

You can bundle applications with Finsemble so that they can be accessed even though if they are not installed on a user's machine. To do so, follow these steps.

  1. Update the appAssets array in configs/application/openfin/manifest-local.json. Note: The first item in the array should be assimilation. This allows any additional apps to be found in the array.
"appAssets": [
	{
		"src":"http://localhost:3375/example.zip", // Your application should be packed into a Zip file, whose location is set at the `src` element and may be hosted at any appropriate URL.
		"alias": "NativeExample", // "alias" will be used to reference your application from your *components.json* file later.
		"version": "1.0", <// This represents the version of the package. You can increment the version to force new updates.
		"target": "example.exe", // "target" should identify the binary file inside the Zip that you want to execute.
		"args":"" // Using "args", you can pass in an argument string as you would write it on the command prompt (e.g., `"-mode=a b c"`).
		// You can add multiple copies of the config to `"appAssets"`, with different `"alias"` and `"args"` settings, to create multiple components (with different launch arguments) from the same `src`.
	}
  1. Then update the alias field in components.json to match the alias of the applications zipped bundle.
		"Native": {
			"window": {
				"id": "Native",
				"windowType": "native",
				"alias": "native",
				"url": "",
				"defaultHeight": 600,
				"autoShow": true,
				"alwaysOnTop": false,
				"resizable": true,
				"showTaskbarIcon": false,
				"contextMenu": true,
				"addToWorkspace": true
			},
			...

Note: These options are defined in the Config Reference.


Logically integrating native applications

A deeper level of integration is possible by having your native apps communicate with each other via Finsemble. This is called logical integration, and it allows users to create custom workflows between two or more interoperating components.

Finsemble-aware native applications are specified with a windowType of native. As before, you can use a full path or an alias for a downlaoded asset.

Native Finsemble clients for .NET/C#/WPF applications

Integrating .NET applications is made possible by using our .NET library, finsemble.dll. As examples, we've made a few .NET sample projects.

Note: In finsemble.dll, the clients are on the FSBL object itself, e.g., FSBL.LinkerClient. This is in contrast with the main JavaScript APIs, where the FSBL object already exists as a global object and the clients are accessed as FSBL.Clients.ClientName.

The following native clients and methods are available for your .NET/C#/WPF applications:

Drag and Drop

  • Emitters: To show the drag and drop icon in the Window Title Bar, you must create an emitter. Here is the code from a sample application that shares a "symbol" object that contains the text from a TextBox called "DataToSend". (See WPF Window Title Bar for more information.) Example:
FSBL.DragAndDropClient.SetEmitters(new List<KeyValuePair<string, DragAndDropClient.emitter>>()
{
	new KeyValuePair<string, DragAndDropClient.emitter>("symbol", () =>
	{
		return new JObject
		{
			["symbol"] = DataToSend.Text,
			["description"] = "Symbol " + DataToSend.Text
		};
	})
});
  • Receivers: To allow data from Finsemble to be dropped onto your application, you must create receivers. Here is the code from our sample application that receives a "symbol" object and sets that as the text of the "DataToSend" TextBox. Example:
FSBL.DragAndDropClient.AddReceivers(new List<KeyValuePair<string, EventHandler<FinsembleEventArgs>>>()
{
	new KeyValuePair<string, EventHandler<FinsembleEventArgs>>("symbol", (s, args) =>
	{
		var data = args.response["data"]?["symbol"]?["symbol"];
		if(data != null)
		{
			Application.Current.Dispatcher.Invoke((Action)delegate //main thread
			{
			DataToSend.Text = data.ToString();
			});
		};
	})
});

Linker

  • Publish: Publish a piece of data. The data will be published to all channels that the component is linked to. Foreign components that are linked to those channels will receive the data if they have subscribed to this data type. They can then use that data to synchronize their internal state (see "Subscribe"). You can publish to specific channels by specifying a channels array in the parameters.
  • Subscribe: Registers a client for a specific data type that is sent to a channel.
  • Unsubscribe: Remove all listeners for the specified data type. Example:
FSBL.LinkerClient.Subscribe("symbol", (sender, event) => {
	var symbol = event.response["data"];
});
FSBL.LinkerClient.Unsubscribe("symbol", (s, e) => { });
  • LinkToChannel: Add a component to a Linker channel programmatically. Components will begin receiving any new contexts published to this channel but will not receive the currently established context.
  • UnlinkFromChannel: Unlinks a component from a Linker channel programmatically. Example:
FSBL.LinkerClient.LinkToChannel("group1", null, (s, e) => { });
FSBL.LinkerClient.UnlinkFromChannel("group1", null, (s, e) => { });

Router Client

The .NET Router Client is very similar to the JavaScript client with a few exceptions:

  • RouterClient.Subscribe: This does not return a subscribeID.
  • RouterClient.Unsubscribe: This takes the same parameters as subscribe above.

Only the following API Calls are currently supported:

  • Transmit
  • AddListener
  • RemoveListener
  • Subscribe
  • Unsubscribe
  • Query
  • AddResponder
  • RemoveResponder

Window Client

  • setComponentState - Given a field, this function sets and persists an application component's state.
 FSBL.WindowClient.SetComponentState(new JObject
{
    ["field"] = "symbol",
    ["value"] = DataToSend.Text
}, delegate (object s, FinsembleEventArgs e) { });
  • getComponentState - Given a field, this function retrieves an application component's state. If no params are given you get the full state.
FSBL.WindowClient.GetComponentState(
    new JObject { ["field"] = "symbol" },
    delegate (object s, FinsembleEventArgs state)
    {
        try {
            if (state.response != null)
            {
                var symbol = (JValue)state.response;
                if (symbol != null)
                {
                    //Do something with the state retrieved
                }
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
        }
    }
);

Partial native clients available via RPC

In addition to the native clients listed above, certain Finsemble clients are available via a remote procedure call (RPC) mechanism. They are not yet fully implemented as native clients.

To use these endpoints, use the RPC function. For example:

// Definition:
RPC(string endpoint, List<JToken> arguments, RPCCallBack callback)

The RPC call takes three parameters. The first one is the API endpoint. The second is a list of all the arguments to the API call that are specified in the JavaScript API documentation—except the callback or eventHandler. The third parameter is the callback or eventHandler.

Here is the list of such Finsemble API endpoints currently supported for .NET. Refer to the documentation of each endpoint in our JavaScript API documentation:

Config Client

  • getValue

Launcher Client

  • showWindow
  • spawn

Logger

  • error
  • warn
  • log
  • info
  • debug
  • verbose

Note: All logs will be sent to Finsemble regardless of settings in the Central Logger.


check   You can both visually and logically integrate native components into Finsemble. Visual integration allows a user to launch, move, dock, group, and save the state of native components that Finsemble launches. Logical integration allows for native components to use Finsemble APIs like the Linker Client or Drag and Drop Client.
 

Further reading