-
Notifications
You must be signed in to change notification settings - Fork 41
Using .NET in Tint
- Download the current binaries for Tint from our github releases.
- The runtime can be executed by the command or powershell prompt (e.g.,
tint some.js
). - Import your DLL's (see below) or use any built in .NET CLR, including WPF or Winforms.
- Integrate or use any node library using npm.
While its fine for users to deal with any (and all of) these frameworks combined, only WPF should be used within Tint SDK as WinForms/MFC are not DPI aware and return in-accurate bounds, unscaled text, and non-conforming accessibility settings. For example; the WorkArea calculations through WinForms and WFC (getclientworkarea) do not factor in high-DPI and produce twice the size of values as WPF which is DPI aware.
You can use .NET Classes, Assemblies (DLL's) (both built in and external) with Tint. The language bridge exists at process.bridge.dotnet and is globally (always) available. The language bridge supports:
- Ability to import any managed C (idiomatic), C# or C++ symbol (and use it)
- Import any .NET Assembly (either built-in or by path)
- Any .NET or managed Class (instantiate or build your own)
- Properties, and Fields (set/get)
- WinForms / WPF and MFC Controls (The application loop GetMessage/Translate/Dispatch is handled for you).
- Static/instance methods or functions
- Built-in types (uint, DWORD, struct, etc)
Import a common assembly contained in any DLL search path;
process.bridge.dotnet.import('System.Windows.Forms');
or from a dll assembly file by a specific path;
process.bridge.dotnet.import('C:\\my\\path\\MyAssembly.dll');
The subsequent loaded classes (consts, enums, etc) are loaded onto process.bridge.dotnet. For example, if you wanted to use System.Windows.Forms.Form, you would use process.bridge.dotnet.import('System.Windows.Forms'); then the class is available at its fully qualified namespace path: process.bridge.dotnet.System.Windows.Forms.Form.
C#/C++ (managed) .NET classes are exactly like Javascript classes. Static methods are on the class, instance methods are on the prototype (e.g., you need to use new Form() taking from the example above). When you create a JS object from the class, you're creating a real .NET object, the constructor in javascript calls the constructor in .NET. You can execute any method, field, property and pass in JS functions for delegates (this is handled automatically for you, no need to worry about types).
In addition Javascript manages your garbage collection. You do not need to explicitly dispose (just as .NET) any of the classes. Just loose the reference and its recollected by .NET's CLR and Javascript's V8.
To create new objects in javascript you can use the bridge to define a new object. All objects must inherit (or extend) from a previous object, therefore you'll need to pick a base class, System.Object will do fine.
$ = process.bridge.dotnet; // for brevity.
var protoClass = $.System.Object.extend('MyNewClass'); // creates a new class "template"
protoClass.addMethod(
"myMethod", // The method name
false, // static or instance, true = static, false = instance,
true, // public=true, private = false, protected does not exist in runtime.
false, // whether to override an existing method name.
$.System.Boolean, // the return type, lets go with true/false.
[ $.System.String ], // The argument types it takes as an array.
function(someString) { // Some javascript function to exec when myMethod is called
console.log(someString);
return false; // must return type "System.Boolean"
}
);
var MyNewClass = protoClass.register(); // create a new REAL class.
// Now we can create a new instance:
var inst = new MyNewClass();
inst.myMethod('This is a c++ DOT net class, but in JS!');
The proto class or class "template" has the following methods, once you're finished with modifying the class you can register it with the register() method. The register method returns back the new .NET class.
var ProtoClass = process.bridge.dotnet.System.Object.extend(className)
ProtoClass.addConstructor = function(public, types, callback)
ProtoClass.addMethod = function(name, static, public, override, retType, types, callback)
ProtoClass.addProperty = function(name, static, public, readOnly, propType, value)
ProtoClass.addField = function(name, static, public, readOnly, propType, value)
ProtoClass.register = function() // returns the new .NET class.
Instead of using the C# event syntax of SomeObject.Event += Delegate
in javascript you can either use the .NET delegate class to manually create a delegate and assign it to the event (just as you would in C++) or you can use the shortcut provided by the language bridge: addEventListener
. This takes two parameters, the first is the name of the event, the second is the callback function to execute on the event. The callback function (when the event occurs) is executed and passed two arguments, the .NET Object that caused the event (sender) as a System::Object
and second, the base System::EventArgs
that holds the arguments to the callback.
$ = process.bridge.dotnet; // done for brevity...
$.import('System.Windows');
var window = new $.System.Windows.Window();
// Implements the MouseDown event on System.Windows.Window class in .NET
window.addEventListener('MouseDown', function(sender, eventargs) {
console.log('mouse down!');
});
Note, you can use addEventListener for any event, regardless of its type signature (this is automatically resolved via reflection).
The main event loop for the application (note, NOT winproc or Window message loop) is handled and dispatches messages to all WinForms, MFC and WPF windows created. While you cannot EASILY intermix controls between WPF/MFC/WinForms there's no restrictions on one window being MFC+GDI, and another being WPF or WinForms. Tint is compatible with any creation method. Note that MFC may be more difficult as reflection is not available and syntax requires using the FFI bridge rather than .NET assembly imports.
```Javascript require('Bridge'); $ = process.bridge.dotnet; $.import("System.Windows.Forms"); $.import("System.Drawing"); var Form = $.System.Windows.Forms.Form; var Button = $.System.Windows.Forms.Button; var Point = $.System.Drawing.Point;// Create a new instance of the form. var form1 = new Form(); // Create two buttons to use as the accept and cancel buttons. var button1 = new Button (); var button2 = new Button ();
// Set the text of button1 to "OK".
button1.Text = "OK";
// Set the position of the button on the form.
button1.Location = new Point(10,10);
// Set the text of button2 to "Cancel".
button2.Text = "Cancel";
// Set the position of the button based on the location of button1.
button2.Location = new Point (button1.Left, button1.Height + button1.Top + 10);
// Set the caption bar text of the form.
form1.Text = "My Dialog Box";
// Display a help button on the form.
form1.HelpButton = true;
// Define the border style of the form to a dialog box.
form1.FormBorderStyle =
### .NET Common Errors
* If you receive `System.BadImageFormatException` when importing, you're most likely importing a Win32 classic DLL.