2009-05-18 36 views
6

Có cách nào để ngăn ứng dụng .NET console không bị đóng không? Tôi có một ứng dụng theo mẫu này:Dừng ứng dụng bảng điều khiển .net bị đóng

while (true) 
{ 
    string x = Console.ReadLine(); 
    StartLongRunningTaskOnSeparateThread(x); 
} 

Vấn đề là có thể đóng cửa sổ điều khiển (và do đó cắt bỏ tác vụ chạy dài). Có một sự tương đồng của sự kiện Forms.OnClosing cho các ứng dụng giao diện điều khiển không?

EDIT - Tôi không cố gắng tạo ra thứ gì đó không thể giết được, chỉ có thể đưa ra một thông điệp cảnh báo e..g "này, tôi chưa xong. Bạn có chắc chắn muốn đóng tôi không?"

EDIT2 - Ngăn chặn thoát không đúng lúc thông qua nút 'x' quan trọng hơn việc chặn Ctrl-C (Tôi đã sử dụng Console.TreatControlCAsInput = true;). Giả sử cho mục đích này mà bất cứ ai bắn lên công việc quản lý muốn giết chương trình rất nhiều mà họ xứng đáng để có thể. Và người dùng cuối sẽ thấy cảnh báo hơn là vô tình hủy tác vụ chạy dài của họ.

+0

Mỗi EDIT2, trong trường hợp đó, chỉ cần xóa nút "X" khỏi cửa sổ. Xem câu trả lời được cập nhật của tôi bên dưới. – beach

+0

@beach thực hiện công việc một cách độc đáo. cảm ơn nhiều. – SillyMonkey

Trả lời

10

Đây là nỗ lực của tôi để giải quyết vấn đề này. Trình quản lý Tác vụ vẫn có thể đóng ứng dụng. Nhưng, suy nghĩ của tôi là cố gắng và phát hiện khi nó đang được đóng lại và sau đó khởi động lại nó. Tuy nhiên, tôi không thực hiện phần đó.

Chương trình sau sẽ phát hiện CTRL-C & & CTRL-BREAK và sẽ tiếp tục.

EDIT: Removed "X" Nút

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

namespace DoNotCloseMe 
{ 
    class Program 
    { 

     const string _title = "DO NOT CLOSE - Important Program"; 

     static void Main(string[] args) 
     { 

      Console.Title = _title; 

      IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle; 
      IntPtr hSystemMenu = GetSystemMenu(hMenu, false); 

      EnableMenuItem(hSystemMenu, SC_CLOSE, MF_GRAYED); 
      RemoveMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND); 

      WriteConsoleHeader(); 

      //This function only seems to be called once. 
      //After calling MainLoop() below, CTRL-C && CTRL-BREAK cause Console.ReadLine() to return NULL 
      Console.CancelKeyPress += (sender, e) => 
      { 
       Console.WriteLine("Clean-up code invoked in CancelKeyPress handler."); 
       Console.WriteLine("Key Pressed: {0}", e.SpecialKey.ToString()); 
       System.Threading.Thread.Sleep(1000); 
       MainLoop(); 
       // The application terminates directly after executing this delegate. 
      }; 

      MainLoop(); 

     } 

     private static void MainLoop() 
     { 
      while (true) 
      { 
       WriteConsoleHeader(); 
       string x = Console.ReadLine(); 
       if (!String.IsNullOrEmpty(x)) 
       { 
        switch (x.ToUpperInvariant()) 
        { 
         case "EXIT": 
         case "QUIT": 
          System.Environment.Exit(0); 
          break; 
         default: 
          StartLongRunningTaskOnSeparateThread(x); 
          break; 
        } 

       } 
      } 
     } 

     private static void StartLongRunningTaskOnSeparateThread(string command) 
     { 
      var bg = new System.ComponentModel.BackgroundWorker(); 
      bg.WorkerReportsProgress = false; 
      bg.WorkerSupportsCancellation = false; 

      bg.DoWork += (sender, args) => 
      { 
       var sleepTime = (new Random()).Next(5000); 
       System.Threading.Thread.Sleep(sleepTime); 
      }; 


      bg.RunWorkerCompleted += (sender, args) => 
      { 
       Console.WriteLine("Commmand Complete: {0}", command); 
      }; 

      bg.RunWorkerAsync(); 

     } 

     private static void WriteConsoleHeader() 
     { 
      Console.Clear(); 
      Console.WriteLine(new string('*', Console.WindowWidth - 1)); 
      Console.WriteLine(_title); 
      Console.WriteLine(new string('*', Console.WindowWidth - 1)); 
      Console.WriteLine("Please do not close this program."); 
      Console.WriteLine("It is maintaining the space/time continuum."); 
      Console.WriteLine("If you close it, Q will not be happy and you will be assimilated."); 
      Console.WriteLine(new string('*', Console.WindowWidth - 1)); 
      Console.WriteLine("Development Mode: Use \"EXIT\" or \"QUIT\" to exit application."); 
      Console.WriteLine(new string('*', Console.WindowWidth - 1)); 
     } 

     #region "Unmanaged" 

     [DllImport("user32.dll")] 
     static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable); 

     [DllImport("user32.dll")] 
     static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 

     [DllImport("user32.dll")] 
     static extern IntPtr RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags); 

     internal const uint SC_CLOSE = 0xF060; 
     internal const uint MF_GRAYED = 0x00000001; 
     internal const uint MF_BYCOMMAND = 0x00000000; 

     #endregion 
    } 
} 
+0

