Download Alchemium v1.0 Today

Use Alchemium to build native Windows applications with HTML5, CSS3, and JavaScript. Extend the platform with a powerful JavaScript to .NET integration bridge.

The Alchemium platform was designed from the ground up to make it easy to build and distribute standalone, native Windows applications using the power of modern HTML5 and JavaScript.

Applications built on Alchemium can target all common versions of Windows from Windows XP through Windows 8.1 (Desktop).

A rich extensibility model lets you leverage Microsoft .NET technologies to extend Alchemium, and the embedded JavaScript environment. Alchemium applications break free from traditonal browser restrictions, and integrate directly with the host operating system.

If you are comfortable with HTML and JavaScript, Alchemium gives you the all the tools needed to create and distribute applications, or breathe new life into existing Windows-based solutions.


Highlights


Application Development
  • A powerful platform that unites HTML5 technologies with traditional desktop development tools and applications.
  • Perfect for packaging, distributing, and monetizing standalone HTML5 games.
  • Easily use popular libraries like Angular, jQuery, Bootstrap, Semantic UI and more in a desktop application.
  • The Alchemium Platform is powered by an embedded, customized version of Google's Chromium Browser. By tracking with Chromium, (currently on par with Chrome 31) Alchemium enables broad HTML5 support. Currently Alchemium scores 507 on the HTML5 test, which is on the bleeding edge when it comes to HTML5 support. Try your current browser and see how it stacks up against Alchemium's HTML5 support.
  • Includes full debugger/inspector tools running in an isolated process.
  • Use your editor or IDE of choice. Alchemium is agnostic.
  • No Sandbox or XHR restrictions.
  • Live update - All changes to source files are automatically compiled and reflected in real time in the application.
  • Auto-compilation of Less, Sass, TypeScript and CoffeeScript source files (also in real-time).
  • Include support - the <a:include/> tag lets you inject fragments of commonly used HTML dynamically into application pages similar to server-side paradigms.
  • Session Management - Easily store data and state that is accessible globally to all the pages in your application.
  • Easily expose .NET code and the full power of the .NET framework to the embedded V8 JavaScript engine as first class JavaScript objects with the Alchemium extensibility model.
  • Dynamic UI/API - Register custom protocol handlers to redirect AJAX/href requests to custom C# or VB.NET code.
  • Automatic handling of marshaling .NET objects to JavaScript, and JavaScript objects to .NET.
  • Full support for interactive debugging of .NET extensions from Visual Studio while your Alchemium app is running.
  • Plays well with Flash - Build hybrid Windows applications and games using HTML5 and Flash. Package them up and ship as a single unit with Alchemium.
Distribution
  • Compile and package a fully native Windows application. Alchemium generates a custom branded exe (icon, version resource etc) for release with everything needed for an XCopy deploy.
  • Not a content shell. A fully native app.
  • Compiler compresses and embeds all source HTML, JS etc. No "loose" files in the redist.
  • Evergreen - Alchemium applications silently, automatically update themselves.

Create your first project with the command line tool acp.exe

The Alchemium Create Project utility (acp) is used to lay down the basic directory structure and runtime for an Alchemium-based application. Alchemium operates in two distinct modes, Architect Mode and Release Mode. acp generates a full project directory and executable that runs in Architect Mode. In Architect Mode, when you run your executable it will automatically pick up any changes in the the project directory (.html, .js, .less, .scss, .ts, .coffe etc.) and recompile, and re-display in real-time.

To create a project, do the following:
  1. From a command prompt or PowerShell prompt, change into the directory where you installed the Alchemium SDK (By default the SDK is installed to c:\Program Files (x86)\AlchemiumSDK).
  2. run acp.exe [App Name] [Target Directory] For example: acp "My App" c:\test\MyApp
 acp usage notes
Target directory must be empty

If you attempt to create a poject in a directory that is not empty acp will warn you of this, and terminate.

Target directory creation

If the target directory does not exist, acp will create it.

Application Launch

After acp.exe has completed its work, your new application will launch in "Architect Mode". You are ready to start live-editing the source for your application. We'll talk more later about the unique features offered when in Architect mode.

Here is a sample sequence:



If you look in the project directory, it will be structured as follows:



Understanding the project file and directory structure

  .\My App.exe (In this case, since we named it "My App" when we ran acp)

This is the "Architect Mode" executable for your project. Note, this is not an application ready for distribution. It is a special version of your application that supports an interactive edit/debug/build cycle. Later, when we talk about distributing your application to end-users we will walk through the process of compiling a release build, which removes Architect mode features, compiles, compresses and secures your content/source, and trims the runtime foootprint to the minimum required for an end user installation.

  .\manifest.txt

Manifest.txt is a file that contains important metadata and configuration settings for your application. When you created your project with acp, a manifest was generated in the folder specified and set to Alchemium's defaults. View a documented manifest.txt here for more information. When you do a release build, the manifest is embedded into the application bundle.

  .\app

The app directory (and its subdirectories) contain your application's source code and content. Typically, your app's entry point will be the file index.html in the .\app\ directory, though this can be overridden in the manifest file.

Referencing your resources in an Alchemium application

Internally, Alchemium binds to a special protocol and domain prefix of "http://app". Basically this means that any files in your ./app/* directory and subdirectories can simply be referenced by their paths. You do not need to worry about prefixing resources with "http://app" just make sure you reference based on the path on disk and Alchemnium takes care of the rest. If you watch network traffic in the developer tools, you will see that the resources are ultimately retrived via the http://app prefix. This architecture ensures maximum flexibility, as your resources will be treated as if they are being fetched over http:// as opposed to the more restictive file:// protocol that typically hampers local web site or web application development when you are not using a web server.

For example
Link to file "index.html" in your project's app folder: <a href="index.html">Go to index.html</a>.
An image tag referencing a file in an .\app\img subdirectory on the file system <img src="img/sample.png"/>.
An image tag referencing a file in an .\app\img\foo\bar subdirectory on the file system <img src="img/foo/bar/sample.png"/>.

No Web Server Required

Alchemium does not require Web server software or network access. The runtime intercepts requests for resources in in the local file system directory where your application is located, and automatically handles them as if they were requests made to "http://app/*", therefore they are handed as true http:// requests, unencumbered by typical limitations of referencing local resources via the file:// protocol prefix. Release builds serve those same resources from a singe compressed, and secured bundle file, so your IP is safe from prying eyes when released.

Standard Web Content Works fine, and all XHR Restrictions are Lifted for AJAX

Alchemium can load any external content directly from the Web with one restriction - pages served from the Web do not support Alchemium's dynamic Less/Sass/CoffeeScript/TypeScript compilation or include tag processing (more on Includes later). Full AJAX/XHR support works against both local resources well as standard http over the Internet. Even better, there are no cross-domain XHR limitations when making an AJAX request from a page in your Alchemium-powered app out to the Web! Alchemium also supports WebSockets in full to handle real-time push/COMET type scenarios.

  .\app\ext

Alchemium supports the development of extensions built on the .NET Framework 4.0 and higher. Extensions expose.NET code and the full power of the .NET framework to the embedded V8 JavaScript engine as first class JavaScript functions and objects via this extensibility model. To use extensions from your JavaScript code simply copy the assemblies (dll files) into this folder.

Please see the .NET Extension Developer's Guide for more information on creating your own extensions.

  .\app\css_inject

Alchemium treats this folder specially. Any .css stylesheets that live here will automatically be added to every page your application loads (just after the DOM is loaded). This includes both pages your application serves up, and pages loaded from the Web.

  .\app\js_inject

Another special folder to Alchemium. Any .js files here will automatically be added and executed in every page your application loads (just after the DOM is loaded). This includes both pages your application serves up, and pages loaded from the Web.

Guidance for Using Injection (css_inject and js_inject)

As tempting as it is, we recommend you use standard css/js loading techniques for most of your content, as opposed to dumping a bunch of files in css_inject and js_inject. The primary reason css_inject and js_inject exist is to handle the scenario where you do NOT control the content being loaded and want to inject custom stylesheets or JavaScript into a page for adorning existing content, integrating with existing code, or scraping scenarios when the source is beyond your control.

An appropriate example of using injection is how we use it to add a "Back to Alchemium Documentation" UI element when we link to an external page in this documentation. In our example we add some css animation for the fade, and JavaScript to detect that we are not on an Alchemium app page, and create the element. Visit Google.com to see an example.

Here is what the code looks like. We have an inject.css in our .\app\css_inject directory. It contains the following:

div.__epFade {
-webkit-animation: xfade 4s;
opacity: 0; !important
}
@-webkit-keyframes xfade {
from {opacity: 0}
to {opacity: 1}
}

Next, we have an inject.js file in our .\app\js_inject directory. It contains the following:

if (location.href.indexOf("http://app/") === -1) {
    
var __plumBack = document.createElement('div');
// We want to know when the animation completes             
__plumBack.addEventListener("webkitAnimationEnd", 
            function() {__plumdimmer22.style.opacity = 1;}, false);
    
__plumBack.style.position = 'fixed';
__plumBack.style.left = 0;
__plumBack.style.top = 0;
__plumBack.style.width = '100%';
__plumBack.style.height = '30px';
__plumBack.style.opacity = .0;
// Referencing the css class we injected...
__plumBack.className = '__epFade';
__plumBack.style.backgroundColor = 'transparent';
__plumBack.style.backgroundColor = 'black';
__plumBack.style.zIndex = 32766;
document.body.insertBefore(__plumBack, document.body.firstChild);
__plumBack.innerHTML = "<a style='font-family:helvetica;font-size:12pt;
                        text-decoration:none;color:white;position:relative;
                        left:10px;top:3px' href='#' 
                        onclick='alchemium.app.goBack();'>
                        <span style='position:relative;top:-1px;font-weight:bold'>
                        ←</span>
                            Return to Alchemium Documentation</a>";
} 

Another potential use case for this functionality would be for testing existing sites, verifying content etc.

  .\runtime

This directory contains the Alchemium runtime files. These files are required for your Alchemium-based application to run. In Architect mode, it has additional files and compilers for Less, Sass, TypeScript, CoffeeScript etc. When you do a release build it will be stripped down to the bare minimum runtime requirements.

Creating projects from a template

acp.exe also supports creating new projects from an existing project template using the /template=[path_to_project_template] command line switch as the 3rd parameter. For example:

acp.exe "MyD3App" "c:\debug\MyD3" /template="c:\Program Files (x86)\AlchemiumSDK\templates\d3"

In the above example we are creating a new project from the D3 template that ships with the Alchemium SDK. D3 is a popular JavaScript data visualization library. When a template is used, acp will recursively copy all the application source files from the template directory to your newly created project's directory. We encourage the use of templates, as they can save lots of time, especially if you always include a few "go-to" libraries and assets with your applications.

Shortcut syntax for creating projects based on the SDK template project samples

The Alchemium SDK currently ships with two templates: "d3" and "bootstrap". Note they are located in the [ALCHEMIUM_SDK_PATH]\templates subdirectory. You can use a slight bit of shorthand when creating a project based on a template the the [ALCHEMIUM_SDK_PATH]\templates subdirectory, instead of providing the full path the the directory that contains the template, you need only provide the name.

For example, to create a project based on the included "bootstrap" template:

acp.exe "My Bootstrap App" "c:\debug\bootstrap" /template=bootstrap

Creating your own project templates

If you have a standard set of javascript and css libraries you use for your Alchemium projects, it is a good idea to create your own project templates. You can see some examples of templates in the [ALCHEMIUM_SDK_PATH]\templates directory. Templates look exactly like any Alchemium project with only one slight difference. In a project template's manifest.txt file you will enter some special macros to have acp dynamically insert certain fields when creating your new project from the template.

Project template macros in manifest.txt
_ID_ acp.exe will replace _ID_ with a new globally unique identifier (GUID) that uniquely defines the project. It is critical that each project have a globally unique project id.
_NAME_ acp.exe will replace _NAME_ with the name that was supplied when acp.exe is executed (the first parameter).

Here is a snippet from the manifest.txt file of a project template, note how the _ID_ macro will be used to direct acp.exe to insert a new unique id in its place, and _NAME_ is used to insert the name chosen when acp.exe is run.:

"id": "_ID_", 
"name": "_NAME_", 
"startURL": "index.html", 
"version": "1.0.0.0",
"cachePath": "{appdata}\\_ID_\\cache",

Let's take a look at the source code for an Alchemium-powered application page. We'll exercise most of the core platform features of Alchemium, and break each one down in detail. The concepts we'll cover are as follows.

  • Using resources embedded in the runtime (jQuery, BootStrap etc.).
  • Include files
  • Automatic compilation of Less, Sass, CoffeeScript, and TypeScript.
  • Using Alchemium's session model for storing global data and passing data between pages.
  • The alchemium.app.* JavaScript API's.
  • Invloking a custom .NET extension via JavaScript.
  • Making AJAX calls from JavaScript to your .NET extensions.
Note each of the superscripts in the sample, they are explained in detail beneath the sample code.
<!DOCTYPE html>
<html>
<head> 
<script src="alch://jquery.js"></script> 1
<a:include data-file="head.html"/> 2
<link rel="stylesheet" type="text/css" href="css/default.css">
<link href="less/sample.less" rel="stylesheet"> 3
<link href="sass/sample.scss" rel="stylesheet"> 3
<script src="ts/sample.ts"></script> 3
<script src="coffee/sample.coffee"></script> 3
<script>
$(function () {
if (typeof alchemiumSession.getSession('loaded')4  === 'undefined') {
 
    console.log('Demo1 initializing...');
 
    if (alchemium.app.installedApplicationUpdate()5) {
        alert('Application was updated!  Welcome to the new version!')
    }
    console.log("Runtime: " + alchemium.app.runtimeVersion);
    alchemiumSession.setSession('loaded', 1);
} else {
    console.log('skipping init...');
}
	
alchemium.app.unloadAppHandler5 = function () {
// Return true to cancel application shutdown
    return false;
}
$("#testExtension").click(function () {
    
    var connStr = "Data Source=(local);Integrated Security=true;Database=Northwind;";
    var sqlStr = "SELECT * FROM Customers";
		
	// Issue a SQL statement to a local SQL Server database and get results	
    var results = com.electricplum.sqlserver.getSQLResults({ "connectionString": connStr, "sql": sqlStr });6
    
    results.data.forEach(function (el) {
        console.log('Company:' + el.CompanyName);
        console.log('Contact:' + el.ContactName);
        console.log('======================================================');
    });

});
$("#testAJAX").click(function () {
var args = {};
args.string = "A string";
args.int = 42;
args.obj = {};
args.obj.p1 = "prop 1";
args.obj.p2 = "prop 2";
	
$.ajax({6a
	url: "http://myextension.com/ajax",
	type: "POST",
	data: JSON.stringify(args),
	contentType: "application/json",
	dataType: "json",
	success: function (json) {
	alert(json.propertyOne);
	}
});
});
    
});
</script>
</head>
<body>
<a href="#" id="testExtension">Click me to call C#</a>
<a href="#" id="testAJAX">Click me to call C via AJAX#</a>
</body>
<html>
</html>

 

1 Using Embedded Libraries

<script src="alch://jquery.js"></script> 
This is an example of using the embedded jQuery 2.0.3. To use an embedded runtime resource we use the alch:// prefix. This is just a convenience feature, you are free to use your own references to libraries in standard fashion either with local copies, or linking to a cdn etc. Alchemium currently embeds the following:

Library Reference URI
Angular.JS 1.2.11 (And modules) alch://angular.js
alch://angular-animate.js
alch://angular-cookies.js
alch://angular-loader.js
alch://angular-mocks.js
alch://angular-resource.js
alch://angular-route.js
alch://angular-sanitize.js
alch://angular-touch.js
Bootstrap v3.1.0 (css) alch://bootstrap.css
Bootstrap v3.1.0 (js) alch://bootstrap.js
jQuery v2.1.0 alch://jquery.js
jQuery v1.11.0 alch://jquery1.js
Leaflet v0.7 alch://leaflet.js
Lo-Dash v2.4.1 alch://lodash.js
Phaser 1.1.5 alch://phaser.js
Pixi.js v1.4 alch://pixi.js
Semantic UI v0.12.4 (css) alch://semantic.css
Semantic UI v0.11.0 (js) alch://semantic.js
Sizzle v1.10.16-pre alch://sizzle.js
Underscore.js v1.5.2 alch://underscore.js
zepto.JS v1.1.2 alch://zepto.js

Using Non Embedded Libraries (Local Copies)

There are no restictions on using local copies of css and JavaScript libraries. The embedded libraries are only included for ease of use. If you want finer control over the versions of libraries employed, simply include them somewhere in your ./app/ directory or any subdirectory and reference them normally. TIP! - We suggest using either embedded or local copies of libraries to ensure your application runs perfectly when the end-user does not have an Internet connection.

 

2 Include Files

<a:include data-file="head.html"/> 

Here we are using Alchemium's include file support. When Alchemium encounters an <a:include data-file='somefile.html'/> tag, it will inject the contents of the referenced data-file directly into the response stream. IMPORTANT: This data file must be located in the .\app\includes project directory. Note, this happens before the page is loaded, so it can be thought of as similar to how server-side technologies like PHP and ASP.NET operate.

Includes can nest other includes for maximum composability. Includes make it much easier to maintain large applications with many pages, since you only need to make the changes in one place. They are commonly used for headers, footers, and requently used fragments of HTML in your application.

 

3 Embedded Compilers - Less, Sass, TypeScript, and CoffeeScript

<link href="less/sample.less" rel="stylesheet"> 3
<link href="sass/sample.scss" rel="stylesheet"> 3
<script src="ts/sample.ts"></script> 3
<script src="coffee/sample.coffee"></script> 3

Alchemium automatically compiles Less, Sass, CoffeScript and TypeScript when resources of their type are requested. Note, the compiler caches the result in Architect mode, and when you do a release build the static results of compilation are embedded in your application's bundle, so you never take a performance hit in the application distributed to your customers.

If you are using CoffeScript, TypeScript there will be a slight delay in Architect mode when the application starts up, as the files are compiled.

Any changes you make to a referenced JavaScript, Less, Sass, CoffeeScript or TypeScript file while your application is running in Architect mode will automatically recompile the source, so you never need to exit the running app to make a change.

At this time, we do not support source maps, so when you are using the integrated debugger, you will be stepping through the resulting JavaScript from the compilation, not the original CoffeeScript/TypeScript.

Ensuring the compiler detects and compiles appropriately

Alchemium invokes the compiler based on the file extension of the resource. Use the following file extensions:

Compiler Extension Example
Less .less <link href="less/sample.less" rel="stylesheet">
Sass .scss <link href="sass/sample.scss" rel="stylesheet">
CoffeeScript .coffee <script src="coffee/sample.coffee"></script>
TypeScript .ts <script src="ts/sample.ts"></script>

 

4 Global Session and State Support

if (typeof alchemiumSession.getSession('loaded') ...	

Alchemium exposes functions to JavaScript that make it very easy to store data globally which can be read and modified from any page in the application. Simply use:
alchemiumSession.setSession(key, value) to store session data and
var theData = alchemiumSession.getSession(key) to retrieve the data.

You can persist complex objects using JSON.stringify() an JSON.parse() in concert with each other. For example:

var myObj = {};
myObj.prop1 = 42;
myObj.prop2 = 'Alchemium Is Cool!';
// Store it in global session
alchemiumSession.setSession('myKey', JSON.stringify(myObj));
// Retrieve and de-serialize (likely from some other page in your app)
var fromSession = JSON.parse(alchemiumSession.getSession('myKey'));
		


Session is not required

If you would rather use more standard HTML5 technologies for storing and passing data, you are free to do so. Cookies, localStorage, Web SQL and Indexed DB are all fully supported and available.


Session does not persist after application exit

Session is designed for runtime creation and access of global data. If you need to persist information, we suggest you use standard HTML5 storage mechanisms such as localStorage, Web SQL, Indexed DB or other 3rd party JavaScript persistence libraries. Note, all storage is private to each application. No HTML5-persisted data is exposed or shared across Alchemium apps. You can of course use Alchemium API's to write directly to the OS file system if you want to share data between applications, but standard HTML5/JavaScript storage APIs write data private to each application.

 

5 The Alchemium JavaScript APIs

if (alchemium.app.installedApplicationUpdate() ... {	

Here we see an example of using the Alchemium APIs from JavaScript in the page. Alchemium enriches the JavaScript execution environment with a number of APIs to allow for far richer integration and interoperability with the host operating system than ever would be possible from a typical Web page, where code is sandboxed.

Alchemium's JavaScript API surface is broken down into a few namespaces, which are all prefixed with alchemium. :

Namespace Notes
app Control various aspects of application behavior. Examples: installedApplicationUpdate(), minimizeApp(), maximizeApp(), setFullScreenMode(), exitApp(), showDevTools(), goBack(), installedApplicaitonUpdate() etc..
io Interact with the local filesystem. Examples: readAllText(file), writeAllText(file, text), chooseFolder(), chooseFile()
os Interact with the local OS, for launching processes. Examples: shellExecute(fileToOpenWithAssociatedAppinOS), runExternalProcess(process, cmdLine, waitForExit)
net Access to the host OS networking state. Example: isInternetAvailable()
You are not limited to Alchemium's API Surface
Alchemium includes an extensibility model that lets you add your own custom APIs to JavaScript. If you can do it in .NET, you can do it from JavaScript with an Alchemium extension. See the .NET Extension Developer's Guide for more information.

The alchemium.* APIs are covered in detail in the JavaScript API Reference
 

6 Invoking .NET Extensions From JavaScript

var results = com.electricplum.sqlserver.getSQLResults({ "connectionString": connStr, "sql": sqlStr });	

In this example, we see JavaScript code calling an extension function. The actual extension functionality is implemented in a C# .NET class library that Implements the IAlchemiumExt interface (VB.NET is fully supported as well). This example uses the sqlserver extension that ships with the Alchemium SDK.

The Alchemium runtime scans the .\app\ext\*.dll folder at startup looking for any assemblies that implement IAlchemiumExt. It then presents all the functions that the extension exposes to JavaScript. Note how the caller can pass an arbitratry object to .NET.

When the extension code is executed in C# the JavaScript object passed in will have it's properies packaged into a name/value pair Dictionary<string, object>. The extension can respond with any serializable .NET object and Alchemium will marshal it into the JavaScript execution context and make it available as a standard JavaScript object.

See the .NET Extension Developer's Guide for information on how to create your own extensions.

 

6a Calling .NET Extensions via AJAX

$.ajax({
url: "http://myextension.com/ajax",
type: "POST",
data: JSON.stringify(args),
contentType: "application/json",
dataType: "json",
success: function (json) {
alert(json.propertyOne);
}
});

Here we see JavaScript that uses jQuery to make an .ajax() call. What may not be immediately obvious is this call will actually be routed to a C# function handler inside of a .NET extension. Extensions can register custom URI schemes which will result in the Alchemium runtime directing the request and POST payload to the extension instead of a network endpoint.

In this example the extension implemented the IAlchemiumExt.getCustomSchemes() function to notify Alchemium that it wants to handle all requests to http://myExtension.com/*

Let's take a look at what a fragment of that C# code in the extension that registers the scheme handler looks like:

// Register for custom schemes 
// We'll listen for any requests (href, AJAX etc) to these URI schemes
// Requests will be routed to our implementation of IAlchemiumExt.processCustomSchemeRequest
List IAlchemiumExt.getCustomSchemes()
{
var schemeList = new List();
var myScheme = new AlchemiumScheme();
// http is the preferred prefix to avoid having to deal with the host Alchemium browser 
// imposing security restrictions on things like post data to non standard URI schemes
myScheme.uriPrefix = "http";
myScheme.domain = "myextension.com";
// Default mimeType for our responses
myScheme.mimeType = "application/json";
schemeList.Add(myScheme);
// At this point, any request to "http://myExtension.com/*" (AJAX, href etc.) will 
// be routed to our implementation of IAlchemiumExt.processCustomSchemeRequest()
return schemeList;
}


While this is a little more involved than standard extension function calls, it offers a few advantages. First, it employs well-worn AJAX idioms to make the call and process the result, meaning it plugs in nicely to existing dynamic Web application concepts. Another advantage is it can be asynchronous, so if your extention was talking to some old backend client server legacy database, doing some long query, the UI remains responsive.

Another scenario this can be quite useful for is mocking an endpoint that will ultimately be a true XHR call using the extension to return dummy or test data in the interim.

As we discussed earlier, Alchemium operates in two distinct modes, Architect Mode and Release Mode. When you are devloping your application, you are running in Architect mode. The basic workflow is as follows:

  1. (One time) Create your project using the acp.exe utility.
  2. Launch your application executuable. It will be in the folder you specified when you ran acp (By default acp.exe will launch your new exe after it creates the project).
  3. Add and edit source files and subdirectories in [path_to_your_project]\app\*. Typically you'll start with your start page (.\app\index.html by default). Tip: Right-click on your application's user interface and select "Edit Page..." to launch the editor associated with the project - you can indicate which editor Alchemium should launch via the "editor" setting in manifest.txt
  4. Live Edit Support - As edits are made and saved, you will see your application update it's user interface in real-time reflecting the changes. We will cover more information on Live Edit later in this section.
  5. Open up the Alchemium Developer tools (F12), set breakpoints, inspect the DOM, profile code, watch resource requets, etc.
  6. Rinse, repeat steps 2-5...
  7. When your masterpiece is complete, do a release build and ship it.

Let's take a look at the developer tools. After you press F12 (or optionally choose 'Developer Tools' from the context menu, or ctrl-shift-c), you will see the developer tools window. In the screen shot below we see the developer tools debugger sitting on a break point. Interestingly, we took this screen shot while we were writing this documentation. This documentation is itself an Alchemium application :)

Screen Shot - In Architect mode, paused in the debugger:

(click for full size)

Live Edits and Compilation

As you edit source files in your application's .\app directory, Alchemium "listens" for saved changes. When you make an edit and save, Alchemium determines what needs to be recompiled based on dependencies, and it initiates the compilation, and refreshes your application's interface accordingly.

Alchemium attempts to retain all application state, and stay on the current page even after compilation. However, some changes will force a full reprocessing of all source files and reload the initial start page. Note, any edits to the application's manifest.txt file will initiate an automatic full reload.

 Visual Studio Limitations for Live Edit

Visual Studio uses shadow copying when editing source files. This unfortunately limits Alchemium's smart compilation. Any edits made to source files using Visual Studio will force Alchemium to do a full recompile and reload of your application start page. The changes will still be picked up, but Alchemium won't be able to retain state and the currently viewed page, it must reload the initial start page.


Learning more about the integrated Chromium Developer Tools
Alchemium's developer tools are based on a slightly modified version of the developer tools in Google's Chromium open source browser (Similar to Google Chrome), so they will likely be a very familiar to you as an experienced front-end Web developer. Regardless of your familiarity with Alchemium, you should feel right at home.

The following is a great resource to learn more about the Chromium dev tools:
Chrome Developer Tools Overview

Note the above "Chrome Developer Tools Overview" documentation was written against a slightly earlier version of the tools. For those interested, Alchemium's embedded dev tools are basically functionally equal to the tools provided in Google Chrome 31 (Q4 2013 time frame).
Unsupported Features
Alchemium does not currently support the "Workspaces" feature of the dev tools. Nothing will happen if you attempt to add a workspaces folder. This is by design.

Architect Mode Only Feature - The Developer Context Menu

When in Architect mode, Alchemium adds a right-click context menu with useful functionality. Right-click anywhere on your application's user interface to summon this menu. Let's have a look at the options.


Back/Forward/Reload - Standard browser behavior.

Restart Application - Re-Execute the startup/compile/load cycle (the same process that happens when the application is initially executed).

Developer tools - Same as F12, shows the dev tools.

Toggle Address Bar - Shows a bare-bones browser-like address bar. This can be usefull if you want to directly load a page in your application. It can also be useful to navigate to a page on the Internet while researching something as you build your app.

Edit Page - This will summon your editor/IDE of choice (UltraEdit, Sublime, Visual Studio etc.), loading the source of the active page. The editor can be configured in your application's manifest.txt file. See the notes on "editor" in the manifest.txt documentation for details.

Compile Release Build - This will compile the application for release to your customers. Release mode applications do not contain the Architect mode features like dev tools and the developer context menu etc. We will discuss release builds in the next section.

Compile Release Build and Create Install Program - This will compile the application for release to your customers. In addition, Alchemium will automatically create a commercial grade installer that you can use to distribute your application. See the Using the Automated Installation Program Creation Function section for more information on distributing your application.

Building

When you are ready to distribute a release to your customers, you must first package a release build. There are two ways to accomplish this.

Build Option 1 - Building From Architect Mode
To build from Architect mode, launch your application in Architect mode, and right-click to bring up the context menu. Select Compile Release Build on the context menu. After a minute or so, Alchemium will notify you that the build is complete, and give you an option to run the release build.
Build Option 2 - Building From the Command Line

To build from the command line with apack.exe:

  1. Launch a Windows PowerShell or Command Prompt.
  2. If the Alchemium SDK is not in your path, change into your Alchemium SDK directory.
  3. Run apack.exe [Path To Your Project]

Here is a screen shot of the sequence. In this case, we have the Alchemium SDK installed in C:\AlchemiumSDK and we are packaging the documentation you are reading right now. Our documentation project is located in the D:\Dropbox\Alchemium31\Documentation directory:


Release Builds - Understanding The Compile and Packaging Process
When you do a release build the following happens:
  1. A static result of all your application's pages is built. This constitutes processing all page's include tags and injecting their contents into the final output, all Less files are compiled down to static css files, all CoffeeScript and TypeScript is compiled to static JavaScript files, and all JavaScript is minified.
  2. The static results are all written to the [Your Project Directory]\Release_Unpackaged folder. This folder is not important for distribution, but can be helpful for debugging and creating static Web sites with Alchemium.
  3. All application source code, content, and extension dependencies are compressed into a single, encrypted application bundle, app.zip. Alchemium Release mode executables handle serving up resources from app.zip (from memory, not temporary disk files) as your users interact with the application.
  4. Architect Mode dependencies and functionality is stripped from the executable.
  5. Icon and Version resources are compiled into the executable (based on your configuration in manifest.txt)
  6. At this point you can run the EXE in the Release_Redist directory to run the Release mode version of your soon to be worldwide best-selling application :)
  7. We will cover packaging up an installation program for distribution later in this section.

Using the Automated Installation Program Creation Function

Alchemium bundles a copy of the popular open source installation program Inno Setup. Inno is a commercial grade installation builder for Windows. If you would like to avoid the hassle of creating an installation program for your application, Alchemium can do it for you automatically.

To compile your application and generate an end-user-ready installation program:

  1. Launch your application in Architect Mode
  2. Right click on your application.
  3. Select "Compile Release Build and Create Install Program" from the context menu.
  4. When compilation is complete, you will be prompted to test the installer.

 Note, the resulting installation program "setup.exe" is created in the .\Installer subdirectory of your project's directory.



The Installer Includes Everything Needed for Distribution

The installation program that Alchemium generates is all you need to zip up and distribute so end users can install your application. The installer automatically installs the Alchemium runtime files to a common, shared location if it needs updating on the target machine. This shared runtime used by all Alchemium applications, and reduces the installation foot print, especially if you distribute multiple Alchemium applications.

The installer also handles optionally deploying the .NET Framework v4.0 if the user does not have it installed. In addition, it supports un-installation via add/remove programs in Windows control panel.


Building a Custom Installer

If you are experienced with building installation programs, or have some other custom deployment needs, then building a custom installation may be the appropriate choice for distributing your application.

If you prefer to build a custom installer for your application, there are just a few simple steps.

  1. Build a release build via the "Compile Release Build" context menu option.
  2. Step 1 will build all your files the the Release_Redist directory, which is a subdirectory of your main application.
  3. IMPORTANT! Be sure to include (and execute) the Alchemium runtime installer with your installation program. The runtime installer is located at [SDK Directory]\support\runtime_redist\setup_runtime.exe. All Alchemium applications require the runtime.
  4. From your installation program invoke the Alchemium runtime installer. There are two variations:
    • setup_runtime.exe /SILENT (Shows a progress user interface while the runtime files are updated).
    • setup_runtime.exe /VERYSILENT (Runs with no user interface)
(Optional) Installing a private/local copy of the Alchemium runtime with your custom installer

In rare cases, you may prefer to include a specific copy of the runtime for use by just your application (as opposed to the default behavior which uses the shared runtime). This is referred to as the "Captive Runtime". If you are installing a private copy of the runtime, skip, steps 3 and 4 above and follow th instructions below.

The files you need to redistribute to use the Captive Runtime are located at:

[ALCHEMIUM_SDK_PATH]\support\runtime_redist\captive_runtime\*.*

(Typically, this will be: c:\Program Files (x86)\AlchemiumSDK\support\runtime_redist\captive_runtime

In your custom installer, make sure these files are copied to: subdirectory. [YOUR_APP_INSTALL_DIR]\runtime (the same directory where your app.zip is located).

Custom Installation Mode - The .NET Framework 4.0 is Required

If you are building a custom installer please note, Alchemium has one external dependency beyond the runtime. Alchemium applications require that the .NET Framework 4.0 or later be installed on the target machine. Note, this must be the standard .NET redist Alchemium does not support the .NET 4 client profile.. The .NET 4.0 redistributable can be found here. That site contains the file you need to distribute, and good information on detection, silent installation and more.

As mentioned earlier, if you are using Alchemium's built-in installation creation features, this will be handled automatically.

Alchemium applications have the ability to automatically check for updates when they are launched. The following steps are involved in making your application auto-update-aware:

  1. Edit the autoUpdateURL setting in your application's manifest.txt file to point at the location on a publicly accessible Web site where Alchemium should check to see if an update is available.
  2. Before doing a Release build, increase the version number stored in the version setting in your application's manifest.txt file.
  3. Do a Release mode build.
  4. After doing a Release mode build, upload the two files (manifest.txt and app.zip) located in [path_to_your_project]\AutoUpdate_Redist to your Web server in the location referenced in step #1.
  5. Repeat this process each time you have a new official release.


The Auto Update Process

Each time an Alchemium release mode application is launched, it checks the following:

  1. Is Internet access available?
  2. Does the application's embedded manifest autoUpdateURL contain a valid Web address?
  3. Can that endpoint be accessed?
  4. Is there a valid manifest.txt and app.zip in that location?

If those four checks pass, the version of the manifest on the Web Server will be compared to the embedded manifest in the application. If the version on the Web is higher, a download of the app.zip will begin. Once app.zip is downloaded, it's integrity will be verified and the existing app.zip will be archived and replaced.

The application launch phase will complete with all resources being served up from the new app.zip. On typical Internet connections, this entire process will be nearly imperceivable to your customer.

Limitation - No support for runtime bootstrapping

At this time, Alchemium cannot update its embedded runtime via auto-update. Auto-updating of your application code, content, and extensions is the only supported scenario. Therefore, if electric plum releases an updated SDK and runtime, and you apply the new runtime to your application, you must do a release build and release a new version of your installation.

Adding an Updated Runtime to an Existing Application Project Created with an Earlier Version

If you would like to update your application with an updated runtime when a new Alchemium SDK is released by electric plum, you must use the acp.exe utility. If you remember, this is the same utility you used to create your Alchemium project.


The steps are as follows:
1. Install an updated version of the Alchemium SDK on your development machine.
2. Close any open instances of the application whose runtime you wish to update.
3. Open a command prompt or PowerShell prompt.
4. Change into your Alchemium SDK installation directory.
5. Run the acp.exe utility with one parameter - your application's project folder: acp ["PATH_TO_YOUR_PROJECT"]

Here is an example sequence (Our application is in the c:\dropbox\Alchemium31\Documentation directory):


6. Perform a new Release Build of your application.
7. Rebuild your application's installation/setup program and re-distribute the full installation program to your customers.

Probably the most powerful aspect of the Alchemium platform is the support provided to deeply extend its capabilities via the .NET framework using Alchemium Extensions. Extensions are integrated by the runtime directly into the JavaScript execution environment using a bridge to the V8 JavaScript engine. This lets front end developers write JavaScript code that executes .NET code exposed by the extension.

Usage Scenarios

Anything is possible with an extension, some examples follow:

  • Build an interface to a legacy API or system and expose an API surface to the Alchemium JavaScript environment.
  • Wrap and expose COM objects to Alchemium via COM Interop.
  • Integrate Alchemium with line of business applications.
  • Integrate with productivity tools like Microsoft Office.
  • Add custom WPF or Windows Forms Interfaces and dialogs to an Alchemium application.
  • Build integrations with backend databases like SQL Server or MySQL.

Extension Development Workflow

Writing an extension entails the following:

  1. Install the Alchemium SDK
  2. Build a .NET Class Library. This library must be set to x86, and use the .NET Framework 4.0. You may use C# or VB.NET.
  3. Set a reference to the AlchemiumInterfaces.dll assembly in your Alchemium SDK directory.
  4. Create a public class that Implements the IAlchemiumExt interface.
  5. Write implementation code describing your object namespace, functions to expose, and handlers for callbacks that are executed in your code when JavaScript invokes them.
  6. When your extension is complete, place the .dll in the .\app\ext directory of the Alchemium application that you would like to extend.


The Runtime Extension Discovery and Execution Process

When an Alchemium application is launched, the runtime will first check to see if any files need to be auto-updated (as discussed in the Updating Alchemium Applications section.) After any extensions or content files are updated, Alchemium scans the .\app\ext\*.dll folder looking for any assemblies that implement IAlchemiumExt. Each assembly that implements IAlchemiumExt is then instantiated and Alchemium begins the process of interrogating the assembly, ultimately presenting its functions to JavaScript as if they were standard JavaScript functions.

When the extension code is executed from JavaScript, Alchemium packages the JavaScript arguments into a name/value pair Dictionary<string, object> and hands that Dictionary to the IAlchemiumExt::invoke implementation, passing the name of the function that was called as well. The extension can respond with any serializable .NET object, and Alchemium will marshal it into the JavaScript execution context and make it available as a standard JavaScript object.

This type of extension function call is synchronous, but we will also cover how extensions can be accessed asynchronously using XHR/AJAX.


Invoking .NET Extensions From JavaScript
var ret = com.electricplum.ext.test1({ p1: 10, p2: 42 });

In this example, we see JavaScript code calling an extension function. The actual extension functionality is implemented in a C# .NET class library that Implements the IAlchemiumExt interface (VB.NET is fully supported as well).

The Alchemium runtime scans the .\app\ext\*.dll folder at startup looking for any assemblies that implement IAlchemiumExt. It then presents all the functions that the extension exposes to JavaScript. Note how the caller can pass an arbitratry object to .NET.

When the extension code is executed in C# the JavaScript object passed in will have it's properies packaged int a name/value pair Dictionary<string, object>. The extension can respond with any serializable .NET object and Alchemium will marshal it into the JavaScript execution context and make it available as a standard JavaScript object.


Calling .NET Extensions via AJAX
$.ajax({
url: "http://myextension.com/ajax",
type: "POST",
data: JSON.stringify(args),
contentType: "application/json",
dataType: "json",
success: function (json) {
alert(json.propertyOne);
}
});

In the snippet of code above, we see some JavaScript code that uses jQuery to make an .ajax() call that ultimately calls our extension. Extensions can register to listen for custom URI schemes via their implementation of IAlchemiumExt.getCustomSchemes(). When an extension registers custom schemes, the Alchemium runtime will direct resource requests and POST payloads to the extension's implementation of IAlchemiumExt.processCustomSchemeRequest() instead of a network endpoint.

In this example, the extension implemented the IAlchemiumExt.getCustomSchemes() function to notify Alchemium that it wants to handle all requests to http://myExtension.com/*

Let's take a look at what a fragment of that C# code in the extension that registers the scheme handler looks like:

// Register for custom schemes 
// We'll listen for any requests (href, AJAX etc) to these URI schemes
// Requests will be routed to our implementation of IAlchemiumExt.processCustomSchemeRequest
List<AlchemiumScheme> IAlchemiumExt.getCustomSchemes()
{
var schemeList = new List<AlchemiumScheme>();
var myScheme = new AlchemiumScheme();
// http is the preferred prefix to avoid having to deal with the host Alchemium browser 
// imposing security restrictions on things like post data to non standard URI schemes
myScheme.uriPrefix = "http";
myScheme.domain = "myextension.com";
// Default mimeType for our responses
myScheme.mimeType = "application/json";
schemeList.Add(myScheme);
// At this point, any request to "http://myExtension.com/*" (AJAX, href etc.) will 
// be routed to our implementation of IAlchemiumExt.processCustomSchemeRequest()
return schemeList;
}
An Extension Code Sample

Let's take a look at a fully implemented extension, and dive in to the core concepts. This extension contains all the code snippets we have looked at so far in this section. This is the source code for a fully functional extension implemented in C#. It is also included in your Alchemium SDK samples directory.

View Extension Sample Code

The extension edit / debug / build cycle

The easiest way to debug your extension while your Alchemium application is running is as follows:

  1. Set your solution to build it's output to your Alchemium application's .\app\ext folder.
  2. From your "project properties" tab in Visual Studio, set the "Start Action" to launch your Alchemium exe.

Setting up your extenstion for debugging:


Once you have followed these steps, you can do a simple run/debug directly from within Visual Studio, set break points etc.

Make sure your extension targets x86 and .NET 4.0

The Alchemium SDK ships with some useful extensions. The extensions are all located in the .\ext subdirectory of your SDK installation. To use a given extension you simply copy the DLL (and possible dependencies where noted) to the ".\app\ext" subdirectory of any Alchemium project. The extension will automatically be packaged and installed with your application when you build an executable and user the integrated distrubution and setup tools.


Microsoft SQL Server Extension (SQLServerExtension.dll)

The com.electricplum.sqlserver extension allows JavaScript to issue queries directly to a SQL Server. It also allows for the execution of SQL statements. The extension has three functions:

  • getSQLResults()
  • executeScalar()
  • executeNonQuery()
. The code sample below illustrates using it from JavaScript.

// A simple query against the SQL Server Northwind sample database
// All APIs expect a connection string in the passed in .connectionString property.
var connStr = "Data Source=(local);Integrated Security=true;Database=Northwind;";

// getSQLResults() returns an array of objects for each row in the result set in the "data" property
// Each row is an object with the property names based on the SQL result column names
var sqlStr = "SELECT * FROM Customers";
var results = com.electricplum.sqlserver.getSQLResults({ "connectionString": connStr, "sql": sqlStr })

// Walk through the result set and output some column values
results.data.forEach(function (el) {
    console.log('Company:' + el.CompanyName);
    console.log('Contact:' + el.ContactName);
});

// executeScalar() executes the query, and returns the first 
// column of the first row in the result set returned by the query. 
// Additional columns or rows are ignored.
// The return value is in the .result property
sqlStr = "SELECT COUNT(*) FROM Customers";
var scalarTest = com.electricplum.sqlserver.executeScalar({ "connectionString": connStr, "sql": sqlStr})
console.log('There are ' + scalarTest.result + ' Customers in Northwind.');

// executeNonQuery() executes a Transact-SQL statement against the 
// connection and returns the number of rows affected in the .result property
sqlStr = "UPDATE Customers SET Fax = 'None' WHERE Fax IS NULL";
var execNonQueryTest = com.electricplum.sqlserver.executeNonQuery({ "connectionString": connStr, "sql": sqlStr })
console.log(execNonQueryTest.result + ' row(s) affected.');


SQLite Extension (SQLLiteExtension.dll)

The com.electricplum.sqlite extension allows JavaScript to issue queries directly to a a local SQLite database on the filesystem. Note, Alchemium's HTML5 storage APIs also support SQLite from the official JavaScript/HTML5 layer, however that is limited to the browser's storage sub system. If you need to directly manipulate and access SQLite databases outside of the browser sandbox, this extension can be handy. The extension has seven functions:

  • create()
  • connect
  • isConnected()
  • close()
  • getSQLResults()
  • executeScalar()
  • executeNonQuery()
  •  Important Dependency/Distribution note:

    The SQLite extension has an additional dependency: System.Data.SQLite.dll.

    Be sure to include both SQLLiteExtension.dll and System.Data.SQLite.dll in your app\ext directory. Both files can be found in the .\ext subdirectory of your Alchemium SDK installation folder.

. The code sample below illustrates using the API from JavaScript.


var sqlStr = "";
var retVal;

// Create a new database in c:\debug (Note use of \\ for proper escaping since 
// our interface to the extension is via JSON... 

// Create a new one every time
if (alchemium.io.fileExists("c:\\debug\\newdb.db")) {
    alchemium.io.deleteFile("c:\\debug\\newdb.db");
}

retVal = com.electricplum.sqlite.create({ "file": "c:\\debug\\newdb.db" });
                        
// The .ok property will be true if all went well
if (retVal.ok) {
    // Now connect.. For efficiency and concurrency issues, 
    // the sqlite extension is designed to connect
    // and then all subsequent calls will simply operate on the current connection.
    // This is different from the SQL Server extension, 
    // where we connect/disconnect on every method call
    retVal = com.electricplum.sqlite.connect({ "file": "c:\\debug\\newdb.db" });
    
    if (retVal.ok) {

        sqlStr = "CREATE TABLE IF NOT EXISTS Foo (F1, F2, F3)";
        retVal = com.electricplum.sqlite.executeNonQuery({ "sql": sqlStr });

        if (retVal.ok) {

            // Insert 100 rows into our new table
            for (var i = 1; i <= 100; i++) {
                sqlStr = "INSERT INTO Foo (F1, F2, F3) ';
                sqlStr = sqlStr + "VALUES (" + i + ",'Some text " + i + "', 'F3 Stuff')";
                retVal = com.electricplum.sqlite.executeNonQuery({ "sql": sqlStr });
                if (retVal.ok) {
                    console.log('Inserted ROW ' + i);
                }
            }

            // Now read some back
            sqlStr = "SELECT * FROM Foo WHERE F1 BETWEEN 42 AND 64";
            var results = com.electricplum.sqlite.getSQLResults({ "sql": sqlStr });

            if (results.ok) {
                results.data.forEach(function (el) {
                    console.log('F1:' + el.F1 + ' F2: ' + el.F2);
                });
            }
        }
    }
} else {
    // If there was an error, we can check the .lastError property for details
    console.log('Error creating Database Database: ' + retVal.lastError);
}

// Important, we need to explicity close SQLite databases
com.electricplum.sqlite.close();


Microsoft Excel Extension (ExcelExtension.dll)

The com.electricplum.excel extension exposes a simple API for creating and manipulating Excel Spreadsheets. The extension has 10 APIs:

  • isExcelInstalled()
  • addSheet()
  • removeSheet()
  • setCellValue()
  • getCellValue()
  • setCellFormula()
  • load()
  • save()
  • show()
  • hide()
The code sample below illustrates using it from JavaScript. Note how most functions require the sheetName argument.

var excelInstalled = com.electricplum.excel.isExcelInstalled({});

if (excelInstalled.installed) {
    
    // Show Excel
    com.electricplum.excel.show({});
    
    // Add a new sheet named foo
    com.electricplum.excel.addSheet({ "sheetName": "foo" });
    
    // Set a formula in a cell
    com.electricplum.excel.setCellFormula({ "sheetName": "foo", "row": 1, "col": 1, "value": "=10+10" });

    var args = {};
	
    // Set the value of 32 cells using row/col index
    for (var i = 0; i < 32; i++) {
    
    	args.sheetName = "foo"
    	args.row = i + 1;
    	args.col = 2;
    	args.value = "Hello Excel from row " + (i + 1);
    		
        com.electricplum.excel.setCellValue(args);
    }

    // Load an existing Workbook (Note the \\ in the filepath)
    com.electricplum.excel.load({"fileName": "c:\\debug\\test.xlsx"});
    

} else {

    console.log("Excel is not installed.");
}

COM Interop Extension (COMInteropExtension.dll)

The com.electricplum.cominterop extension allows JavaScript to call functions, properties and methods of COM objects to facillitate integration with legacy systems and APIs. The extension has two functions:

  • createObject()
  • callCOMObject()
One important limitation to note is there is no support for "ByRef" parameters -- the call will execute, but the value of the byref parameter can't be accessed. Also, please note that the maximum number of arguments that can be passed to a COM method/function call (via the args[] array) is 16. Last but not least, this is a very verbose and expensive API, so we suggest you use it judiciously :)

The code sample below illustrates using the COM Interop Extension from JavaScript. The example covers making a method call, a function call, property let, and property get.

// Create our object, we will pass the someCOMObject JavaScript object 
// in future calls to "callCOMObject()" to invoke properties and 
// methods of the COM object returned by createObject()
// progId is the same as the COM object's progID used when doing late-bound object creation 
// from .NET or classic COM

var someCOMObject = com.electricplum.cominterop.createObject({ "progId": "COMTest.Test" });     

// Standard COM method calls use callType: "method"
// The next line is equivalent the code: someCOMObject.foo(42, "FortyTwo"); 
// NOTE: the extension only supports up to 16 parameters per function call in the args[] array.

com.electricplum.cominterop.callCOMObject({ "object": someCOMObject, 
                                            "procName": "foo", 
                                            "callType": "method", 
                                            "args": [42, "FortyTwo"] });

// Access functions that have a return value with callType: "get"
// The next line is equivalent the code: var sum = someCOMObject.sum(1, 5, 12, 20);

var sum = com.electricplum.cominterop.callCOMObject({ "object": someCOMObject, 
                                                      "procName": "sum", 
                                                      "callType": "get", 
                                                      "args": [1, 5, 12, 20] });
console.log("sum = " + sum.value); // <= 38

// Property Lets use callType: "let"
com.electricplum.cominterop.callCOMObject({ "object": someCOMObject, 
                                            "procName": "someProperty", 
                                            "callType": "let", 
                                            "args": ['Hello from JavaScript'] });
                                            
// Property Lets use callType: "get"
var propVal = com.electricplum.cominterop.callCOMObject({ "object": someCOMObject, 
                                                          "procName": "someProperty", 
                                                          "callType": "get", 
                                                          "args": [] });

console.log("propVal = " + propVal.value); // <= 'Hello from JavaScript'



XBox 360 Game Controller Extension (GameControllerExtension.dll)

The com.electricplum.xboxController extension allows JavaScript to access any connected XBox 360 Game controllers. While there are official integrated Game Controller APIs in the works for Chromium, they are still not ready for production. Thus, Alchemium includes this extension for HTML5 game developers. The extension uses DirectX/XInput to present the game controller to JavaScript. Typical usage involves polling the controller in your game loop (typically using a game loop that employs requestAnimationFrame() for optimal performance and fidelity).

The code sample below illustrates using the GameController Extension from JavaScript.

 XBox 360 Controller Only

Note, this extension will only support XBox 360 controllers (wireless or wired). We suggest you test the state.connected return value to determine if a 360 controller is installed, and fallback gracefully to an alternate input scheme.


// ...
// ... some game loop where you would poll getControllerState() repeatedly ...
// ...
var results = com.electricplum.xboxController.getControllerState({ "controller": "1" });

if (!results.state.connected) {
	alert("No powered on 360 Controllers detected!);
	// ** Abort, fallback etc.. ** /
} 

console.log("Controller 1 - connected: " + results.state.connected");
// the following properties are returned in results.state:
console.log(results.state.ADown);
console.log(results.state.BDown);
console.log(results.state.XDown);
console.log(results.state.YDown);
console.log(results.state.BackDown);
console.log(results.state.StartDown);
console.log(results.state.LShoulderDown);
console.log(results.state.RShoulderDown);
console.log(results.state.LStickButtonDown);
console.log(results.state.RStickButtonDown);
console.log(results.state.DPadUp);
console.log(results.state.DPadDown);
console.log(results.state.DPadRight);
console.log(results.state.DPadLeft);
console.log(results.state.LTrigger);
console.log(results.state.RTrigger);
console.log(results.state.LThumbX);
console.log(results.state.LThumbY);
console.log(results.state.RThumbX);
console.log(results.state.RThumbY);

Alchemium provides a small set of JavaScript API's that facillitate interacting with the Alchemium runtime and the host operating system. We have kept the API surface small and simple on purpose. Our goal is for the community to build even richer API's using the Alchemim Extension Model. If you don't see something you need out of the box, it is trivial to add APIs if you have experience building class libraries with C# or VB.NET. In this section we'll break down each of the alchemium.* APIs by namespace.

alchemium.app namespace


alchemium.app.setTitle(title)
Set the title of the native application window. (Initially set by Alchemium based on the manifest.txt file.
Arguments
title (string)
alchemium.app.setDimensions(width, height)
Set the native application window dimensions. (Initially set by Alchemium based on the manifest.txt file.
Arguments
width (int) in pixels
height (int) in pixels
alchemium.app.setResizeMode(mode)
Set the window's border style. (Initially set by Alchemium based on the manifest.txt file.
Arguments
mode (int) 1 = Sizable, 2 = FixedSinge, 3 = Fixed Dialog
alchemiumSession.setSession(key, value)
Add data to the globally managed session store. More info on session can be found here
Arguments
key (string) Unique key identifying this value
lalue Value to store in session
alchemiumSession.getSession(key)
Function() Returns string data from the globally managed session store based on the key.
Arguments
key (string) Unique key identifying this value
alchemium.app.setMaximizeButtonMode(show)
Should the maximize button be shown in the window's non-client area. (Initially set by Alchemium based on the manifest.txt file.
Arguments
show (bool)
alchemium.app.setMinimizeButtonMode(show)
Should the minimize button be shown in the window's non-client area. (Initially set by Alchemium based on the manifest.txt file.
Arguments
show (bool)
alchemium.app.setBackButtonMode(enabled)
If true, the backspace key navigate to the previously viewed application page like a standard browser. (Initially set by Alchemium based on the manifest.txt file.
Arguments
enabled (bool)
alchemium.app.setF5RefreshMode(enabled)
If true, the F5 key will reload the current application page like a standard browser. (Initially set by Alchemium based on the manifest.txt file.
Arguments
enabled (bool)
alchemium.app.showAddressBar(show)
If true, Alchemium will display an address bar and bak/forward buttons at the top of the application's UI.
Arguments
show (bool)
alchemium.app.minimizeApp()
Minimize the application window.
alchemium.app.maximizeApp()
Maximize the application window.
alchemium.app.setFullScreenMode(enabled)
If true, puts the application in full screen mode (useful for Kiosk-based apps as well as immersive games). (Initially set by Alchemium based on the manifest.txt file.
Arguments
enabled (bool)
alchemium.app.showDevTools()
Show the developer tools. Only functional in Architect mode.
alchemium.app.exitApp()
Close the application window and quit.
alchemium.app.goBack()
Navigate backward. Note, this should be used instead of the window.history implementation.
alchemium.app.goForward()
Navigate forward. Note, this should be used instead of the window.history implementation.
alchemium.app.installedApplicationUpdate()
Function() returns true if the application was automatically updated when launched. More information on auto updating can be found here.
alchemium.app.isInternetAvailable()
Function() returns true the Internet can currently be accessed.
alchemium.app.getSourceFileName()
Function() returns the string representing the source file on disk for the active application page (Only available in Architect Mode).
alchemium.app.isReleaseBuild()
Function() returns true if the application is running in Release mode, and false if running in Architect mode.
alchemium.app.getManifestJSON()
Function() returns an Object representation of the manifest.txt file for the current application. Note the manifest also supports you adding "custom" key/values. More information on the manifest.txt file can be found here..

alchemium.app namespace callback functions

For performance and synchrony reasons, Alchemium will look for implementations of certain callback functions, and if you have provided an implementation for them, they will be invoked when various application events occur.


alchemium.app.windowMaximized()
Callback - If your code implements this function it will be called when the OS application window is maximized. To create the callback add the following code to your page (or include to use across multiple pages):

alchemium.app.windowMaximized = function () {
// Do something here 
}
alchemium.app.windowMinimized()
Callback - If your code implements this function it will be called when the OS application window is minimized.
alchemium.app.windowRestored()
Callback - If your code implements this function it will be called when the OS application window is restored to normal state from a minimized or maximized state.
alchemium.app.beforeNavigate()(currentPage, newPage)
Callback - If your code implements this function it will be called when your application is changing pages
Arguments
currentPage The URI of the current page.
newPage The URI of the page the application is navigating to.

alchemium.os namespace


alchemium.os.messageBox(msg, title, buttons, icon)
Function() Shows an OS native MessageBox to the user with optional buttons and icons, returns the user's response. For example:

var mbRet;
var msg = "What say you?";
var title = "My App";
var buttons = alchemium.const.mbButtons_AbortRetryIgnore;
var icon = alchemium.const.mbIcon_Question;

// Show the "Abort/Retry/Ignore messageBox
mbRet = alchemium.os.messageBox(msg, title, buttons, icon);

if (mbRet === alchemium.const.mbResult_Ignore) {
    alert("Don't Ignore Me!");

} else {
    alert("you answered " + mbRet);
}
                                
Arguments
msg (string) Descriptive text for message.
title (string) Title for message
buttons (int) The type of buttons to show. For convenience, constants have been defined in the alchemium.const.* namespace:
  • alchemium.const.mbButtons_AbortRetryIgnore
  • alchemium.const.mbButtons_OK
  • alchemium.const.mbButtons_OKCancel
  • alchemium.const.mbButtons_RetryCancel
  • alchemium.const.mbButtons_YesNo
  • alchemium.const.mbButtons_YesNoCancel
icon (int) The type of icon to show. For convenience, constants have been defined in the alchemium.const.* namespace:
  • alchemium.const.mbIcon_Yes
  • alchemium.const.mbIcon_Error
  • alchemium.const.mbIcon_Exclamation
  • alchemium.const.mbIcon_Hand
  • alchemium.const.mbIcon_Information
  • alchemium.const.mbIcon_None
  • alchemium.const.mbIcon_Question
  • alchemium.const.mbIcon_Stop
  • alchemium.const.mbIcon_Warning
Returns
Return Value (int) The input option chosen by the user. For convenience, constants have been defined in the alchemium.const.* namespace:
  • alchemium.const.mbResult_Abort
  • alchemium.const.mbResult_Cancel
  • alchemium.const.mbResult_Ignore
  • alchemium.const.mbResult_No
  • alchemium.const.mbResult_None
  • alchemium.const.mbResult_OK
  • alchemium.const.mbResult_Retry
  • alchemium.const.mbResult_Yes
alchemium.os.shellExecute(fileName)
Open fileName with the OS application associated with the file's extension.
Arguments
fileName (string)
alchemium.os.runExternalProcess(exeName, arguments, runHidden, waitForExit)
Launch the process exeName.
Arguments
exeName (string) Process to execute
arguments (string) Command line arguments to pass to process.
runHidden (bool) If true, hides the launched process' application window.
waitForExit (bool) If true, runs the process synchronously. Control will not return to the JavaScript calling code until the process is closed. (WARNING use with care!)
alchemium.os.getRegistryValue(keyName, valueName)
Function() returns value of requested registry key. For example:
var regVal = alchemium.os.getRegistryValue("HKEY_CURRENT_USER\\Software\\MyApp", "MyValue")
alert("Registry value: " + regVal);
Arguments
keyName (string) Name of the registry key to read.
valueName (string) The name of the value to read from the "keyName" registry key.
alchemium.os.setRegistryValue(keyName, valueName, valueToSet)
Set value of a registry key. For example:
alchemium.os.setRegistryValue("HKEY_CURRENT_USER\\Software\\MyApp", "MyValue", "Some value")
Arguments
keyName (string) Name of the registry key to read.
valueName (string) The name of the value we'll be writing to.
valueToSet (string) The value we will set "valueName" to.
alchemium.os.subscribeToProcessChannel(channel)
Used for inter-process communication between your Alchemium applications. In order to begin receiving messages on this channel you must implement a handler like so:

//Listen on channel 'foo'
alchemium.os.subscribeToProcessChannel("foo");
	
// When another app broadcasts a message to channel 'foo', our handler will be invoked
alchemium.os.processMessageReceived = function (channel, msg) {
    alert('Received msg on channel = ' + channel + ', msg = '  + msg);
}
Arguments
channel (string) The channel to listen on. When other processes broadcast a message to this channel your application's implementation of alchemium.os.processMessageReceived() will be invoked if it exists.
alchemium.os.unSubscribeFromProcessChannel(channel)
Used for inter-process communication between your Alchemium applications. After an unsubscribe, your process will no longer receive messaages broadcasted to channel.
Arguments
channel (string) The channel to unsubscribe from.
alchemium.os.broadcastProcessMessage(channel, message)
Used for inter-process communication between your Alchemium applications. This method will send the string message to any other Alchemium applications that have subscribed to channel via the alchemium.os.subscribeToProcessChannel() method.

Note, you will not receive messages from your own broadcastProcessMessage() call, even if you are listening on the channel.

 Tip: Use JSON.stringify() and JSON.parse() together to broadcast objects from process to process.

Arguments
channel (string) The channel to broadcast to broadcast to.
message (string) The string message to send.

alchemium.io namespace


alchemium.io.fileExists(fileName)
Function() Returns true if fileName exists, false if not.
Arguments
fileName (string) Full path to file to check.
alchemium.io.directoryExists(directoryName)
Function() Returns true if directoryName exists, false if not.
Arguments
directoryName (string) Full path to directory to check.
alchemium.io.deleteFile(fileName)
Deletes file fileName permanently.
Arguments
fileName (string) Full path to file to delete.
alchemium.io.readAllText(fileName)
Function() Returns string contents of file fileName.
Arguments
fileName (string) Full path to file to read.
alchemium.io.writeAllText(fileName, text)
Writes the string text to file fileName.
Arguments
fileName (string) Full path to file to read.
text (string) String of text to write.
alchemium.io.chooseFile(title, initialDir, filters)
Function() Shows the OS "Open File Dialog" and returns string with the full path of the file name selected. The dialog's file types dropdown will be populated by parsing the filter passed in.. For example:

var title = "Select a file";
var filter = "All Files (*.*)|*.*|Text files (*.txt)|*.txt";
var initDir = "c:\";
var file = alchemium.io.chooseFile(title, initDir, filter);
alert("You chose: " + file);	    					
	    			
Arguments
title (string) Descriptive text for dialog.
initialDir (string) Directory to start in.
filters (strings) Pipe delimited list of filter definitions (see the example above).
alchemium.io.chooseFolder(description)
Function() Shows OS "Select Folder" dialog and returns the string name of the folder the user selected.
Arguments
description (string) Descriptive text to show in the dialog.