有没有办法在Windows应用程序中显示控制台?
我想做这样的事情:
static class Program { [STAThread] static void Main(string[] args) { bool consoleMode = Boolean.Parse(args[0]); if (consoleMode) { Console.WriteLine("consolemode started"); // ... } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
Igal Serban.. 76
你想要做的事情是不可能的.有一个类似的问题,所以看看答案.
然后还有一个疯狂的方法(网站关闭 - 这里备份.)由Jeffrey Knight编写:
问题:如何创建可在GUI(Windows)模式或命令行/控制台模式下运行的应用程序?
从表面上看,这似乎很简单:您创建一个控制台应用程序,向其添加一个窗体,然后您就可以开始运行了.但是,有一个问题:
问题:如果你在GUI模式下运行,你最终会在后台潜伏一个窗口和一个讨厌的控制台,你没有办法隐藏它.
人们似乎想要的是一个真正的两栖动物应用程序,可以在任何一种模式下顺利运行.
如果你将其分解,实际上有四个用例:
User starts application from existing cmd window, and runs in GUI mode User double clicks to start application, and runs in GUI mode User starts application from existing cmd window, and runs in command mode User double clicks to start application, and runs in command mode.我发布代码来做到这一点,但有一点需要注意.
我实际上认为这种方法会让你在路上遇到更多麻烦而不是它的价值.例如,您将必须有两个不同的UI' - 一个用于GUI,一个用于命令/ shell.你将不得不构建一些奇怪的中央逻辑引擎,它从GUI和命令行中抽象出来,而且它会变得奇怪.如果是我,我会退后一步思考如何在实践中使用它,以及这种模式切换是否值得工作.因此,除非有一些特殊情况需要它,否则我不会自己使用这个代码,因为一旦我遇到需要API调用才能完成某些事情的情况,我倾向于停下来问自己"我是不是太复杂了? ".
输出类型= Windows应用程序
using System; using System.Collections.Generic; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; using Microsoft.Win32; namespace WindowsApplication { static class Program { /* DEMO CODE ONLY: In general, this approach calls for re-thinking your architecture! There are 4 possible ways this can run: 1) User starts application from existing cmd window, and runs in GUI mode 2) User double clicks to start application, and runs in GUI mode 3) User starts applicaiton from existing cmd window, and runs in command mode 4) User double clicks to start application, and runs in command mode. To run in console mode, start a cmd shell and enter: c:\path\to\Debug\dir\WindowsApplication.exe console To run in gui mode, EITHER just double click the exe, OR start it from the cmd prompt with: c:\path\to\Debug\dir\WindowsApplication.exe (or pass the "gui" argument). To start in command mode from a double click, change the default below to "console". In practice, I'm not even sure how the console vs gui mode distinction would be made from a double click... string mode = args.Length > 0 ? args[0] : "console"; //default to console */ [DllImport("kernel32.dll", SetLastError = true)] static extern bool AllocConsole(); [DllImport("kernel32.dll", SetLastError = true)] static extern bool FreeConsole(); [DllImport("kernel32", SetLastError = true)] static extern bool AttachConsole(int dwProcessId); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); [STAThread] static void Main(string[] args) { //TODO: better handling of command args, (handle help (--help /?) etc.) string mode = args.Length > 0 ? args[0] : "gui"; //default to gui if (mode == "gui") { MessageBox.Show("Welcome to GUI mode"); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else if (mode == "console") { //Get a pointer to the forground window. The idea here is that //IF the user is starting our application from an existing console //shell, that shell will be the uppermost window. We'll get it //and attach to it IntPtr ptr = GetForegroundWindow(); int u; GetWindowThreadProcessId(ptr, out u); Process process = Process.GetProcessById(u); if (process.ProcessName == "cmd" ) //Is the uppermost window a cmd process? { AttachConsole(process.Id); //we have a console to attach to .. Console.WriteLine("hello. It looks like you started me from an existing console."); } else { //no console AND we're in console mode ... create a new console. AllocConsole(); Console.WriteLine(@"hello. It looks like you double clicked me to start AND you want console mode. Here's a new console."); Console.WriteLine("press any key to continue ..."); Console.ReadLine(); } FreeConsole(); } } } }
我发现微软很讽刺它以及如何为它的所有API创建C#接口,但是没有C#方法来执行这么简单的任务. (12认同)
我建议使用`-1`(API常量`ATTACH_PARENT_PROCESS`的值)调用`AttachConsole`,而不是希望前台窗口是要写入的正确命令窗口. (5认同)
您可以使用winapi获取当前进程的父进程ID,而不是依赖于作为前台窗口的控制台:http://stackoverflow.com/a/3346055/855432 (2认同)
截至撰写本文时,该文章的备份副本可在此处获取http://web.archive.org/web/20111227234507/http://www.rootsilver.com/2007/08/how-to-create-a -consolewindow (2认同)
嗨!我发现如果我从像Far这样的shell运行这个解决方案,它会创建新的控制台.如果我像cmd一样附加到远程控制台,那就错了.我建议创建ConsoleApplication,如果需要GUI,则执行FreeConsole(); 优秀的文章!谢谢! (2认同)
小智.. 66
这有点旧(好吧,它很老),但我现在正在做同样的事情.这是一个非常简单的解决方案,对我有用:
[DllImport("kernel32.dll", SetLastError = true)] static extern bool AllocConsole(); [DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); const int SW_HIDE = 0; const int SW_SHOW = 5; public static void ShowConsoleWindow() { var handle = GetConsoleWindow(); if (handle == IntPtr.Zero) { AllocConsole(); } else { ShowWindow(handle, SW_SHOW); } } public static void HideConsoleWindow() { var handle = GetConsoleWindow(); ShowWindow(handle, SW_HIDE); }
工作比接受的答案要好得多. (6认同)
如果您在cmd窗口中运行它,这将打开另一个控制台窗口,这在自动化过程中不需要捕获控制台输出. (4认同)
ICR.. 18
最简单的方法是启动WinForms应用程序,转到设置并将类型更改为控制台应用程序.
你想要做的事情是不可能的.有一个类似的问题,所以看看答案.
然后还有一个疯狂的方法(网站关闭 - 这里备份.)由Jeffrey Knight编写:
问题:如何创建可在GUI(Windows)模式或命令行/控制台模式下运行的应用程序?
从表面上看,这似乎很简单:您创建一个控制台应用程序,向其添加一个窗体,然后您就可以开始运行了.但是,有一个问题:
问题:如果你在GUI模式下运行,你最终会在后台潜伏一个窗口和一个讨厌的控制台,你没有办法隐藏它.
人们似乎想要的是一个真正的两栖动物应用程序,可以在任何一种模式下顺利运行.
如果你将其分解,实际上有四个用例:
User starts application from existing cmd window, and runs in GUI mode User double clicks to start application, and runs in GUI mode User starts application from existing cmd window, and runs in command mode User double clicks to start application, and runs in command mode.我发布代码来做到这一点,但有一点需要注意.
我实际上认为这种方法会让你在路上遇到更多麻烦而不是它的价值.例如,您将必须有两个不同的UI' - 一个用于GUI,一个用于命令/ shell.你将不得不构建一些奇怪的中央逻辑引擎,它从GUI和命令行中抽象出来,而且它会变得奇怪.如果是我,我会退后一步思考如何在实践中使用它,以及这种模式切换是否值得工作.因此,除非有一些特殊情况需要它,否则我不会自己使用这个代码,因为一旦我遇到需要API调用才能完成某些事情的情况,我倾向于停下来问自己"我是不是太复杂了? ".
输出类型= Windows应用程序
using System; using System.Collections.Generic; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; using Microsoft.Win32; namespace WindowsApplication { static class Program { /* DEMO CODE ONLY: In general, this approach calls for re-thinking your architecture! There are 4 possible ways this can run: 1) User starts application from existing cmd window, and runs in GUI mode 2) User double clicks to start application, and runs in GUI mode 3) User starts applicaiton from existing cmd window, and runs in command mode 4) User double clicks to start application, and runs in command mode. To run in console mode, start a cmd shell and enter: c:\path\to\Debug\dir\WindowsApplication.exe console To run in gui mode, EITHER just double click the exe, OR start it from the cmd prompt with: c:\path\to\Debug\dir\WindowsApplication.exe (or pass the "gui" argument). To start in command mode from a double click, change the default below to "console". In practice, I'm not even sure how the console vs gui mode distinction would be made from a double click... string mode = args.Length > 0 ? args[0] : "console"; //default to console */ [DllImport("kernel32.dll", SetLastError = true)] static extern bool AllocConsole(); [DllImport("kernel32.dll", SetLastError = true)] static extern bool FreeConsole(); [DllImport("kernel32", SetLastError = true)] static extern bool AttachConsole(int dwProcessId); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); [STAThread] static void Main(string[] args) { //TODO: better handling of command args, (handle help (--help /?) etc.) string mode = args.Length > 0 ? args[0] : "gui"; //default to gui if (mode == "gui") { MessageBox.Show("Welcome to GUI mode"); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else if (mode == "console") { //Get a pointer to the forground window. The idea here is that //IF the user is starting our application from an existing console //shell, that shell will be the uppermost window. We'll get it //and attach to it IntPtr ptr = GetForegroundWindow(); int u; GetWindowThreadProcessId(ptr, out u); Process process = Process.GetProcessById(u); if (process.ProcessName == "cmd" ) //Is the uppermost window a cmd process? { AttachConsole(process.Id); //we have a console to attach to .. Console.WriteLine("hello. It looks like you started me from an existing console."); } else { //no console AND we're in console mode ... create a new console. AllocConsole(); Console.WriteLine(@"hello. It looks like you double clicked me to start AND you want console mode. Here's a new console."); Console.WriteLine("press any key to continue ..."); Console.ReadLine(); } FreeConsole(); } } } }
这有点旧(好吧,它很老),但我现在正在做同样的事情.这是一个非常简单的解决方案,对我有用:
[DllImport("kernel32.dll", SetLastError = true)] static extern bool AllocConsole(); [DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); const int SW_HIDE = 0; const int SW_SHOW = 5; public static void ShowConsoleWindow() { var handle = GetConsoleWindow(); if (handle == IntPtr.Zero) { AllocConsole(); } else { ShowWindow(handle, SW_SHOW); } } public static void HideConsoleWindow() { var handle = GetConsoleWindow(); ShowWindow(handle, SW_HIDE); }
最简单的方法是启动WinForms应用程序,转到设置并将类型更改为控制台应用程序.
有一种方法可以实现这一点,这很简单,但我不建议这是一个很好的方法,你会让别人看到的应用程序.但是如果你有一些开发人员需要同时显示控制台和windows窗体,那么它可以很容易地完成.
此方法还支持仅显示控制台窗口,但不支持仅显示Windows窗体 - 即始终显示控制台.您只能交互(即接收数据- ,Console.ReadLine()
)Console.Read()
与控制台窗口,如果你不显示Windows窗体; 输出到控制台 - Console.WriteLine()
- 在两种模式下都有效.
这是按原样提供的; 不能保证这不会在以后做一些可怕的事情,但确实有效.
从标准的控制台应用程序开始.
将Main
方法标记为[STAThread]
将项目中的引用添加到System.Windows.Forms
将Windows 窗体添加到项目中.
将标准Windows启动代码添加到您的Main
方法:
您将拥有一个显示控制台和可选Windows窗体的应用程序.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace ConsoleApplication9 { class Program { [STAThread] static void Main(string[] args) { if (args.Length > 0 && args[0] == "console") { Console.WriteLine("Hello world!"); Console.ReadLine(); } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace ConsoleApplication9 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Click(object sender, EventArgs e) { Console.WriteLine("Clicked"); } } }
再次复活一个非常老的线程,因为这里的答案都不适合我.
我找到了一种看似非常健壮和简单的简单方法.它对我有用.想法:
将项目编译为Windows应用程序.可执行文件启动时可能有父控制台,但可能没有.目标是重新使用现有控制台(如果存在),或者如果不存在则创建新控制台.
AttachConsole(-1)将查找父进程的控制台.如果有一个,它会附加到它,你就完成了.(我试过这个,从cmd调用我的应用程序时它工作正常)
如果AttachConsole返回false,则没有父控制台.使用AllocConsole创建一个.
例:
static class Program { [DllImport( "kernel32.dll", SetLastError = true )] static extern bool AllocConsole(); [DllImport( "kernel32", SetLastError = true )] static extern bool AttachConsole( int dwProcessId ); static void Main(string[] args) { bool consoleMode = Boolean.Parse(args[0]); if (consoleMode) { if (!AttachConsole(-1)) AllocConsole(); Console.WriteLine("consolemode started"); // ... } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
需要注意的是:如果您在连接或分配控制台之前尝试写入控制台,这种方法似乎不起作用.我的猜测是你第一次调用Console.Write/WriteLine,如果还没有控制台,那么Windows会自动为你创建一个隐藏的控制台.(所以在您已经写入控制台后,Anthony的ShowConsoleWindow答案可能会更好,如果您尚未写入控制台,我的答案会更好).需要注意的重要一点是,这不起作用:
static void Main(string[] args) { Console.WriteLine("Welcome to the program"); //< this ruins everything bool consoleMode = Boolean.Parse(args[0]); if (consoleMode) { if (!AttachConsole(-1)) AllocConsole(); Console.WriteLine("consolemode started"); //< this doesn't get displayed on the parent console // ... } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } }