1

I have a console application that needs to send a data to a Google Extension created by me also.

This is the manifest.json file:

{
  "manifest_version": 2,

  "name": "Busca Cliente Lipigas",
  "description": "Esta extensión permite recibir un número de teléfono desde el servidor DDE y realizar la búsqueda del cliente en la página Web de Lipigas.",
  "version": "1.0",

  "permissions": [
    "tabs",
    "nativeMessaging"
  ],

  "icons" : { "16": "img/icon16.png",
              "48": "img/icon48.png",
              "128": "img/icon128.png" },

  "background": {
    "scripts": ["main.js"],
    "persistent": false
    }

}

This is the background page:

var clientSearchPage;
var clientEditPage;

/**
 * Listens for the app launching then creates the window
 *
 * @see https://developer.chrome.com/apps/app_runtime
 * @see https://developer.chrome.com/apps/app_window
 */

console.log('Extensión iniciada.');
var port = chrome.runtime.connectNative('com.xxx.yyy');
console.log('Escuchando en el puerto ' + port);
port.onMessage.addListener(function (msg) {
    console.log("Se recibió el comando " + msg);

    port.postMessage({ status: processCommand(request.comando) });
});

// event logger
var log = (function () {
    var logLines = [];
    var logListener = null;

    var output = function (str) {
        if (str.length > 0 && str.charAt(str.length - 1) != '\n') {
            str += '\n'
        }
        logLines.push(str);
        if (logListener) {
            logListener(str);
        }
    };

    var addListener = function (listener) {
        logListener = listener;
        // let's call the new listener with all the old log lines
        for (var i = 0; i < logLines.length; i++) {
            logListener(logLines[i]);
        }
    };

    return { output: output, addListener: addListener };
})();

function processCommand(cmd) {
    var cmd = line.split(/\s+/);
    try {
        switch (cmd[0]) {
            case 'Phone':
                setPhone(cmd[1]);
                return '+OK-Phone';
                break;
            case 'SetClientPage':
                clientEditPage = cmd[1];
                return '+OK-SetClientPage';
                break;
            case 'SetSearchPage':
                clientSearchPage = cmd[1];
                return '+OK-SetSearchPage';
                break;
            default:
                return '+ERR-Comando No Encontrado';
        }
        //tcpConnection.sendMessage(Commands.run(cmd[0], cmd.slice(1)));
    } catch (ex) {
        return '+ERR-Comando No Procesado'
    }
}

function setPhone(phone) {
    log.output('Se recibió llamada desde el teléfono ' + phone + '. Refrescando página.');
    /*
    chrome.runtime.sendMessage({ phone: phone }, function (response) {
        // los valores de respuesta válidos son:
        //   -1: búsqueda en página nueva
        //   -2: búsqueda en página existente
        var tipoBusqueda = '';
        switch (response) {
            case '-1':
                tipoBusqueda = 'nueva'; break;
            case '-2':
                tipoBusqueda = 'existente'; break;
        }
        if (tipoBusqueda == '')
            console.log('No hubo comunicación con la extensión cliente.');
        else
            console.log('Cliente con el teléfono ' + phone + ' fue buscado en una página ' + tipoBusqueda + '.');
    });
    */
    /*
    chrome.tabs.query({
    }, function (tabs) {
        var tabURL = tabs[0].url;
        console.log(tabURL);
    });
    */
}

This is the NativeMessage Host manifest file (com.xxx.yyy.json):

{
  "name": "com.xxx.yyy",
  "description": "Native Messaging API para el Servicio Windows",
  "path": "ConsolaDDE.exe",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://laanpfddmhkpefimbmmbhojppeefdkbb/"
  ]
}

The ID "laanpfddmhkpefimbmmbhojppeefdkbb" is the exact ID of the extension I saw after I installed it.

This code is in the Main method of Console application:

            DataHelper.NativeMessage message = new DataHelper.NativeMessage("12345");
            message.Send();