@SM - Như đã nêu trong câu trả lời. Nhưng tôi đã cho bạn một kế hoạch tấn công. ;) – beach

+0

@SM - Đã xóa nút "X". Task Manager vẫn có thể giết nó. – beach

+0

Nút "X" khá hiệu quả và vì mục đích của tôi, đó chỉ là thứ tôi cần. Cảm ơn. – aboy021

0

Tôi không biết về bất kỳ chức năng tương đương nào của Biểu mẫu.Đóng vai trò cho ứng dụng Bảng điều khiển. Tuy nhiên, ngay cả Forms.OnClosing không phải là một cách dễ dàng để ngăn chặn một ứng dụng đóng lại. Tôi có thể dễ dàng tìm thấy chương trình trong trình quản lý tác vụ và xóa nó. Điều này sẽ hoàn toàn bỏ qua thủ thuật Forms.OnClosing và tắt ứng dụng của bạn một cách thô lỗ. Không có gì bạn có thể làm để ngăn chặn điều này.

Bạn có thể cho chúng tôi biết thêm một chút ngữ cảnh về lý do bạn muốn thực hiện điều này không?

3

Không dễ dàng như trình quản lý tác vụ hoặc tắt máy là đủ để dừng tác vụ, tuy nhiên, bạn có viết ứng dụng dưới dạng Dịch vụ hay không ít nhất nó sẽ không được đặt trên màn hình với "x" hấp dẫn để mọi người đánh?

EDIT: Dựa trên nhận xét của bạn. Ứng dụng bảng điều khiển yêu cầu đầu vào của người dùng mà bạn không thể viết lại sẽ luôn có thể đóng được bằng "x".

Việc viết lại dưới dạng dịch vụ không phải là một nhiệm vụ lớn. Một dịch vụ thực sự không có gì hơn là một tệp thực thi với một số mã trình bao bọc.

Khó khăn đi kèm với đầu vào của người dùng. Tuy nhiên, bạn có thể viết chuỗi chạy dài của mình dưới dạng dịch vụ nhưng vẫn có ứng dụng giao diện điều khiển để chuyển hướng dẫn để chạy chuỗi.

Ngoài ra, nếu bạn chỉ muốn ngăn mọi người vô tình nhấn "x", tại sao không điền 10 dòng đầu tiên của ứng dụng bảng điều khiển với "QUY TRÌNH QUAN TRỌNG KHÔNG ĐÓNG !!"

+0

1. Không muốn viết lại 2. Dịch vụ không tốt theo nhu cầu nhập của người dùng – SillyMonkey

1

Có cách nào để ngăn ứng dụng .NET console không bị đóng không?

No. Bạn có thể chặn điều khiển-C (xem sự kiện Console.CancelKeyPress), nhưng không kiểm soát ngắt.

Nếu bạn cần điều gì đó khó ngăn bạn cần xem xét việc tạo dịch vụ Windows, với ACL để chặn nó bị dừng (ngoại trừ hệ thống ... để hệ thống có thể tắt).

Bổ sung: Nếu tương tác người dùng là bắt buộc, sau đó chia ứng dụng thành hai phần. Một dịch vụ tiếp tục chạy, để lộ một điểm vào liên tục. Và một giao diện người dùng cung cấp khả năng tương tác và sử dụng các giao tiếp liên ngành để giao tiếp với dịch vụ.

2

Tại sao bạn không viết lối vào Winforms nhỏ? Việc cung cấp phản hồi trực quan dễ dàng hơn khi người dùng đóng.Bạn có thể tắt các nút giảm thiểu/tối đa/đóng.

Ý tôi là, không có hình phạt trong việc điều hành một ứng dụng winforms superthin có thể thực hiện công cụ của bạn.

tôi giả sử bạn đang ở trên Windows, nhưng nếu điều này là Mono.NET bạn có thể sử dụng GTK hoặc tương đương.

0

tôi sẽ không ngăn chặn người dùng từ thoát khỏi chương trình. Những gì tôi sẽ làm là cung cấp cho họ một cảnh báo khi bạn bắt đầu quá trình nói rằng "Điều này có thể mất vài phút. Xin vui lòng chờ ..."

Sau đó, nếu họ quyết định giết nó họ giết nó.

Cá nhân tôi không thích nó khi một quá trình mất đi kiểm soát quá nhiều từ tôi.

0
[DllImport("Kernel32")] 
    public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add); 

    // An enumerated type for the control messages 
    // sent to the handler routine. 
    public enum CtrlTypes 
    { 
     CTRL_C_EVENT = 0, 
     CTRL_BREAK_EVENT, 
     CTRL_CLOSE_EVENT, 
     CTRL_LOGOFF_EVENT = 5, 
     CTRL_SHUTDOWN_EVENT 
    } 

    // A delegate type to be used as the handler routine 
    // for SetConsoleCtrlHandler. 
    public delegate bool HandlerRoutine(CtrlTypes CtrlType); 

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType) 
    { 
     Trace.WriteLine("** Received termination event : " + ctrlType.ToString()); 
     return true; 
    } 

    static void Main(string[] args) 
    { 

     SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true); 

    } 
Các vấn đề liên quan