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 Java and .NET applications to communicate through Finsemble's API.
Finsemble achieves native integration using 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.
This tutorial introduces the concepts needed to integrate native applications into Finsemble workflows.
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.
Note: Note that Finsemble disables the ability of WPF components to maximize using aero snap (i.e., WINDOWS KEY + UP). This is done to ensure that these components do not overlap the Finsemble Toolbar.
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
}
}
}
}
path
, you may use the
application file location or simply add the file name if it is on your machine's system path.windowType
to native
if you are running a .NET/WPF/C# application.windowType
to assimilation
if you are running your application from a binary file that you do not have the
source code for.params.argumentsAsQueryString
is true
, arguments should be
a single string in uri format (i.e,. a=1&b=2).If you wish to integrate a native application into Finsemble that is launched via an intermediary process, such as a batch script or protocol handler registered with your operating system (e.g., myLauncher://myapp), then note that you will need to integrate the Finsemble DLL into the application so that it can register itself with Assimilation by passing in the window handle of its window(s).
When using windowType: "assimilation"
, Finsemble Assimilation is designed to observe the process and capture the first
window handle that it creates (that passes any windowTitleWhiteList
or windowTitleBlackList
set) and then begin
managing that window. However, where an intermediary process is used to launch the application, Assimilation will not be
able to observe the creation of window handles. By integrating the Finsemble DLL into the application and using
windowType: "native"
, the application spawned can instead proactively register its window handle(s) with Finsemble
Assimilation, bypassing this issue.
You can bundle applications with Finsemble so that they can be accessed even though if they are not installed on a user's machine. Use this method to bundle AssimilationMain.EXE with your SmartDesktop.
appAssets
array in ..configs/application/application/manifest-local.json. Note: The first item in
the array should be assimilation
."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`.
}
"Native": {
"window": {
"id": "Native",
"windowType": "native",
"alias": "native",
"url": "",
"defaultHeight": 600,
"autoShow": true,
"alwaysOnTop": false,
"resizable": true,
"showTaskbarIcon": false,
"addToWorkspace": true
},
...
Note: These options are defined in the Config Reference.
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.
For the most part, Java applications have parity with the JavaScript API. The Java API calls follow a paradigm
appropriate for that language: they are accessed at FSBL.getClients().getClientName().method
, e.g.,
FSBL.getClients().getLauncherClient().getComponentsThatCanReceiveDataTypes
.
As examples, we've made a few Java sample projects.
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.
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:In C#:
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
};
})
});
In Java:
final Map<String, Function> emitters = new HashMap<>();
emitters.put("symbol", this::emitterCallback);
emitters.put("description", "Symbol" + symbolToSend);
fsbl.getClients().getDragAndDropClient().setEmitters(emitters);
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:In C#:
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();
});
};
})
});
In Java:
final Map<String, CallbackListener> receivers = new HashMap<>();
receivers.put("symbol", this::symbolReceiverCallback);
fsbl.getClients().getDragAndDropClient().addReceivers(receivers);
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:In C#:
FSBL.LinkerClient.Subscribe("symbol", (sender, event) => {
var symbol = event.response["data"];
});
FSBL.LinkerClient.Unsubscribe("symbol", (s, e) => { });
In Java:
fsbl.getClients().getLinkerClient().subscribe("symbol", this::handleSymbol);
fsbl.getClients().getLinkerClient().unsubscribe("symbol", (e, r) -> {});
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:In C#:
FSBL.LinkerClient.LinkToChannel("group1", null, (s, e) => { });
FSBL.LinkerClient.UnlinkFromChannel("group1", null, (s, e) => { });
In Java:
fsbl.getClients().getLinkerClient().linkToChannel(channel, wi, (err, res) -> { });
fsbl.getClients().getLinkerClient().unlinkFromChannel(channel, wi, (err, res) -> { });
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
getSpawnData
- Retrieves data that was set with LauncherClient.spawn
.
setComponentState
- Given a field, this function sets and persists an application component's state.
In C#:
FSBL.WindowClient.SetComponentState(new JObject
{
["field"] = "symbol",
["value"] = DataToSend.Text
}, delegate (object s, FinsembleEventArgs e) { });
In Java:
final JSONObject state = new JSONObject() {{
put("field", "symbol");
put("value", symbolTextField.getText())
}};
fsbl.getClients().getWindowClient().setComponentState(state, (err, res) -> {});
getComponentState
- Given a field, this function retrieves an application component's state. If no params are given
you get the full state.In C#:
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);
}
}
);
In Java:
final JSONObject field = new JSONObject() {{
put("field", "symbol");
}};
fsbl.getClients().getWindowClient().getComponentState(field, (err, res) -> {
if (err != null) {
// do something with the error state
} else {
// do something with the symbol response
}
});
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:
getValue
getActiveDescriptors
showWindow
spawn
error
warn
log
info
debug
verbose
Note: All logs will be sent to Finsemble regardless of settings in the Central Logger.
You can modify Assimilation's behavior, if desired, by modifying the AssimilationMain.EXE asset. This is typically done by creating an INI file. Your modified Assimilation asset should then be hosted on a server and bundled with your SmartDesktop, as per normal.
An example configuration that turns off hotkeys can be found at the Hotkeys tutorial.
One of the native applications many users are interested in integrating into their SmartDesktop is the Bloomberg Terminal. The Finsemble Ecosystem Team has provided a sample of this integration using Bloomberg Terminal Connect. With Bloomberg Terminal Connect, you can create a one-to-many connection between the Bloomberg Terminal and the applications integrated into your SmartDesktop.
Learn more about the Bloomberg Terminal Connect Integration by reading its documentation.
We've created a few sample projects to illustrate how to use the native API clients. _ Sample .NET projects _ Sample Java projects
It's simple to run web apps as part of the Finsemble framework. Read the Integrating HTML Application documentation here.