2015-12-15 2 views
2

Итак, у меня есть рабочий пример Chrome Native Messaging, работающий с C#, и он отлично работает с приложением, а затем получает ответ. Однако мне действительно нужно сделать это, чтобы иметь возможность вызвать мое собственное приложение и отправить его на расширение chrome (для загрузки URL-адреса веб-сайта).Как получить доступ к приложениям Chrome для прослушивания приложения?

Проблема в том, что когда я вызываю свое приложение (консольное приложение) с аргументами, хром не прослушивает. Когда я впервые прослушиваю хром, он запускает мое приложение, и я больше не могу его отправлять, и если я начну его снова, хром не подключился к нему, поэтому ничего не произойдет.

В идеале я хочу назвать мое заявление, как:

nativeapplication.exe viewAccount ABCDEFG

и есть мое расширение, которое слушает запустить его метод viewAccount с этим аргументом ABCDEFG.

У меня это хорошая работа от chrome -> application -> chrome, но я хочу пойти other application (or command line with arguments) -> application -> chrome.

Это единственный способ сделать это, чтобы мое приложение выполнялось как услуга wcf или аналогично, а другое приложение отправило ему данные, а затем отправило сообщение на хром? Я бы хотел, чтобы мое приложение не сидело и не читалось из файла, или иным образом не использовало ресурсы во время «бездействия». Единственный экземпляр с WCF - лучший вариант, или я пропустил что-то простое?

Примечание. Примеры на языках, отличных от C#, являются точными, если его собственное приложение вызывает расширение, а не наоборот.

ответ

2

Ну я в конечном итоге происходит с одним приложением экземпляра, и используемый код для SingleInstance я нашел где-то (извините прошел так много сайтов ищет простейшим)

Законченное с помощью этого основного класса

/// <summary> 
/// Holds a list of arguments given to an application at startup. 
/// </summary> 
public class ArgumentsReceivedEventArgs : EventArgs 
{ 
    public string[] Args { get; set; } 
} 

public class SingleInstance : IDisposable 
{ 
    private Mutex _mutex; 
    private readonly bool _ownsMutex; 
    private Guid _identifier; 

    /// <summary> 
    /// Enforces single instance for an application. 
    /// </summary> 
    /// <param name="identifier">An _identifier unique to this application.</param> 
    public SingleInstance(Guid identifier) 
    { 
     this._identifier = identifier; 
     _mutex = new Mutex(true, identifier.ToString(), out _ownsMutex); 
    } 

    /// <summary> 
    /// Indicates whether this is the first instance of this application. 
    /// </summary> 
    public bool IsFirstInstance 
    { get { return _ownsMutex; } } 

    /// <summary> 
    /// Passes the given arguments to the first running instance of the application. 
    /// </summary> 
    /// <param name="arguments">The arguments to pass.</param> 
    /// <returns>Return true if the operation succeded, false otherwise.</returns> 
    public bool PassArgumentsToFirstInstance(string[] arguments) 
    { 
     if (IsFirstInstance) 
      throw new InvalidOperationException("This is the first instance."); 

     try 
     { 
      using (var client = new NamedPipeClientStream(_identifier.ToString())) 
      using (var writer = new StreamWriter(client)) 
      { 
       client.Connect(200); 

       foreach (var argument in arguments) 
        writer.WriteLine(argument); 
      } 
      return true; 
     } 
     catch (TimeoutException) 
     { } //Couldn't connect to server 
     catch (IOException) 
     { } //Pipe was broken 

     return false; 
    } 

    /// <summary> 
    /// Listens for arguments being passed from successive instances of the applicaiton. 
    /// </summary> 
    public void ListenForArgumentsFromSuccessiveInstances() 
    { 
     if (!IsFirstInstance) 
      throw new InvalidOperationException("This is not the first instance."); 
     ThreadPool.QueueUserWorkItem(ListenForArguments); 
    } 

    /// <summary> 
    /// Listens for arguments on a named pipe. 
    /// </summary> 
    /// <param name="state">State object required by WaitCallback delegate.</param> 
    private void ListenForArguments(object state) 
    { 
     try 
     { 
      using (var server = new NamedPipeServerStream(_identifier.ToString())) 
      using (var reader = new StreamReader(server)) 
      { 
       server.WaitForConnection(); 

       var arguments = new List<string>(); 
       while (server.IsConnected) 
        arguments.Add(reader.ReadLine()); 

       ThreadPool.QueueUserWorkItem(CallOnArgumentsReceived, arguments.ToArray()); 
      } 
     } 
     catch (IOException) 
     { } //Pipe was broken 
     finally 
     { 
      ListenForArguments(null); 
     } 
    } 

