C# native host with Chrome Native Messaging
Asked Answered
E

2

31

I spent a few hours today researching how to get Chrome native messaging working with a C# native host. Conceptually it was quite simple, but there were a few snags that I resolved with help (in part) from these other questions:

Native Messaging Chrome
Native messaging from chrome extension to native host written in C#
Very Slow to pass "large" amount of data from Chrome Extension to Host (written in C#)

My solution is posted below.

Encarnalize answered 17/6, 2015 at 1:3 Comment(0)
E
43

Assuming the manifest is set up properly, here is a complete example for talking to a C# host using the "port" method:

using System;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace NativeMessagingHost
{
   class Program
   {
      public static void Main(string[] args)
      {
         JObject data;
         while ((data = Read()) != null)
         {
            var processed = ProcessMessage(data);
            Write(processed);
            if (processed == "exit")
            {
               return;
            }
         }
      }

      public static string ProcessMessage(JObject data)
      {
         var message = data["text"].Value<string>();
         switch (message)
         {
            case "test":
               return "testing!";
            case "exit":
               return "exit";
            default:
               return "echo: " + message;
         }
      }

      public static JObject Read()
      {
         var stdin = Console.OpenStandardInput();
         var length = 0;

         var lengthBytes = new byte[4];
         stdin.Read(lengthBytes, 0, 4);
         length = BitConverter.ToInt32(lengthBytes, 0);

         var buffer = new char[length];
         using (var reader = new StreamReader(stdin))
         {
            while (reader.Peek() >= 0)
            {
               reader.Read(buffer, 0, buffer.Length);
            }
         }

         return (JObject)JsonConvert.DeserializeObject<JObject>(new string(buffer));
      }

      public static void Write(JToken data)
      {
         var json = new JObject();
         json["data"] = data;

         var bytes = System.Text.Encoding.UTF8.GetBytes(json.ToString(Formatting.None));

         var stdout = Console.OpenStandardOutput();
         stdout.WriteByte((byte)((bytes.Length >> 0) & 0xFF));
         stdout.WriteByte((byte)((bytes.Length >> 8) & 0xFF));
         stdout.WriteByte((byte)((bytes.Length >> 16) & 0xFF));
         stdout.WriteByte((byte)((bytes.Length >> 24) & 0xFF));
         stdout.Write(bytes, 0, bytes.Length);
         stdout.Flush();
      }
   }
}

If you don't need to actively communicate with the host, using runtime.sendNativeMessage will work fine. To prevent the host from hanging, simply remove the while loop and do Read/Write once.

To test this, I used the example project provided by Google here: https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/docs/examples/api/nativeMessaging

Note: I'm using Json.NET to simplify the json serialization/de-serialization process.

I hope this is helpful to somebody!

Encarnalize answered 17/6, 2015 at 1:3 Comment(8)
I'm searching this for Java but I can't find anywhere :/Compensate
@farukdgn Specifically, what is proving difficult to find? A Java implementation should be fairly similar.Encarnalize
Where's the connect? i tried to run it and the extension gives me "Native host has exited."Bayless
When initializing the connection from background script (chrome extension) - connection fails even though the host.exe opens up. "Failed to connect: Error when communicating with the native messaging host. " According to Google link it is because of wrong serialization/size declaration. Any clue?Stereometry
Why not just create a StreamWriter and write the string.Length and string? Why do you have to use WriteByte to write the int?Enshroud
Actually, why not just do stdout.Write(BitConverter.GetBytes(bytes.Length));?Enshroud
Just adding it here. Is there a way(an example) to communicate with multiple loaded chrome extension under chrome user profiles? Thanks in advanced.Clite
I know this is a while ago, but does this piece of code still work with .NET 8? or what framework did you use at the time? Because I can't get Console.OpenStandardInput to work in .NET 8's Windows Application anymore.Ladybug
P
0

You can also use regular http communication. And send messages using fetch or other js api. And host app will be regular web api project that runs on localhost. You also will need to enable cors policy in your web app. Maybe it's overkill for some cases and probably not as fast. But it is more transparent for most developers and works great in my project.

Pelting answered 13/11, 2022 at 21:56 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewMud

© 2022 - 2024 — McMap. All rights reserved.