2009-10-06 40 views
18

liên quan:
Should I include a command line mode in my applications?
How to grab parent process standard output?
Can a console application detect if it has been run from Explorer?Có thể xây dựng một ứng dụng Console không hiển thị cửa sổ bảng điều khiển khi nhấp đúp không?

Tôi muốn xây dựng một ứng dụng giao diện điều khiển, đó là bình thường chạy từ dòng lệnh.

Nhưng, khi nó được nhấp đúp từ bên trong Explorer (trái với việc chạy từ dấu nhắc cmd.exe) thì tôi muốn chương trình KHÔNG hiển thị cửa sổ bảng điều khiển.

Tôi muốn tránh điều này:

alt text http://i36.tinypic.com/1088p5s.jpg

Có thể?

EDIT Tôi đoán một cách khác để hỏi nó là, là nó có thể cho một chương trình để biết làm thế nào nó đã được gọi - cho dù bằng cách double-click hoặc bằng dòng lệnh?

Tôi đang làm việc trong .NET, trên Windows.

CHỈNH SỬA 2: Từ this Old New Thing blog post Tôi đã học được một số nội dung hay. Dưới đây là những gì tôi biết bây giờ ...

Trong Windows, các tệp EXE được đánh dấu là GUI hoặc không phải GUI. Với csc.exe, điều này được chọn với /target:winexe hoặc /target:exe. Trước khi lệnh đầu tiên trong tiến trình thực thi, hạt nhân Windows thiết lập môi trường thực thi. Tại thời điểm đó, nếu EXE được đánh dấu GUI, hạt nhân thiết lập stdin/stdout cho tiến trình thành NULL, và nếu non-GUI (dòng lệnh) hạt nhân tạo một bảng điều khiển và đặt stdin/stdout cho quá trình đó giao diện điều khiển.

Khi khởi chạy quá trình, nếu không có stdin/stdout (== /target:winexe), thì cuộc gọi sẽ trả về ngay lập tức. Vì vậy, khởi chạy một ứng dụng gui từ một cmd.exe, bạn sẽ ngay lập tức nhận được nhắc nhở cmd của bạn trở lại. Nếu có một stdin/stdout, và nếu chạy từ cmd.exe, thì cmd.exe cha mẹ chờ quá trình thoát.

"Trả về ngay lập tức" rất quan trọng vì nếu bạn mã ứng dụng GUI để đính kèm vào bảng điều khiển của cha mẹ, bạn có thể thực hiện giao diện điều khiển.vv. Nhưng lời nhắc cmd.exe đang hoạt động. Người dùng có thể gõ lệnh mới, bắt đầu một quy trình mới, v.v. Nói cách khác, từ một winexe, chỉ cần gắn vào bảng điều khiển cha với AttachConsole(-1) sẽ không "biến nó thành" một ứng dụng giao diện điều khiển.


Tại thời điểm này tôi nghĩ rằng cách duy nhất để cho phép ứng dụng sử dụng giao diện điều khiển nếu nó được gọi từ cmd.exe, và KHÔNG sử dụng nó nếu nó là kích đúp, là để xác định exe như một bảng điều khiển thông thường exe (/target:exe) và ẩn cửa sổ khi khởi động nếu thích hợp. Bạn vẫn nhận được một cửa sổ giao diện điều khiển xuất hiện một thời gian ngắn.

Tôi vẫn chưa tìm ra cách để biết liệu nó đã được khởi chạy từ trình thám hiểm hay cmd.exe, nhưng tôi đang tiến gần hơn ..


TRẢ LỜI

Nó không phải là có thể xây dựng một ứng dụng giao diện điều khiển không hiển thị một cửa sổ giao diện điều khiển.

là có thể để tạo ứng dụng bảng điều khiển ẩn cửa sổ của ứng dụng rất nhanh, nhưng không quá nhanh đến mức cửa sổ không bao giờ xuất hiện.

