4

I have a simple clientside javascript application. I want it to load a DLL file (for a SwipeReader CR100) and call functions from the DLL library from within the javascript code. The second is to add listeners to events fired by the SwipeReader, like DocumentRead or DocumentReadError and handle them in javascript.

So, I have 4 minor issues to solve:

  1. Load DLL in javascript (mainly Chrome V8 engine).
  2. Call function in DLL.
  3. Add listener to event fired in DLL.
  4. On callback with response object do something in JS (alert, console.log data)

Has anyone done this before or is this even possible?

Thank you in advance, Daniel.

Daniel Colceag
  • 190
  • 1
  • 3
  • 15
  • 1
    You can't load a `dll` with javascript in the browser (Unless you can find some settings which would completely disable all security and sandboxing, which I'm not sure, even then, would help). You could however, load the dll on your server, and have the javascript interact with the server (which in turn interacts with the dll). – Rob Jan 14 '16 at 13:54

2 Answers2

6

I've done it. The solution is to use EdgeJS as a bridge between NodeJS V8 and C# CLR. Edge loads the DLL and creates a communication channel between V8 and CLR, the messages are functions of the form Func<object, Task<object>> or function(payload, callback) that are marshalled between each language VM.

I'll post the code sample below:
C#

public abstract class NetWebSocket
{
    private Func<object, Task<object>>  SendImpl { get; set; }

    protected NetWebSocket(Func<object, Task<object>> sendImpl)
    {
        this.SendImpl = sendImpl;
    }

    protected abstract Task ReceiveAsync(string message);

    public Func<object, Task<object>> ReceiveImpl
    {
        get
        {
            return async (input) =>
            {
                Console.Out.WriteLine(input);
                await this.ReceiveAsync((string) input);
                return Task.FromResult<object>(null);
            };
        }
    }

    protected async Task SendAsync(string message)
    {
        await this.SendImpl(message);
        return;
    }
}

public class MyNetWebSocketImpl : NetWebSocket
{
    public CHello module;
    private string JSONCodelineDataRepr = "not set";

    public MyNetWebSocketImpl(Func<object, Task<object>> sendImpl) : base(sendImpl)
    {
        // do other stuff after calling the super class constructor  
        module = new CHello();
        module.DocumentReadEvent += this.DocumentReadEventHandler;
        module.DocumentReadErrorEvent += this.DocumentReadErrorEventHandler;
        // uncomment after the websocket communication works
        module.Start();
    }

    protected override async Task ReceiveAsync(string message)
    {
        // not really needed because only the NodeJS Server listens to C# .NET Server messages
        Console.WriteLine(message);
        if (message.Equals("shutdown"))
        {
            module.Close();
        }
        // not necessary (can comment the send function call)
        // if I eventually receive a message, respond with the JSON representation of the Patient ID Card
        await this.SendAsync("I received a message from you, but I'll ignore it and send you the Patient" +
                             " ID Card Data instead.. I'm a fish, so start phishing! PersonData = " +
                             JSONCodelineDataRepr);
        return;
    }

    private async void DocumentReadEventHandler(string args)
    {
        this.JSONCodelineDataRepr = args;
        await this.SendAsync(args);
    }

    private async void DocumentReadErrorEventHandler(string args)
    {
        await this.SendAsync(args);
    }
}

public class Startup
{
    
    public static MyNetWebSocketImpl ws;

    public async Task<object> Invoke(Func<object, Task<object>> sendImpl)
    {
        ws = new MyNetWebSocketImpl(sendImpl);
       
        return ws.ReceiveImpl;
    }
}

Javascript/NodeJS