    /// <summary> 
    /// Calls the OnArgumentsReceived method casting the state Object to String[]. 
    /// </summary> 
    /// <param name="state">The arguments to pass.</param> 
    private void CallOnArgumentsReceived(object state) 
    { 
     OnArgumentsReceived((string[])state); 
    } 
    /// <summary> 
    /// Event raised when arguments are received from successive instances. 
    /// </summary> 
    public event EventHandler<ArgumentsReceivedEventArgs> ArgumentsReceived; 
    /// <summary> 
    /// Fires the ArgumentsReceived event. 
    /// </summary> 
    /// <param name="arguments">The arguments to pass with the ArgumentsReceivedEventArgs.</param> 
    private void OnArgumentsReceived(string[] arguments) 
    { 
     if (ArgumentsReceived != null) 
      ArgumentsReceived(this, new ArgumentsReceivedEventArgs() { Args = arguments }); 
    } 

    #region IDisposable 
    private bool disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (_mutex != null && _ownsMutex) 
      { 
       _mutex.ReleaseMutex(); 
       _mutex = null; 
      } 
      disposed = true; 
     } 
    } 

    ~SingleInstance() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    #endregion 
} 

И мое приложение C# в основном взяты из (C# native host with Chrome Native Messaging):

class Program 
{ 
    const string MutexId = "ENTER YOUR GUID HERE, OR READ FROM APP"; 

    public static void Main(string[] args) 
    { 
     using (var instance = new SingleInstance(new Guid(MutexId))) 
     { 
      if (instance.IsFirstInstance) 
      { 
       instance.ArgumentsReceived += Instance_ArgumentsReceived; 
       instance.ListenForArgumentsFromSuccessiveInstances(); 

       DoMain(args); 
      } 
      else 
      { 
       instance.PassArgumentsToFirstInstance(args); 
      } 
     } 
    } 

    private static void Instance_ArgumentsReceived(object sender, ArgumentsReceivedEventArgs e) 
    { 
     TryProcessAccount(e.Args); 
    } 

    // This is the main part of the program I use, so I can call my exe with program.exe 123 42424 to have it open that specific account in chrome. Replace with whatever code you want to happen when you have multiple instances. 

    private static void TryProcessAccount(string[] args) 
    { 
     if (args == null || args.Length < 2 || args[0] == null || args[1] == null || args[0].Length != 3) { return; } 
     var openAccountString = GetOpenAccountString(args[0], args[1]); 
     Write(openAccountString); 
    } 

    private static void DoMain(string[] args) 
    { 
     TryProcessAccount(args); 

     JObject data = Read(); 
     while ((data = Read()) != null) 
     { 
      if (data != null) 
      { 
       var processed = ProcessMessage(data); 
       Write(processed); 
       if (processed == "exit") 
       { 
        return; 
       } 
      } 
     } 

    } 

    public static string GetOpenAccountString(string id, string secondary) 
    { 
     return JsonConvert.SerializeObject(new 
     { 
      action = "open", 
      id = id, 
      secondary = secondary 
     }); 
    } 

    public static string ProcessMessage(JObject data) 
    { 
     var message = data["message"].Value<string>(); 
     switch (message) 
     { 
      case "test": 
       return "testing!"; 
      case "exit": 
       return "exit"; 
      case "open": 
       return GetOpenAccountString("123", "423232"); 
      default: 
       return 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))["data"]; 
    } 

    public static void Write(JToken data) 
    { 
     var json = new JObject 
     { 
      ["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(); 
    } 
} 
1

Вы не пропустите ничего простого: Native Messaging работает только, запустив новый процесс, он не может подключиться к существующему.

Однако вы можете развернуть экземпляр и сохранить его с помощью connectNative вместо sendNativeMessage для одного обмена. Затем этот экземпляр должен будет прослушать какое-то внешнее событие.

На очень высоком уровне это действительно может быть achieved by a single-instance application. У меня нет более конкретных рекомендаций для C#.

+0

ОК спасибо, я в конечном итоге завершить его прошлой ночью, как один экземпляр приложение и разместил мой код ниже. Просто хотел удостовериться, что я не делал что-то совершенно неправильно или что-то пропустил :) – John