Bây giờ, để xác định xem một ứng dụng giao diện điều khiển đã được đưa ra từ nhà thám hiểm, một số người đã đề nghị phải nhìn vào giao diện điều khiển nó đang chạy trong
(từ mgb's answer, và KB article 99115):

int left = Console.CursorLeft; 
    int top = Console.CursorTop; 
    bool ProcessWasRunFromExplorer = (left==0 && top==0); 

này cho quý vị nếu quá trình này đã được khởi chạy trong bảng điều khiển của riêng nó, nhưng không phải là nó là nhà thám hiểm. Một cú nhấp đúp trong thám hiểm sẽ làm điều này, nhưng cũng là một Start.Process() từ bên trong một ứng dụng sẽ làm điều tương tự.

Nếu bạn muốn đối xử với những tình huống khác nhau, sử dụng này để tìm hiểu tên của quá trình cha mẹ:

System.Console.WriteLine("Process id: {0}", Process.GetCurrentProcess().Id); 
    string name = Process.GetCurrentProcess().ProcessName ; 
    System.Console.WriteLine("Process name: {0}", name); 
    PerformanceCounter pc = new PerformanceCounter("Process", "Creating Process Id", name); 
    Process p = Process.GetProcessById((int)pc.RawValue); 
    System.Console.WriteLine("Parent Process id: {0}", p.Id); 
    System.Console.WriteLine("Parent Process name: {0}", p.ProcessName); 

    // p.ProcessName == "cmd" or "Explorer" etc 

Để ẩn cửa sổ một cách nhanh chóng sau khi quá trình này được đưa ra, sử dụng này:

private static readonly int SW_HIDE= 0; 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); 

    .... 
    { 
    IntPtr myHandle = Process.GetCurrentProcess().MainWindowHandle; 
    ShowWindow(myHandle, SW_HIDE); 
    } 

Nếu bạn sản xuất winexe (ứng dụng WinForms) và tùy chọn đính kèm vào bảng điều khiển chính khi thích hợp với AttachConsole(-1), bạn không nhận được tương đương với ứng dụng bảng điều khiển thông thường. Đối với một winexe, quá trình cha mẹ (như cmd.exe) sẽ trở lại dấu nhắc lệnh ngay lập tức sau khi bắt đầu một ứng dụng GUI. Nói cách khác, dấu nhắc lệnh đang hoạt động và sẵn sàng cho đầu vào trong khi quá trình vừa được khởi chạy có thể phát ra đầu ra. Điều này là khó hiểu và có lẽ chỉ hữu ích để gỡ lỗi các ứng dụng winforms.

Điều này phù hợp với tôi.

+0

Bạn muốn thay vào đó làm gì? –

+0

Tôi muốn nó vô hình. – Cheeso

+0

Kiểm tra để xác định xem chương trình đã được khởi động trong bảng điều khiển của riêng nó có sai không. Việc nhập 'cls & program.exe' vào dòng lệnh sẽ báo lỗi rằng chương trình đã được bắt đầu trong giao diện điều khiển của riêng nó. Bạn có thể làm điều tương tự từ một tập tin thực thi. Có khả năng có nhiều cách khác để đánh bại bài kiểm tra. –

Trả lời

4

Chỉ cần tạo ứng dụng dưới dạng ứng dụng Windows Forms, nhưng đừng cho GUI. Thật không may sau đó bạn sẽ không nhận được bất kỳ đầu ra giao diện điều khiển khi nó chạy từ dòng lệnh, hoặc là ... là một vấn đề?

+0

Hmm, tôi biết cách làm việc xung quanh * đó *. Cảm ơn! – Cheeso

+0

Suy nghĩ về điều này nhiều hơn một chút, tôi không nghĩ rằng điều này sẽ làm việc. Tôi biết làm thế nào để làm cho một EXE hoặc một ứng dụng giao diện điều khiển hoặc một ứng dụng WinForms lúc chạy, sử dụng pinvoke trên AttachConsole(). Nhưng tôi không biết làm thế nào để xác định khi nào để làm cho nó một ứng dụng giao diện điều khiển hoặc một ứng dụng Winforms. Tôi không biết làm thế nào để phát hiện nếu nó được lauched bởi một nhấp đúp chuột trong thám hiểm, hoặc đưa ra từ một cửa sổ giao diện điều khiển. – Cheeso

+0

