Использование Console.ReadKey() после вызова AttachConsole(-1) приводит к зависанию приложения на ReadKey ()

В настоящее время я стараюсь изо всех сил иметь одно приложение, которое можно использовать через командную строку или через приложение Windows Form. Это приложение также будет использоваться как услуга. По понятным причинам (например, переписывание кода и отслеживание изменений в двух приложениях) я хочу создать только одно приложение.

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

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyApplicationSpace
{
    static class Program
    {
        #region Private class APIs
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool AttachConsole(int pid);

        [DllImport("kernel32")]
        private static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool FreeConsole();
        #endregion

        #region Constructor
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        private static void Main(string[] args)
        {
            if (args.Contains("-service"))
            {
                ServiceBase[] servicesToRun;
                servicesToRun = new ServiceBase[]
                {
                new MyServiceClass()
                };

                if (Environment.UserInteractive)
                {
                    if (!AttachConsole(-1)) AllocConsole();

                    RunInteractive(servicesToRun);

                    FreeConsole();
                    SendKeys.SendWait("{ENTER}");
                }
                else
                    ServiceBase.Run(servicesToRun);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
        #endregion

        #region Private class functions
        private static void RunInteractive(ServiceBase[] servicesToRun)
        {
            Console.WriteLine("Services running in interactive mode.");
            Console.WriteLine();

            MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (ServiceBase service in servicesToRun)
            {
                Console.Write("Starting {0}...", service.ServiceName);
                onStartMethod.Invoke(service, new object[] { new string[] { } });
                Console.Write("Started");
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Press any key to stop the services and end the process...");
            Console.WriteLine("BEFORE ReadKey");

            File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "error.log", "BEFORE ReadKey");
            try
            {
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "error.log", ex.Message);
            }
            File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "error.log", "AFTER ReadKey");

            Console.WriteLine("AFTER ReadKey");
            Console.WriteLine();

            Console.WriteLine("Continuing...");

            MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
            Console.WriteLine("onStopMethod is null = " + (onStopMethod == null));

            Console.WriteLine("Foreach service in service to run count:" + servicesToRun.Count());
            foreach (ServiceBase service in servicesToRun)
            {
                Console.Write("Stopping {0}...", service.ServiceName);
                onStopMethod.Invoke(service, null);
                Console.WriteLine("Stopped");
            }

            Console.WriteLine("All services stopped.");
            // Keep the console alive for a second to allow the user to see the message.
            Thread.Sleep(1000);
        }
        #endregion
    }
}

Проблема возникает, когда я пытаюсь позвонить Console.ReadKey(), Программа, кажется, зависает или просто выходит в некоторой степени. Например, когда я запускаю его из командной строки, он запускается, как ожидалось, а затем показывает "Нажмите любую клавишу, чтобы остановить службы и завершить процесс...", а также "ПЕРЕД ReadKey". Затем, как только я ударил [ENTER] Консоль просто возвращается к командной строке по умолчанию. Тем не менее по какой-то причине приложение по-прежнему отображается как запущенное в диспетчере задач. Кажется, будто это зависает.

Если я изменю тип приложения на console application все работает как положено и выглядит великолепно. Но мне нужно построить его как windows application, Я думаю, что проблема использует AttachConsole(-1) это не то же самое, что создать его как консольное приложение.

1 ответ

В этом заслуга Ганса. Я не уверен, почему он удалил свой ответ, но я бы хотел, чтобы он этого не сделал.

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

Он предложил мне сделать одну из двух вещей.

  1. Создать небольшое приложение "my app name.com" отдельно от моего приложения "my app name.exe" и пусть он сам создаст новое командное окно для запуска сервиса.

  2. Используйте Windows start команда для запуска приложения вместо того, чтобы пытаться запустить его нормально.

Я выбираю метод лестниц. С помощью переключателя ожидания он заставляет командный процессор ждать, пока приложение не завершит работу, пока оно не попытается снова захватить нажатия клавиш. Обратите внимание на третий параметр при запуске start, это "" что две двойные кавычки, чтобы передать пустой параметр после /wait пары. Это необходимо для того, чтобы передать ваши параметры после запуска приложения.

До

C:\"my app name.exe" -сервис

После

C:\start /wait "" "my app name.exe" -сервис

Другие вопросы по тегам