(function(e,d,g,e){

var edge = require('edge'),
    http = require('http'),
    WebSocketServer = require('ws').Server,
    swipe = edge.func('./dlls/ActiveXCOM.dll');

var server = http.createServer(function(req,res){
    res.writeHead(200, {'Content-Type' : 'text/html'});
    res.end((
        function () { /*
            <!DOCTYPE html>
            <html>
            <head>
            </head>
            <body>
                <div id='jsonOutput'>
                </div>
                <script>
                    var ws = new WebSocket('ws://' + window.document.location.host);
                    
                    ws.onmessage = function (event) {
                        console.log(event.data);
                        var div = document.getElementById('jsonOutput');
                        div.innerHTML = event.data;
                    }

                    ws.onopen = function (event) {
                        // send something to the server
                        ws.send('I am the client from the browser calling you, the NodeJS WebSocketServer!');
                    }

                    ws.onclose = function (event) {
                        alert('websocket closing');
                    }

                    window.onbeforeunload = function myonbeforeUnload() {
                        return "Are you sure?";
                    }

                    window.onunload = function myonunload() {
                        confirm('Are you really sure?');
                        ws.close();
                        return "Are you really sure?";
                    }
                </script>
            </body>
            </html>
        */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]);
});

var wss = new WebSocketServer({server: server});

wss.on('connection', function(ws) {
    var sendImpl = function (message, callback) {
        console.log(message);
        ws.send(message);
        callback();
    };

    var receiveHandler = swipe(sendImpl, true); 

    ws.on('message', function (message) {
        receiveHandler(message);
    });

    ws.on('close', function close(){
        console.log('****************************The client disconnected!');
        receiveHandler('shutdown');
        delete receiveHandler;
    });
});

server.listen(process.env.PORT || 8080);
module.exports = this;
})();

I hope the implementation is clear. If you have any trouble understanding it, please don't hesitate to write to me.

Happy Coding!

[Don't listen to the naysayers!]

Community
  • 1
  • 1
Daniel Colceag
  • 190
  • 1
  • 3
  • 15
2

Call functions from the DLL library from within the javascript code.

No. You can't load a DLL inside JavaScript.

Why?

JavaScript is executed in the stack of the browser. To make anything available, you'll have to wire it up with the browser and then make it accessible; too much of work.

Work Around

You can have a client application written in say C# which connects to a JS websocket, then transfer the data. The WebSocket can check for specific chunks of data, and process it the way you want.

I have used it the way I have described in a project using a fingerprint scanner. Works great! If you add a little bit of Crypto, even better!

weirdpanda
  • 2,521
  • 1
  • 20
  • 31
  • I don't want any application to be installed on clientside except the CR100 Driver. I've already developed a C# application that can be installed on the client computer which uses the CR100 driver and starts up a WCF Json REST service that can be called to get the data from the SwipeReader. I want that Angular app that calls the REST service to use the driver itself (through a javascript module). First, I want it to work in plain javascript. One step at a time. I think it's kind of like how the navigator.getUserMedia gets starts the laptop webcam and captures video from it. – Daniel Colceag Jan 15 '16 at 14:31
  • Well, you can't use any `.dll` in JavaScript. Why not make the Angular app talk to the WCF app? – weirdpanda Jan 15 '16 at 14:34
  • that is already done. Angular calls that REST service and gets the ID Card data. I should be more specific next time.. 'I want that Angular app that calls the REST service to use the Driver (.dll file) itself (through a javascript module).' Sry, the angular app already connects to an application installed on the client machine which uses the webapp that exposes a json rest service and an endpoint to get the id card data. – Daniel Colceag Jan 15 '16 at 14:45
  • Oh, in which case, I am really sorry to tell you, but it's not possible. JS can't consume any context-specific binary. – weirdpanda Jan 15 '16 at 14:47
  • It is possible, and I've done it. Finally. The trick is to use a 3rd party library named EdgeJS by tjanczuk. You load the DLL and pass a function to the dll as a delegate function for the event handler. The DLL returns another delegate function to the DLL handler. It's somewhat a websocket implementation between CLR and V8. I'll post a sample below as an answer. – Daniel Colceag Jan 25 '16 at 14:38
  • 1
    Exactly. There is no native interface between JavaScript and .dll's as I said. I told you that, yes, it is possible, but the way you say, it isn't. :) And yeah, it'd be great if you post a sample! – weirdpanda Jan 25 '16 at 14:40
  • I was going to comment to your solution as well, thanks, it's kind of the same concept as you've described it, websocket communication was implemented in the final form to communicate between the browser and the nodejs service (websocket server). The next thing is to figure out how to use this edge module, in browser, not sure it's possible (yet), since it's a node module, not a client-side javascript module (??, correct or complete me). Thanks all for your help and support! – Daniel Colceag Jan 25 '16 at 14:57