Tại sao không sử dụng đối số dòng lệnh để chọn chế độ hiển thị bảng điều khiển? Bằng cách đó khi chạy từ Explorer, nó sẽ không có một; trừ khi bạn tạo một phím tắt và thêm đối số ở đó - cho phép bạn có cả hai có và không có bàn điều khiển khởi chạy từ Explorer. – Clifford

0

Điều này có giống với Dịch vụ hơn không?

HOẶC

gì về một ứng dụng Windows Forms mà không có một hình thức có thể nhìn thấy? Nó sẽ vẫn hiển thị trong danh sách các trình quản lý tác vụ.

5

cụ Vì vậy, tôi đã viết bằng cả hai một giao diện và một CLI. Phần cứng đã tìm ra cái nào để mở - trong trường hợp của chúng tôi, mặc dù, phiên bản CLI đã yêu cầu các thông số, vì vậy tôi chỉ cần mở GUI nếu không có bất kỳ tham số nào. Sau đó, nếu họ muốn một bảng điều khiển, hãy gọi một chức năng trông giống như sau:

private const int ATTACH_PARENT_PROCESS = -1; 
private const int ERROR_INVALID_HANDLE = 6; 
[DllImport("kernel32.dll", SetLastError = true)] 
static extern bool AttachConsole(int dwProcessId); 
[DllImport("kernel32.dll")] 
static extern bool AllocConsole(); 
[DllImport("kernel32.dll")] 
static extern bool FreeConsole(); 

private static bool StartConsole() 
{ 
    if (!AttachConsole(ATTACH_PARENT_PROCESS)) // try connecting to an existing console 
    { 
     if (Marshal.GetLastWin32Error() == ERROR_INVALID_HANDLE) // we don't have a console yet 
     { 
      if (!AllocConsole()) // couldn't create a new console, either 
       return false; 
     } 
     else 
      return false; // some other error 
    } 
    return true; 
} 

Trả lại xem bảng điều khiển đã được tạo chưa. Đừng quên FreeConsole() khi bạn đã hoàn tất!

Trong trường hợp của chúng tôi, tất nhiên, nếu chúng ta không tạo bảng điều khiển, chúng tôi tạo GUI. Tuy nhiên, cũng dễ dàng tạo giao diện điều khiển hoặc không có giao diện người dùng.

EDIT: Điều đó hoàn toàn không trả lời được câu hỏi trong bản chỉnh sửa không có ở đó khi tôi bắt đầu viết, tất nhiên. Khác hơn là hack của chúng tôi đã chỉ kiểm tra xem nó được gọi là với các tham số dòng lệnh hay không.

+0

Điều này hữu ích - nó cho phép tôi tạo một ứng dụng bảng điều khiển hoặc không phải lúc chạy. Điều quan trọng là, làm thế nào để xác định xem một giao diện điều khiển có mặt không. Tôi nghĩ rằng đó là AttachConsole (-1), nhưng ngay cả khi trả về 0, tôi không biết làm thế nào để ngăn chặn giao diện điều khiển khi nó không có mặt. Tôi sẽ phải thử một vài thứ. cảm ơn – Cheeso

0

Tôi đã không đọc tất cả mọi thứ qua, nhưng chuyện này lại (một chút thời gian trước, thử nghiệm nhiều hơn cần thiết):

DWORD proc[2],procsfound=GetConsoleProcessList(proc,ELEMS(proc)); 
if (procsfound>1) 
// I'm started as a command in cmd.exe 
else 
// started from explorer or other non-console parent 

IFF có nhiều hơn một proc đính kèm, tôi cần phải khôi phục lại giao diện điều khiển mà tôi thao túng , nếu không thì không. Có thể hữu ích, ít nhất đó là sự đơn giản. Bắt đầu mã từ VS sẽ mang lại một hệ thống đính kèm duy nhất, chạy nó từ commandprompt đã kích hoạt nhánh để dọn dẹp đống lộn xộn của tôi. Btw, giao diện điều khiển được khởi chạy từ trình khám phá hoặc ứng dụng không phải bàn điều khiển khác sẽ có tiêu đề không có độ dài bằng 0?

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