Finally, this is the NativeMessage class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace DataHelper
{
    public class NativeMessage
    {
        public int Length;
        public byte[] Data;

        public string UTF8()
        {
            return Encoding.UTF8.GetString(Data);
        }

        public NativeMessage(int length, byte[] data)
        {
            Length = length;
            Data = data;
        }

        public NativeMessage(string utf8)
        {
            byte[] data = Encoding.UTF8.GetBytes(utf8);

            Length = data.Length;
            Data = data;
        }

        public string GetData()
        {
            return Encoding.UTF8.GetString(Data);
        }

        public NativeMessage Send(Stream s = null)
        {
            if (s == null)
            {
                s = Console.OpenStandardOutput();
            }

            s.Write(BitConverter.GetBytes(Length), 0, sizeof(int));
            s.Write(Data, 0, Length);
            s.Flush();

            return this;
        }

        public static NativeMessage Read(Stream s = null)
        {
            if (s == null)
            {
                s = Console.OpenStandardInput();
            }

            byte[] i = new byte[sizeof(int)];
            s.Read(i, 0, sizeof(int));
            int len = BitConverter.ToInt32(i, 0);

            byte[] data = new byte[len];
            s.Read(data, 0, len);

            return new NativeMessage(len, data);
        }
    }
}

I have the doubt when the host application is run. This is an application that is intended to be in execution all the time (finally, it will become a Windows Service).

To configure the host application, I have added this to the Windows registry:

REG ADD "HKLM\Software\Google\Chrome\NativeMessagingHosts\com.xxx.yyy" /ve /t REG_SZ /d "%~dp0com.xxx.yyy.json" /f

The process I followed is to add the Chrome extension and then execute the console application that immediately tries to send a message to the extension. I expect a log to be shown in console Window when the message is received.

EDIT:

Now, when I install Google Chrome extension, the host process is started, but I cannot send a message to the extension yet. I am using this piece of code:

        DataHelper.NativeMessage message = new DataHelper.NativeMessage(String.Concat("{ command: Phone, parameter: ", e.Telefono, " }"));
        message.Send();

But when the event is called in the extension, by mean of this listener:

port.onMessage.addListener(function (msg) {
    console.log("Se recibió el comando " + msg.command + ' con el parámetro ' + msg.parameter);

    port.postMessage({ status: processCommand(msg.command + ' ' + msg.parameter) });
});

Both msg.command and msg.parameter are undefined.

jstuardo
  • 3,901
  • 14
  • 61
  • 136
  • Host app is a console application developed using Visual Studio so I am able to debug. What I see is that when I write to Stdout, data appears in console window, and it is not redirected to the extension. This seems logical for me. There might be several applications that sends and receives data using Stdout and Stdin. – jstuardo Aug 29 '16 at 21:02

1 Answers1

0

Please be aware in the mechanism of Native Messaging, the communication is started by the extension. It is Chrome that starts the host in a separate process then they can communicate with each other using stdin and stdout.

So at the first glance, your problem might be you didn't start the communication in the extension side, which means calling port.postMessage() outside the onMessage handler.

Haibara Ai
  • 10,703
  • 2
  • 31
  • 47
  • Thanks, you were right, but another problem I had was that I needed to use full path to the host executable and besides, double backslash in the path. I have updated the question. – jstuardo Aug 30 '16 at 00:27
  • @jstuardo, your original post looks a little confusing, but from above comment, which part do you mean you need to use full path? The manifest file or anything else? If the former, it can be relative to the manifest file – Haibara Ai Aug 30 '16 at 00:34
  • Yes it can be relative, but the problem I have now, is concerning message passing using JSON format. String I am passing, it is not being recognized by the exntension. – jstuardo Aug 30 '16 at 00:41
  • @jstuardo, I suggest you take a look at this sample http://stackoverflow.com/questions/30880709/c-sharp-native-host-with-chrome-native-messaging, it's really too detailed for us to debug such questions. – Haibara Ai Aug 30 '16 at 00:52