Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4406
Т.е.
1) запустилась консоль/ запустилась main()
2) запустились дела
3) зарядились события
4) события ловятся и пишут в консоль
Console.WriteLine("Я тут. Дела идут.")

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

Примитивно
            While (bДелаИдут = True)
               Application.DoEvents() 'опционально
            End While

Чревато "загрузкой процессора"
Можно еще засунуть
           Console.ReadLine()

(типа нажал Enter - вышел)

Конкретно: создаем задание факса для Windows Fax Server и его тут же и отслеживаем через события objFaxServer,
надоело отслеживать, "стукнули" по консоли и вышли (оно от этого выполняться не перестанет).
(Через GUI отслеживается пока открыта форма, теперь надо сделать скупо через консоль, цикл или таймер как таковой не нужен, все через события в модуле, но надо чтоб main не завершалась)

По хорошему еще б обратное управление процессом через консоль
Команды Cancel/Delete, Pause, Resume (в любой момент).
31 май 19, 23:34    [21899282]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
hVostt
Member

Откуда:
Сообщений: 15834
Дмитрий77,

Запускаешь задачу в потоке, добавляешь в Continuation принудительный выход из программы. Пока задача выполняется работаешь с консолью стандартным образом, прокидываешь внутрь задачи команды через события. Вроде всё очевидно.
1 июн 19, 01:52    [21899299]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
hVostt
Member

Откуда:
Сообщений: 15834
Дмитрий77,

вот простейший пример:

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // для принудительной отмены работы
                var cts = new CancellationTokenSource();
                // запускаем задачу в фоне
                var task = Task
                    // передаём токен для отмены работы
                    .Run(() => DoWorkAsync(cts.Token))
                    // по окончанию работы нужно принудительно выйти из приложения
                    .ContinueWith(t => Environment.Exit(0));

                var input = string.Empty;
                // работаем  с вводом от пользователя
                while (true)
                {
                    switch (input?.ToLower())
                    {
                        // если ввести "c", то выйти
                        case "c":
                            Console.WriteLine("Canceled");
                            cts.Cancel();
                            break;
                        // если ввести "p", поставить на паузу
                        case "p":
                            Console.WriteLine("Paused");
                            mrw.Reset();
                            break;
                        // если ввести "r", продолжить работу
                        case "r":
                            Console.WriteLine("Resets");
                            mrw.Set();
                            break;
                        // вывести справку
                        default:
                            Console.WriteLine("type [c]ancel, [p]ause, [r]eset: ");
                            break;
                    }
                    input = Console.ReadLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        // событие для ручного управления работой
        private static ManualResetEvent mrw = new ManualResetEvent(true);

        // метод, выполняющий работу
        static async Task DoWorkAsync(CancellationToken ct)
        {
            // конечное кол-во итераций для проверки выхода по окончанию работы
            var counter = 10;
            // всегда проверяем, не поступила ли команда завершить работу
            while (!ct.IsCancellationRequested && --counter > 0)
            {
                mrw.WaitOne();
                // делаем какую-то работу
                Console.WriteLine("im working");
                await Task.Delay(1000, ct);
            }
        }
    }
1 июн 19, 02:31    [21899303]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4406
hVostt,
сложно что-то. И Task-и кажется отсутствуют в .Net 2.0 (у меня дублированные exe Net 4.5/2.0)

У меня "постановка/запуск задачи" и инициализация COM-событий делается в потоке Main()

Решение нарыл.
Application.Run()

(ну я так понял это эквивалент стандартной петли обработки сообщений, которая делается в C++, процессор не "грузится")

События сыплются, c Console.WriteLine("Я тут. Дела идут.") проблем нет.
Консоль не закрывается.

Для автозавершения и корректного продвижения в конец Main() из соответствующих событий достаточно сделать
Application.Exit()
либо
Application.ExitThread()

Уж не знаю чего правильнее, но подозреваю для моего случая правилен любой вариант.
Типа так
  Private Sub g_objFaxServer_OnOutgoingJobRemoved(pFaxServer As FAXCOMEXLib.FaxServer, bstrJobId As String) Handles g_objFaxServer.OnOutgoingJobRemoved
    If (fJob.Id <> "") AndAlso (bstrJobId = fJob.Id) Then
      AddSendFaxDebugLog("EVENT: OnOutgoingJobRemoved (JobId=" & bstrJobId & ")...")

      If bConsole Then Application.Exit()

      If fJob.bUseFaxOutgoingMessage = False Then
        If bConsole = False Then FormTrack.ProcessOnOutgoingMessageRemoved()
      End If
    End If
  End Sub


Остается вопрос с "управлением", уж не знаю можно ли при такой примитивной "конструкции",
но он изначально в моем "техзадании" не стоял (подумалось а че бы нет).
Основная задача "консоли", именно удержать процесс в напр. автоматическом последовательном режиме бат-файла.
А для управления уже сделан GUI-режим с кнопочками и свистелками (аж с найтивным Ribbon UI, рука набита).
1 июн 19, 04:05    [21899307]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
hVostt
Member

Откуда:
Сообщений: 15834
Дмитрий77
сложно что-то. И Task-и кажется отсутствуют в .Net 2.0 (у меня дублированные exe Net 4.5/2.0)


.NET 4.0 поддерживается даже на XP

https://docs.microsoft.com/ru-ru/dotnet/framework/get-started/system-requirements

версии 2.0 уже 15 лет почти стукнуло. зачем страдать? )


Дмитрий77
Остается вопрос с "управлением", уж не знаю можно ли при такой примитивной "конструкции",


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

Для управления я уже привёл код, даже если без тасков и в 2.0 есть BackgorundWorker и ThreadPool, [url=]https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.manualresetevent?view=netframework-2.0сигнальное событие[/url], которое в моём примере всё также актуально и для старого фреймворка.
2 июн 19, 01:09    [21899667]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать незакрытие "Консольного приложения", чтоб main() не выходила  [new]
hVostt
Member

Откуда:
Сообщений: 15834
сигнальное событие
2 июн 19, 01:10    [21899668]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить