Могу ли я выполнить код в существующем процессе?

У меня есть приложение, которое работает и постоянно отображается на значке в системном трее. Он гарантирует, что это единственный запущенный экземпляр моего приложения, запустив некоторый код, использующий мьютекс @Global.

Из-за ограничений стороннего поставщика единственный (разумный) способ, которым я могу интегрироваться с одной частью приложения поставщика, - это указать в файле конфигурации, что вызывается произвольный исполняемый файл командной строки. Параметры, которые меня интересуют, автоматически добавляются в исполняемый файл, который я указываю.

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

Мне интересно, есть ли способ сделать этот псевдокод.

    static void Main(string[] args)
    {
        if (isrunningcommandLine)
        {
            ConnectToAlreadyRunningProcessAndPassInfo(args); // find already running process by its process name and somehow pass the command line params
            KillProgram();
        }
        else
        {
            CheckGlobalMutexAndStart();
        }
    }

По сути, если я запускаю через командную строку, подключаюсь к уже запущенному глобальному процессу и передаю ему некоторые данные.

Я контролирую код, который будет клиентом и сервером, это фактически один и тот же проект.


person benstpierre    schedule 18.02.2015    source источник
comment
Внедрение поведения в другой процесс/окно в основном запрещено, но не невозможно, поскольку мы делаем это все время, используя пространство имен UITesting, найденное здесь: msdn.microsoft.com/en-us/library/ Существуют и другие способы, но, как вы упомянули, все, что я знаю, требует, чтобы процесс работал - чтобы каким-то образом узнать о чем-то, что изменяет его поведение. В частности, в C++ существует набор классов, известных как класс IPC (Inter-Process-Communications), которые делают именно то, что вам нужно. Проблема как в клиенте, так и в другом pgm. должен быть готов к сообщениям.   -  person JWP    schedule 18.02.2015
comment
Вы написали приложение со значком в трее, которое должно взаимодействовать с другим вашим приложением через командную строку? При чем здесь серверный сокет? В чем именно проблема?   -  person David Ching    schedule 18.02.2015
comment
Да, это возможно. Все, что вам нужно, — это хорошо известная конечная точка для вашего работающего экземпляра, к которой можно подключиться при вызове его из командной строки. Есть несколько подходов к этому; вы можете, например, открыть конечную точку именованного канала WCF с фиксированным именем и передать это имя конечной точки в качестве аргумента вашему консольному приложению.   -  person Jeroen Mostert    schedule 18.02.2015
comment
Значок в трее взаимодействует с нашим веб-приложением через REST API и с решением стороннего поставщика через COM. В одном месте приложение поставщика не использует COM, а вызывает предварительно настроенный оператор командной строки при нажатии кнопки. Это плохой выбор дизайна в старой программе, мне просто нужно поработать в программном обеспечении поставщика ... Что я могу сказать, 90-е были сумасшедшим временем ...   -  person benstpierre    schedule 18.02.2015


Ответы (1)


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

  • Если нет, запустите сервер, который будет получать команды и управлять ими.
  • Если да, запустите клиент и просто отправьте команды на сервер.

Затем используйте TCP-соединение на локальном хосте для обмена сообщениями.

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;

    namespace Test42
    {
        internal static class Program
        {
            private static int PORT = 1337;

            private static void Main()
            {
                bool ok;

                // Try to build a mutex.
                var mutex = new Mutex(true, @"Test42", out ok);

                // If build is ok, we run as a server. 
                // Otherwise, the server is already running, so we run as a client.
                if (ok)
                {
                    var server = new MyServer(PORT);
                    server.Start();
                }
                else
                {
                    var r = new Random();
                    var message = "Ho Hey : " + r.Next(50);

                    var client = new MyClient();
                    client.Send(PORT, message);
                }
            }
        }

        internal class MyClient
        {
            /// <summary>
            /// Send a message to localhost.
            /// </summary>
            /// <param name="port">The port to connect.</param>
            /// <param name="message">The message to send.</param>
            public void Send(int port, string message)
            {
                var client = new TcpClient();
                var serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);

                client.Connect(serverEndPoint);

                using (var stream = client.GetStream())
                {
                    var messageBuffer = Encoding.Unicode.GetBytes(message);
                    var lengthBuffer = BitConverter.GetBytes(messageBuffer.Length);

                    // Send message length.
                    stream.Write(lengthBuffer, 0, lengthBuffer.Length);

                    // Send message.
                    stream.Write(messageBuffer, 0, messageBuffer.Length);

                    stream.Flush();
                }

                client.Close();
            }
        }

        internal class MyServer
        {
            private readonly int _port;

            public MyServer(int port)
            {
                _port = port;
            }

            public void Start()
            {
                Console.WriteLine("wait for messages");
                var thread = new Thread(ThreadStart);
                thread.Start();
            }

            private void ThreadStart()
            {
                var listener = new TcpListener(IPAddress.Any, _port);
                listener.Start();
                while (true)
                {
                    var client = listener.AcceptTcpClient();
                    var clientThread = new Thread(ClientThreadStart);
                    clientThread.Start(client);
                }
            }

            private void ClientThreadStart(object obj)
            {
                var client = obj as TcpClient;
                if (client == null) return;

                using (var stream = client.GetStream())
                {
                    const int lengthLength = sizeof(int) / sizeof(byte);

                    // Read the message length.
                    var lengthBuffer = new byte[lengthLength];
                    stream.ReadAsync(lengthBuffer, 0, lengthLength).Wait();
                    var messageLength = BitConverter.ToInt32(lengthBuffer, 0);

                    // Read the message.
                    var messageBuffer = new byte[messageLength];
                    stream.ReadAsync(messageBuffer, 0, messageLength).Wait();
                    var message = Encoding.Unicode.GetString(messageBuffer);

                    Console.WriteLine("Client says: " + message);
                }

                client.Close();
            }
        }
    }
person Orace    schedule 18.02.2015